|
UGAVAC Code Patterns for µ-C
Expressions:
Assumption: the code for an expression is generated in such a way that
if the expression has an l-value, the l-value of the
result is placed on top of the stack; otherwise the
r-value is placed on top of the stack.
Factor:
* numeric constant 'pushc[I|R] <const_value>'
* string constant 'pushs <string text>'
* variable or formal parameter
- local 'pusha <offset>'
- non-local 'pushga <lev-diff>, <offset>'
* func( )
'enter 1'
'call <entrypoint>, 0
--- See Note 2)
* func( expression-1, ..., expression-n )
'enter 1'
----------------
| expression-1 |
| code |
----------------
'fetch[I|R]' --- See Note 1)
'flt|int' --- See Note 8)
...
...
----------------
| expression-n |
| code |
----------------
'fetch[I|R]' --- See Note 1)
'flt|int' --- See Note 8)
'call <entrypoint>, <# of params>'
--- See Note 2)
* (expression)
--------------
| expression |
| code |
--------------
* + factor
---------------
| factor |
| code |
---------------
'fetch[I|R]' --- See Note 1)
* - factor
---------------
| factor |
| code |
---------------
'fetch[I|R]' --- See Note 1)
'neg[I|R]'
Term:
* just one factor
--------------
| factor |
| code |
--------------
* binary multiplication -- See Note 9)
--------------
| factor code |
| (left arg) |
--------------
'fetch[I|R]' --- See Note 1)
--------------
| factor code |
| (right arg) |
--------------
'fetch[I|R]' --- See Note 1)
'mul[I|R]'
* binary division -- See Note 9)
--------------
| factor code |
| (left arg) |
--------------
'fetch[I|R]' --- See Note 1)
--------------
| factor code |
| (right arg) |
--------------
'fetch[I|R]' --- See Note 1)
'div[I|R]'
Simple_Expression:
* just one term
--------------
| term code |
| |
--------------
* binary addition -- See Note 9)
--------------
| term code |
| (left arg) |
--------------
'fetch[I|R]' --- See Note 1)
--------------
| term code |
| (right arg) |
--------------
'fetch[I|R]' --- See Note 1)
'add[I|R]'
* binary subtraction -- See Note 9)
--------------
| term code |
| (left arg) |
--------------
'fetch[I|R]' --- See Note 1)
--------------
| term code |
| (right arg) |
--------------
'fetch[I|R]' --- See Note 1)
'sub[I|R]'
Relational_Expression:
* just a Simple_Expression
---------------
| simple expr |
| code |
---------------
* binary less-than (<=, >=, and > are similar) -- See Note 9)
--------------
| simple expr |
| (left arg) |
--------------
'fetch[I|R]' --- See Note 1)
--------------
| simple expr |
| (right arg) |
--------------
'fetch[I|R]' --- See Note 1)
'lt[I|R]'
Equality_Expression:
* just a Relational_Expression
---------------
| relat. expr |
| code |
---------------
* binary == (!= is similar) -- See Note 9)
--------------
| relat. expr |
| (left arg) |
--------------
'fetch[I|R]' --- See Note 1)
--------------
| relat. expr |
| (right arg) |
--------------
'fetch[I|R]' --- See Note 1)
'eq[I|R]'
Expression:
* just an Equality_Expression
---------------
| equal. expr |
| code |
---------------
* binary assignment '='
--------------
| equal. expr |
| (left arg) |
--------------
--------------
| equal. expr |
| (right arg) |
--------------
'fetch[I|R]' --- See Note 1)
'store[I|R]'
Statements:
* expression statement:
expression ";"
--------------
| expression |
| code |
--------------
'pop[I|R] 4' --- See Note 3)
* return statement:
"return" ";"
'returnf'
"return" expression ";"
--------------
| expression |
| code |
--------------
'fetch[I|R]' --- See Note 1)
'setrv[I|R]' --- See Note 10)
'returnf'
* conditional (IF):
"if" "(" expression ")"
statement
--------------
| expression |
| code |
--------------
'fetch[I|R]' --- See Note 1)
'jumpz <end-label>' --- See Note 10)
--------------
| statement |
| code |
--------------
'<end-label>' --- See Note 4)
"if" "(" expression ")"
statement-1
"else"
statement-2
--------------
| expression |
| code |
--------------
'fetch[I|R]' --- See Note 1)
'jumpz <else-label>' --- See Note 10)
--------------
| statement-1 |
| code |
--------------
'jump <end-label>'
'<else-label>'
--------------
| statement-2 |
| code |
--------------
'<end-label>'
* WHILE loop:
"while" "(" expression ")" statement
'<label>'
--------------
| expression |
| code |
--------------
'fetch[I|R]' --- See Note 1)
'jumpz <end-label>' --- See Note 10)
--------------
| statement |
| code |
--------------
'jump <label>'
'<end-label>'
* Compound statement:
"{" stat-1 stat-2 ... stat-n "}"
--------------
| stat-1 |
| code |
--------------
--------------
| stat-2 |
| code |
--------------
....
....
--------------
| stat-n |
| code |
--------------
Function definition
type|void funcname( params|void )
{
[decls]
stat-1
stat-2
...
stat-n
}
'$funcname<N>'
'alloc <# of required locations>'
-------------- --- See Note 5)
| stat-1 |
| code |
--------------
--------------
| stat-2 |
| code |
--------------
....
....
--------------
| stat-n |
| code |
--------------
'returnf'
Translation unit
function-def-1 --- See Note 6)
function-def-2
...
function-def-n
-----------------
| function-def-1 |
| code |
-----------------
-----------------
| function-def-2 |
| code |
-----------------
...
-----------------
| function-def-n |
| code |
-----------------
'main'
'enter 0' --- See Note 7)
'alloc <# of required words>'
'enter 0'
'call <main-entry-point>, 0'
'return'
NOTES:
1) The fetch instruction should be used only if the preceding
expression had the l-value, in which case the corresponding
r-value must be fetched.
2) <entrypoint>'s, i.e. entry points (labels) to procedures
must be unique!
Hint: Generate an <entrypoint> to be of the form
$funcname<number>, where <number> is a unique (among all
functions) integer.
3) The 'pop[I|R] 4' following an expression statement is intended
to remove the "left-over" value, i.e. the value of the just
evaluated expression. Note that both a function call and an
assignment produce a valuse on the stack. You may always
generate 'popI 4', as the type here is irrelevant.
4) Labels must be unique! Hint: generate a label name to
be of the form '$<number>'.
5) The alloc instruction must allocate the required number of words of
memory for the local variables (do not count parameters).
6) Intermediate code is generated only for function definitions.
7) The alloc instruction must allocate the required number of words of
memory for the global variables.
8) flt or int instruction should be used if a conversion of the actual
parameter type to conform to the formal parameter type (int->float or
float->int) is required. You may need to modify the grammar, in
order to facilitate code generation for such type conversions.
9) For all binary numeric operators, operands should have the same
(numeric) types. This may require the use of int, flt, intb, or
fltb instruction. For example,
for the expression: 2 + 3.1
the generated code should be:
pushcI 2
pushcR 3.1
fltb
addR
for the expression: 2.1 + 3
the generated code should be:
pushcR 2.1
pushcI 3
flt
addR
Note that you will know if conversion is necessary only *after*
parsing and generating code for 1st and 2nd argument, and right
before generating the operator code.
10) The instruction with this note may require
an additional type conversion instruction (flt or int).
Either 'int' or 'flt' may be needed in an assignment expression, if the
types of the left-hand-side expression and the right-hand-side expression
are not identical.
The instruction 'int' is necessary if the type of the expression for
the 'while' or 'if' statement is 'float', since 'jumpz' tests if
zero using integer comparison.
Also, 'int' or 'flt' is required right before 'setrv[I|R]'
in the return statement, if the expression and function return
types are not the same.
|