Exercise: Logical And
As an exercise now support a logical And. This can be done in the same fashion the logical Or was supported:
-
The grammar update is provided and based on the C grammar.
-
Define an enum constant EK_LOGICAL_AND for the corresponding expression kind in expr.h
-
Support constant folding by adapting constFoldBinary() in expr.c.
-
Adapt functions loadExpr() and condJmpExpr() in expr.c
-
Adapt function printExprNode() in expr.c
For code generation the most relevant part will be condJmpExpr()`. And again, considering flow charts for the two cases where either a "true label" or "false label" is provided describes pretty much how to implement the relevant cases.
Grammar Update
The precedence of the logical And is higher than the precedence of the logical Or. In the production rules of the grammar it shows up between the production rule for the logical Or expressions and equality expressions:
\[\begin{array}{rcl}\text{logical-or-expr} & = & \text{logical-and-expr}\; \{\; \texttt{"||"}\; \text{logical-and-expr} \} \\\text{logical-and-expr} & = & \text{equality-expr}\; \{\; \texttt{"&&"}\; \text{equality-expr} \} \\\text{equality-expr} & = & \text{relational-expr}\; \{\; (\; \texttt{"=="}\; |\; \texttt{"!="}\; )\; \text{relational-expr} \} \\\text{relational-expr} & = & \text{additive-expr}\; \{\; (\; \texttt{">"}\; |\; \texttt{"<"}\; |\; \texttt{">="}\; |\; \texttt{"<="}\; )\; \text{additive-expr} \} \\\text{additive-expr} & = & \text{multiplicative-expr}\; \{\; (\; \texttt{"+"}\; |\; \texttt{"-"}\; )\; \text{multiplicative-expr} \} \\\text{multiplicative-expr} & = & \text{unary-expr}\; \{\; (\; \texttt{"*"}\; |\; \texttt{"/"}\; |\; \texttt{"%"} )\; \text{unary-expr} \} \\\end{array}\]As before the same precedence level as in C can be used:
Precedence |
Operators |
Meaning |
13 |
* (multiply) / (divide) % (modulo) |
Multiplicative |
12 |
+ (add) - (subtract) |
Additive |
10 |
< (less) > (greater) <= (less equal) >= (greater equal) |
Relation |
9 |
== != |
Equality Inequality |
5 |
&& |
Logical And |
4 |
|| |
Logical Or |
Code Generation
Again we have to distinguish two cases. First the case that the jump should take place if the condition is true:
Flow chart for the logical And conjunction: |
Flow chart with child nodes of the logical And conjunction: |
And the case that the jump should take place if the condition is false:
Flow chart for the logical And conjunction: |
Flow chart with child nodes of the logical And conjunction: |
Tests
Here some simple test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $< 1 && 2;
$< 1 && 0;
$< 0 && 1;
$> a;
$> b;
x = a && (a = a + 1);
$< x;
$< a;
x = a && a + b > 0 && a + b < 10;
$< x;
x = a == 42 || a + b > 0 && a + b < 10;
$< x;
|
And here a test run:
theon$ make logical_and ../xtest_abc logical_and.s < logical_and.abc ../../../ulm-generator/1_ulm_build/stack/ulmas logical_and.s getuint64.s printuint64.s (echo "#! ../../../ulm-generator/1_ulm_build/stack/ulm"; cat a.out) > logical_and rm -f a.out chmod +x logical_and theon$ echo "3 4" | ./logical_and 1 0 0 1 4 1 1 theon$ echo "0 4" | ./logical_and 1 0 0 0 0 0 1 theon$ echo "7 4" | ./logical_and 1 0 0 1 8 0 0 theon$ echo "42 4" | ./logical_and 1 0 0 1 43 0 0 theon$
Here some test for short-circuit evaluation for the logical And:
1 2 3 4 5 | $> a;
x = a && (a = a + 1);
$< x;
$< a;
|
Only when a is non-zero it gets incremented:
theon$ make logical_and_sce ../xtest_abc logical_and_sce.s < logical_and_sce.abc ../../../ulm-generator/1_ulm_build/stack/ulmas logical_and_sce.s getuint64.s printuint64.s (echo "#! ../../../ulm-generator/1_ulm_build/stack/ulm"; cat a.out) > logical_and_sce rm -f a.out chmod +x logical_and_sce rm logical_and_sce.s theon$ echo "1" | ./logical_and_sce 1 2 theon$ echo "0" | ./logical_and_sce 0 0 theon$
Here the generated logical-and-sce.pdf for the expression trees in the program.