В настоящее время я работаю над созданием DSL в xText и сталкиваюсь с проблемой, которая, вероятно, связана с неоднозначностью или проблемой левой рекурсии.Я не уверен, какая из этих двух проблем относится к моему случаю (похожие темы, которые я нашел в Интернете, также упоминают, что эти проблемы часто кажутся связанными), но я предполагаю, что это связано с левой рекурсией.
В строке 100 в моемКод DSL Я объявляю правило под названием Expression.Как вы можете видеть, он агрегирует несколько других типов (которые, в свою очередь, снова агрегируют несколько других типов, и в конечном итоге также могут быть агрегированы типы, называемые Фактором (в строке 130)).В конечном итоге все это «дерево агрегации» сводится к проблеме с этим типом фактора.Как видите, этот тип может снова агрегировать Expression.Так что есть петля;тип Expression может в конечном итоге содержать тип Factor, а тип Factor может затем снова содержать тип Expression (после чего этот цикл теоретически может продолжаться бесконечно; я полагаю, что в этом проблема, потому что анализатор ANTLR, используемый xText, не был разработан для этоговид рекурсии).Я пытался решить эту проблему, используя синтаксический предикат (=> символ) в типе Expression (см.
(=> "endSimpleExpression")
, но он все еще не работает. Я точно знаю, что это связано с отношениями междутипы Выражения и Фактор (потому что, если я не добавляю типы Выражения в тип Фактора, 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='=='
;