0

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?

1
  • The compiler is punishing you for calling parentheses "brackets". Commented Nov 22, 2013 at 10:19

4 Answers 4

1

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? %% 
Sign up to request clarification or add additional context in comments.

Comments

0

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.

1 Comment

I dont really understand what to do.., can you copy and correct my cod e?
0

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.

Comments

0

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.

1 Comment

The return 0 part is really not recommended. In this case, it is useless, and otherwise, one should rather use YYABORT.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.