COMPILER Taste ' types Const undef As Integer = 0 Const [integer] As Integer = 1 Const [boolean] As Integer = 2 ' object kinds Const var As Integer = 0 Const proc As Integer = 1 Public tab As SymbolTable Public gen As CodeGenerator CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . digit = "0123456789" . cr = '\r' . lf = '\n' . tab = '\t' . TOKENS ident = letter {letter | digit} . number = digit {digit} . COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS /*----------------------------------------------------------------------------*/ Taste (. Dim name As String = Nothing .) = "program" Ident<name> (. tab.OpenScope() .) '{' { VarDecl | ProcDecl } '}' (. tab.CloseScope() If gen.progStart = -1 Then SemErr("main function never defined") End If .) . /*----------------------------------------------------------------------------*/ Ident<ByRef name As String> = ident (. name = t.val .) . /*----------------------------------------------------------------------------*/ VarDecl (. Dim name As String = Nothing Dim _type As Integer .) = Type<_type> Ident<name> (. tab.NewObj(name, var, _type) .) { ',' Ident<name> (. tab.NewObj(name, var, _type) .) } ';' . /*----------------------------------------------------------------------------*/ Type<ByRef _type As Integer> = (. _type = undef .) ( "int" (. _type = [integer] .) | "bool" (. _type = [boolean] .) ) . /*----------------------------------------------------------------------------*/ ProcDecl (. Dim name As String = Nothing Dim obj As Obj Dim adr As Integer .) = "void" Ident<name> (. obj = tab.NewObj(name, proc, undef) obj.adr = gen.pc If name = "Main" Then gen.progStart = gen.pc End If tab.OpenScope() .) '(' ')' '{' (. gen.Emit(Op.ENTER, 0) adr = gen.pc - 2 .) { VarDecl | Stat } '}' (. gen.Emit(Op.LEAVE) gen.Emit(Op.RET) gen.Patch(adr, tab.topScope.nextAdr) tab.CloseScope() .) . /*----------------------------------------------------------------------------*/ Stat (. Dim type As Integer Dim name As String = Nothing Dim obj As Obj Dim adr As Integer, adr2 As Integer, loopstart As Integer .) = Ident<name> (. obj = tab.Find(name) .) ( '=' (. If obj.kind <> var Then SemErr("cannot assign to procedure") End If .) Expr<type> ';' (. If type <> obj.type Then SemErr("incompatible types") End If If obj.level = 0 Then gen.Emit(Op.STOG, obj.adr) Else gen.Emit(Op.STO, obj.adr) End If .) | '(' ')' ';' (. If obj.kind <> proc Then SemErr("object is not a procedure") End If gen.Emit(Op.[CALL], obj.adr) .) ) | "if" '(' Expr<type> ')' (. If type <> [boolean] Then SemErr("boolean type expected") End If gen.Emit(Op.FJMP, 0) adr = gen.pc - 2 .) Stat [ "else" (. gen.Emit(Op.JMP, 0) adr2 = gen.pc - 2 gen.Patch(adr, gen.pc) adr = adr2 .) Stat ] (. gen.Patch(adr, gen.pc) .) | "while" (. loopstart = gen.pc .) '(' Expr<type> ')' (. If type <> [boolean] Then SemErr("boolean type expected") End If gen.Emit(Op.FJMP, 0) adr = gen.pc - 2 .) Stat (. gen.Emit(Op.JMP, loopstart) gen.Patch(adr, gen.pc) .) | "read" Ident<name> ';' (. obj = tab.Find(name) If obj.type <> [integer] Then SemErr("integer type expected") End If gen.Emit(Op.READ) If obj.level = 0 Then gen.Emit(Op.STOG, obj.adr) Else gen.Emit(Op.STO, obj.adr) End If .) | "write" Expr<type> ';' (. If type <> [integer] Then SemErr("integer type expected") End If gen.Emit(Op.WRITE) .) | '{' { Stat | VarDecl } '}' . /*----------------------------------------------------------------------------*/ Expr<ByRef type As Integer> (. Dim type1 As Integer Dim op As Op .) = SimExpr<type> [ RelOp<op> SimExpr<type1> (. If type <> type1 Then SemErr("incompatible types") End If gen.Emit(op) type = [boolean] .) ] . /*----------------------------------------------------------------------------*/ SimExpr<ByRef type As Integer> (. Dim type1 As Integer Dim op As Op .) = Term<type> { AddOp<op> Term<type1> (. If type <> [integer] OrElse type1 <> [integer] Then SemErr("integer type expected") End If gen.Emit(op) .) } . /*----------------------------------------------------------------------------*/ Term<ByRef type As Integer> (. Dim type1 As Integer Dim op As Op .) = Factor<type> { MulOp<op> Factor<type1> (. If type <> [integer] OrElse type1 <> [integer] Then SemErr("integer type expected") End If gen.Emit(op) .) } . /*----------------------------------------------------------------------------*/ Factor<ByRef type As Integer> (. Dim n As Integer Dim obj As Obj Dim name As String = Nothing .) = (. type = undef .) ( Ident<name> (. obj = tab.Find(name) type = obj.type If obj.kind = var Then If obj.level = 0 Then gen.Emit(Op.LOADG, obj.adr) Else gen.Emit(Op.LOAD, obj.adr) End If Else SemErr("variable expected") End If .) | number (. n = Convert.ToInt32(t.val) gen.Emit(Op.[CONST], n) type = [integer] .) | '-' Factor<type> (. If type <> [integer] Then SemErr("integer type expected") type = [integer] End If gen.Emit(Op.NEG) .) | "true" (. gen.Emit(Op.[CONST], 1) type = [boolean] .) | "false" (. gen.Emit(Op.[CONST], 0) type = [boolean] .) ) . /*----------------------------------------------------------------------------*/ MulOp<ByRef op As Op> = (. op = Op.MUL .) ( '*' | '/' (. op = Op.DIV .) ) . /*----------------------------------------------------------------------------*/ AddOp<ByRef op As Op> = (. op = Op.ADD .) ( '+' | '-' (. op = Op.[SUB] .) ) . /*----------------------------------------------------------------------------*/ RelOp<ByRef op As Op> = (. op = Op.EQU .) ( "==" | '<' (. op = Op.LSS .) | '>' (. op = Op.GTR .) ) . END Taste .