lex literal `var `if `then `else `while `do `for `read `write `end `to `goto literal `:= `!= `; `+ `- `* `/ `= `( `) `: ignore /'//' [^\n]* '\n'/ ignore /[\n\t ]+/ token id /[a-zA-Z_]+/ token integernumber /[0-9]+/ token stringlit /'"' [^"]* '"'/ end def program [statement*] def statement [declaration] | [assignment_statement] | [if_statement] | [while_statement] | [do_statement] | [for_statement] | [read_statement] | [write_statement] | [labelled_statement] | [goto_statement] def declaration [`var id `;] def assignment_statement [id `:= expression `;] def if_statement [`if expression `then statement* opt_else_statement `end] def opt_else_statement [`else statement*] | [] def while_statement [`while expression `do statement* `end] def do_statement [`do statement* `while expression `;] def for_statement [`for id `:= expression `to expression `do statement* `end] def read_statement [`read id `;] def write_statement [`write expression `;] def expression [term] | [expression eqop term] def eqop [`=] | [`!=] def term [factor] | [term addop factor] def addop [`+] | [`-] def factor [primary] | [factor mulop primary] def mulop [`*] | [`/] def primary [id] | [lit] | [`( expression `)] def lit [integernumber] | [stringlit] def labelled_statement [id `: statement] def goto_statement [`goto id `;] parse P: program[stdin] #for S:statement* in P #{ # if match S [L0: id ':' # First: statement # Rest: statement*] # { # for Check: statement* in Rest # { # if match Check # ['if' E: expression 'then' # 'goto' Targ: id ';' # 'end' # T: statement*] # { # # This truncates Rest # Check = construct statement* [] # # # Replace the labeled statement through to the goto with a # # do ... while. # S = construct statement* # ['do' # First # Rest # 'while' E ';' # T] # break # } # } # } #} for S: statement* in P { if match S [Label: id `: First: statement Rest: statement*] { Expr: expression Following: statement* # Look though the remaining statements for a goto back to the label. # The repeat iterator yields only top-level statement lists. It # restricts our search to the same nesting depth as the label. for Check: statement* in Rest { if match Check [`if E: expression `then `goto L:id `; `end SL: statement*] { Expr = E Following = SL # Check iterates over tails of Rest. Assigning an empty list # to check truncates the Rest list. What we cut off is saved in # Following (excluding the if statement). Check = construct statement* [] } } # If a goto was found, then perform the rewrite. if ( Expr ) { # Replace the labelled statement through to the goto # with a do ... while. S = construct statement* [ "do " [^First] " [^Rest] "while [^Expr]; Following] } } } print( P ) ##### IN ##### var a; a := 1; head: a := a + 1; c := d; if a = 10 then goto head; end hi := there; ##### EXP ##### var a; a := 1; do a := a + 1; c := d; while a = 10; hi := there;