Initiating a short circuit rule in Bison for && and || operations

I program a simple calculator in Bison and Flex using C / C ++ (the logic is done in Bison, and part of C / C ++ is responsible for data structures like STL, etc.).

I have the following problem:

In my calculator, the dollar sign $ means i ++ and ++ i (both prefix and postfix), for example:

 int y = 3; -> $y = 4 -> y$ = 4 

When the user clicks: int_expression1 && int_expression2 , if int_expression1 evaluates to 0 (i.e. false), then I do not want the bison to evaluate int_expression2 !

For instance:

 int a = 0 ; int x = 2 ; 

and the user presses: int z = a&&x$ ...

So, the variable a is evaluated as 0 , so I don't want to evaluate x , however it still grows by 1 ... here is the bison / C ++ code:

 %union { int int_value; double double_value; char* string_value; } %type <int_value> int_expr %type <double_value> double_expr %type <double_value> cmp_expr int_expr: | int_expr '&&' int_expr { /* And operation between two integers */ if ($1 == 0) $$ = 0; else // calc $$ = $1 && $3; } 

How can I tell a bison not to evaluate the second expression if the first has already been evaluated as false (i.e. 0 )?

+4
source share
2 answers

Convert an extensive comment into a response:

How can I tell Bison not to evaluate the second expression if the first has already been evaluated as false?

This is your code that does the evaluation, not Bison; put the “guilt” where it belongs.

You need to determine that you are dealing with the && rule before evaluating RHS. Most likely, you need to paste the code after && and until the second int_expr , which pauses the evaluation if the first int_expr is evaluated to 0. You will also need to change all other evaluation code to check and obey the "do not evaluate" flag.

In addition, you have a Bison that parses and creates a program that you execute when the parsing is completed, and not evaluated during the analysis. This is a much larger set of changes.

Are you sure you put some code before the second int_expr? I can't seem to find a plausible way to do this. This is a good trick, but I can't find a way to actually tell Bison not to rate the second int_expr without ruining the whole evaluation.

You must write your code so that it does not evaluate when it should not be evaluated. Bison Syntax:

 | int_expr '&&' {...code 1...} int_expr {...code 2...} 

"Code 1" will check for $1 and arrange for an evaluation stop (set a global variable or something like that). "Code 2" will conditionally evaluate $4 (4, because "code 1" is now equal to 3 US dollars). The entire evaluation code must obey the instructions “code 1” - it must not evaluate whether “code 1” means “do not evaluate”. Or you can do what I suggested, and aselle suggested ; analyze and evaluate separately.

I aselle's second suggestion about the UNIX programming environment . There is a whole chapter on calculator development (they call it hoc for a higher order calculator), which is worth reading. Keep in mind, however, that the book was published in 1984 and prepared in advance for standard C by a good margin. There are no prototypes in C code, and (by modern standards) several freedoms are required. I have hoc6 (the latest version of hoc that they describe, as well as versions 1-3) in modern C - contact me if you want (see My profile).

This is the problem: I cannot stop evaluating in the middle of the rule, since I cannot use return (I can, but to no avail, it makes the program exit). | intExpr '&&' { if ($1 == 0) {/* turn off a flag */ } } intExpr { /* code */} | intExpr '&&' { if ($1 == 0) {/* turn off a flag */ } } intExpr { /* code */} After exiting $3 , $4 is automatically evaluated.

You can stop evaluating in the middle of the rule, but you need to code the code for the expression evaluation code to take this possibility into account. And when I said “stop evaluating”, I meant “stop doing calculations” and not “stop the parser on its tracks”. The parsing should continue; your code that calculates values ​​should only be evaluated when an evaluation is required, and not when an evaluation is not required. It could be a global flag (ugh!), Or you could have some other mechanism.

It is probably best to convert your parser into a code generator and execute the code after parsing it. Such a complication is why this is a good strategy.

@JonathanLeffler: You really are the king! This should be the answer !!!

Now this is the answer.

+2
source

You almost certainly want to generate a different view before evaluating in your calculator. The parsing tree or ast are classic methods, but a simple stack machine is also popular. There are many great examples of how to do this, but my favorite is http://www.amazon.com/Unix-Programming-Environment-Prentice-Hall-Software/dp/013937681X This shows how to take a simple direct assessment tool as you done in yacc (old bison), and completely translate it into a programming language that is almost as powerful as BASIC. All on very few pages. This is a very old book, but worth reading.

You can also see SeExpr http://www.disneyanimation.com/technology/seexpr.html which is a simple expression language calculator for scalars and 3 vectors. If you look at https://github.com/wdas/SeExpr/blob/master/src/SeExpr/SeExprNode.cpp on line 313 you will see the && implementation of the eval () function:

 void SeExprAndNode::eval(SeVec3d& result) const { // operands and result must be scalar SeVec3d a, b; child(0)->eval(a); if (!a[0]) { result[0] = 0; } else { child(1)->eval(b); result[0] = (b[0] != 0.0); } } 

This file contains all objects representing operations in the parse tree. These objects are generated during code analysis (these are actions in yacc). Hope this helps.

+1
source

All Articles