# # Sample Ibpag2 grammar file. # # # The code between %{ and %} gets copied directly. Note the Iconish # comment syntax. # %{ # Note: If IIDEBUG is defined in the output file, debugging messages # about the stacks and actions get displayed. # $define IIDEBUG 1 %} # # Here we declare the tokens returned by the lexical analyzer. # Precedences increase as we go on. Note how (unlike YACC), tokens # are separated by commas. Note also how UMINUS is used only for its # %prec later. # %token NUMBER %left '+', '-' %left '*', '/' %right UMINUS %% # # After this point, and up to the next %%, we have the grammar itself. # By default, the start symbol is the left-hand side of the first # rule. # lines : lines, expr, '\n' { write($2) } | lines, '\n' | epsilon # Note use of epsilon/error tokens. | error, '\n' { write("syntax error; try again:") # like YACC's yyerrok macro iierrok } ; expr : expr, '+', expr { return $1 + $3 } | expr, '-', expr { return $1 - $3 } | expr, '*', expr { return $1 * $3 } | expr, '/', expr { return $1 / $3 } | '(', expr, ')' { return $2 } | '-', expr %prec UMINUS { return -$2 } | NUMBER { return $1 } ; %% # # From here on, code gets copied directly to the output file. We are # no longer in the grammar proper. # # # The lexical analyzer must be called iilex, with the module name # appended (if there is one). It must take one argument, infile (an # input stream). It must be a generator, and fail on EOF (not return # something <= 0, as is the case for YACC + Lex). Iilval holds the # literal string value of the token just suspended by iilex(). # procedure iilex(infile) local nextchar, c, num initial { # Here's where you'd initialize any %{ globals %} declared # above. } nextchar := create !(!infile || "\n" || "\n") c := @nextchar | fail repeat { if any(&digits, c) then { if not (\num ||:= c) then num := c } else { if iilval := \num then { suspend NUMBER num := &null } if any('+-*/()\n', c) then { iilval := c suspend ord(c) } else { if not any(' \t', c) then { # deliberate error - will be handled later suspend &null } } } c := @nextchar | break } if iilval := \num then { return NUMBER num := &null } end procedure main() return iiparse(&input, 1) end