;@echo off
;goto make
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; Tiny - Tiny编译器的汇编版本,只有17KB,比原来39.KB,少左好多,不过其实还可以精简,没扩充,而且减少好多
; 中间变量,全部放入寄存器中
; 作用:
;
; Written by 问风 (wenfengmtd@163.com)
; Debug is fun job's in OLLyDBG v1.09
;
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.386
.model flat, stdcall
option casemap:none
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; I N C L U D E F I L E S
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
include /masm32/include/windows.inc
include /masm32/include/kernel32.inc
include /masm32/include/user32.inc
include /masm32/include/MASM32.INC
include /masm32/include/shell32.inc
include /masm32/macros/mymacros.asm
include /masm32/include/comdlg32.inc
includelib /masm32/lib/kernel32.lib
includelib /masm32/lib/user32.lib
includelib /masm32/lib/MASM32.LIB
includelib /masm32/lib/shell32.lib
includelib /masm32/lib/comdlg32.lib
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; U S E R D E F I N E D E Q U A T E S
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;define the C Type
CTypeD
;define the buffer's store length of read from file and the ID maximus length
BUFLEN equ 256
MAXTOKENLEN equ 40
;define the tree's children node num
MAXCHILDREN equ 3
;define the condition's compiler flag
TraceScan equ TRUE
NO_PARSE equ FALSE
TraceAnalyze equ TRUE
ANALYZE equ TRUE
TraceCode equ FALSE
TraceParse equ TRUE
;define the TokenType pre-T
enum TType, TENDFILE, TERROR, TIF, TTHEN, TELSE, TEND, TREPEAT, TUNTIL, TREAD, TWRITE, TID, /
TNUM, TASSIGN, TEQ, TLT, TPLUS, TMINUS, TTIMES, TOVER, TMOD, TLPAREN, TRPAREN, TSEMI, TWHILE, TDO,/
TNONE
;define the NodeKind
enum NKind, StmtK, ExpK, NNONE
;define the StmtKind
enum SKind, IfK, RepeatK, AssignK, ReadK, WriteK, WhileK, DoK, SNONE
;define the ExpKind
enum EKind, OpK, ConstK, IdK, ENONE
;define the ExpType for type checking
enum EType, Void, Integer, Boolean, ETNONE
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; U S E R D E F I N E D M A C R O S
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;the Macros to see the mymacros, here some come from the MASM 9.0 macro
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; D A T A
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.data
;define the DFA table col
Classify char 256 dup(17)
;use the hash funtion to find the token is ID or keyword, the hash funtion is s[1]+s[2]%19, TNONE mean is ID
hashTab TType TWHILE, TEND, TNONE, TNONE, TREPEAT, TNONE, TNONE, TIF, TREAD, TNONE, TWRITE, /
TNONE, TNONE, TNONE, TELSE, TTHEN, TDO, TUNTIL, TNONE
; some message string
Accpect char "Accpect!",0dh, 0ah, 0
Error char "Error!",0dh, 0ah, 0
;the buffer to store the char from source file
lpbuffer byte BUFLEN dup(0), 0
;the source filename
filename char 20 dup(0)
filename1 char 20 dup(0)
filename2 char 20 dup (0)
filename3 char "code.temp", 0
testfile char "test", 0
TNY char ".tny", 0
TM char ".tm", 0
filenameMsg char "Could not open the file, use the defaule filename: test.tny, test.tm", 0dh, 0ah, 0
;to save the token sting
tokenString char MAXTOKENLEN dup (0), 0
;when could not open the source file ,show the message
ErrorMsg char "Could not open the file", 0dh, 0ah, 0
;the CR LF char to convenience show string
CRLF char 0dh, 0ah, 0
;to save 32bit b-num to ASCII string,but you will see is reversal,so here i open a var to change the sequence
ASCVALUE1 char 20 dup(0), 0
ASCVALUE2 char 20 dup(0), 0
;Scoure File's handle
hScoureFile dword ?
hcodeFile dword ?
hAcodeFile dword ?
hFcodeFile dword ?
lpNumber dword ?
;the var record the current line number
lineno dword 1
;the var record the char number of buffer
bufferSize dword 0
;the keyword
reservedWord1 char 'while', 0
reservedWord2 char 'end', 0
reservedWord3 char 'repeat', 0
reservedWord4 char 'if', 0
reservedWord5 char 'read', 0
reservedWord6 char 'write', 0
reservedWord7 char 'else', 0
reservedWord8 char 'then', 0
reservedWord9 char 'do', 0
reservedWord0 char 'until', 0
;the keyword tab ,use in the hash find is ID or keyword. if compare equ, the token is keyword.
reservedWordTab dword offset reservedWord1,offset reservedWord2,0,0,offset reservedWord3,0,0,offset reservedWord4,/
offset reservedWord5, 0, offset reservedWord6, 0,0,0,offset reservedWord7,offset reservedWord8,offset reservedWord9,/
offset reservedWord0, 0
;chr$产生的字符串是在堆栈中的,如果把其它定义放在它后面会访问出错
;define the treenode structure
treeNode struct
child dword MAXCHILDREN dup(NULL)
sibling dword NULL
lineno dword ?
nodekind NKind ?
kind byte ? ;StmtKind or Expkind
attr dword ? ;include the TokenType, val, or name
exptype EType ETNONE
treeNode ends
szBuffer byte 4096 dup (?)
allocMsg char 'Out of memory error at line', 0
ArgNum equ 1
ItemBuffer dword 20 dup(0)
BAT char '.bat', 0
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; P R O D U R E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; getNextChar
;ecx to save the current next char pos(linepos) ,if ecx > bufferSize mean must read the next line
;esi save the lpbuffer current char point
;edi save the tokenString current char point
;and here 0 mean the EOF flag
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
getNextChar PROC uses ecx
mov ecx, esi
SBB ecx, offset lpbuffer
cmp ecx, bufferSize
jb @read ;如果没有读到行结束,简单返回下一个字符
;inc lineno ;否则读入新的一行
mov bufferSize, fread(hScoureFile, addr lpbuffer, 256)
cmp eax, 0
je @EOF ;如果不能再读入,说明到达了文件的结束,返回-1代表EOF
mov esi, offset lpbuffer
jmp @read
@EOF: mov eax, 0
inc edi
ret
@read: mov al, [esi]
mov [edi], al
cmp al, 0ah
jne noEndLine
inc lineno
noEndLine: inc esi
inc edi
and eax, 0FFh
ret
getNextChar ENDP
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; ungetNextChar
; because use assembly languang, ungectChar only doing is dec esi
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ungetNextChar PROC
dec esi
ret
ungetNextChar ENDP
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; fillTab
; fill the DFA tab's col ,may be you will ask how about DFA tab's row, you will see it define
; in DFA produre, here i use a assembly tip. The jump table.Jump table's always see in assembly
; code. This is hight language could not to give us!
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
FillTab proc uses ebx ecx
lea ebx, Classify
mov esi, 48
assume ebx: ptr byte
digit_: mov [ebx+esi], 0
inc esi
cmp esi, 57
jbe digit_
mov esi, 65
ualpha_:
mov [esi+ebx], 1
inc esi
cmp esi, 90
jbe ualpha_
mov esi, 97
lalpha_:
mov [esi+ebx], 1
inc esi
cmp esi, 122
jbe lalpha_
mov esi, ':'
mov [esi+ebx],2
mov esi, ' '
mov [esi+ebx],3
mov esi, 09h
mov [esi+ebx],3
mov esi, 0dh
mov [esi+ebx],3
mov esi, 0ah
mov [esi+ebx],3
mov esi, '{'
mov [esi+ebx],4
mov esi, '='
mov [esi+ebx],6
mov esi, 0
mov [esi+ebx],5
mov esi, '<'
mov [esi+ebx],7
mov esi, '+'
mov [esi+ebx],8
mov esi, '-'
mov [esi+ebx],9
mov esi, '*'
mov [esi+ebx],10
mov esi, '/'
mov [esi+ebx],11
mov esi, '%'
mov [esi+ebx],12
mov esi, '('
mov [esi+ebx],13
mov esi, ')'
mov [esi+ebx],14
mov esi, ';'
mov [esi+ebx],15
mov esi, '}'
mov [esi+ebx],16
assume ebx: nothing
ret
FillTab endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; hashLookup
; edx save the hash valus (s[1]+s[2])%19
; then we use the cmpsb to find the token is realy a token.Sure if the hash value is 0
; that mean it can't be the keyword, see the hashtab define
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
hashLookup proc uses eax edx edi esi
xor eax, eax
xor edx, edx
mov ecx, edi
mov edi, offset tokenString
sub ecx, edi
mov al, [edi+1]
add al, [edi+2]
mov ebx, 19
div ebx
mov esi, reservedWordTab[edx*4]
cmp esi, 0
je hid
cld
repe cmpsb
jne hid
mov cl, hashTab[edx]
ret
hid: mov cl, TID
ret
hashLookup endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; BTOACS
; eax save the coming change value
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
BTOACS proc uses ecx esi edx edi
mov ecx, 10
LEA esi, ASCVALUE1
LEA edi, ASCVALUE2
BTOACSL1:
CMP eax, ecx
jb BTOACSL2
xor edx, edx
div ecx
or dl, 30h
mov [esi], dl
inc esi
jmp BTOACSL1
BTOACSL2:
or al, 30h
mov [edi], al
inc edi
mov ecx, esi
sub ecx, offset ASCVALUE1
cmp ecx, 0
jne BTOACSL3
mov byte ptr [edi], ':'
mov byte ptr [edi+1], ' '
mov byte ptr [edi+2], 0
invoke StdOut, addr ASCVALUE2
ret
BTOACSL3:
dec esi
BTOACSL4:
mov al, [esi]
mov [edi], al
dec esi
inc edi
loop BTOACSL4
mov byte ptr [edi], ':'
mov byte ptr [edi+1], ' '
mov byte ptr [edi+2], 0
invoke StdOut, addr ASCVALUE2
ret
BTOACS endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; printfToken
; here same the C Tiny printfToken, but i use jump table instead of the switch statement
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
printToken proc uses ebx ecx
mov ebx, ecx
jmp TokenCodeTab[ebx*4]
TokenCodeTab dword PENDFILECode,PErrorCode, PReservedWordCode, PReservedWordCode, PReservedWordCode, /
PReservedWordCode, PReservedWordCode, PReservedWordCode, PReservedWordCode, /
PReservedWordCode, PIDCode, PNUMCode, PASSIGNCode, PEQCode, PLTCode, PPLUSCode, PMINUSCode, /
PTIMESCode, POVERCode, PMODCode, PLPARENCode, PRPARENCode, PSEMICode, /
PReservedWordCode, PReservedWordCode
PErrorCode :
invoke StdOut, chr$('ERROR: ')
invoke StdOut, addr tokenString
invoke StdOut, addr CRLF
ret
PReservedWordCode :
invoke StdOut, chr$('reserved word: ')
invoke StdOut, addr tokenString
invoke StdOut, addr CRLF
ret
PASSIGNCode:
invoke StdOut, chr$(':=')
invoke StdOut, addr CRLF
ret
PLTCode:
invoke StdOut, chr$('<')
invoke StdOut, addr CRLF
ret
PEQCode:
invoke StdOut, chr$('=')
invoke StdOut, addr CRLF
ret
PLPARENCode:
invoke StdOut, chr$(40)
invoke StdOut, addr CRLF
ret
PRPARENCode:
invoke StdOut, chr$(41)
invoke StdOut, addr CRLF
ret
PSEMICode:
invoke StdOut, chr$(';')
invoke StdOut, addr CRLF
ret
PPLUSCode:
invoke StdOut, chr$('+')
invoke StdOut, addr CRLF
ret
PMINUSCode:
invoke StdOut, chr$('-')
invoke StdOut, addr CRLF
ret
PTIMESCode:
invoke StdOut, chr$('*')
invoke StdOut, addr CRLF
ret
POVERCode:
invoke StdOut, chr$('/')
invoke StdOut, addr CRLF
ret
PMODCode:
invoke StdOut, chr$('%')
invoke StdOut, addr CRLF
ret
PENDFILECode:
invoke StdOut, chr$('EOF')
invoke StdOut, addr CRLF
ret
PNUMCode:
invoke StdOut, chr$('NUM, val=')
invoke StdOut, addr tokenString
invoke StdOut, addr CRLF
ret
PIDCode:
invoke StdOut, chr$('ID, name=')
invoke StdOut, addr tokenString
invoke StdOut, addr CRLF
ret
printToken endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; getToken
; the getToken produre, in assembly language use the Tab instead of the many contion statement
; will more nature
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
getToken proc uses ebx eax
xor eax, eax
xor ecx, ecx
mov edi, offset tokenString
lea ebx, Classify
State0: invoke getNextChar
xlat Classify
mov cl, TokenTab[eax]
cmp al,3
jb S0next
cmp al,5
ja S0next
dec edi
S0next: jmp State0Tab[eax*4]
TokenTab TType TNONE, TNONE, TNONE, TNONE, TNONE, TENDFILE, TEQ, TLT, /
TPLUS, TMINUS, TTIMES, TOVER, TMOD, TLPAREN,TRPAREN,TSEMI, /
TERROR, TERROR
State0Tab dword State3, State4, State2, State0, State1, State5, State5, State5,/
State5, State5, State5, State5, State5, State5, State5, State5,/
State5, State5
State1: invoke getNextChar
dec edi
xlat
cmp al, 16
je State0
jmp State1
State2: invoke getNextChar
xlat
cmp al, 6
jne S2_NEQ
mov cl, TASSIGN
jmp State5
S2_NEQ: invoke ungetNextChar
dec edi
mov cl, TERROR
jmp State5
State3: invoke getNextChar
xlat
cmp al, 0
je State3
invoke ungetNextChar
dec edi
mov cl, TNUM
jmp State5
State4: invoke getNextChar
xlat
cmp al, 1
je State4
invoke ungetNextChar
dec edi
mov cl, TID
;jmp State5 --这条指令可省
State5:
assume edi : ptr byte
mov [edi], 0
.if cl == TID
invoke hashLookup
.endif
if TraceScan
push ecx
invoke StdOut, chr$(09h)
mov eax, lineno
invoke BTOACS
pop ecx
invoke printToken
endif
assume edi : nothing
ret
getToken endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; newStmtNode
; function newStmtNode creates a new statement node for syntax tree construction
; kind mean the StmtKind, and the result-newStmtNode will return by the eax rv
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
newStmtNode proc uses ecx edx, kind
mov eax, halloc(sizeof(treeNode))
cmp eax, NULL
jne @alloc
invoke StdOut, addr allocMsg
mov eax, lineno
invoke BTOACS
invoke StdOut, addr CRLF
ret
@alloc: assume eax: ptr treeNode
mov ecx, 0
.while ecx < 3
mov [eax].child[ecx*4], NULL
inc ecx
.endw
mov [eax].sibling, NULL
mov edx, lineno
mov [eax].lineno, edx
mov edx, kind
mov [eax].kind, dl
mov [eax].nodekind, StmtK
assume eax: nothing
ret
newStmtNode endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; newExpNode
; function newExpNode creates a new expression node for syntax tree construction
; kind mean the ExpKind, and the result-newStmtNode will return by the eax rv
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
newExpNode proc uses ecx edx, kind
mov eax, halloc(sizeof(treeNode))
cmp eax, NULL
jne @alloc
invoke StdOut, addr allocMsg
mov eax, lineno
invoke BTOACS
invoke StdOut, addr CRLF
ret
@alloc: assume eax: ptr treeNode
mov ecx, 0
.while ecx < 3
mov [eax].child[ecx*4], NULL
inc ecx
.endw
mov [eax].sibling, NULL
mov edx, lineno
mov [eax].lineno, edx
mov edx, kind
mov [eax].kind, dl
mov [eax].nodekind, ExpK
mov [eax].exptype, Void
assume eax: nothing
ret
newExpNode endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; CopyString
; function CopyString allocates amd makes a new copy of an existing string
; return from the eax rv
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
copyString proc uses ecx edi esi,s
.if s == NULL
mov eax, NULL
ret
.endif
mov eax, halloc(len(s))
.if eax == NULL
invoke StdOut, addr allocMsg
mov eax, lineno
invoke BTOACS
invoke StdOut, addr CRLF
.else
cld
push eax
mov ecx, len(s) ; marcros will modify the eax
pop eax
mov esi, s
mov edi, eax
rep movsb
.endif
ret
copyString endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; syntaxError
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
syntaxError proc message
pushad
invoke StdOut, addr CRLF
invoke StdOut, chr$(">>> ")
invoke StdOut, chr$("Syntax error at line ")
mov eax, lineno
invoke BTOACS
invoke StdOut, chr$(": ")
invoke StdOut, message
mov Error, TRUE
popad
ret
syntaxError endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; match
; ecx is the token
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
match proc expected
.if ecx == expected
invoke getToken
.else
invoke syntaxError, chr$("unexpected token -> ");
invoke printToken
push ecx
invoke StdOut, chr$(" ");
pop ecx
.endif
ret
match endp
statement proto
stmt_sequence proto
if_stmt proto
repeat_stmt proto
assign_stmt proto
read_stmt proto
write_stmt proto
while_stmt proto
do_stmt proto
exp proto
simple_exp proto
term proto
factor proto
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; exp
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
exp proc uses ebx
invoke simple_exp
mov ebx, eax
.if ecx == TLT || ecx ==TEQ
invoke newExpNode, OpK
assume eax: ptr treeNode
.if eax != NULL
mov [eax].child[0], ebx
mov [eax].attr, ecx
mov ebx, eax
.endif
assume eax: nothing
invoke match, ecx
.if ebx != NULL
invoke simple_exp
assume ebx: ptr treeNode
mov [ebx].child[4], eax
assume ebx: nothing
.endif
.endif
mov eax, ebx
ret
exp endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; simple_exp
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
simple_exp proc uses ebx
assume eax: ptr treeNode
assume ebx: ptr treeNode
invoke term
mov ebx, eax
.while ecx == TPLUS || ecx == TMINUS
invoke newExpNode, OpK
.if eax != NULL
mov [eax].child[0], ebx
mov [eax].attr, ecx
mov ebx, eax
invoke match, ecx
invoke term
mov [ebx].child[4], eax
.endif
.endw
assume eax: nothing
assume ebx: nothing
mov eax, ebx
ret
simple_exp endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; term
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
term proc uses ebx
assume eax: ptr treeNode
assume ebx: ptr treeNode
invoke factor
mov ebx, eax
.while ecx == TTIMES || ecx == TOVER || ecx == TMOD ; Add the mod op
invoke newExpNode, OpK
.if eax != NULL
mov [eax].child[0], ebx
mov [eax].attr, ecx
mov ebx, eax
invoke match, ecx
invoke factor
mov [ebx].child[4], eax
.endif
.endw
assume eax: nothing
assume ebx: nothing
mov eax, ebx
ret
term endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; factor
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
factor proc uses ebx
assume eax: ptr treeNode
mov eax, NULL
.if ecx == TNUM
invoke newExpNode, ConstK
.if eax != NULL
push eax
push ecx
invoke atol, addr tokenString
mov ebx,eax
pop ecx
pop eax
mov [eax].attr, ebx
.endif
invoke match, TNUM
.elseif ecx == TID
invoke newExpNode, IdK
.if eax != NULL
push eax
invoke copyString, addr tokenString
mov ebx, eax
pop eax
mov [eax].attr, ebx
.endif
invoke match, TID
.elseif ecx == TLPAREN
invoke match, TLPAREN
invoke exp
invoke match, TRPAREN
.else
invoke syntaxError, chr$("unexpected token -> ");
invoke printToken
invoke getToken
.endif
assume eax: nothing
ret
factor endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; if_stmt
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
if_stmt proc uses ebx
invoke newStmtNode, IfK
mov ebx, eax
invoke match, TIF
assume ebx: ptr treeNode
.if ebx != NULL
invoke exp
mov [ebx].child[0], eax
.endif
invoke match, TTHEN
.if ebx != NULL
invoke stmt_sequence
mov [ebx].child[4], eax
.endif
.if ecx == TELSE
invoke match , TELSE
.if ebx != NULL
invoke stmt_sequence
mov [ebx].child[8], eax
.endif
.endif
invoke match, TEND
assume ebx: nothing
mov eax, ebx
ret
if_stmt endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; repeat_stmt
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
repeat_stmt proc uses ebx
invoke newStmtNode, RepeatK
mov ebx, eax
invoke match, TREPEAT
assume ebx: ptr treeNode
.if ebx != NULL
invoke stmt_sequence
mov [ebx].child[0], eax
.endif
invoke match, TUNTIL
.if ebx != NULL
invoke exp
mov [ebx].child[4], eax
.endif
assume ebx: nothing
mov eax, ebx
ret
repeat_stmt endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; assign_stmt
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
assign_stmt proc uses ebx
invoke newStmtNode, AssignK
mov ebx, eax
assume ebx: ptr treeNode
.if ebx != NULL && ecx == TID
invoke copyString, addr tokenString
mov [ebx].attr, eax
.endif
invoke match, TID
invoke match, TASSIGN
.if ebx != NULL
invoke exp
mov [ebx].child[0], eax
.endif
assume ebx: nothing
mov eax, ebx
ret
assign_stmt endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; read_stmt
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
read_stmt proc uses ebx
invoke newStmtNode, ReadK
mov ebx, eax
invoke match, TREAD
assume ebx: ptr treeNode
.if ebx != NULL && ecx == TID
invoke copyString, addr tokenString
mov [ebx].attr, eax
.endif
invoke match, TID
assume ebx: nothing
mov eax, ebx
ret
read_stmt endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; write_stmt
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
write_stmt proc uses ebx
invoke newStmtNode, WriteK
mov ebx, eax
invoke match, TWRITE
assume ebx: ptr treeNode
.if ebx != NULL
invoke exp
mov [ebx].child[0], eax
.endif
assume ebx: nothing
mov eax, ebx
ret
write_stmt endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; while_stmt
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
while_stmt proc uses ebx
invoke newStmtNode, WhileK
mov ebx, eax
invoke match, TWHILE
assume ebx: ptr treeNode
.if ebx != NULL
invoke exp
mov [ebx].child[0], eax
.endif
invoke match, TDO
.if ebx != NULL
invoke stmt_sequence
mov [ebx].child[4], eax
.endif
invoke match, TEND
assume ebx: nothing
mov eax, ebx
ret
while_stmt endp
do_stmt proc uses ebx
invoke newStmtNode, DoK
mov ebx, eax
assume ebx: ptr treeNode
invoke match, TDO
.if ebx != NULL
invoke stmt_sequence
mov [ebx].child[0], eax
.endif
invoke match, TWHILE
.if ebx != NULL
invoke exp
mov [ebx].child[4], eax
.endif
assume ebx: nothing
mov eax, ebx
ret
do_stmt endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; statemen
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
statement proc uses ebx
mov eax, NULL
.if ecx == TIF
invoke if_stmt
.elseif ecx == TREPEAT
invoke repeat_stmt
.elseif ecx == TID
invoke assign_stmt
.elseif ecx == TREAD
invoke read_stmt
.elseif ecx == TWRITE
invoke write_stmt
.elseif ecx == TWHILE
invoke while_stmt
.elseif ecx == TDO
invoke do_stmt
.else
invoke syntaxError, chr$("unexpected token -> ")
push eax
invoke printToken
invoke getToken
pop eax
.endif
ret
statement endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; stmt_sequence
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
stmt_sequence proc uses ebx edx
local t: dword
invoke statement
mov t, eax
mov ebx, eax
.while ecx !=TENDFILE && ecx !=TEND && ecx != TELSE && ecx!=TUNTIL && ecx != TWHILE ; add
invoke match, TSEMI
invoke statement ;这里修改了ebx?
mov edx, eax
.if edx != NULL
.if ebx == NULL ;表示第一条语句
mov ebx, edx
mov t, edx
.else
assume ebx : ptr treeNode
mov [ebx].sibling, edx
assume ebx : nothing
mov ebx, edx
.endif
.endif
.endw
mov eax, t
ret
stmt_sequence endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; parese
; return the TreeNode* in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
parse proc
invoke getToken
invoke stmt_sequence
.if ecx != TENDFILE
invoke syntaxError, chr$("Code ends before file ");
invoke StdOut, addr CRLF
.endif
ret
parse endp
printSpace proc uses ecx edx eax
mov ecx, 0
.while ecx < edx
push ecx
push edx
invoke StdOut, chr$(" ")
pop edx
pop ecx
inc ecx
.endw
ret
printSpace endp
printTree proc uses ecx
assume eax: ptr treeNode
add edx, 2
.while eax != NULL
invoke printSpace
.if [eax].nodekind == StmtK
push eax
push edx
push ecx
.if [eax].kind == IfK
invoke StdOut, addr reservedWord4
invoke StdOut, addr CRLF
.elseif [eax].kind == RepeatK
invoke StdOut, addr reservedWord3
invoke StdOut, addr CRLF
.elseif [eax].kind == AssignK
push eax
invoke StdOut, chr$("Assgin to: ")
pop eax
invoke StdOut, [eax].attr
invoke StdOut, addr CRLF
.elseif [eax].kind == ReadK
push eax
invoke StdOut, chr$("Read: ")
pop eax
invoke StdOut, [eax].attr
invoke StdOut, addr CRLF
.elseif [eax].kind == WriteK
invoke StdOut, addr reservedWord6
invoke StdOut, addr CRLF
.elseif [eax].kind == WhileK
invoke StdOut, addr reservedWord1
invoke StdOut, addr CRLF
.elseif [eax].kind == DoK
invoke StdOut, addr reservedWord9
invoke StdOut, addr CRLF
.else
invoke StdOut, chr$("Unknow ExpNode")
invoke StdOut, addr CRLF
.endif
pop ecx
pop edx
pop eax
.elseif [eax].nodekind == ExpK
push eax
push edx
push ecx
.if [eax].kind == OpK
push eax
invoke StdOut, chr$("Op: ")
pop eax
mov ecx, [eax].attr
invoke printToken
.elseif [eax].kind == ConstK
push eax
invoke StdOut, chr$("const: ")
pop eax
push eax
mov eax, [eax].attr
invoke BTOACS
pop eax
invoke StdOut, addr CRLF
.elseif [eax].kind == IdK
push eax
invoke StdOut, chr$("Id: ")
pop eax
invoke StdOut, [eax].attr
invoke StdOut, addr CRLF
.else
invoke StdOut, chr$("Unknow ExpNode")
invoke StdOut, addr CRLF
.endif
pop eax
pop edx
pop eax
.else
push eax
push edx
push ecx
invoke StdOut, chr$("Unknow node kind")
invoke StdOut, addr CRLF
pop eax
pop edx
pop eax
.endif
mov ecx, 0
.while ecx < MAXCHILDREN
push eax
mov eax, [eax].child[ecx*4]
invoke printTree
inc ecx
pop eax
.endw
mov eax, [eax].sibling
.endw
sub edx, 2
assume eax: nothing
ret
printTree endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; symtab
; Symbol tab implementation for the TINY compiler (allows only one symbol table)
; Symbol table is implemented as a chained hash table
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.data
tabSize equ 211
SHIFT equ 4
LineListRec struct
lineno dword ?
next dword ? ;here next is the pointer of the LineListRec
LineListRec ends
BucketListRec struct
varName dword ?
lines dword ? ;the head pointer of the LineListRec
memloc dword ?
next dword ? ;the pointer of the BucketListRec
BucketListRec ends
hashTable dword tabSize dup (NULL) ;211's pointer of BucketListRec
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; hash
; the hash funtion, will modify the rv eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
hash proc uses ebx edx ecx,varName
xor eax, eax
xor ebx, ebx
mov ecx, tabSize
mov ebx, [varName+ebx]
assume ebx : ptr byte
.while [ebx] != 0
shl eax, SHIFT
add al, [ebx]
xor edx, edx
div ecx
mov eax, edx
inc ebx
.endw
ret
hash endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; st_insert
; procedure st_insert inserts line numbers and memory locations into the symbol table
; loc = memory location is inserted only the first time, otherwise ignored
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
st_insert proc uses eax ebx ecx edx, varName, line_no, loc
invoke hash, varName
push eax ;push the hash value
mov ebx, hashTable[eax*4] ;get the BucketList head
assume ebx: ptr BucketListRec
@begin: or ebx, ebx
jz @end
invoke szCmp, varName, [ebx].varName ;will modify edx
or eax, eax
jnz @end
mov ebx, [ebx].next
jmp @begin
@end: .if ebx == NULL ;here much m2m instuction , so may be can do well use the rv pass parameter
mov ebx, halloc(sizeof(BucketListRec))
mov eax, varName
mov [ebx].varName, eax
mov [ebx].lines, halloc(sizeof(LineListRec))
mov eax, loc
mov [ebx].memloc, eax
pop ecx ;get the hash value
mov eax, hashTable[ecx*4]
mov [ebx].next, eax
mov hashTable[ecx*4], ebx
mov ebx, [ebx].lines
assume ebx: ptr LineListRec
mov eax, line_no
mov [ebx].lineno, eax
mov [ebx].next, NULL
.else
assume ebx: ptr BucketListRec
mov ebx, [ebx].lines
.while [ebx].next != NULL
assume ebx: ptr LineListRec
mov ebx, [ebx].next
.endw
mov [ebx].next, halloc(sizeof(LineListRec))
mov ebx, [ebx].next
mov eax, line_no
mov [ebx].lineno, eax
mov [ebx].next, NULL
pop ecx ;to balance the stack
.endif
ret
st_insert endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; st_lookup
; Function st_loopup returns the memory location of a variable or -1 if
; not found, return in the ebx
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
st_lookup proc uses eax edx, varName
invoke hash, varName
mov ebx, hashTable[eax*4]
assume ebx: ptr BucketListRec
@begin: or ebx, ebx
jz @end
invoke szCmp, varName, [ebx].varName
or eax, eax
jnz @end
mov ebx, [ebx].next
jmp @begin
@end: .if ebx == NULL
mov ebx, -1
.else
mov ebx, [ebx].memloc
.endif
ret
st_lookup endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; printSymTab
; Procedure printSymTab prints a formatted listing of the symbol table
; contents to the listing file. eax store the tree pointer
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
printSymTab proc uses eax ecx edx
invoke StdOut, chr$("Variable Name Location Line Numbers")
invoke StdOut, addr CRLF
invoke StdOut, chr$("------------- -------- ------------")
invoke StdOut, addr CRLF
mov ecx, 0
.while ecx < tabSize
.if hashTable[ecx*4] != NULL
mov ebx, hashTable[ecx*4]
assume ebx: ptr BucketListRec
assume edx: ptr LineListRec
.while ebx != NULL
mov edx, [ebx].lines
push edx
push ecx
invoke StdOut, [ebx].varName ;will modify eax, ecx ,edx
invoke StdOut, chr$(" ")
mov eax, [ebx].memloc
invoke BTOACS
pop ecx
pop edx
.while edx !=NULL
mov eax, [edx].lineno
invoke BTOACS
mov edx, [edx].next
.endw
push edx
push ecx
invoke StdOut, addr CRLF
pop ecx
pop edx
mov ebx, [ebx].next
.endw
.endif
inc ecx
.endw
ret
printSymTab endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; traverse
; Procedure traverse is a generic recursive syntax tree treaversal routine:
; it applies preProc in preorder and postProc and postProc in postorder to tree pointed to by t
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
traverse proc uses ecx, preProc, postProc
assume eax: ptr treeNode
.if eax != NULL
call preProc
mov ecx, 0
.while ecx < MAXCHILDREN
push eax
mov eax, [eax].child[ecx*4]
invoke traverse, preProc, postProc
pop eax
inc ecx
.endw
call postProc
push eax
mov eax, [eax].sibling
invoke traverse, preProc, postProc
pop eax
.endif
ret
traverse endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; nullProc
; nullProc is a do-nothing procedure to generate preorder-only or postorder-only
; traversals from traverse
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
nullProc proc
ret
nullProc endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; insertNode
; Procedure inserNode inserts identifiers stored in t into the symbol table,
; edx is the couter for variable memory locations
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
insertNode proc
assume eax: ptr treeNode
.if [eax].nodekind == StmtK
.if [eax].kind == AssignK || [eax].kind == ReadK
invoke st_lookup, [eax].attr
.if ebx == -1
invoke st_insert, [eax].attr, [eax].lineno, edx
inc edx
.else
invoke st_insert, [eax].attr, [eax].lineno, 0
.endif
.endif
.elseif [eax].nodekind == ExpK
.if [eax].kind == IdK
invoke st_lookup, [eax].attr
.if ebx == -1
invoke st_insert, [eax].attr, [eax].lineno, edx
inc edx
.else
invoke st_insert, [eax].attr, [eax].lineno, 0
.endif
.endif
.endif
ret
insertNode endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; buildSymtab
; Function buildSymtab constructs the symbol table by preorder traversal of the syntax tree
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
buildSymtab proc uses eax
xor edx, edx ;counter for variable memory locations
invoke traverse, insertNode, nullProc
if TraceAnalyze
invoke StdOut, addr CRLF
invoke StdOut, chr$("Symbol table: ")
invoke StdOut, addr CRLF
invoke StdOut, addr CRLF
invoke printSymTab
endif
ret
buildSymtab endp
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; typeError
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
typeError proc uses eax edx ecx ,message
assume eax: ptr treeNode
push eax
invoke StdOut, chr$("Type error at line ")
pop eax
mov eax, [eax].lineno
invoke BTOACS
invoke StdOut, message
mov Error, TRUE
ret
typeError endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; checkNode
; Procedure checkNode performs type checking at a single tree node
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
checkNode proc uses eax ebx ecx
assume eax: ptr treeNode
assume ebx: ptr treeNode
assume ecx: ptr treeNode
.if [eax].nodekind == ExpK
.if [eax].kind == OpK
mov ecx, [eax].child
mov ebx, [eax].child[4]
.if [ebx].exptype != Integer || [ecx].exptype != Integer
invoke typeError, chr$("Op applied to non-integer")
.endif
.if [eax].attr == TEQ || [eax].attr == TLT
mov [eax].exptype, Boolean
.else
mov [eax].exptype, Integer
.endif
.elseif [eax].kind == ConstK || [eax].kind == IdK
mov [eax].exptype, Integer
.else
.endif
.elseif [eax].nodekind == StmtK
push eax
.if [eax].kind == IfK
mov eax, [eax].child
.if [eax].exptype == Integer
invoke typeError, chr$("if test is not Boolean")
.endif
.elseif [eax].kind == AssignK
mov eax, [eax].child
.if [eax].exptype != Integer
invoke typeError, chr$("assignment of non-integer value")
.endif
.elseif [eax].kind == WriteK
mov eax, [eax].child
.if [eax].exptype != Integer
invoke typeError, chr$("write of non-integer value")
.endif
.elseif [eax].kind == RepeatK
mov eax, [eax].child[4]
.if [eax].exptype == Integer
invoke typeError, chr$("repeat test is not Boolean")
.endif
.elseif [eax].kind == WhileK
mov eax, [eax].child
.if [eax].exptype == Integer
invoke typeError, chr$("while test is not Boolean")
.endif
.elseif [eax].kind == DoK
mov eax, [eax].child[4]
.if [eax].exptype == Integer
invoke typeError, chr$("dowhile test is not Boolean")
.endif
.else
.endif
pop eax
.else
ret
.endif
ret
checkNode endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; typeCheck
; Procedure typeCheck performs type checking by a postorder syntax tree traversal
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
typeCheck proc
invoke traverse, nullProc, checkNode
ret
typeCheck endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; Code emitting utilities for the TINY compiler and interface to the TM machine
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; pc = program counter
pc equ 7
; mp = "memory pointer" points to top of memory (for temp storage)
mp equ 6
; gp = "global pointer" points to top of memory for (glocal) variable storage
gp equ 5
; accumulator
ac0 equ 0
; 2nd accumulator
ac1 equ 1
; TM location number for current instruction emission -------esi
; Highest TM location emitted so far For use in conjunction with
; emitSkip, emitBackup and emitRestore-----------------------edi
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; emitComment
; procedure emitComment prints a comment line with comment c in the code file
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.data
szFmtWord1 byte "* %s", 0dh, 0ah, 0
.code
emitComment proc c0
pushad
.if TraceCode
invoke wsprintf, addr szBuffer, addr szFmtWord1, c0
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
.endif
popad
ret
emitComment endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; emitRO
; procedure emitRO emits a register-only TM instruction
; op = the opcode
; r = target register
; s = 1st source register
; t = 2st source register
; c = a comment to be printed if TranceCode is TRUE
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.data
szFmtWord2 byte "%3d: %5s %d, %d, %d ", 0
szFmtWord3 byte 09h, "%s", 0
.code
emitRO proc uses eax ecx, op1, r1, s1, t1, c1
invoke wsprintf, addr szBuffer, addr szFmtWord2, esi, op1, r1, s1, t1
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
inc esi
.if TraceCode
invoke wsprintf, addr szBuffer, addr szFmtWord3, c1
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
.endif
invoke WriteFile, hcodeFile, addr CRLF, 2, addr lpNumber, NULL
.if edi < esi
mov edi, esi;
.endif
ret
emitRO endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; emitRM
; procedure emitRM emits a register-to-memory TM instruction
; op = the opcode
; r = target register
; d = the offset
; s = the base register
; c = a comment to be printed if TranceCode is TRUE
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.data
szFmtWord4 byte "%3d: %5s %d, %d(%d) ", 0
.code
emitRM proc uses eax ecx, op2, r2, d2, s2, c2
invoke wsprintf, addr szBuffer, addr szFmtWord4, esi, op2, r2, d2, s2
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
inc esi
.if TraceCode
invoke wsprintf, addr szBuffer, addr szFmtWord3, c2
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
.endif
invoke WriteFile, hcodeFile, addr CRLF, 2, addr lpNumber, NULL
.if edi < esi
mov edi, esi;
.endif
ret
emitRM endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; emitSkip
; Function emitSkip skips "howmany" code locations for later backpatch.It also returns
; the current code position, return value put in the eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
emitSkip proc howmany
mov eax, esi
add esi, howmany
.if edi < esi
mov edi, esi;
.endif
ret
emitSkip endp
.data
szMsg1 byte "BUG in emitBackup", 0
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; emitBackup
; procedure emitBackup backs up to loc = a previously skipped location
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
emitBackup proc loc
.if edi <= loc
invoke emitComment, addr szMsg1
.endif
mov esi, loc
ret
emitBackup endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; emitRestore
; procedure emitRestore restores the current code position to the hightest previously
; unemitted position
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
emitRestore proc
mov esi, edi
ret
emitRestore endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; emitRM_Abs
; procedure emitRM_Abs converts an absolute reference to a pc-relative reference when
; emitting a register-to-memory TM instruction
; op = the opcode
; r = target register
; d = the offset
; a = the obsolute location in memory
; c = a comment to be printed if TranceCode is TRUE
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
emitRM_Abs proc op3, r3, a3, c2
pushad
mov eax, a3
sub eax, esi
dec eax
invoke wsprintf, addr szBuffer, addr szFmtWord4, esi, op3, r3, eax, pc
inc esi
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
.if TraceCode
invoke wsprintf, addr szBuffer, addr szFmtWord3, c2
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
.endif
invoke WriteFile, hcodeFile, addr CRLF, 2, addr lpNumber, NULL
.if edi < esi
mov edi, esi;
.endif
ret
emitRM_Abs endp
; tempOffset storge the memory offset for temps
; It is decremented each time a temp is
; stored, and incremented when loaded again
.data
tempOffset dword 0
.const
szMsg2 byte "-> if", 0
szMsg3 byte "if: jump to else belongs here", 0
JEQ byte "JEQ", 0
szMsg4 byte "if: jump to else ", 0
szMsg5 byte "<- if",0
szMsg6 byte "-> repeat", 0
szMsg7 byte "<- repeat", 0
LDA byte "LDA",0
szMsg8 byte "if: jump to end", 0
szMsg9 byte "repeat: jump after body comes back here", 0
szMsg10 byte "repeat: jump back to body", 0
szMsg11 byte "->assign", 0
szMsg12 byte "<-assign", 0
IST byte "ST", 0
szMsg13 byte "assign: store value", 0
IIN byte "IN", 0
szMsg14 byte "read: integer value", 0
szMsg15 byte "read: store value", 0
IOUT byte "OUT", 0
szMsg16 byte "write ac", 0
szMsg43 byte "->while", 0
szMsg44 byte "<-while", 0
szMsg45 byte "while: jump Out", 0
szMsg46 byte "while: if exp test not true jump to here",0
szMsg47 byte "->dowhile", 0
szMsg48 byte "<-dowhile", 0
szMsg49 byte "dowhile: jump after body comes back here", 0
szMsg50 byte "dowhile: jump back to the body", 0
IJNE byte "JNE", 0
szMsg51 byte "while: jump to body", 0
IJMP byte "JMP", 0
szMsg52 byte "while: body, while if while jump back", 0
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; genStmt
; Procedure genStmt generates code at a statement node
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
genStmt proc uses eax ebx
local savedLoc1
local savedLoc2
local currentLoc
mov ebx, eax
.if [ebx].kind == IfK
.if TraceCode
invoke emitComment, addr szMsg2
.endif
mov eax, [ebx].child
call cGen
invoke emitSkip, 1
mov savedLoc1, eax
invoke emitComment, addr szMsg3
mov eax, [ebx].child[4]
call cGen
invoke emitSkip, 1
mov savedLoc2, eax
invoke emitComment, addr szMsg3
invoke emitSkip, 0
mov currentLoc, eax
invoke emitBackup, savedLoc1
invoke emitRM_Abs, addr JEQ, ac0, currentLoc, addr szMsg4
invoke emitRestore
mov eax, [ebx].child[8]
call cGen
invoke emitSkip, 0
mov currentLoc, eax
invoke emitBackup, savedLoc2
invoke emitRM_Abs, addr LDA, pc, currentLoc, addr szMsg8
invoke emitRestore
.if TraceCode
invoke emitComment, addr szMsg5
.endif
.elseif [ebx].kind == RepeatK
.if TraceCode
invoke emitComment, addr szMsg6
.endif
invoke emitSkip, 0
mov savedLoc1, eax
invoke emitComment, addr szMsg9
mov eax, [ebx].child
call cGen
mov eax, [ebx].child[4]
call cGen
invoke emitRM_Abs, addr JEQ, ac0, savedLoc1, addr szMsg10
.if TraceCode
invoke emitComment, addr szMsg7
.endif
.elseif [ebx].kind == AssignK
.if TraceCode
invoke emitComment, addr szMsg11
.endif
mov eax, [ebx].child
call cGen
invoke st_lookup, [ebx].attr
invoke emitRM, addr IST, ac0, ebx, gp, addr szMsg13
.if TraceCode
invoke emitComment, addr szMsg12
.endif
.elseif [ebx].kind == ReadK
invoke emitRO, addr IIN, ac0, 0, 0, addr szMsg14
invoke st_lookup, [ebx].attr
invoke emitRM, addr IST, ac0, ebx, gp, addr szMsg15
.elseif [ebx].kind == WriteK
mov eax, [ebx].child
call cGen
invoke emitRO, addr IOUT, ac0, 0, 0, addr szMsg16
.elseif [ebx].kind == WhileK
.if TraceCode
invoke emitComment, addr szMsg43
.endif
mov eax, [ebx].child
call cGen
invoke emitSkip, 1 ;exp
mov savedLoc1, eax
invoke emitComment, addr szMsg45
mov eax, [ebx].child[4] ;body
call cGen
invoke emitRM_Abs, addr IJMP, ac0, savedLoc1, addr szMsg51
invoke emitSkip, 0
mov currentLoc, eax
invoke emitBackup, savedLoc1
invoke emitRM_Abs, addr JEQ, ac0, currentLoc, addr szMsg46
invoke emitRestore
.if TraceCode
invoke emitComment, addr szMsg44
.endif
.elseif [ebx].kind == DoK
.if TraceCode
invoke emitComment, addr szMsg47
.endif
invoke emitSkip, 0
mov savedLoc1, eax
invoke emitComment, addr szMsg49
mov eax, [ebx].child
call cGen
mov eax, [ebx].child[4]
call cGen
invoke emitRM_Abs, addr IJNE, ac0, savedLoc1, addr szMsg50
.if TraceCode
invoke emitComment, addr szMsg48
.endif
.else
.endif
ret
genStmt endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; genExp
; procedure genExp generates code at an expression node
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.const
szMsg17 byte "-> Const", 0
LDC byte "LDC", 0
szMsg18 byte "load const", 0
szMsg19 byte "<- Const", 0
LD byte "LD", 0
szMsg20 byte "-> Id", 0
szMsg21 byte "<- ID", 0
szMsg22 byte "load id value", 0
szMsg23 byte "-> Op", 0
szMsg24 byte "<- Op", 0
szMsg25 byte "op: push left", 0
szMsg26 byte "op: load left", 0
IADD byte "ADD", 0
ISUB byte "SUB", 0
IIMUL byte "MUL", 0
IIDIV byte "DIV", 0
szMsg27 byte "op +", 0
szMsg28 byte "op -", 0
szMsg29 byte "op *", 0
szMsg30 byte "op /", 0
szMsg31 byte "op <", 0
JLT byte "JLT", 0
szMsg32 byte "br if true", 0
szMsg33 byte "false case", 0
szMsg34 byte "unconditional jmp", 0
szMsg35 byte "true case", 0
szMsg36 byte "op ==", 0
.code
genExp proc uses eax ebx
mov ebx, eax
.if [ebx].kind == ConstK
.if TraceCode
invoke emitComment, addr szMsg17
.endif
invoke emitRM, addr LDC, ac0, [ebx].attr, 0, addr szMsg18
.if TraceCode
invoke emitComment, addr szMsg19
.endif
.elseif [ebx].kind == IdK
.if TraceCode
invoke emitComment, addr szMsg20
.endif
invoke st_lookup, [ebx].attr
invoke emitRM, addr LD, ac0, ebx, gp, addr szMsg22
.if TraceCode
invoke emitComment, addr szMsg21
.endif
.elseif [ebx].kind == OpK
.if TraceCode
invoke emitComment, addr szMsg23
.endif
mov eax, [ebx].child
call cGen
invoke emitRM, addr IST, ac0, tempOffset, mp, addr szMsg25
dec tempOffset
mov eax, [ebx].child[4]
call cGen
inc tempOffset
invoke emitRM, addr LD, ac1, tempOffset, mp, addr szMsg26
.if [ebx].attr == TPLUS
invoke emitRO, addr IADD, ac0, ac1, ac0, addr szMsg27
.elseif [ebx].attr == TMINUS
invoke emitRO, addr ISUB, ac0, ac1, ac0, addr szMsg28
.elseif [ebx].attr == TTIMES
invoke emitRO, addr IIMUL, ac0, ac1, ac0, addr szMsg29
.elseif [ebx].attr == TOVER
invoke emitRO, addr IIDIV, ac0, ac1, ac0, addr szMsg30
.elseif [ebx].attr == TLT
invoke emitRO, addr ISUB, ac0, ac1, ac0, addr szMsg31
invoke emitRM, addr JLT, ac0, 2, pc, addr szMsg32
invoke emitRM, addr LDC, ac0, 0, ac0, addr szMsg33
invoke emitRM, addr LDA, pc, 1, pc, addr szMsg34
invoke emitRM, addr LDC, ac0, 1, ac0, addr szMsg35
.elseif [ebx].attr == TEQ
invoke emitRO, addr ISUB, ac0, ac1, ac0, addr szMsg36
invoke emitRM, addr JEQ, ac0, 2, pc, addr szMsg32
invoke emitRM, addr LDC, ac0, 0, ac0, addr szMsg33
invoke emitRM, addr LDA, pc, 1, pc, addr szMsg34
invoke emitRM, addr LDC, ac0, 1, ac0, addr szMsg35
.elseif [ebx].attr == TMOD
invoke emitRO, addr IIDIV, ac0, ac1, ac0, addr szMsg30
.else
.endif
.if TraceCode
invoke emitComment, addr szMsg24
.endif
.else
.endif
ret
genExp endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; cGen
; procedure cGen recirsively generates code by tree traversal, the eax is the pointer of
; treeNode
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
cGen proc
.if eax != NULL
.if [eax].nodekind == StmtK
invoke genStmt
.elseif [eax].nodekind == ExpK
invoke genExp
.else
.endif
mov eax, [eax].sibling
call cGen
.endif
ret
cGen endp
.const
szFmtWord5 byte "File: %s",0
szMsg37 byte "TINY Compilation to TM code", 0
szMsg38 byte "Standard prelude", 0
szMsg39 byte "load maxaddress from location 0", 0
szMsg40 byte "clear location 0", 0
szMsg41 byte "End of standard prelude", 0
szMsg42 byte "End of execution", 0
HALT byte "HALT", 0
non_char byte 0
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; the primary function of the code generator--codeGen
; procedure codeGen generates code to a code file by traversal of the syntax tree.
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
codeGen proc
invoke emitComment, addr szMsg37
push eax
invoke wsprintf, addr ASCVALUE1, addr szFmtWord5, addr filename1
pop eax
invoke emitComment, addr ASCVALUE1
invoke emitComment, addr szMsg38
invoke emitRM, addr LD, mp, 0, ac0, addr szMsg39
invoke emitRM, addr IST, ac0, 0, ac0, addr szMsg40
invoke emitComment, addr szMsg41
call cGen
invoke emitComment, addr szMsg42
invoke emitRO, addr HALT, 0, 0, 0, addr non_char
ret
codeGen endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; code generator for the MASM code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.data
;define the op's string
IAMOV db "MOV", 0
IAADD db "ADD", 0
IASUB db "SUB", 0
IAXCHG db "XCHG", 0
IAIMUL db "IMUL", 0
IAIDIV db "IDIV", 0
IAJMP db "JMP", 0
IAXOR db "XOR", 0
IAJC db "JC", 0
IAJNC db "JNC", 0
IACLC db "CLC", 0
IASTC db "STC", 0
IAJB db "JB", 0
IAJE db "JE", 0
EEAX db "EAX", 0
EEBX db "EBX", 0
EECX db "ECX", 0
EEDX db "EDX", 0
Lable dword 0
LableFmtStr db "_Lable%d:", 0dh,0ah, 0
LableStr db 50 dup (0)
emitCode db 100 dup (0)
num db 10 dup (0)
numFmtStr db "%d", 0
OP3FmtStr db 09h,"%s %s, %s", 0dh, 0ah, 0
OP2FmtStr db 09h,"%s %s", 0dh, 0ah, 0
OP1FmtStr db 09h,"%s", 0dh, 0ah, 0
CommentFmtstr db "; %s", 0dh, 0ah, 0
blank db 100 dup (' '), 0
ConsoleBuffer db "consoleBuffer", 0
IAADDR db "addr ", 0
Chrnum db "10", 0
invokeStdIN db 09h,"invoke StdIn, addr consoleBuffer, 10", 0dh, 0ah, 0
invokeAtodw db 09h,"invoke atol, addr consoleBuffer", 0dh, 0ah, 0
invokeDwtoa db 09h,"invoke dwtoa, eax, addr consoleBuffer", 0dh, 0ah, 0
invokeStdOut db 09h,"invoke StdOut, addr consoleBuffer", 0dh, 0ah, 0
varFmtStr db "%s dd ?", 0dh, 0ah, 0
headCode db ";@echo off", 0dh, 0ah, ";goto make", 0dh, 0ah, 0dh, 0ah, 0dh, 0ah
db ";****************************************************************", 0dh, 0ah
db ".386", 0dh, 0ah
db ".model flat, stdcall", 0dh, 0ah, "option casemap:none", 0dh, 0ah
db 0dh, 0ah, 0dh, 0ah, 0dh, 0ah
db ";****************************************************************", 0dh, 0ah
db "include /masm32/include/windows.inc", 0dh, 0ah
db "include /masm32/include/kernel32.inc",0dh, 0ah
db "include /masm32/include/user32.inc", 0dh, 0ah
db "include /masm32/include/MASM32.INC", 0dh, 0ah
db "include /masm32/include/shell32.inc", 0dh, 0ah
db "includelib /masm32/lib/kernel32.lib", 0dh, 0ah
db "includelib /masm32/lib/user32.lib", 0dh, 0ah
db "includelib /masm32/lib/MASM32.LIB", 0dh, 0ah
db "includelib /masm32/lib/shell32.lib", 0dh, 0ah
db 0dh, 0ah, 0dh, 0ah, 0dh, 0ah
db ";****************************************************************", 0dh, 0ah
db ";变量定义", 0dh, 0ah
db ".data", 0dh, 0ah
db "consoleBuffer dd 10 dup(?)", 0dh, 0ah, 0
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
emitOP3 proc uses eax ecx,OP, OP1, OP2
invoke wsprintf, addr emitCode, addr OP3FmtStr, OP, OP1, OP2
invoke lstrlen, addr emitCode
mov ecx, eax
invoke WriteFile, hAcodeFile, addr emitCode, ecx, addr lpNumber, NULL
add esi, [lpNumber]
.if edi < esi
mov edi, esi;
.endif
ret
emitOP3 endp
emitOP2 proc uses eax ecx, OP, OP1
invoke wsprintf, addr emitCode, addr OP2FmtStr, OP, OP1
invoke lstrlen, addr emitCode
mov ecx, eax
invoke WriteFile, hAcodeFile, addr emitCode, ecx, addr lpNumber, NULL
add esi, [lpNumber]
.if edi < esi
mov edi, esi;
.endif
ret
emitOP2 endp
emitOP1 proc uses eax ecx, OP
invoke wsprintf, addr emitCode, addr OP1FmtStr, OP
invoke lstrlen, addr emitCode
mov ecx, eax
invoke WriteFile, hAcodeFile, addr emitCode, ecx, addr lpNumber, NULL
add esi, [lpNumber]
.if edi < esi
mov edi, esi;
.endif
ret
emitOP1 endp
emitLabel proc uses eax ecx
invoke wsprintf,addr LableStr, addr LableFmtStr, Lable
inc Lable
invoke lstrlen, addr LableStr
mov ecx, eax
invoke WriteFile, hAcodeFile, addr LableStr, ecx, addr lpNumber, NULL
mov eax, [lpNumber]
mov LableStr[eax-3], 0
add esi, eax
.if edi < esi
mov edi, esi;
.endif
ret
emitLabel endp
emitCommentA proc uses eax ecx, CommentA
invoke wsprintf, addr emitCode, addr CommentFmtstr, CommentA
invoke lstrlen, addr emitCode
mov ecx, eax
invoke WriteFile, hAcodeFile, addr emitCode, ecx, addr lpNumber, NULL
add esi, [lpNumber]
.if edi < esi
mov edi, esi;
.endif
ret
emitCommentA endp
emitSkipA proc
mov eax, esi
push eax
invoke WriteFile, hAcodeFile, addr blank, 100, addr lpNumber, NULL
pop eax
add esi, 100
.if edi < esi
mov edi, esi;
.endif
ret
emitSkipA endp
emitRestoreA proc
mov esi, edi
invoke SetFilePointer, hAcodeFile, esi, NULL, FILE_BEGIN
ret
emitRestoreA endp
emitBackupA proc loc
.if edi <= loc
invoke emitCommentA, addr szMsg1
.endif
mov esi, loc
invoke SetFilePointer, hAcodeFile, esi, NULL, FILE_BEGIN
ret
emitBackupA endp
emitRead proc uses ebx eax
invoke lstrlen, addr invokeStdIN
mov ecx, eax
invoke WriteFile, hAcodeFile, addr invokeStdIN, ecx, addr lpNumber, NULL
add esi, [lpNumber]
invoke lstrlen, addr invokeAtodw
mov ecx, eax
invoke WriteFile, hAcodeFile, addr invokeAtodw, ecx, addr lpNumber, NULL
add esi, [lpNumber]
.if edi < esi
mov edi, esi;
.endif
ret
emitRead endp
emitWrite proc uses ebx eax
invoke lstrlen, addr invokeDwtoa
mov ecx, eax
invoke WriteFile, hAcodeFile, addr invokeDwtoa, ecx, addr lpNumber, NULL
add esi, [lpNumber]
invoke lstrlen, addr invokeStdOut
mov ecx, eax
invoke WriteFile, hAcodeFile, addr invokeStdOut, ecx, addr lpNumber, NULL
add esi, [lpNumber]
.if edi < esi
mov edi, esi;
.endif
ret
emitWrite endp
emitVar proc varName
pushad
invoke wsprintf,addr emitCode, addr varFmtStr, varName
invoke lstrlen, addr emitCode
mov ecx, eax
invoke WriteFile, hFcodeFile, addr emitCode, ecx, addr lpNumber, NULL
popad
ret
emitVar endp
emitHead proc
pushad
invoke lstrlen, addr headCode
mov ecx, eax
invoke WriteFile, hFcodeFile, addr headCode, ecx, addr lpNumber, NULL
xor ecx, ecx
.while ecx < tabSize
.if hashTable[ecx*4] != NULL
mov ebx, hashTable[ecx*4]
assume ebx: ptr BucketListRec
.while ebx != NULL
invoke emitVar ,[ebx].varName ;will modify eax, ecx ,edx
mov ebx, [ebx].next
.endw
.endif
inc ecx
.endw
popad
ret
emitHead endp
.data
bodyCode db 0dh, 0ah, 0dh, 0ah, 0dh, 0ah
db ";****************************************************************", 0dh, 0ah
db ".code", 0dh, 0ah, "start proc", 0dh, 0ah, 0
endFmtCode db 09h, "invoke ExitProcess, 0", 0dh, 0ah
db "start endp", 0dh, 0ah
db "end start", 0dh, 0ah
db 0dh, 0ah, 0dh, 0ah, 0dh, 0ah
db ";****************************************************************", 0dh, 0ah
db ":make", 0dh, 0ah
db "set drv=%s", 0dh, 0ah
db 0dh, 0ah, 0dh, 0ah, 0dh, 0ah, 0
shortname db 20 dup(0)
endCode char "/masm32/bin/ml /c /coff %drv%.bat", 0dh, 0ah,/
"/masm32/bin/Link /SUBSYSTEM:CONSOLE %drv%.obj", 0dh, 0ah, 0dh, 0ah,/
"del %drv%.obj", 0dh, 0ah, /
"echo.", 0dh, 0ah, /
"pause", 0dh, 0ah, 0
.code
emitBody proc
pushad
invoke lstrlen, addr bodyCode
mov ecx, eax
invoke WriteFile, hFcodeFile, addr bodyCode, ecx, addr lpNumber, NULL
popad
ret
emitBody endp
emitEnd proc
pushad
invoke wsprintf,addr szBuffer, addr endFmtCode, addr shortname
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hFcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
invoke lstrlen, addr endCode
mov ecx, eax
invoke WriteFile, hFcodeFile, addr endCode, ecx, addr lpNumber, NULL
popad
ret
emitEnd endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; genStmt
; Procedure genStmt generates code at a statement node
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
genStmtA proc uses eax ebx
local savedLoc1
local savedLoc2
local currentLoc
mov ebx, eax
assume ebx : ptr treeNode
.if [ebx].kind == IfK
.if TraceCode
invoke emitCommentA, addr szMsg2
.endif
mov eax, [ebx].child
call cGenA
invoke emitSkipA
mov savedLoc1, eax
invoke emitCommentA, addr szMsg3
mov eax, [ebx].child[4]
call cGenA
invoke emitSkipA
mov savedLoc2, eax
invoke emitCommentA, addr szMsg3
invoke emitLabel
invoke emitBackupA, savedLoc1
invoke emitOP2, addr IAJC, addr LableStr ;间断测试结果,通过C位
invoke emitRestoreA
mov eax, [ebx].child[8]
call cGenA
invoke emitLabel
invoke emitBackupA, savedLoc2
invoke emitOP2, addr IAJMP, addr LableStr ;真的执行完后,无条件退出
invoke emitRestoreA
.if TraceCode
invoke emitCommentA, addr szMsg5
.endif
.elseif [ebx].kind == RepeatK
.if TraceCode
invoke emitCommentA, addr szMsg6
.endif
invoke emitLabel
invoke emitCommentA, addr szMsg9
invoke copyString, addr LableStr ;要保存标号,不然可以会修改
push eax
mov eax, [ebx].child
call cGenA
mov eax, [ebx].child[4]
call cGenA
pop edx
invoke emitOP2, addr IAJC, edx
hfree(edx)
.if TraceCode
invoke emitCommentA, addr szMsg7
.endif
.elseif [ebx].kind == AssignK
.if TraceCode
invoke emitCommentA, addr szMsg11
.endif
mov eax, [ebx].child
call cGenA
invoke emitOP3, addr IAMOV, [ebx].attr,addr EEAX
.if TraceCode
invoke emitCommentA, addr szMsg12
.endif
.elseif [ebx].kind == ReadK
invoke emitRead
invoke emitOP3, addr IAMOV,[ebx].attr, addr EEAX
.elseif [ebx].kind == WriteK
mov eax, [ebx].child
call cGenA
invoke emitWrite
.elseif [ebx].kind == WhileK
.if TraceCode
invoke emitCommentA, addr szMsg43
.endif
invoke emitLabel
invoke copyString, addr LableStr
push eax
mov eax, [ebx].child
call cGenA
invoke emitSkipA ;exp
mov savedLoc1, eax
invoke emitCommentA, addr szMsg45
mov eax, [ebx].child[4] ;body
call cGenA
pop edx
invoke emitOP2, addr IAJMP, edx
hfree(edx)
invoke emitLabel
invoke emitBackupA, savedLoc1
invoke emitOP2, addr IAJC, addr LableStr
invoke emitRestoreA
.if TraceCode
invoke emitCommentA, addr szMsg44
.endif
.elseif [ebx].kind == DoK
.if TraceCode
invoke emitCommentA, addr szMsg47
.endif
invoke emitLabel
invoke copyString, addr LableStr
push eax
invoke emitCommentA, addr szMsg49
mov eax, [ebx].child
call cGenA
mov eax, [ebx].child[4]
call cGenA
pop edx
invoke emitOP2, addr IAJNC, edx
hfree(edx)
.if TraceCode
invoke emitCommentA, addr szMsg48
.endif
.else
.endif
ret
genStmtA endp
genExpA proc uses eax ebx
local savedLoc1
local savedLoc2
mov ebx, eax
.if [ebx].kind == ConstK
.if TraceCode
invoke emitCommentA, addr szMsg17
.endif
invoke wsprintf,addr num, addr numFmtStr, [ebx].attr
invoke emitOP3, addr IAMOV, addr EEAX ,addr num
.if TraceCode
invoke emitCommentA, addr szMsg19
.endif
.elseif [ebx].kind == IdK
.if TraceCode
invoke emitCommentA, addr szMsg20
.endif
invoke emitOP3, addr IAMOV, addr EEAX ,[ebx].attr
.if TraceCode
invoke emitCommentA, addr szMsg21
.endif
.elseif [ebx].kind == OpK
.if TraceCode
invoke emitCommentA, addr szMsg23
.endif
mov eax, [ebx].child
call cGenA
invoke emitOP3, addr IAMOV, addr EEBX ,addr EEAX
mov eax, [ebx].child[4]
call cGenA
invoke emitOP3, addr IAXCHG, addr EEBX, addr EEAX ;这里可以移进除法中,从而优化代码
.if [ebx].attr == TPLUS
invoke emitOP3, addr IAADD, addr EEAX ,addr EEBX
.elseif [ebx].attr == TMINUS
invoke emitOP3, addr IASUB, addr EEAX ,addr EEBX
.elseif [ebx].attr == TTIMES
invoke emitOP2, addr IAIMUL ,addr EEBX
.elseif [ebx].attr == TOVER
invoke emitOP3, addr IAXOR ,addr EEDX, addr EEDX
invoke emitOP2, addr IAIDIV ,addr EEBX
.elseif [ebx].attr == TLT
invoke emitOP3, addr IASUB, addr EEAX, addr EEBX
invoke emitSkipA
mov savedLoc1, eax
invoke emitOP1, addr IASTC
invoke emitSkipA
mov savedLoc2, eax
invoke emitLabel
invoke emitBackupA, savedLoc1
invoke emitOP2, addr IAJB, addr LableStr
invoke emitRestoreA
invoke emitOP1, addr IACLC
invoke emitLabel
invoke emitBackupA, savedLoc2
invoke emitOP2, addr IAJMP, addr LableStr
invoke emitRestoreA
.elseif [ebx].attr == TEQ
invoke emitOP3, addr IASUB, addr EEAX, addr EEBX
invoke emitSkipA
mov savedLoc1, eax
invoke emitOP1, addr IASTC
invoke emitSkipA
mov savedLoc2, eax
invoke emitLabel
invoke emitBackupA, savedLoc1
invoke emitOP2, addr IAJE, addr LableStr
invoke emitRestoreA
invoke emitOP1, addr IACLC
invoke emitLabel
invoke emitBackupA, savedLoc2
invoke emitOP2, addr IAJMP, addr LableStr
invoke emitRestoreA
.elseif [ebx].attr == TMOD
invoke emitOP3, addr IAXOR ,addr EEDX, addr EEDX
invoke emitOP2, addr IAIDIV ,addr EEBX
invoke emitOP3, addr IAXCHG, addr EEDX, addr EEAX
.else
.endif
.if TraceCode
invoke emitCommentA, addr szMsg24
.endif
.else
.endif
ret
genExpA endp
cGenA proc
.if eax != NULL
.if [eax].nodekind == StmtK
invoke genStmtA
.elseif [eax].nodekind == ExpK
invoke genExpA
.else
.endif
mov eax, [eax].sibling
call cGenA
.endif
ret
cGenA endp
codeGenA proc
invoke emitCommentA, addr szMsg37
push eax
invoke wsprintf, addr ASCVALUE1, addr szFmtWord5, addr shortname
pop eax
invoke emitCommentA, addr ASCVALUE1
invoke emitCommentA, addr szMsg38
invoke emitHead
invoke emitCommentA, addr szMsg41
invoke emitBody
call cGenA
call printPrettyCode
invoke emitCommentA, addr szMsg42
invoke emitEnd
ret
codeGenA endp
printPrettyCode proc
pushad
invoke SetFilePointer, hAcodeFile, 0, NULL, FILE_BEGIN ;回到初始
.while TRUE
invoke ReadFile, hAcodeFile, addr szBuffer, 4096,addr lpNumber, NULL
mov ecx, [lpNumber]
.break .if !ecx
mov esi, offset szBuffer
mov edi, offset szBuffer
xor edx, edx
mov dl, [esi]
.while ecx != 0
.if dl != ' '
next: movsb
dec ecx
mov dl, [esi]
cmp dl, 0ah
jne next
movsb
dec ecx
.else
inc esi
dec ecx
.endif
mov dl, [esi]
.endw
mov dl,0
mov [edi], dl
invoke lstrlen, addr szBuffer
mov ecx, eax
invoke WriteFile, hFcodeFile, addr szBuffer, ecx, addr lpNumber, NULL
.endw
popad
ret
printPrettyCode endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; start
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
start proc
local syntaxTree : ptr treeNode
invoke ArgClC, ArgNum, addr ItemBuffer
invoke GetCL, ArgNum, addr filename
.if eax == 1
invoke InString,1,addr filename,chr$(".")
.if eax == 0
invoke lstrcpy, addr filename1, addr filename
invoke lstrcpy, addr filename2, addr filename
invoke lstrcpy, addr shortname, addr filename
invoke lstrcat, addr filename, addr TNY
invoke lstrcat, addr filename1, addr TM
invoke lstrcat, addr filename2, addr BAT
.else
cld
mov ecx, eax
dec ecx
mov esi, offset filename
mov edi, offset filename1
rep movsb
invoke lstrcpy, addr filename2, addr filename1
invoke lstrcpy, addr shortname, addr filename1
invoke lstrcat, addr filename1, addr TM
invoke lstrcat, addr filename2, addr BAT
.endif
.else
invoke StdOut, addr filenameMsg
invoke lstrcpy, addr filename, addr testfile
invoke lstrcpy, addr filename1, addr testfile
invoke lstrcpy, addr filename2, addr testfile
invoke lstrcpy, addr shortname, addr testfile
invoke lstrcat, addr filename, addr TNY
invoke lstrcat, addr filename1, addr TM
invoke lstrcat, addr filename2, addr BAT
.endif
invoke FillTab
mov esi, offset lpbuffer
mov hScoureFile, fopen_r(filename)
if NO_PARSE
push ecx
test_:
invoke getToken
cmp ecx, TENDFILE
jne test_
pop ecx
else
invoke parse
.if TraceParse && Error != TRUE
xor edx, edx
push eax
invoke printTree ;will modify the eax value
pop eax
.endif
endif
if ANALYZE
.if Error != TRUE
push eax
invoke StdOut, addr CRLF
invoke StdOut, chr$("Building Symbol Table..")
invoke StdOut, addr CRLF
pop eax
invoke buildSymtab
push eax
invoke StdOut, addr CRLF
invoke StdOut, chr$("Checking Types...")
invoke StdOut, addr CRLF
pop eax
invoke typeCheck
push eax
invoke StdOut, addr CRLF
invoke StdOut, chr$("Type Checking Finished")
invoke StdOut, addr CRLF
.endif
endif
invoke CreateFile, addr filename1, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, /
FILE_ATTRIBUTE_NORMAL, 0
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox, NULL, addr ErrorMsg, NULL, MB_OK OR MB_ICONEXCLAMATION
invoke ExitProcess, 0
.endif
mov hcodeFile, eax
invoke CreateFile, addr filename3, GENERIC_WRITE OR GENERIC_READ, 0, NULL, CREATE_ALWAYS, /
FILE_ATTRIBUTE_NORMAL, 0
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox, NULL, addr ErrorMsg, NULL, MB_OK OR MB_ICONEXCLAMATION
invoke ExitProcess, 0
.endif
mov hAcodeFile, eax
invoke CreateFile, addr filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, /
FILE_ATTRIBUTE_NORMAL, 0
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox, NULL, addr ErrorMsg, NULL, MB_OK OR MB_ICONEXCLAMATION
invoke ExitProcess, 0
.endif
mov hFcodeFile, eax
pop eax
xor esi, esi
xor edi, edi
push eax
invoke codeGen
pop eax
xor esi, esi
xor edi, edi
invoke codeGenA
invoke CloseHandle, hAcodeFile
invoke CloseHandle, hFcodeFile
invoke CloseHandle, hScoureFile
invoke CloseHandle, hcodeFile
invoke DeleteFile, addr filename3
invoke ExitProcess,0
start endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
end start
:make
set drv=Tiny
/masm32/bin/ml /c /coff %drv%.bat
/masm32/bin/Link /SUBSYSTEM:CONSOLE %drv%.obj
del %drv%.obj
echo.
pause
介绍了一个仅17KB大小的Tiny-Tiny编译器汇编版本,该编译器通过优化减少了文件大小并提升了效率。作者详细描述了编译器的工作原理、符号表实现以及代码生成过程。
6945

被折叠的 条评论
为什么被折叠?



