【问题标题】:how to resolve this choice conflict - JavaCC如何解决这个选择冲突 - JavaCC
【发布时间】:2012-12-20 09:41:34
【问题描述】:

我有一个 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,我很容易得到这样的结果: 如果 (variable1 = variable3 )

我试图通过将条件表达式的逻辑与一般表达式的逻辑分开来纠正这个问题:

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()
|

另一个问题是运算符优先级以某种方式搞砸了,例如 如果(“a”==“a”|“c”=="c") 结果|在使用“c”作为其第二个操作数并给出 ClassCastException 的第二个 == 运算符之前被解释,我得出结论,解决这个问题需要重写整个语法,所以我想可能在复合的单个条件周围强制使用括号像这样的条件语句 如果((“a”==“a”)|(“c”==“c”)) 我只是不知道该怎么做。

【问题讨论】:

  • 您允许表达式完全为空?你不想用( SimpleExpression() )+ 表达吗?
  • 你是对的,事实上我发布了一些我正在试验的代码,但这不是问题。

标签: grammar parser-generator operator-precedence javacc


【解决方案1】:

使用? 代替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)
  )?
}

这不应该产生任何冲突,AFAIK。

【讨论】:

    【解决方案2】:

    第二个问题

    另一个问题是运算符优先级被搞砸了,像 IF ( "a" == "a" | "c"=="c" ) 导致 |在第二个 == 运算符之前被解释,使用“c”作为其第二个操作数并给出 ClassCastException,

    由于您没有发布与 | 运算符相关的语法规则,因此很难诊断。不需要您提出的解决方案。

    我希望您不要介意对语言设计的评论:尝试使用语法强制类型正确性通常是一个糟糕的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 1970-01-01
      • 1970-01-01
      • 2019-10-26
      • 1970-01-01
      • 1970-01-01
      • 2019-12-04
      相关资源
      最近更新 更多