Назначение как выражение в грамматике Antlr - PullRequest
4 голосов
/ 06 декабря 2011

Я пытаюсь расширить грамматику Крошечного Языка , чтобы рассматривать назначение как выражение. Таким образом было бы правильно написать

a = b = 1; // -> a = (b = 1)
a = 2 * (b = 1); // contrived but valid
a = 1 = 2; // invalid

Назначение отличается от других операторов в двух аспектах. Это ассоциативно справа (не имеет большого значения), и его левая часть должна быть переменной. Поэтому я изменил грамматику следующим образом

statement: assignmentExpr | functionCall ...;

assignmentExpr: Identifier indexes? '=' expression;

expression: assignmentExpr | condExpr;

Это не работает, потому что содержит решение без LL (*). Я также попробовал этот вариант:

assignmentExpr: Identifier indexes? '=' (expression | condExpr);

но я получил ту же ошибку. Я заинтересован в

  • Этот конкретный вопрос
  • Учитывая грамматику с решением без LL (*), как найти два пути, которые вызывают проблему
  • Как это исправить

Ответы [ 2 ]

2 голосов
/ 07 декабря 2011

Я думаю, что вы можете изменить свою грамматику таким образом, чтобы добиться того же самого, не используя синтаксические предикаты:

statement: Expr ';' | functionCall ';'...;

Expr: Identifier indexes? '=' Expr  |  condExpr ;

condExpr: .... and so on;

Я изменил пример Барта с этой идеей:

grammar TL;

options {
  output=AST;
}

tokens {
  ROOT;
}

parse
  :  stat+ EOF -> ^(ROOT stat+)
  ;

stat
  :  expr ';' 
  ;

expr
  : Id Assign expr -> ^(Assign Id expr)

  | add
  ;

add
  :  mult (('+' | '-')^ mult)*
  ;

mult
  :  atom (('*' | '/')^ atom)*
  ;

atom
  :  Id
  |  Num
  |  '('! expr ')' !
  ;

Assign  :   '=' ;
Comment : '//' ~('\r' | '\n')* {skip();};
Id      : 'a'..'z'+;
Num     : '0'..'9'+;
Space   : (' ' | '\t' | '\r' | '\n')+ {skip();};

А для ввода:

a=b=4;
a = 2 * (b = 1);

вы получите следующее дерево разбора: enter image description here

1 голос
/ 06 декабря 2011

Ключевым моментом здесь является то, что вам нужно «заверить» синтаксический анализатор, что внутри выражения есть что-то впереди, что удовлетворяет выражению.Это можно сделать с помощью синтаксического предиката (части ( ... )=> в правилах add и mult).

Быстрая демонстрация:

grammar TL;

options {
  output=AST;
}

tokens {
  ROOT;
  ASSIGN;
}

parse
  :  stat* EOF -> ^(ROOT stat+)
  ;

stat
  :  expr ';' -> expr
  ;

expr
  :  add
  ;

add
  :  mult ((('+' | '-') mult)=> ('+' | '-')^ mult)*
  ;

mult
  :  atom ((('*' | '/') atom)=> ('*' | '/')^ atom)*
  ;

atom
  :  (Id -> Id) ('=' expr -> ^(ASSIGN Id expr))?
  |  Num
  |  '(' expr ')' -> expr
  ;

Comment : '//' ~('\r' | '\n')* {skip();};
Id      : 'a'..'z'+;
Num     : '0'..'9'+;
Space   : (' ' | '\t' | '\r' | '\n')+ {skip();};

, которая будет анализировать ввод:

a = b = 1;       // -> a = (b = 1)
a = 2 * (b = 1); // contrived but valid

в следующие AST:

enter image description here

...