Анализатор Antlr4 неправильно анализирует инструкцию переназначения

#antlr #antlr4

#antlr #antlr4

Вопрос:

Я создавал анализатор грамматики с использованием Antlr4 и хотел добавить переназначение переменной (без необходимости объявлять новую переменную)

Я пытался изменить оператор переназначения на выражение, но это ничего не изменило

Вот сокращенная версия моей грамматики:

 grammar MyLanguage;

program: statement* EOF;

statement
    : expression EOC
    | variable EOC 
    | IDENTIFIER ASSIGNMENT expression EOC
    ;

variable: type IDENTIFIER (ASSIGNMENT expression)?;

expression
    : STRING
    | INTEGER
    | IDENTIFIER
    | expression MATH expression
    | (' ' | '-') expression
    ;

MATH:       ' ' | '-' | '*' | '/' | '%' | '//' | '**';
ASSIGNMENT: MATH? '=';
EOC:        ';';
WHITESPACE: [ trn]  -> skip;

STRING:     '"' (~[u0000-u0008u0010-u001F"] | [t])* '"' | ''' (~[u0000-u0008u0010-u001F'] | [t])* ''';
INTEGER:    '0' | (' ' | '-')? [1-9][0-9]*;
IDENTIFIER: [a-zA-Z_][a-zA-Z0-9_]*;

type:      'str';
  

если что-то еще может иметь отношение к делу, пожалуйста, спросите

итак, я попытался проанализировать

 str test = "empty";
test = "not empty";
  

которая сработала, но когда я попытался (часть функции fibbionaci)

 temp = n1;
n1 = n1   n2;
n2 = temp;
  

он выдал ошибку и проанализировал ее как

 temp = n1; //statement
n1 = n1 //statement - <missing ';'>
 n2; //statement
n2 = temp; //statement
  

Комментарии:

1. Выполняет ли он синтаксический анализ n1 n2 , когда назначение не задействовано? Если это работает до тех пор, пока вы не введете дополнение, то, возможно, проблема в добавлении, а не в назначении.

2. Пожалуйста, включите все определения, чтобы кто-нибудь смог воспроизвести проблему.

3. @sepp2k похоже, что это так, я никогда не тестировал это самостоятельно, и это был результат: n1 /*statement - no viable alternative*/ n2; //statement

4. @BilltheLizard Я добавил все к этим соответствующим определениям (ни у какого другого оператора не возникает проблем)

5. @Dia.Frost по-прежнему не компилируется для меня. После того, как я добавляю grammar fileName; в начале, я получаю «ссылку на неопределенное правило» для WHITESPACE и constant_mod . Пожалуйста, опубликуйте версию вашего кода, которая компилирует и воспроизводит проблему (в идеале вы бы удалили все части, которые не имеют отношения к проблеме, но все же протестировали сокращенную версию, чтобы убедиться, что она компилируется и все еще демонстрирует проблему).

Ответ №1:

Ваша проблема не имеет ничего общего с операторами присваивания. Дополнения просто вообще не работают — независимо от того, являются они частью назначения или нет. Таким образом, простейшим вводом для получения ошибки было бы x y; . Если вы распечатаете поток токенов для этого ввода (например, используя grun с -tokens опцией), вы получите следующий результат:

 [@0,0:0='x',<IDENTIFIER>,1:0]
[@1,1:1=' ',<' '>,1:1]
[@2,2:2='y',<IDENTIFIER>,1:2]
[@3,3:3=';',<';'>,1:3]
[@4,4:3='<EOF>',<EOF>,1:4]
line 1:1 no viable alternative at input 'x '
  

Теперь сравните это с x*y; , который работает нормально:

 [@0,0:0='x',<IDENTIFIER>,1:0]
[@1,1:1='*',<MATH>,1:1]
[@2,2:2='y',<IDENTIFIER>,1:2]
[@3,3:3=';',<';'>,1:3]
[@4,4:3='<EOF>',<EOF>,1:4]
  

Важным отличием здесь является то, что * распознается как MATH токен, но им не является. Вместо этого он распознается как ' ' токен.

Это происходит потому, что вы ввели отдельный ' ' '-' ) тип токена в альтернативе | (' ' | '-') expression . Таким образом, всякий раз, когда лексер видит , он создает ' ' токен, а не MATH токен, потому что строковые литералы в правилах синтаксического анализа имеют приоритет над правилами именованного лексера.

Если вместо этого вы включаете MATH в правило синтаксического анализа math (или, возможно mathOperator ), все операторы будут литералами, и проблема исчезнет. Тем не менее, вам, вероятно, не нужно единое правило для всех математических операторов, потому что это не дает вам желаемого приоритета, но это другая проблема.

PS: Что-то вроде x 1 все равно не сработает, потому что оно будет восприниматься 1 как один INTEGER токен. Вы можете исправить это, удалив из правила начальные - и INTEGER (таким образом, x = -2 это было бы проанализировано как унарный минус, применяемый к целому числу 2 вместо просто целого -2 числа, но это не проблема).

Комментарии:

1. Математический токен фактически уже разделен в моей исходной грамматике, так что это не проблема, я попробую изменить его на правило синтаксического анализа.