flat assembler
Message board for the users of flat assembler.

Index > Tutorials and Examples > Custom Source Code Viewer

Author
Thread Post new topic Reply to topic
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 07 Feb 2013, 04:35
Preview:
Image
Image
Download: http://sungod777.zxq.net/codeview.zip

How-To: Scroll: Mouse, wheel, UP/DOWN keys. Next theme: Right click. Select File: LEFT/RIGHT keys
Post 07 Feb 2013, 04:35
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4354
Location: Now
edfed 07 Feb 2013, 10:34
coool

but at least, under windows, it would be better to render in a window.

the over use of gradient is a bit too much also. Smile

the scroll bars are "bugged" in a sense that if you hold the clic button and goes out the scroll bar, you should continue to interact with the cursor.
Post 07 Feb 2013, 10:34
View user's profile Send private message Visit poster's website Reply with quote
HaHaAnonymous



Joined: 02 Dec 2012
Posts: 1178
Location: Unknown
HaHaAnonymous 07 Feb 2013, 12:23
[ Post removed by author. ]


Last edited by HaHaAnonymous on 28 Feb 2015, 21:41; edited 1 time in total
Post 07 Feb 2013, 12:23
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1708
Location: Toronto, Canada
AsmGuru62 07 Feb 2013, 17:31
When every little item on screen is gradiented -- it does not look good.
Or maybe it is just me?
Post 07 Feb 2013, 17:31
View user's profile Send private message Send e-mail Reply with quote
HaHaAnonymous



Joined: 02 Dec 2012
Posts: 1178
Location: Unknown
HaHaAnonymous 07 Feb 2013, 17:45
[ Post removed by author. ]


Last edited by HaHaAnonymous on 28 Feb 2015, 21:39; edited 2 times in total
Post 07 Feb 2013, 17:45
View user's profile Send private message Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 07 Feb 2013, 23:25
Again, my examples are intended for LL systems/graphics programmers who must write their own everything from scratch.

This example demonstrates how to draw custom text/code manually using my raster FONT.INC engine and no OS-specific code (TextOutA). 100% customizable: Themes, color, fonts, sizes, clarity, etc. You can easily change the entire interface just by editing 1-3 lines and/or by replacing the default font file. Included themes are extreme hypothetical graphics examples and not meant to be used literally.

I offer general ideas, algorithms, sketches and templates, not specific implementations. If I submitted a joystick configuration utility for example, would you complain that it's not a complete game?

Scrollbar was a quick sketch until I finish the custom control. Toolbar was left blank for icons: next, previous, home, search, etc. It will evolve into like a .PDF viewer, book reader or mini web browser. Future versions will feature clear fonts, dynamic zoom and velocity-based scrolling depending on mouse wheel strength.

Thanks for viewing.
Post 07 Feb 2013, 23:25
View user's profile Send private message Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 19 Feb 2013, 17:32
uart777

Your code viewer is impressive from the graphical point of view but I'd like to tell something related rather to its internal structure. Now it's not so much important but when you migrate to real source code editor it may be crucial in some situations. I think you should improve the parsing mechanism because, as I suppose, now the decimal numbers are treated as integral tokens even if they in fact are components of bigger strings such as hex numbers and identifiers, see these screenshots:

Image

Image

Moreover, the assembler keywords shouldn't be distinguished if they are parts of the identifiers:

Image

or, like in the example presented below, parts of the instruction names:

Image

I guess that the parsing mechanism may be changed this way that it would search the longest matches first instead of current "ungreedy" matching, so it would search the tokens in the order presented below:
  1. comments

  2. identifiers

  3. assembler keywords

  4. hex numbers

  5. signed decimal numbers

  6. unsigned decimal numbers
. Smile
Post 19 Feb 2013, 17:32
View user's profile Send private message Visit poster's website Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 21 Feb 2013, 23:39
MHajduk: Updated SYNTAX.INC:

Code:
; $$$$$$$$$$$$$$$ Z77 ASM LIBRARY $$$$$$$$$$$$$$$$
; *************** SUNGOD SOFTWARE ****************
; ????????????????? SYNTAX.INC ???????????????????

; SOURCE CODE WITH SYNTAX HIGHLIGHTING

; font code1-5 is compatible with all resolutions:

; code1: QVGA-VGA
; code2: SVGA-XGA
; code3: >=XGA
; code4/5: HD+

align 4

BOOLEAN in.comment?=NO, in.number?=NO,\
 in.text?=NO, in.name?=NO, in.keyword?=NO

macro reset.in.source {
let [in.comment?]=NO,\
 [in.number?]=NO, [in.text?]=NO,\
 [in.name?]=NO, [in.keyword?]=NO
}

COLOR page.color, code.color, keyword.color,\
 number.color, symbol.color, text.color,\
 comment.color, shade.color

macro set.syntax.colors \
 pc, cc, kc, nc, sc, tc, coc {
let [page.color]=pc, [code.color]=cc,\
 [keyword.color]=kc, [number.color]=nc,\
 [symbol.color]=sc, [text.color]=tc,\
 [comment.color]=coc
get [shade.color]=lightness [page.color], -192
}

macro set.default.syntax.colors {
set.syntax.colors 0FFFFFFh, BLACK, 04040FFh,\
0EF1070h, 08000AFh, 0FF1777h, 0777777h
}

;;;;;;;;;;;;;;;;;; SOURCE THEME ;;;;;;;;;;;;;;;;;;

MESSAGEZ source.themes, source.theme, ST,\
 DEFAULT='Professional',\
 BLUE_CONSOLE='Sexy Blue Console',\
 BLACK_CONSOLE='Classic Black Console',\
 PURPLE_HAZE='Purple Haze',\
 ALIEN_TERMINAL='Alien Terminal'

TEXT source.theme.f='Theme: %t'
macro set.source.theme theme
 { let [source.theme]=theme }

macro next.source.theme {
.if [source.theme]<(ST_LAST-1)
  let [source.theme]++
.else
  let [source.theme]=0
.end
update.source.colors
let [display.theme?]=1
}

macro previous.source.theme {
.if [source.theme]>0
  let [source.theme]--
.else
  let [source.theme]=(ST_LAST-1)
.end
update.source.colors
let [display.theme?]=1
}

; pc, cc, kc, nc, sc, tc, coc

function update.source.colors
.if [source.theme]=0 ; ST_DEFAULT
  jmp .default.colors
.else.if [source.theme]=ST_BLUE_CONSOLE
  set.syntax.colors 40h, WHITE, 000BAFFh,\
  0FFFF77h, 20FF20h, 0B700C7h, 02200FFh
.else.if [source.theme]=ST_BLACK_CONSOLE
  set.syntax.colors BLACK, WHITE, 04057FFh,\
  0B700C7h, 20FF20h, 0FF27A7h, 777777h
  let [shade.color]=GRAY25
.else.if [source.theme]=ST_PURPLE_HAZE
  set.syntax.colors 11032Dh, LILAC, 20FF20h,\
  0B700C7h, 04057FFh, 0FF27A7h, VIOLET
  let [shade.color]=DARK.VIOLET ;PURPLE
.else.if [source.theme]=ST_ALIEN_TERMINAL
  set.syntax.colors BLACK, 10FF10h, WHITE,\
  0D4FF1Fh, 0F9FF0Dh, POWER.BLUE, 137600h
  let [shade.color]=72FF13h
.else
  .default.colors:
  set.default.syntax.colors
.end
endf

;;;;;;;;;;;;;;;;; ASM SOURCE CODE ;;;;;;;;;;;;;;;;

; words to highlight in ASM source

TEXTS asm.keywords[]=\
'!if', '.else', '.else.if', '.end', '.endl',\
'.endw', '.for', '.if', '.loop', '.while',\
'align', 'allocate', 'allocate.p', 'allocate.x',\
'byte', 'close', 'code', 'common', 'create',\
'destiny', 'db', 'dd', 'define', 'destroy', 'dword',\
'draw', 'else', 'end', 'endf', 'equ', 'escape',\
'escape?', 'exit', 'fail', 'fail?', 'false', 'fix',\
'forward', 'function', 'get', 'if', 'include',\
'integer', 'key', 'let', 'local', 'locale', 'locals',\
'macro', 'main', 'match', 'mouse', 'not', 'numeric',\
'omega', 'open', 'origin', 'powers', 'read',\
'render', 'ret', 'return', 'reverse', 'seek',\
'source', 'string', 'token', 'timer', 'true',\
'try', 'use', 'vga', 'virtual', 'word', 'write',\
'ARRAY', 'ASSUME', 'BOOLEAN', 'BOX', 'BYTE',\
'COLOR', 'ENDS', 'FONT', 'IMAGE', 'INFINITE',\
'INHERIT', 'INVALID', 'NO', 'NOTHING', 'NUMBER',\
'TEXT', 'STRUCTURE', 'TYPE', 'VOID', 'WORD', 'YES'

; search alphabetic text array...

function text.array.equal.az, ta, t, n
locals i
let eax=[t]
.loop [i]=0 to [n]
  let eax=[i], eax<<2, eax+[ta]
  text.compare [t], [eax]
  .if not eax
    return [i]
  .end
.endl
@@:
let eax=INVALID
endf

macro .if.asm.keyword {
text.array.equal.az asm.keywords,\
 [token], asm.keywords.$
.if eax not INVALID
}

; a colorful variation of draw.text (FONT)
; that draws Z77 ASM source code...

function draw.asm, t, x, y
locals i, p, c, cx, cy, fc, ix, iy
let eax=&[ix], ecx=&[iy]
text.insets eax, ecx
let eax=[ix], [x]+eax, ecx=[iy], [y]+ecx,\
 eax=[t], [p]=eax, [i]=0, [cy]=[y]

.while byte [eax]      ; draw all characters
  let ecx=[i],\        ; x=i*font.w+x
  ecx*[font.w],\
  ecx+[x], [cx]=ecx,\
  eax=[p],\            ; get c
  eax=>[eax], [c]=eax

  .if eax=0Dh          ; return?
    let [p]++,\        ; skip
    [i]=0,\            ; reset x
    ecx=[font.h],\
    [cy]+ecx,\         ; y+font.h
    [in.comment?]=NO,\
    [in.name?]=NO,\
    [in.keyword?]=NO,\
    ecx=[screen.h]
    .if [cy]>ecx
      escape
    .end
    jmp .next
  .end

  .if [in.comment?]
    let [fc]=[comment.color]
    jmp @f
  .end
  .if [in.text?]
    .if [c] not ''''
      let [fc]=[text.color]
      jmp @f
    .end
  .end
  set.source [p]
  get.token

  .if.is [c], NUMBER
    ; if previous was identifier, skip
    let eax=[p], ecx=>[eax-1]
    .if.c NAME
      jmp @f
    .end
    let [fc]=[number.color]
    jmp @f
  .end

  .if.is [c], SYMBOL
    .if [c]=';' ; comment?
      let [fc]=[comment.color],\
      [in.comment?]=YES
      jmp @f
    .end

    .if [c]='''' ; text?
      let [fc]=[text.color]
      toggle [in.text?]
      jmp @f

    .else
      let [fc]=[symbol.color],\
       [in.keyword?]=NO
      jmp @f
    .end
  .end

  ; if previous character is identifier,
  ; skip keyword check...

  .if [i]
    .if not [in.keyword?]
      let eax=[p], ecx=>[eax-1]
      .if.c NAME
        jmp @f
      .end
    .end
  .end

  .if.asm.keyword ; keyword?
    let [fc]=[keyword.color],\
    [in.keyword?]=YES
    jmp @f
  .end
  .if [in.keyword?]
    .if.is [c], END
      let [in.keyword?]=NO
    .else
      let [fc]=[keyword.color]
      jmp @f
    .end
  .end

  let [fc]=[code.color]  ; default
  @@:
  set.font.color [fc]
  draw.c [c], [cx], [cy] ; draw character
  let [i]++
  .next:
  let [p]++, eax=[p] ; eax=p for while
.endw
endf

function draw.code, t, x, y
.if [parse.type]&(PT_ASM or PT_Z77)
  draw.asm [t], [x], [y]
.else.if [parse.type]&(PT_C or PT_CPP)
  ; draw.cpp [t], [x], [y]
.else.if [parse.type]&PT_HTML
  ; draw.html [t], [x], [y]
.else.if [parse.type]&PT_BASIC
  ; draw.basic [t], [x], [y]
.end
endf

; 2-DO: CUSTOM HELP VIEWER FOR Z77 ASM/INC
; FILES. FORMAT:

; <t>         ; enable text, disable code
; <c>         ; enable code, disable text
; <f='name'>  ; set font style
; <f>         ; restore previous font
; <#000000h>  ; set font color
; <#>         ; restore previous color
; <a=LEFT>    ; set alignment
; <a>         ; restore previous alignment
; <i='name'>  ; insert image
; <b='name'>  ; insert button
; <link='to'> ; start link
; <l>         ; end link
; <s>         ; space
; <r>         ; return
; << >>       ; < >    


PARSE.INC:
Code:
; $$$$$$$$$$$$$$$ Z77 ASM LIBRARY $$$$$$$$$$$$$$$$
; *************** SUNGOD SOFTWARE ****************
; ?????????????????? PARSE.INC ???????????????????

; load.source $file
; set.source $s     ; set source address
; end.source        ; deallocate

; "skip" advances source while or until type.
; "copy" copies source to token then increments
; while type. copy.until.c copies until the
; specified character and while not 0. to copy
; until type, invert the character BITs:
; "while not return" = "until return"

; skip.while type
; skip.until type
; copy.while type
; copy.until.c c

; skip.space   ; skip only spaces and tabs
; skip.comment
; skip.x       ; skip all whitespace, returns
               ; and comments

; copy token from source. return 0 if end
; or unrecognized

; copy.token   ; no skip
; read.token   ; skip *only spaces and tabs
; get.token    ; skip all whites/comments first

; * read.token will only skip returns and
; comments if previous line ends with ,=
; which are continuation symbols

; parse.symbol ; no skip...
; parse.c
; parse.name
; parse.number
; parse.text

align 8

VOID source.type, source.filename,\
source.base, source.last, source.base.last

VOID token
NUMBER token.type, token.class,\
 token.size, token.value, token.index
VOID token.address

NUMBER line.number=1,\
 number.lines

powers PT_ASM, PT_Z77, PT_EZ7, PT_C, PT_CPP,\
 PT_BASIC, PT_HTML, PT_IDENTIFY

NUMBER parse.type=PT_ASM+PT_IDENTIFY

;;;;;;;;;;;;;;;;; SYNTAX ERRORS ;;;;;;;;;;;;;;;;;;

ARRAY syntax.errors(2*KB)
NUMBER se.limit=3

VOID error.t
TEXT error.m='Error (#$line): %t',\
format.t(32)
error.t equ ?t

MESSAGES se.keys,\
SE_KEY_FILE='$file', SE_KEY_LINE='$line',\
SE_KEY_WHY='$why', SE_KEY_TOKEN='$t'

; report error, add message to
; syntax.errors[] array

function _syntax.error, i
locals p, e
let ecx=[se.limit] ; maximum?
.if [syntax.errors.n]>=ecx
  return 0
.end
try [p]=array.expand syntax.errors
text.copy [error.t], error.m
let ecx=[i]
print [p], [error.t], [se.errors+ecx*4]
let eax=[p]
endf

macro syntax.error e { _syntax.error SE_##e }

if used !_syntax.error
MESSAGES se.errors,\
SE_0       ='None',\
SE_SYNTAX  ='Syntax',\
SE_LOAD    ='Load: $file',\
SE_UNEXPECT='$t: Unexpected',\
SE_EXPECTN ='$t: Number expected',\
SE_EXPECTA ='$t: Name expected',\
SE_NAME    ='$t: Invalid name',\
SE_RESERVE ='$t: Reserved name',\
SE_UNDEFINE='$t: Undefined',\
SE_REDEFINE='$t: Redefinition',\
SE_SIZE    ='Invalid size',\
SE_EXPECTT ='$t: Text expected',\
SE_ENDB    ='No end for: $t',\
SE_ENDT    ='Text has no end ''',\
SE_PARENTH ='Unmatched parenthesis',\
SE_PARAMS  ='$t: Invalid # parameter/s',\
SE_PTYPE   ='$t: Invalid parameter type',\
SE_ASSIGN  ='$t: Invalid assignment',\
SE_POINTER ='$t: Invalid pointer syntax'
end if

;;;;;;;;;;;;;;;;;;; KEYWORDS ;;;;;;;;;;;;;;;;;;;;;

; is keyword? return index or INVALID. for case
; sensitive search: set.case 0 before then
; restore it after

function is.keyword, name
locals i
.loop [i]=0 to keywords.$
  let ecx=[i]
  .if.text.equal [name], [keywords+ecx*4]
    return [i]
  .end
.endl
let eax=INVALID
endf

macro .if.keyword name {
is.keyword name
.if eax not INVALID
}

if used !is.keyword
MESSAGES keywords,\
K_CELSE='#else', K_CEND='#end', K_CIF='#if',\
K_ALIAS='alias', K_ALIGN='align',\
K_ARRAY='array', K_ASSUME='assume',\
K_BIT='bit', K_BOOLEAN='boolean',\
K_BYTE='byte', K_CODE='code', K_COLOR='color',\
K_DATA='data', K_DEFINE='define',\
K_DEFINED='defined', K_DRAW='draw',\
K_ELSE='else', K_EMIT='emit', K_END='end',\
K_FONT='font', K_FUNCTION='function', K_IF='if',\
K_IMAGE='image', K_IMPORT='import',\
K_INCLUDE='include', K_INJECT='inject',\
K_INHERIT='inherit', K_INTEGER='integer',\
K_LOOP='loop', K_MACRO='macro',\
K_MODERM='mode.rm', K_NUMBER='number',\
K_NUMERAL='numeral', K_NUMERIC='numeric',\
K_NUMERO='numero', K_POWERS='powers',\
K_REAL='real', K_REAL8='real8', K_RETURN='return',\
K_SIB='sib', K_SYNTAX='syntax', K_TEXT='text',\
K_TYPE='type', K_UNDEFINE='undefine',\
K_UNION='union', K_UNTIL='until', K_USE='use',\
K_USED='used', K_VARIANT='variant',\
K_VOID='void', K_WHILE='while'
end if

;;;;;;;;;;;;;;;;; SET/LOAD SOURCE ;;;;;;;;;;;;;;;;

function set.source, s
.if [s]=INVALID
  return [source]
.end
let eax=[s], [source.last]=[source],\
 [source.base.last]=[source.base],\
 [source]=eax, [source.base]=eax,\
 [line.number]=1
endf

function reset.source
let [source]=[source.last],\
[source.base]=[source.base.last]
endf

function load.source, file
try load.text [file]
set.source eax
let [source.filename]=[file]
endf

function end.source
destroy [source.base]
destroy [token]
endf

;;;;;;;;;;;;;;;;;; SKIP, COPY ;;;;;;;;;;;;;;;;;;;;

; advance source while type. return end
; address or 0

function skip.while, type
let eax=[source]
@@:
 let ecx=>[eax], ecx=>[TT+ecx]
 test ecx, [type]
 jz @f
 let eax++
jmp @b
@@:
let [source]=eax
.if byte [eax]=0
  let eax=0
.end
endf

; advance source until type or 0

function skip.until, type
let eax=[type], not eax
skip.while eax
endf

; copy token=source while type

function copy.while, type
let eax=[source], edx=[token]
@@:
 let ecx=>[eax], ecx=>[TT+ecx]
 test ecx, [type]
 jz @f
 let cl=[eax], [edx]=cl, eax++, edx++
jmp @b
@@:
let [source]=eax, byte [edx]=0
.if byte [eax]=0
  let eax=0
.end
endf

; copy token=source until character and
; while not 0

function copy.until.c, c
let eax=[source], edx=[token]
@@:
 let ecx=>[eax]
 test ecx, ecx
 jz @f
 cmp ecx, [c]
 je @f
 let cl=[eax], [edx]=cl, eax++, edx++
jmp @b
@@:
let [source]=eax, byte [edx]=0
.if byte [eax]=0
  let eax=0
.end
endf

;;;;;;; SKIP WHITESPACE, RETURNS, COMMENTS ;;;;;;;

macro skip.space   { skip.while C_SPACE }
macro skip.white   { skip.while C_WHITE }
macro skip.comment { skip.until C_RETURN }

function skip.x
.skip:
let eax=[source]
.if byte [eax]=0   ; EOF
  let eax=0
  escape
.end
let ecx=>[eax]
.if.c SPACE        ; SPACE
  try skip.space
.end
let eax=[source]
.if byte [eax]=';' ; COMMENT
  try skip.comment
  jmp .skip
.end
let eax=[source]
.if byte [eax]=0Dh ; RETURN?
  let [source]+2,\
  [line.number]++
  jmp .skip
.end
let eax=1
endf

;;;;;;;;;;;;; TOKEN TYPE/VALUE/SIZE ;;;;;;;;;;;;;;

macro set.token.type t  { let [token.type]=C_#t }
macro set.token.class t { let [token.class]=t }
macro set.token.value v { let [token.value]=v }

function get.token.size
cmp [token.value], 255
jg .32
cmp [token.value], -128
jl .32
let [token.size]=8
jmp .8
.32: let [token.size]=32
.8:
endf

macro .if.token.is t
{ .if [token.type]=C_#t }
macro .if.token.is.not t
{ .if [token.type] not C_#t }
macro .else.if.token.is t
{ .else.if [token.type]=C_#t }

;;;;;;;;;;;; COPY NAME/NUMBER/TEXT/ETC ;;;;;;;;;;;

function parse.symbol
set.token.type SYMBOL
let eax=[source], edx=[token],\
 cl=[eax], [edx]=cl, eax++, edx++,\
 ecx&0FFh, [token.value]=ecx,\
 [source]=eax, byte [edx]=0,\
eax=C_SYMBOL
endf

function parse.text
let eax=[source], eax++,\ ; past '
 edx=[token]
.while byte [eax]
  let ecx=>[eax]
  .if ecx=27h             ; '
    .if byte [eax+1]=27h  ; 2 '' for I''m
      let ecx=27h         ; can''t, etc
    .else
      jmp @f
    .end
  .end
  .get:
  let [edx]=cl, eax++, edx++
.endw
.if byte [eax]=0     ; end not found
  let [source]=eax,\
  byte [edx]=0
  syntax.error ENDT  ; 'Text has no end'
  return 0
.end
@@:
.if ecx=27h
  let eax++
.end
set.token.type TEXT
let [source]=eax, byte [edx]=0,\
eax=C_TEXT
endf

function parse.number
locals n, c, b, s
copy.while C_DIGIT
let eax=[source],\
 ecx=>[eax-1],\        ; get last character
 [c]=ecx, [b]=[BASE],\ ; save current base
 [BASE]='n'            ; default signed decimal
.if.c NUMBER           ; ends with 0-9?
  jmp .convert
.end
cmp ecx, 'h'           ; hexadecimal
je .base
cmp ecx, 'b'           ; binary
je .base
cmp ecx, 'k'           ; kilobyte
je .x
cmp ecx, 'm'           ; megabyte
je .x
jmp .error             ; unrecognized
.base:
let [BASE]=ecx         ; reset base
.x:                    ; remove suffix
let byte [edx-1]=0
.convert:              ; convert to number
get [n]=t2n [token]
let [BASE]=[b]         ; restore previous base
.if [c]='k'
  shl [n], 10          ; k=n*1024
.else.if [c]='m'
  shl [n], 20          ; m=n*1048576
.end
set.token.type NUMBER
set.token.value [n]
get.token.size
let eax=C_NUMBER
escape
.error: let eax=0
endf

function parse.name
try copy.while C_NAME
.if [parse.type]&PT_IDENTIFY
  call !identify.name
.end
let eax=[token.type]
endf

; copy.token - copy next token from source.
; numbers must begin with 0-9 and may contain
; A-F/a-f and end with h/b/k/m/H/B/K/M.
; names/identifiers may consist of A-Z, 0-9
; or _.?!@$ but cannot begin with a number.
; examples:

; numbers: 7Fh, 0AAh, 1010b, 64k (65536)
; names: ?image.p, @color, $file, clear_screen?

; hex numbers that begin with letters must be
; prefixed with 0 (0FFh)

; '-' is recognized as a generic symbol. it can
; have different meanings: -(aINVALID-c--).
; the expression parser distinguishes between
; unary, negative, subtract or decrement
; depending on the context

function copy.token
set.token.type 0
set.token.class 0
set.token.value 0
let eax=[source]
.if byte [eax]=0
  jmp .r0
.end
let ecx=>[eax]
.if.c NUMBER
  parse.number
  return
.end
.if.c SYMBOL
  .if ecx=27h  ; '
    parse.text
    return
  .end
  parse.symbol
  return
.end
.if.c NAME
  parse.name
  return
.end
.r0: let eax=0
endf

; skip spaces and tabs then copy token.
; this will only skip return\s and comments
; if previous line ends with ,= which are
; continuation symbols

function read.token
cmp [token], ','
je .skip.x
cmp [token], '='
jne .skip.s
.skip.x: try skip.x
jmp .copy
.skip.s: try skip.space
.copy: copy.token
endf

; skip all whitespace, returns and comments
; then copy token

function get.token
try skip.x
copy.token
endf

macro .if.token.equal t
{ !if text.equal, [token], t }
macro .if.token.not t
{ !if.not text.equal, [token], t }
macro .else.if.token.equal t
{ !else.if text.equal, [token], t }

macro .if.next.symbol s {
skip.space
.if byte [eax]=s
}

macro .if.next.symbol.not s {
skip.space
.if byte [eax] not s
}

; get and expect type

function get.x, t
try skip.space
try copy.token
let ecx=[token], ecx=>[ecx]
.if.n ecx&[t]
  .if not [token.class]
    .if.c SYMBOL
      syntax.error SYNTAX
    .else
      syntax.error UNDEFINE
    .end
  .end
.end
let eax=[source]
endf

macro get.name   { get.x C_ALPHA }
macro get.number { get.x C_NUMBER }
macro get.value  { get.x C_ALNUM }
macro get.text   { get.x C_TEXT }

;;;;;;;;;;;;;;;;;; DEFINITIONS ;;;;;;;;;;;;;;;;;;;

; define name value

STRUCTURE DEFINITION
 NUMBER type         ; 'l'/abel, 'm'/acro, etc
 TEXT name(32)
 VOID value          ; or address/index
ENDS ?define

align 8
ARRAY defines(DEFINITION.$)

; is name defined? return index or INVALID

function is.define, name
locals i
.loop [i]=0 to [defines.n]
  array.index defines, [i]
  let eax=&[?define.name+eax]
  .if.text.equal [name], eax
    return [i]
  .end
.endl
let eax=INVALID
endf

macro .if.define name {
is.define name
.if eax not INVALID
}

; is name defined of type? return index or INVALID

function is.define.type, type, name
locals i
get [i]=is.define [name]
.if [i] not INVALID
  array.index defines, eax
  let ecx=[?define.type+eax]
  .if ecx=[type]
    return [i]
  .end
.end
endf

macro .if.define.type type, name {
is.define.type type, name
.if eax not INVALID
}

; validate name. return 0 if invalid

function valid.name, name
.if.keyword [name]        ; reserved keyword?
  syntax.error RESERVE
  return 0
.end
.if.define [name]         ; redefinition?
  syntax.error REDEFINE
  return 0
.end
text.n [name]
.if eax>23                ; name too long?
  syntax.error NAME
  return 0
.end
let eax=1
endf

; create new define

function create.define, type, name, value
try valid.name [name]
try array.expand defines
let [?define.type+eax]=[type],\
[?define.value+eax]=[value]
push eax
let eax+?define.name
text.copy eax, [name]
pop eax
endf

; remove define

function un.define, name
.if.defined [name]
  array.remove defines, eax
.end
endf

; get define.name by index. note: "i/name"
; must be valid for these...

function get.define.name, i
array.index defines, [i]
.if eax not INVALID
  let eax+?define.name
.end
endf

; get define.value by index

function get.define.value, i
array.index defines, [i]
.if eax not INVALID
  let eax=[?define.value+eax]
.end
endf

; get define.value by name

function get.define, name
.if.define [name]
  get.define.value eax
.end
endf

; assign define.value by name

function set.define, name, v
.if.define [name]
  let [?define.value+eax]=[v]
.end
endf

; display defines for testing

function show.defines
locals i
jmp @f
TEXT define.f='Type: %c. Name: %t. Value: %hh'
@@:
.loop [i]=0 to [defines.n]
  array.index defines, [i]
  let ecx=&[?define.name+eax],\
   edx=[?define.value+eax],\
   eax=[?define.type+eax]
  print [?t], define.f, eax, ecx, edx
  log [?t]
.endl
execute log.file
endf

; identify name token

BOOLEAN identified?

function identify.name
let [identified?]=YES
.if.keyword [token]       ; keyword?
  set.token.value eax
  set.token.type KEYWORD
  return 1
.end
.if.define [token]        ; define?
  get.define.value eax
  set.token.value eax
  set.token.type NUMBER
  set.token.class 'd'
  return 1
.end
set.token.type NAME
let [identified?]=NO,\    ; undefined
eax=1
endf

;;;;;;;;;;;;;;;;;;;; DEFINE ;;;;;;;;;;;;;;;;;;;;;;

; process define statement. example:
; define SIZE 4k ; comment

function parse.define
try get.name
text.copy [?t], [token]
try read.token
create.define 'd', [?t], [token.value]
endf

;;;;;;;;;;;;;;;;;;;;; LABELS ;;;;;;;;;;;;;;;;;;;;;

; create new label at ip

function create.label, name
create.define 'l', [name], [omega]
endf

macro is.label name { is.define.type 'l', name }

function offset?, name
is.label [name]
.if eax not INVALID
  get.define [name]
.end
endf

macro rva? a {
offset? a
let eax+1000h, eax-200h
}

function address?, a
rva? [a]
.if eax not INVALID
  let eax+400000h
.end
endf    


Last edited by uart777 on 07 Aug 2013, 19:04; edited 1 time in total
Post 21 Feb 2013, 23:39
View user's profile Send private message Reply with quote
KevinN



Joined: 09 Oct 2012
Posts: 160
KevinN 22 Feb 2013, 04:30
Thanks uart
Post 22 Feb 2013, 04:30
View user's profile Send private message Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 22 Feb 2013, 13:12
uart777 wrote:
MHajduk: I have corrected this in my latest version of the program. It was an easy fix. It should not highlight partial keywords like password.
Yeah, seems that everything is OK now. Smile I was only wondering whether the unary minus sign should be colored with the same color as decimal number it precedes or not. I don't know if it would be a problem to distinguish the unary plus and minus from the corresponding binary operators. Anyway, it's not so important IMHO.
uart777 wrote:
Sorry to change the subject but for some reason, you remind me of David Attenborough who is a genius in my mind. I love his connection with nature/animals and I watch all of his BBC documentaries. What a great man! Smile
Well, I feel truly honored by such a comparison, thank you. I've never thought about myself this way, I'm rather concerned on admiring others' talents and, talking honestly, I'm really thankful to all those creative people such as artists, scientists and masters of their profession because their creations somehow hold me on this world, give sense to my life. Smile
Post 22 Feb 2013, 13:12
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.