Решение проблемы левой рекурсии в xText - PullRequest
0 голосов
/ 09 мая 2019

В настоящее время я работаю над созданием 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='=='
;

1 Ответ

0 голосов
/ 10 мая 2019

InternalFinalDsl.g: 139: 2: [фатальное] правило ruleFunctionElements принимает решение без LL (*) из-за рекурсивных вызовов правил, достижимых с alts 1,2.

Итак, давайте посмотрим на правило FunctionElements:

  FunctionElements:
    ifElseStatements += IfElseStatements |
    statements += Statement 
;

Хорошо, так что FunctionElements может быть IfElseStatement или Statement. Это звучит подозрительно и достаточно точно: Statement может быть StructuredStatement, что, в свою очередь, может быть IfElseStatement. Таким образом, вышесказанное неоднозначно, поскольку IfElseStatement может быть получен либо напрямую через FunctionElements -> IfElseStatement, либо косвенно через FunctionElements -> Statement -> StructuredStatement -> IfElseStatement.

Таким образом, вы должны просто удалить альтернативу IfElseStatement, потому что она избыточна.

...