Reputation: 11444
this is my bison code:
%}
%union {
int int_val;
}
%left '+' '-'
%nonassoc '(' ')'
%token INTEGER PRINT
%type <int_val> expr_int INTEGER
%%
program: command '\n' { return 0; }
;
command: print_expr
;
print_expr: PRINT expr_int { cout<<$2<<endl; }
expr_int: expr_int '+' expr_int { $$ = $1 + $3; }
| expr_int '-' expr_int { $$ = $1 - $3; }
| '(' expr_int ')' { $$ = $2; }
| INTEGER
;
and this is the flex code:
%}
INTEGER [1-9][0-9]*|0
BINARY [-+]
WS [ \t]+
BRACKET [\(\)]
%%
print{WS} { return PRINT; }
{INTEGER} { yylval.int_val=atoi(yytext); return INTEGER; }
{BINARY}|\n { return *yytext; }
{BRACKET} { return *yytext; }
{WS} {}
. { return *yytext; }
%%
//////////////////////////////////////////////////
int yywrap(void) { return 1; } // Callback at end of file
Invalid inputs for the program are:
print 5
output:
5
input:
print (1+1)
output:
2
But for some reason, for the following inputs I do not get immediate error:
print (1+1))
output:
2
some error
input:
print 5!
output:
5
some error
I would like an error to be printed immediately, without commiting the print command and then throwing an error.
How should I change the program so it will not print errornous inputs?
Upvotes: 0
Views: 575
Reputation: 126203
In yacc/bison, the code associated with a semantic action is executed as soon as the rule in question is reduced, which may happen immediately after the tokens for the rule have been shifted, before looking at any following context to see if there's and error or not (a so-called "default" reduction, used to make the parse tables smaller).
If you want to avoid printing an answer until an entire line is read (and recognized), you need to include the newline in the rule that has the action that prints the message. In your case, you can move the newline from the program
rule to the print_expr
rule:
program: command { return 0; } ;
print_expr: PRINT expr_int '\n' { cout<<$2<<endl; }
Of course, this will still give you an error (after printing output) if you give it multiple lines of input.
Upvotes: 0
Reputation: 1064
Download the "flex & bison" book by John Levine or the "bison" manual from gnu. Both contain an infix calculator that you can reference.
The grammar you have written " '(' expr_int ')'" reduces to expr_int before the grammatically incorrect ')' in "(1 + 1))' is detected. That is the parser does:
(1 + 1)) => ( expr_int )) => expr_int)
and then sees the error. In order to capture the error you have to change the parser to see the error before the reduction, and you have to do it for all errors that you want treated. Therefore you would write (in this case):
expr_int '(' expr_int ')' ')' { this is an error message }
The short answer, after the long answer, is that it is impractical to generate a parser containing instances of all possible errors. What you have is fine for what you are doing. What you should explore is how to (gracefully) recover from an error rather than abandoning parsing.
Your "program" and "command" non-terminals can be combined as:
program: print-expr '\n' { return 0; }
On a separate note, your regular expressions can be rewritten to good effect as:
%%
INTEGER [0-9]+
WS [ \t]+
%%
print/{WS} { return PRINT; }
{INTEGER} { yylval.int_val=atoi(yytext); return INTEGER; }
'(' { return '('; }
')' { return ')'; }
'+' { return '+'; }
'-' { return '-'; }
{WS}* {}
\n { return '\n'; }
. { return *yytext; } // do you really want to do this?
%%
Upvotes: 1
Reputation: 6118
Well that is because you are executing the code while parsing it. The good old bison calculator is meant to teach you how to write a grammar, not implement a full compiler/interpreter.
The normal way to build compiler/interpreter is the following:
lexer -> parser -> semantic analyser -> code generator -> interpreter
Granted building a fully fledged compiler may be overkill in your case. What you need to to is store the result somewhere and only output it after yyparse
has returned without an error.
Upvotes: 0
Reputation: 27577
Create an end-of-line token (eg ;
) for your language and make all lines statements exactly at the point when they encounter this end-of-line token.
Upvotes: 0