我有一个 javacc 语法,它定义了一种简单的脚本语言,其中包含简单的表达式和条件语句,我正在审查并尝试更正粗略的定义,如下所示:
void Statement() : {}
{
Assignment()
|
IfStatement()
}
void Assignment() : {}
{
RealIdentifier() "=" SimpleExpression()
|
StringIdentifier() "=" StringExpression()
}
void IfStatement() : {}
{
"IF" Expression() "THEN" Block()
(
"ENDIF;"
|
"ELSE" Block() "ENDIF;"
)
}
void Expression() #void : {}
{
SimpleExpression()
(
"<" SimpleExpression() #LTNode(2)
|
">" SimpleExpression() #GTNode(2)
|
"<=" SimpleExpression() #LENode(2)
|
">=" SimpleExpression() #GENode(2)
|
"==" SimpleExpression() #EQNode(2)
|
"!=" SimpleExpression() #NENode(2)
)*
}
void SimpleExpression() #void : {}
{
Term()
(
"+" Term() #AddNode(2)
|
"-" Term() #SubsNode(2)
|
"|" Term() #OrNode(2)
)*
}
void Term() #void : {}
{
Factor()
(
"*" Factor() #MultNode(2)
|
"/" Factor() #DivNode(2)
|
"&" Factor() #AndNode(2)
)*
}
void Factor() #void : {}
{
Real()
|
RealIdentifier()
|
Function()
|
"(" Expression() ")"
|
"!" Factor() #NotNode(1)
|
StringExpression()
}
void Function() :
{
Token t;
int args = 0;
}
{
t = <FUNCTION> { jjtThis.setID(t.image, legacyCharset); } "(" args = ArgumentList() ")"
{ jjtThis.setArgs(args); }
}
int ArgumentList() #void :
{
int args = 0;
}
{
Expression() {args++;} ( "," Expression() {args++;} )*
{ return args; }
}
void StringIdentifier() :
{
Token t;
}
{
t = <STRING_IDENTIFIER>
{
System.out.println("kind="+t.kind+" image="+t.image);
}
}
void RealIdentifier() :
{
Token t;
}
{
t = <REAL_IDENTIFIER>
{
System.out.println("kind="+t.kind+" image="+t.image);
}
}
第一个明显的问题是表达式的定义方式,因为它用于定义 IfStatement,所以我很容易得到这样的结果: if (变量1 < 变量2 >= 变量3 )
我试图通过将条件表达式的逻辑与一般表达式的逻辑分开来纠正这个问题:
void IfStatement() : {}
{
"IF" ConditionalExpression() "THEN" Block()
(
"ENDIF;"
|
"ELSE" Block() "ENDIF;"
)
}
void ConditionalExpression() #void : {}
{
SimpleExpression()
(
"<" #LTNode(2)
|
">" #GTNode(2)
|
"<=" #LENode(2)
|
">=" #GENode(2)
|
"==" #EQNode(2)
|
"!=" #NENode(2)
)SimpleExpression()
}
void Expression() #void : {}
( SimpleExpression() )*
}
编译生成的 jj 文件时,我收到以下警告: 警告:第 210 行第 3 列 (...)* 构造中的选择冲突。 嵌套在构造中的扩展和构造后的扩展 有共同的前缀,其中之一是:“+” 考虑使用 2 或更多的前瞻来进行嵌套扩展。
错误行号是生成的 jj 文件中的一行。我假设冲突是在遇到 SimpleExpression 时发生的,因为它无法确定正在解析的内容是 ConditionalExpression 还是 Expression,所以我尝试使用:
void Expression() #void : {}
{
( LOOKAHEAD(2) SimpleExpression() )*
}
然后
void ConditionalExpression() #void : {}
{
( LOOKAHEAD(2)
SimpleExpression()
(
但它并没有消失。 jj 文件中表示存在选择冲突的行是
void Statement() : {/*@bgen(jjtree) Statement */
ASTStatement jjtn000 = new ASTStatement(JJTSTATEMENT);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/} // <-------------------------------------- line 210
{/*@bgen(jjtree) Statement */
try {
/*@egen*/
Assignment()
|
另一个问题是运算符优先级在某种程度上被搞砸了,比如 IF (“a”==“a”|“c”==“c”) 结果在 |在使用“c”作为第二个操作数的第二个 == 运算符之前进行解释,并给出 ClassCastException,我得出的结论是修复此问题需要重写整个语法,因此我想到可能会在复合的单个条件周围强制使用括号像这样的条件语句 if ((“a”==“a”)|(“c”==“c”)) 我只是不知道该怎么做。
最佳答案
使用 ?
代替 kleen-star *
,使关系表达式的右侧(包括运算符)成为可选,以便单个 SimpleExpression()
也会匹配:
void Expression() #void : {}
{
SimpleExpression()
( "<" SimpleExpression() #LTNode(2)
| ">" SimpleExpression() #GTNode(2)
| "<=" SimpleExpression() #LENode(2)
| ">=" SimpleExpression() #GENode(2)
| "==" SimpleExpression() #EQNode(2)
| "!=" SimpleExpression() #NENode(2)
)?
}
据我所知,这不应该产生任何冲突。
关于grammar - 如何解决这个选择冲突 - JavaCC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13969165/