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 PP: program[stdin] P: program = PP.tree #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 )