(* l07 - expressions, constant folding *) program = [ 'CONST' { id '=' expression ';' } ] [ 'VAR' { id ':' id ';' } ] 'BEGIN' statement { ';' statement } '.' . statement = [ id ':=' expression | 'WRITE' expression ] . expression = simplexpr [ relop simplexpr ] . simplexpr = [ '+' | '-' ] term { addop term } . term = factor { mulop factor } . factor = number | id | '(' expression ')' | '~' factor . relop = '=' | '#' | '<>' | '<' | '<=' | '>' | '>=' . addop = '+' | '-' | '|' . mulop = '*' | '/' | '&' . (* l07 = l06 + constant folding 2010-07-15, v00: The ugly truth about l06 is the restriction of constant integers to non-negative values. With l02 already, this issue had been solved by coding a special parsing procedure for constant expressions. As first shot, I'll adopt that solution. 2010-07-17, v01: With v00, Prsr.mi has 351 lines. Parameterising Expression() with a boolean "const" will shrink the code... to 312 lines. 2010-07-27, v02: Only the ugly minus in mind, I didn't see that variables are quite useless in l07 - everything can be done with constants as well. Nevertheless, parser and generator are still quite simple, making the exercise "constant folding" easier to solve. One solution is to turn the boolean parameter "const" from an input to an output parameter. Instead of requiring a factor/term/simplexpr/ expression to be constant, the procedures decide - just as upon the type. Code emission is delayed upon var recognition. The exchange of operands is reversed by additional machine codes for noncommutable operations (stack architecture problem; alternatively, one exchange operation could have been added). This could be avoided by emitting not before the end of simplexpr (relops are symmetric already), requiring some kind of abstract syntax tree. 2010-07-27, v03: Some Prsr cleanup done by putting the operations handling outside the expression procedure. For TS-compatibility, TValue has been changed to LONGINT. 2010-08-11, v04: Compiletime evaluation should be done in the same manner as runtime evaluation, so it should be done by the generator. Although this further simplifies the parser, it leads to a strange generator interface, since Op2() implies Val() if (and only if) one operand is on stack already. Since the generator shouldn't care about types, the corresponding field is removed from TItemDesc and seperated again. *)