0
votes

For simplification of the original problem, supposed I wanted to parse a string of left and right parentheses. The flex file would have the tokens

"(" return LPAREN
")" return RPAREN

and the bison file would have the productions

completedparse: pair {printf("Success!\n");}
;
pair: LPAREN pair RPAREN
    | LPAREN RPAREN pair
    | LPAREN RPAREN
;

IF given the string "(()()(()))" or "()()(())" It would succeed.

The problem I have is that "(()()))" would print the success statement, immediately before failure. I know that bison creates the production

$accept: completedparse $end

which is how bison accepts or rejects the string. All my problems would go away if I could write my own $accept production and include any print statements in that production. But according to the 3.0.2 manual $accept cannot be used in the grammar.

My problems would also go away if I could modify the return value of yyparse() (assume that I need more information than just 0 => success, 1 => failure). I don't think this is possible though.

If you have any insight please respond, and thanks for any help!

1

1 Answers

1
votes

One simple solution:

completedparse: pair {printf("Success!\n");} 
              | pair error
              ;

The error pseudo-terminal won't match all errors, but it will match the one where an EOF is expected and something else is found. If the error is encountered in some other context, the error production won't apply. In general, you should use yyerror to perform an action on a syntax error; the above rule is simply a way to avoid invoking the completedparse action in the case that there is garbage at the end of the input.

By the way, your grammar does not match (())(). You might want to use:

pair:         /* EMPTY */
    |         '(' pair ')' pair
    ;

Additionally:

In response to the addendum in the comments:

  1. You can use the action { YYABORT } in the error production in order to immediately return (with a return value of 1, indicating a syntax error). If you want to print a generic error message, you are probably better off doing so in your yyerror implementation, since that will be called on any syntax error, while the error production will only be reduced on certain errors. You can use error productions to generate more specific error messages, but that's a lot more work.

  2. You cannot customize the $accept pseudo-production. However, the above technique is more or less equivalent.

  3. You cannot change the return type or values of yyparse (0 success, 1 syntax error, 2 allocation error). However, it is often useful to return more data from a parse (for example, an AST). The "traditional" solution is to just use a global variable, but for those of us with a distaste for global variables, another solution is to use the [%parse-param][1] declaration to add one or more additional arguments; normally, your start production will set the value of the objects to which these arguments point. If you do this, you should always check the return value of yyparse before relying on the additional return information, exactly because the start production may be evaluated even in the case of an error.