我正在尝试将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
;
答案 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,a
和b
为子节点
例如,采用以下语法:
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_expr
,and_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结束。