ANTLR4 left-recursive error - recursion

My ANTLR4 grammar in file power.g4 is this:
assign : id '=' expr ;
id : 'A' | 'B' | 'C' ;
expr : expr '+' term
| expr '-' term
| term ;
term : term '*' factor
| term '/' factor
| factor ;
factor : expr '**' factor
| '(' expr ')'
| id ;
WS : [ \t\r\n]+ -> skip ;
When I run command
antlr4 power.g4
This error occurred:
error(119): power.g4::: The following sets of rules are mutually left-recursive [expr, factor, term]
What can I do?

To avoid the left recursion error, put all forms of an expr in one rule, ordered by desired precedence:
expr : '(' expr ')'
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| expr '**' expr
| id
;

Related

Error about left-recursive in ANTLR . Need to do what now?

//Expression
exp: exp1 ASS_OP exp | exp1;
exp1: exp1 OR_OP exp2 | exp2;
exp2: exp2 AND_OP exp3 | exp3;
exp3: exp4 (EQUAL_OP | NOT_EQUAL_OP) exp4 | exp4;
exp4: exp5 (LESS_OP|GREATER_OP|LESS_EQUAL_OP|GREATER_EQUAL_OP) exp5 | exp5;
exp5: exp5 (ADD_OP | SUB_OP) exp6 | exp6;
exp6: exp6 (MUL_OP | DIV_OP | MOD_OP) exp7 | exp7;
exp7: (ADD_OP | SUB_OP | NOT_OP) exp7 | exp8;
exp8: LB exp RB | expl;
expl: invocation_exp | index_exp | ID | INTLIT |FLOATLIT | BOOLEANLIT | STRINGLIT;
index_exp: exp LSB exp RSB;
invocation_exp: ID LB (exp (COMMA exp)*)? RB;
[error] error(119): MC.g4::: The following sets of rules are mutually left-recursive [exp, index_exp, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8, expl]
[trace] Stack trace suppressed: run last *:Antlr generates lexer and parser for the full output.
Hi, I'm new. I read some topics so that ANTLR4 supports only direct left-recursion. And authors seem don't want to change that. So anyone can help me fix my code? Thank for reading this.
One of the great things about ANTLR4 as opposed to some of the older tools is that you don't often have to "chain" your operator precedence like this:
exp: exp1 ASS_OP exp | exp1;
exp1: exp1 OR_OP exp2 | exp2;
exp2: exp2 AND_OP exp3 | exp3;
I remember those days of chaining expression rules for strict BNF grammars. But in ANTLR4, we can do better and have a clearer grammar too. Since the rules are evaluated top to bottom, the highest-predecence rules are listed first like in this snippet:
expr
: expr POW<assoc=right> expr #powExpr
| MINUS expr #unaryMinusExpr
| NOT expr #notExpr
| expr op=(MULT | DIV | MOD) expr #multiplicationExpr
| expr op=(PLUS | MINUS) expr #additiveExpr
| expr op=(LTEQ | GTEQ | LT | GT) expr #relationalExpr
| expr op=(EQ | NEQ) expr #equalityExpr
| expr AND expr #andExpr
| expr OR expr #orExpr
| atom #atomExpr
This might solve your operator precedence issues without wrangling with mutual left recursion. Highest precedence at top, with power (exponentiation) in this example (and by mathematical convention) having the highest binding in an expression.

jq: error: number and object cannot be subtracted

I'm using jq 1.4 and am confused about the following situation. I can calculate a number, but get an error when I try to construct an object with this number:
echo '{"aggregations":{"sent":{"value":25},"bounced":{"value":null},"incoming_act":{"value":25}}}' |
jq '.aggregations
| {"num_sent": .sent.value, "num_incoming_act": .incoming_act.value }
| .num_sent as $x
| .num_incoming_act as $y
| $y-$x as $d
| $d'
0
works fine. But
echo '{"aggregations":{"sent":{"value":25},"bounced":{"value":null},"incoming_act":{"value":25}}}' |
jq '.aggregations
| {"num_sent": .sent.value, "num_incoming_act": .incoming_act.value }
| .num_sent as $x
| .num_incoming_act as $y
| $y-$x as $d
| {diff: $d}'
jq: error: number and object cannot be subtracted
doesn't work. Same happens when I ask for objects in the last part:
echo '{"aggregations":{"sent":{"value":25},"bounced":{"value":null},"incoming_act":{"value":25}}}' |
jq '.aggregations
| {"num_sent": .sent.value, "num_incoming_act": .incoming_act.value }
| .num_sent as $x
| .num_incoming_act as $y
| $y-$x as $d
| objects'
jq: error: number and object cannot be subtracted
I love jq's pipe system. However, something seems to be going on here. What is the "0" that I get in the first example? It doesn't seem to be a normal number 0. This works again:
jq -n ' 0 as $x | {diff: $x} '
This
echo '{"aggregations":{"sent":{"value":25},"bounced":{"value":null},"incoming_act":{"value":12}}}' | jq '.aggregations | {"num_sent": .sent.value, "num_incoming_act": .incoming_act.value } | {diff:(.num_sent as $x | .num_incoming_act as $y | $y-$x as $d | $d)}'
Will Produce:
{
"diff": -13
}
Difference being here;
Previous: .num_sent as $x | .num_incoming_act as $y | $y-$x as $d | {diff: $d}'
Now: {diff:(.num_sent as $x | .num_incoming_act as $y | $y-$x as $d | $d)}'
You can probably see by visualising the difference, where jq is processing things.
In the examples where you get an error, write ($y-$x) as $d rather than just $y-$x as $d. The parentheses are sometimes necessary, and always advisable, when writing (COMPOUND INFIX EXPRESSION) as $variable.
Explanation:
The parser treats expressions of the form:
3-2 as $d | EXPR
as:
3-(2 as $d | EXPR)
This means that 3-2 as $d|$d is parsed as 3-(2 as $d|$d) which evaluates to 3-2. Notice, though, that in this case, $d itself has the value 2.

Eliminate left recursion for my grammar

Can you help me with this example? How should i do left recursion elimination with this size? i know how to do it for simpler examples.
Expr1 ::= Number
| String
| `true`
| `false`
| `undefined`
| Expr1 `+` Expr1
| Expr1 `-` Expr1
| Expr1 `*` Expr1
| Expr1 `%` Expr1
| Expr1 `<` Expr1
| Expr1 `===` Expr1
| Ident AfterIdent
| `[` Exprs `]`
| `[` `for` `(` Ident `of` Expr `)` ArrayCompr Expr `]`
| `(` Expr `)`
Is this the solution?
Expr1 ::= Number ExprB
| String ExprB
| `true` ExprB
| `false` ExprB
| `undefined` ExprB
| Ident AfterIdent ExprB
| `[` Exprs `]`
| `[` `for` `(` Ident `of` Expr `)` ArrayCompr Expr `]`
| `(` Expr `)`
ExprB ::= ϵ
| `+` Expr1 ExprB
| `-` Expr1 ExprB
| `*` Expr1 ExprB
| `%` Expr1 ExprB
| `<` Expr1 ExprB
| `===` Expr1 ExprB
The trick I've learned is to introduce constructive non-terminals to get fewer grammar rules at any one spot. You'll still have some nasty expansions inherent in the language, but you can make the process easier at each step.
Scalar ::= Number | String | `true` | `false` | `undefined`
Op ::= '+' | '-' | '*' | '%' | '<' | '==='
OpExpr ::= Expr1 Op Expr1
ParenExpr ::=
`[` Exprs `]`
| `[` `for` `(` Ident `of` Expr `)` ArrayCompr Expr `]`
| `(` Expr `)`
Expr1 ::=
Scalar
| OpExpr
| ParenExpr
| Ident AfterIdent
There are two main gains here. One is that if you're implementing the parser, the rules now more closely match the families of processing. You can take certain common actions upon the classified reductions. The second is that you can simplify your elimination of recursion: you have the same quantity of terminals to begin an Expr1, but only one rule to expand, the definition of OpExpr.
I know that I haven't completed the exercise for you, but I hope that this helps enough to get you moving. You might also want to check out operator precedence grammars: they handle some of this in elegant fashion, depending on your application.

Maximum and Minimum using awk

How would you find the maximum and minimum a,b,c values for the rows that start with MATH from the following file?
TITLE a b c
MATH 12.3 -0.42 5.5
ENGLISH 70.45 3.21 6.63
MATH 3.32 2.43 9.42
MATH 3.91 -1.56 7.22
ENGLISH 89.21 4.66 5.32
It can not be just 1 command line. It has to be a script file using BEGIN function and END.
I get the wrong minimum value and I end up getting a string for max when I run my program. Please help!
Here is my code for the column a:
BEGIN { x=1 }
{
if ($1 == "MATH") {
min=max=$2;
for ( i=0; i<=NF; i++) {
min = (min < $i ? min : $i)
max = (max > $i ? max : $i)
}
}
}
END { print "max a value is ", max, " min a value is ", min }
Thanks!
This code could demonstrate a concept of what you want:
awk '$1!="MATH"{next}1;!i++{min=$2;max=$2;}{for(j=2;j<=NF;++j){min=(min<$j)?min:$j;max=(max>$j)?max:$j}}END{printf "Max value is %.2f. Min value is %.2f.\n", max, min}' file
Output:
MATH 12.3 -0.42 5.5
MATH 3.32 2.43 9.42
MATH 3.91 -1.56 7.22
Max value is 12.30. Min value is -1.56.
Remove 1 to suppress the messages:
awk '$1!="MATH"{next};...
Script version:
#!/usr/bin/awk
$1 != "MATH" {
# Move to next record if not about "MATH".
next
}
!i++ {
# Only does this on first match.
min = $2; max = $2
}
{
for (j = 2; j <= NF; ++j) {
min = (min < $j) ? min : $j
max = (max > $j) ? max : $j
}
}
END {
printf "Max value is %.2f. Min value is %.2f.\n", max, min
}
look at your for loop
it starts from i=0 so the condition should be
i<NF
instead of
i<= NF
try the following line instead of that line .... i hope you get what u are looking for
for(i=0;i<NF;i++){
rest all looks fine to me.... thanks
The i variable in the for loop should at least begin with 2(the 2rd field), not 0, which represent the whole line, and end with NF.
BEGIN { x=1;min=2147483647;max=-2147483648}
{
if ($1 == "MATH") {
for ( i=2; i<=NF; i++) {
min = (min < $i ? min : $i)
max = (max > $i ? max : $i)
}
}
}
END { print "max a value is ", max, " min a value is ", min }
Run with command:(testawk.script for the above awk script filename, test.data for input data filename)
cat test.data | awk -f testawk.script
output:
max a value is 12.30 min a value is -1.56
I don't have a terminal handy on me right now but something along these lines will get the smallest of each line.
cat YOURFILE | grep "^MATH" | cat test | \
while read CMD; do
A=`echo $CMD | awk '{ print $2 }'`
B=`echo $CMD | awk '{ print $3 }'`
C=`echo $CMD | awk '{ print $4 }'`
#IF Statement for comparing the three of them
#echo the smallest
done

how to remove left-recursion

I'd like to make a grammar that will allow curried function calls.
That is:
a() /// good
a()() /// good
a()()() /// good
a(a) /// good
a(a()()) /// good
/// etc
My first stab was this:
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
fncall : expr '(' (expr (',' expr)*)? ')';
expr : ID|fncall;
But that fails due to left recursion.
Assuming (a)() would also be valid, here's a way to solve this:
grammar T;
options {
output=AST;
}
tokens {
EXPR_LIST;
CALL;
INDEX;
LOOKUP;
}
parse
: expr EOF -> expr
;
expr
: add_expr
;
add_expr
: mul_exp (('+' | '-')^ mul_exp)*
;
mul_exp
: atom (('*' | '/')^ atom)*
;
atom
: fncall
| NUM
;
fncall
: (fncall_start -> fncall_start) ( '(' expr_list ')' -> ^(CALL $fncall expr_list)
| '[' expr ']' -> ^(INDEX $fncall expr)
| '.' ID -> ^(LOOKUP $fncall ID)
)*
;
fncall_start
: ID
| '(' expr ')' -> expr
;
expr_list
: (expr (',' expr)*)? -> ^(EXPR_LIST expr*)
;
NUM : '0'..'9'+;
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
The parser generated from the grammar above would parse the input:
(foo.bar().array[i*2])(42)(1,2,3)
and construct the following AST:
Without the tree rewrite rules, the grammar would look like this:
grammar T;
parse
: expr EOF
;
expr
: add_expr
;
add_expr
: mul_exp (('+' | '-') mul_exp)*
;
mul_exp
: atom (('*' | '/') atom)*
;
atom
: fncall
| NUM
;
fncall
: fncall_start ( '(' expr_list ')' | '[' expr ']' | '.' ID )*
;
fncall_start
: ID
| '(' expr ')'
;
expr_list
: (expr (',' expr)*)?
;
NUM : '0'..'9'+;
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;

Resources