【问题标题】:Antlr left recursiveAntlr 左递归
【发布时间】:2011-11-11 23:51:23
【问题描述】:

我正在尝试将 EBNF 形式的 scala 中的后缀、中缀和前缀规则转换为 ANTLR,但在中缀表达式规则上看到与左递归有关的错误。

有问题的规则是:

public symbolOrID
:   ID
|   Symbol
;

public postfixExpression
:   infixExpression symbolOrID? -> ^(R__PostfixExpression infixExpression symbolOrID?)
;

public infixExpression
:   prefixExpression
|   infixExpression (symbolOrID infixExpression)? -> ^(R__InfixExpression infixExpression symbolOrID? infixExpression?)
;

public prefixExpression
:   prefixCharacter? simpleExpression -> ^(R__PrefixExpression prefixCharacter? simpleExpression)
;

public prefixCharacter
:   '-' | '+' | '~' | '!' | '#'
;

public simpleExpression
:   constant
;

如果我将中缀表达式规则更改为:

public infixExpression
:   prefixExpression (symbolOrID infixExpression)? -> ^(R__InfixExpression prefixExpression symbolOrID? infixExpression?)
;

然后它反而抱怨:

warning(200): Hydra.g3:108:26: Decision can match input such as "{ID, Symbol} {'!'..'#', '+', '-', '~'} String" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
warning(200): Hydra.g3:108:26: Decision can match input such as "{ID, Symbol} {'!'..'#', '+', '-', '~'} Number" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
warning(200): Hydra.g3:108:26: Decision can match input such as "{ID, Symbol} {'!'..'#', '+', '-', '~'} Boolean" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
warning(200): Hydra.g3:108:26: Decision can match input such as "{ID, Symbol} {'!'..'#', '+', '-', '~'} Regex" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
warning(200): Hydra.g3:108:26: Decision can match input such as "{ID, Symbol} {'!'..'#', '+', '-', '~'} Null" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input

最后,有没有一种方法可以有条件地在 AST 中创建节点,这样如果只有规则的左侧部分为真,那么它就不会添加该级别?例如:

conditional_or_expression:
    conditional_and_expression  ('||' conditional_or_expression)?
;

假设我创建的语法遵循如下层次结构:

conditional_and_expression
  conditional_or_expression
    null_coalescing_expression

如果解析的表达式是a || b,则当前为该表达式创建的 AST 将是

conditional_and_expression
  conditional_or_expression

我怎样才能得到它,所以它只得到conditional_or_expression 部分?

在 JavaCC 中,您可以只设置节点数量,例如:#ConditionalOrExpression(>1)

编辑:昨晚有点晚了,现在修改了中缀表达式!

最终编辑:我最终让它工作的方式是以下规则:

public symbolOrID
:   ID
|   Symbol
;

public postfixExpression
:   infixExpression (symbolOrID^)?
;

public infixExpression
:   (prefixExpression symbolOrID)=> prefixExpression symbolOrID^ infixExpression
|   prefixExpression
;

public prefixExpression
:   prefixCharacter^ simpleExpression
|   simpleExpression
;

public prefixCharacter
:   '-' | '+' | '~' | '!' | '#'
;

public simpleExpression
:   constant
;

【问题讨论】:

  • 您发布的规则不是左递归的。您能否编辑您的问题并提供一个完整的语法,我或其他人可以在不修改显示您提到的错误的情况下运行?而且我不确定“有条件地创建节点”是什么意思。而且您两次发布了infixExpression 规则(您没有更改任何内容......)。
  • 不幸的是,这对语言来说是一个相当关键的早期阶段,所以我不得不对语法的全部细节保密。一旦它有了实现,我将把它开源发布

标签: scala antlr grammar ebnf


【解决方案1】:

Darkzaelus 写道:

我正在尝试将 EBNF 形式的 scala 中的后缀、中缀和前缀规则转换为 ANTLR,但我看到与左递归有关的错误

正如我在评论中所说:您发布的规则中没有左递归。

Darkzaelus 写道:

我怎样才能得到它,所以它只得到 conditional_or_expression 部分?

我假设您使用的是 ANTLRWorks 的解释器或调试器,在这种情况下是树:

conditional_and_expression
            \
  conditional_or_expression

只是这样显示(显示的是解析树,而不是 AST)。如果您将orExpression 正确转换为AST,则表达式a || b 将变为:

  ||
 /  \
a    b

(即 || 作为根节点,ab 作为子节点)

例如,取如下语法:

grammar T;

options {
  output=AST;
}

parse
  :  expr EOF -> expr
  ;

expr
  :  or_expr
  ;

or_expr
  :  and_expr ('||'^ and_expr)*
  ;

and_expr
  :  add_expr ('&&'^ add_expr)*
  ;

add_expr
  :  atom (('+' | '-')^ atom)*
  ;

atom
  :  NUMBER
  |  '(' expr ')' -> expr
  ;

NUMBER : '0'..'9'+;

如果您现在使用从上述语法生成的解析器来解析 12+34,ANTLRWorks(或 Eclipse ANTLR IDE)将显示以下解析树:

但这不是解析器创建的AST。 AST 实际上看起来像:

(即or_exprand_expr “层”不在那里)

Darkzaelus 写道:

不幸的是,这对语言来说是一个相当关键的早期阶段,所以我不得不对语法的全部细节保密。

没问题,但您必须意识到,如果您隐瞒重要信息,人们将无法正确回答您的问题。您不需要发布整个语法,但如果您需要左递归方面的帮助,您必须发布实际上会导致您提到的错误的(部分)语法。如果我不能复制它,它就不存在! :)

【讨论】:

  • Bart,能不能给你发一份.g3,等问题解决了再更新答案?
  • @Darkzaelus,但是答案与这里的问题不同步。如果您不能以可以重现错误的方式减少语法,我无能为力,抱歉。我接受一对一咨询,但不是免费的:)(如果你想知道我的小时费率,请给我留言:我的电子邮件在我的个人资料中)。
  • 巴特,不幸的是,大约半小时前修正了语法!我会将您的答案标记为正确,因为我使用了您的技巧来标记根。感谢您的帮助和良好的答案
【解决方案2】:

这个作品:

infixExpr ::= PrefixExpr
            | InfixExpr id [nl] InfixExpr

可以改写为

infixExpr ::= PrefixExpr
            | PrefixExpr id [nl] InfixExpr

事实上,我敢打赌这只是语法错误。让我们举一个例子,它是好的。让我们用第一个语法减少(部分)一些东西,然后尝试第二个。

InfixExpr id [nl] InfixExpr                      
// Apply the second reduction to the first InfixExpr
InfixExpr id [nl] InfixExpr id [nl] InfixExpr
// Apply the first reduction to the (new) first InfixExpr
PrefixExpr id [nl] InfixExpr id [nl] InfixExpr
// Apply the first reduction to the new first InfixExpr
PrefixExpr id [nl] PrefixExpr id [nl] InfixExpr
// Apply the first reduction to the new first InfixExpr
PrefixExpr id [nl] PrefixExpr id [nl] PrefixExpr

让我们用第二种语法来化简它:

PrefixExpr id [nl] InfixExpr                      
// Apply the second reduction to the first InfixExpr
PrefixExpr id [nl] PrefixExpr id [nl] InfixExpr
// Apply the first reduction to the new first InfixExpr
PrefixExpr id [nl] PrefixExpr id [nl] PrefixExpr

如您所见,在这两种情况下都以等效的 AST 结尾。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多