Tokens
SEMI: ";"
OPEN: "("
CLOSE: ")"
ADD: "+"
SUB: "-"
DIV: "/"
MUL: "*"
ASN: "="
ADDASN: "+="
SUBASN: "-="
IDENT: [a-z]+
NUMLIT: [0-9]+
| Grammar 1. statements: assign statements 2. statements: assign 3. assign: IDENT assignop addexpr SEMI 4. assignop: ASN 5. assignop: ADDASN 6. assignop: SUBASN 7. addexpr: addexpr addop multexpr 8. addexpr: multexpr 9. multexpr: multexpr multop brackexpr 10. multexpr: brackexpr 11. brackexpr: OPEN addexpr CLOSE 12. brackexpr: value 13. value: NUMLIT 14. value: IDENT 15. addop: ADD 16. addop: SUB 17. multop: MUL 18. multop: DIV *rules numbered to allow easier referencing in discussions |
Sample Solution:
... assuming everyone is fine with sketching parse trees by now,
the only real trick was spotting the initial addexpr captures the - op
(see simplified AST below for confirmation on the expression structure)
|
Sample Solution:
Just the raw expression tree, none of the syntactic fluff, e.g.
=
/ \
x -
/ \
/ \
/ \
(div)/ +
/ \ / \
/ \ x y
/ \
* *
/ \ / \
/ \ a 5
* +
/ \ / \
a 5 x y
|
Sample Solution:
This is just collapsing the common arcs for the tree above, notably
(i) having a single a*5 subtree that is referenced twice
(ii) having a single leaf for each of a, x, y, 5
(x and y getting referenced once each from the x*y plus once each from the x+y)
|
| index | node/leaf | operand1 | operand2 |
| 0 | leaf: a | symbol table ref to a | n/a |
| 1 | leaf: x | symbol table ref to x | n/a |
| 2 | leaf: y | symbol table ref to y | n/a |
| 3 | leaf: 5 | literal 5 | n/a |
| 4 | node: * | 0 (index for a) | 3 (index for 5) |
| Sample solution | |||
| 5 | node: * | 1 (index for x) | 2 (index for y) |
| 6 | node: * | 4 (a*5) | 5 (x*y) |
| 7 | node: / | 6 ((a*5)*(x*y)) | 4 (a*5) |
| 8 | node: + | 1 (index for x) | 2 (index for y) |
| 9 | node: - | 7 (whole numerator) | 8 (x+y) |
| 10 | node: = | 1 (index for x) | 9 (expression result) |
R1 = a R2 = x R3 = y R4 = 5 R5 = R1 * R4 ... |
Sample Solution: The choice of core operations seems pretty basic, just assignment and the usual basic math ops (+ - * /) R1 = a R2 = x R3 = y R4 = 5 R5 = R1 * R4 (a*5) R6 = R2 * R3 (x*y) R7 = R5 * R6 (a*5)*(x*y) R8 = R7 / R5 ((a*5)*(x*y))/(a*5) R9 = R2 + R3 (x+y) R10 = R8 - R9 full RHS expression R2 = R10 (or use R2 as LHS in prev step?) x = R2 |
a = 200 ; b = a + 1 ; x = a * 7 ; y = 23 * x ; a += b ; a = x + y ; b = a + 1 ; a += b ; b = x + y ; y -= 200 ; x = x + y |
Sample Solution: Here I assumed our 'variables' are likely to be register based, so added variables for the literal values as well (V1, V7, V23, V200), then introduced a new variable each time we changed the computed value for a, b, x, or y (to hold the newly computed value separate from earlier stored values) v1 = 1 v7 = 7 v23 = 23 v200 = 200 a1 = 200 ; b1 = a1 + v1 ; x1 = a1 * v7 ; y1 = v23 * x1 ; a2 = a1 + b1 ; a3 = x1 + y1 ; b2 = a3 + v1 ; a4 = a3 + b2 ; b3 = x1 + y1 ; y2 = y1 - v200 ; x2 = x1 + y2 |