
; text type flags

ttText    = 0      ; usual text
ttStr     = 1      ; string
ttComment = 2      ; comment
ttNum     = 3      ; number
ttChar    = 4      ; symbol character


; syntax color indexes.

clDefaultText   = 0
clSymbol        = 1
clNumber        = 2
clString        = 3
clComment       = 4
clRegister      = 5
clInstruction   = 6
clDirective     = 7
clPreprocessor  = 8

SyntaxColorCount = 8 ; 1..8 above.

macro dps [txt] {
    forward
      if txt eq 0
        db 0
      else
        db txt
        db 0
        dw 0
      end if
  }


  struc synList minLen, maxLen, ptrlist {
    .MinLen  dd minLen
    .MaxLen  dd maxLen
    .ptrList dd ptrlist
  }

  virtual at 0
    synList synList 0, 0, 0
  end virtual


proc fasm_syntax, .ptrLine, .ptrColors
.status      dd ?
.wlen        dd ?
.w           rw aeLineCharLen
.lastword    dd ?
.Quo         dw ?       ; the last open quote character

; Sometimes, AsmEdit calls this procedure with wrong ptrLine.
; In these cases GPF appear.

begin
        pushad

        mov     [.status], ttText
        xor     ebx, ebx
        mov     [.wlen], 0
        mov     esi, [.ptrLine]
        mov     edi, [.ptrColors]
        mov     [.lastword], edi
        mov     ecx, aeLineCharLen

        cmp     esi, $ffff         ; sometimes the AsmEdit passes invalid pointer to syntax and it crashes.
        jbe     .end

.loop:
        lodsw

        cmp     [.status], ttComment
        je      .endif

        cmp     [.status], ttStr
        jne     .ifnotstr

        cmp     ax, [.Quo]
        jne     .endif

        mov     [.status], ttText
        jmp     .endif

.ifnotstr:
        cmp     ax, ';'
        jne     .notcomment

        mov     [.status], ttComment
        mov     bl, clComment
        jmp     .endif

.notcomment:
        cmp     ax, '"'
        je      .str
        cmp     ax, "'"
        jne     .notstr

.str:
        mov     [.status], ttStr
        mov     [.Quo], ax
        mov     bl, clString
        jmp     .endif

.notstr:
        test    ah, ah
        jnz     .notsym

        call    .CharInSymbols
        jnc     .notsym

        mov     [.status], ttChar
        mov     bl, clSymbol

        call    .MakeWord
        jmp     .endif

.notsym:
        lea     edx, [esi-aeCharSize]
        cmp     edx, [.ptrLine]
        je      .maybenum               ; the first character

        cmp     [.status], ttChar
        jne     .notnumbeg

.maybenum:
        call    .CharInNum
        jnc     .notnum

        mov      [.status], ttNum
        mov      bl, clNumber
        jmp      .endif

.notnum:
        mov     [.status], ttText

        xor     ebx, ebx
        mov     [.wlen], 2
        mov     [.w], ax
        mov     [.lastword], edi
        jmp     .endif

.notnumbeg:
        cmp     [.status], ttText
        jne     .endif

        lea     ebx, [.w]
        add     ebx, [.wlen]
        mov     [ebx], ax

        xor     ebx, ebx
        add     [.wlen], 2

.endif:
        mov     [edi], bx
        lea     edi, [edi + aeCharSize]
        dec     ecx
        jnz     .loop

        popad
        return



.MakeWord:
        pushad

        cmp     [.wlen],0
        je      .end

        lea     esi, [.w]
        push    esi edi

        lea     edi, [.w]

 .new_char:
        lodsw
        cmp     ax, 0
        je      .ok

        test    ah, ah
        jnz     @f

        cmp     ax,"A"
        jl      @F
        cmp     ax,"Z"
        jg      @F
        add     ax, 20h         ; lower case

@@:
        stosw
        jmp     .new_char

.ok:
        pop     edi esi

        mov     bl, clRegister

        stdcall FindInstr, sSymbols, esi, [.wlen], 2, 0
        jnc     .maybeinstr

        cmp     dl, 10h
        je      .found

        mov     bl, clDirective
        jmp     .found

.maybeinstr:
        mov     bl, clInstruction

        stdcall FindInstr, sInstructions, esi, [.wlen], 3, 1
        jnc     .maybeoperator

        cmp     edx, fasm_instructions - instruction_handler
        jae     .found

        mov     bl, clDirective
        jmp     .found

.maybeoperator:
        mov     bl, clDirective
        stdcall SearchSimple, directive_operators, esi, [.wlen], 1
        jc      .found

        stdcall FindInstr, sDataDirectives, esi, [.wlen], 3, -1
        jc      .found

        mov     bl, clPreprocessor
        stdcall SearchSimple, preprocessor_directives, esi, [.wlen], 2
        jc      .found

        stdcall SearchSimple, macro_directives, esi, [.wlen], 2
        jnc     .notfound

.found:
        mov     ecx, [.wlen]
        mov     edi, [.lastword]

.chgcolor:
        mov     [edi], bx
        lea     edi, [edi+aeCharSize]

        dec     ecx
        jnz     .chgcolor

.notfound:
        and     [.wlen], 0

.end:
        popad
        retn


.CharInSymbols:
        push    edi ecx

        mov     edi, symbol_characters+1
        movzx   ecx, byte [edi-1]

        repne scasb
        jne     @f

        stc
        pop     ecx edi
        ret
@@:
        clc
        pop     ecx edi
        retn


.CharInNum:
        cmp     ax, '$'
        jne     @f
        stc
        retn

@@:
        cmp     ax, '0'
        jb      @f
        cmp     ax, '9'
        ja      @f
        stc
        retn
@@:
        clc
        retn

endp



proc FindInstr, .ptrArray, .ptrWord, .len, .addbytes, .return
.count dd ?
begin

        push    eax ebx ecx esi edi

        sar     [.len], 1

        mov     ecx, [.ptrArray]
        mov     edi, [.ptrWord]
        mov     edx, [.len]

        cmp     edx, [ecx+synList.MinLen]
        jb      .notfound

        cmp     edx, [ecx+synList.MaxLen]
        ja      .notfound

        mov     esi, [ecx+synList.ptrList]

        sub     edx, [ecx+synList.MinLen]
        movzx   eax, word [esi+4*edx+2]       ; items count
        mov     [.count], eax
        movzx   ebx, word [esi+4*edx]         ; offset to esi
        add     esi, ebx
        mov     edx, [.len]
        add     edx, [.addbytes]

.loopmain:
        dec     [.count]
        js      .notfound

        xor     ebx, ebx
        xor     eax, eax

.loopword:
        mov     ax, [edi+2*ebx]
        cmp     al, [esi+ebx]
        ja      .next
        jb      .notfound
        inc     ebx
        cmp     ebx, [.len]
        jne     .loopword

        cmp     [.return], 0
        jl      .found

        lea     eax, [esi+ebx]
        add     eax, [.return]

        movsx   edx, word [eax]

.found:
        stc
        jmp     .end

.next:
        add     esi, edx
        jmp     .loopmain

.notfound:
        clc

.end:
        pop     edi esi ecx ebx eax
        return
endp



proc SearchSimple, .ptrList, .ptrWord, .len, .addbytes
.count dd ?
begin
        push    eax ecx edx esi edi

        mov     esi, [.ptrList]

        shr     [.len], 1
        mov     edx, [.len]

.loopmain:
        lodsb
        test    al, al
        jz      .notfound

        cmp     al, dl
        jne     .next

        mov     edi, [.ptrWord]
        movzx   ecx, al

        xor     eax, eax

.cmp:
        lodsb
        cmp     [edi], ax
        lea     edi, [edi+2]
        jne     .nxt

        loop    .cmp
        jmp     .found

.nxt:
        add     esi, ecx
        add     esi, [.addbytes]
        jmp     .loopmain

.next:
        movzx   eax, al
        lea     esi, [esi+eax]
        add     esi, [.addbytes]
        jmp     .loopmain

.found:
        stc
        jmp     .end

.notfound:
        clc
.end:
        pop     edi esi edx ecx eax
        return
endp





iglobal
  sInstructions   synList 2, 16, instructions
  sSymbols        synList 1, 11, symbols
  sDataDirectives synList 2, 4, data_directives
endg
