Antlr离开了递归

时间:2011-11-11 23:51:23

标签: scala antlr grammar ebnf

我正在尝试将EBNF格式的scala中的后缀,中缀和前缀规则转换为ANTLR但是在infixExpression规则上看到与左递归相关的错误。

有问题的规则是:

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
;

如果我将infixExpression规则更改为:

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中有条件地创建节点,这样如果只有规则的左边部分为真,那么它不会添加该级别? E.g:

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中,您可以设置节点arity,例如:#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
;

2 个答案:

答案 0 :(得分:1)

  

Darkzaelus写道:

     

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

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

  

Darkzaelus写道:

     

我怎么能得到它所以只得到conditional_or_expression部分?

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

conditional_and_expression
            \
  conditional_or_expression

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

  ||
 /  \
a    b

(例如||为root,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)将显示以下解析树:

enter image description here

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

enter image description here

(即or_exprand_expr“图层”

  

Darkzaelus写道:

     

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

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

答案 1 :(得分:0)

此制作:

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结束。