04 September 2009

10. Variables

Copy paren.pb to var.pb. We will now implement support for variables in the expression parser. Here is the old grammar:
digit      ::= 0..9
integer    ::= <digit> {<digit>}
value      ::= <integer> | '(' <expression> ')'
mulop      ::= * | /
addop      ::= + | -
mulexp     ::= <value>  { <mulop> <value> }
addexp     ::= <mulexp> { <addop> <mulexp> }
expression ::= <addexp>
A variable can represent a value, right? In fact, we don't actually want the variable itself, we want the value stored in that variable.

So we can add a bit to our grammar:
name       ::= <alpha> { <alpha> | <digit> }
variable   ::= <name>
value      ::= <integer> | <variable> | '(' <expression> ')'

Adding support for this in Value() should be easy:
Procedure Value()
  ; value  ::= <integer> | <variable> | '(' <expression> ')'
  If IsDigit(Look)
    Emit("mov  eax, " + GetInteger())
  ElseIf IsAlpha(Look)
    Emit("mov  eax, " + VarValue(GetName()))
  ElseIf Look = '('
    MatchWhite('(')
    Expression()
    MatchWhite(')')
  EndIf
EndProcedure

We can see an extra procedure here: VarValue(). What this does is to generate asm code to get the value of a variable by using a memory reference (the square brackets around the name). I have chosen to prefix all global variable names with v_ to avoid name collisions with internal labels (which we need when generating if's and so on).

Procedure.s VarValue(Var.s)
  ProcedureReturn "[v_" + Var + "]"
EndProcedure

Done. This isn't getting any harder, is it? Of course we need to register all variables in a symbol table and actually allocate space for them, but that's easy anyways. Maybe I'll show it later.

No comments: