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 .