【发布时间】:2019-05-09 14:51:43
【问题描述】:
我目前正致力于在 xText 中创建 DSL,但我偶然发现了一个可能与歧义或左递归问题有关的问题。我不确定这两个问题中的哪一个适用于我的案例(我在网上找到的类似主题也提到这些问题通常看起来相关)但我想这与左递归有关。
在我的 DSL 代码的第 100 行,我声明了一个名为 Expression 的规则。如您所见,它聚合了多种其他类型(它们又聚合了多种其他类型,最终也可以聚合称为 Factor 的类型(第 130 行))。最终,整个“聚合树”归结为这种因子类型的问题。如您所见,这种类型可以再次聚合一个表达式。所以有一个循环; Expression 类型最终可以包含一个 Factor 类型,然后 Factor 类型可以再次包含一个 Expression 类型(之后这个循环理论上可以无限继续;我想这就是问题所在,因为 xText 使用的 ANTLR 解析器不是为此而设计的一种递归)。我试图通过在 Expression 类型中使用语法谓词(=> 符号)来解决这个问题(参见
(=> "endSimpleExpression")
但它仍然无法正常工作。我确定它与 Expressions 和 Factor 类型之间的关系有关(因为如果我不在 Factor 类型中添加 Expression 类型,DSL 就可以正常工作)。我假设我没有将句法谓词放在正确的位置。我考虑的另一个解决方案是使用左分解,但我不知道在这种情况下如何应用左分解。我很好奇你对这个问题的看法。
grammar org.xtext.example.mydsl.FinalDsl with org.eclipse.xtext.common.Terminals
generate finalDsl "http://www.xtext.org/example/mydsl/FinalDsl"
Model:
'functionName' name = STRING
functions += FunctionElements*
;
// Function elements of which the model exists. The model can contain
// library functions, for loops, and if/else statements.
FunctionElements:
ifElseStatements += IfElseStatements |
statements += Statement
;
// IfElse Statements requiring if statements and optionally followed by
// one else statement.
IfElseStatements:
ifStatements += IfStatements
(elseStatement = ElseStatement)?
;
// If statements requiring conditions and optionally followed by
// library functions or for loops.
IfStatements:
'if'
expression = Expression
(ifFunctions += libraryFunctionsEnum | forLoops += ForLoops)
;
// Else statement requiring one or multiple library functions.
ElseStatement:
'else' elseFunctions += libraryFunctionsEnum
;
// For loops requiring one condition and followed by zero or more
// library functions
ForLoops:
'for'
expressions = Expression
libraryFunctions += libraryFunctionsEnum*
;
Statement:
//compoundStatement += CompoundStatement | //left out of Statement because
// otherwise a recursive call exists (statement += compoundstatement += statement
simpleStatement += SimpleStatement |
structuredStatement += StructuredStatement
;
SimpleStatement:
classOperationStatement += ClassOperationStatement |
libraryInterFaceMethodStatement += LibraryInterFaceMethodStatement |
libraryPersistenceMethodStatement += LibraryPersistenceMethodStatement
;
StructuredStatement:
forLoops += ForLoops | ifElseStatements += IfElseStatements
;
ClassOperationStatement:
classOperationName += libraryFunctionsEnum
;
LibraryInterFaceMethodStatement:
interfaceMethods += libraryInterFaceMethodStatementEnum
;
LibraryPersistenceMethodStatement:
persistenceMethods += libraryPersistenceMethodStatementEnum
;
//*Eventually filled with details from class diagram, but for now we manually fill it for the sake of testing.
enum libraryFunctionsEnum:
login='login'|
hasCode= 'encrypt'|
display='display'
;
enum libraryPersistenceMethodStatementEnum:
createInstance = "createInstance" |
log = "log"
;
enum libraryInterFaceMethodStatementEnum:
mesasge = "message" |
error = "error"
;
Expression:
simpleExpression = SimpleExpression
(relationalOperator = RelationalOperator
additionalSimpleExpression = SimpleExpression)?
(=> "endSimpleExpression")
;
SimpleExpression:
term = Term
additionalExpressions += AdditionalExpressions*
;
AdditionalExpressions:
additionOperator = AdditionOperator
term = Term
;
Term:
factorTerm = Factor
additionalTerm += AdditionalTerm*
;
AdditionalTerm:
multiplicationOperator = MultiplicationOperator
factor = Factor
;
// We can optionally integrate Java types right here (int, boolean, string, etc.)
Factor: {Factor} (
"(" expression = Expression ")" |
//'not' factor += Factor |
operationParameterName = OperationParameterName |
classAttributeName += ClassAttributeName |
INT //| STRING //| set = Set
)
;
OperationParameterName: // We can use identifiers right here, but for now I put in a string
'operationParameter' STRING
;
ClassAttributeName: // We can use identifiers right here, but for now I put in a string
STRING
;
RelationalOperator:
"=" | "<>" | "<" | "<=" | ">" | ">=" | "in"
;
AdditionOperator:
"+" | "-" | "or"
;
MultiplicationOperator:
"*" | "/" | "and"
;
enum logicalOperators:
greaterThan='>'|
smallerThan='<'|
greaterOrEqualThan='=>'|
smallerOrEqualThan='<='|
equalTo='=='
;
【问题讨论】:
-
一个表达式可以包含一个词,一个词可以包含一个表达式,这并没有错。 ANTLR 不仅完全能够处理这种递归,而且大多数语言都需要这种递归。 ANTLR 无法处理的是左递归(尽管如果您以某种方式构建语法,ANTLR 4 可以处理它,但这无关紧要,因为 xtext 使用 ANTLR 3),但是您的规则不是左递归的,因为有一个“(”在调用
Expression之前,这意味着递归不是定义的最左边部分。 -
所以请更具体地说明您的问题。您是否收到一条错误消息,告诉您您的语法不明确或左递归?如果是这样,请准确发布该错误消息。还是语法根本不匹配您想要匹配的内容?如果是这样,请显示一个应该匹配但不匹配的简单输入(反之亦然)。
-
@sepp2k 感谢您的回复。问题不在于我的 xText 语法无法编译。上面的语法实际上并没有给出任何直接的错误,但是当它编译时我无法执行编译后的文件(我可以,但是当执行编译后的文件以在新的 Eclipse 环境中启动我的 DSL 时,出现插件错误意味着显然出了点问题)。但是,控制台在编译语法时确实会出现以下错误:
-
错误(211):../org.xtext.example.finaldsl/src-gen/org/xtext/example/mydsl/parser/antlr/internal/InternalFinalDsl.g:139:2: [致命] 规则 ruleFunctionElements 具有非 LL(*) 决策,因为可以从 alts 1,2 访问递归规则调用。通过左分解或使用句法谓词或使用 backtrack=true 选项来解决。
-
所以“在幕后”这似乎是一个左递归问题(尽管它以“(”开头,正如你已经指出的那样)。问题是当我删除这些括号,受此左递归问题影响的规则立即用红线下划线。当我将鼠标悬停在它们上时,它指出“此规则调用是左递归调用图的一部分”。所以它似乎是左递归问题(是否添加“(”括号无关紧要)。