Thanks for your reply.
Yes. With this grammar, whatever rule I came up with to allow Pow on the rhs would fail some of the other tests, so I left the grammar as it is on purpose…
With precedence operators, it’s usually better to put every type of expression in one big
expressionrule rather than having subcategories likesecondaryExpression,primaryExpression,juxtaposeExpression, etc. It makes the grammar easier to read, faster to parse, and avoids issues like this.
That’s how I structured my grammar in the full version (with one big expression). This was my attempt at avoiding some expressions to be valid, like -a-b being parsed as Mul( Negate(a), Negate(b) ) through the implicit multiplication. I separated like this to try to be more strict in some rules.
Below is another grammar where I bunched up things in a big expression and made the Juxtapose more general. In this one, stuff like abc^{2} works as expected, but -a-b-c fails as it is parsed as the implicit multiplication of (-a) * (-b) * (-c). This was my original problem. I got the abc^{2} problem only after trying to fix the -a-b-c one.
@top Program { expression* }
@precedence {
highest @left
pow @right
times @left
unary @left
juxt @left
juxtfunc @left
implicitmul @left
div @left
plus @left
minus @left
lowest @left
}
expression {
Variable | Constant | unaryExpression | binaryExpression | juxtaposeExpression
}
Pow { expression !pow "^{" expression "}"}
Add { expression !plus "+" expression}
Sub { expression !minus "-" expression}
Mul { expression !times ("*"|'\\cdot') expression}
Div { expression !div "/" expression | !div '\\frac{'expression'}{'expression'}'}
binaryExpression {
Add | Sub | Mul | Div | Pow
}
Negate { !unary "-" expression}
unaryExpression {
Negate
}
juxtaposeExpression {
Mul { (Variable | Constant) !implicitmul expression } | // Specific one I want to catch here
FunctionCall { FunctionName !juxtfunc expression } | // Specific one I want to catch here
// I'll have a bunch of other specific ones...
Juxtapose { expression !juxt expression } // General juxtaposition that I deal with it later
}
@skip { '$' | space | '\\ ' }
@tokens {
space { @whitespace }
Variable { ('_')*$[A-Za-z]("_{"($[A-Za-z]|@digit+)*"}")*}
FunctionName { ("\\sin" | "\\cos" | "\\tan")}
Constant {
(
(std.digit+ ("." std.digit*)?)
) |
std.digit+ $[uU]? |
"0x" (std.digit | $[a-fA-F])+ $[uU]?
}
}