Pregunta

Estoy tratando de extender la gramática del pequeño idioma tratar la asignación como expresión. Por lo tanto, sería válido escribir

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

La asignación difiere de otros operadores en dos aspectos. Es correcto asociativo (no es un gran problema), y su lado izquierdo tiene que ser una variable. Entonces cambié la gramática de esta manera

statement: assignmentExpr | functionCall ...;

assignmentExpr: Identifier indexes? '=' expression;

expression: assignmentExpr | condExpr;

No funciona, porque contiene una decisión no LL (*). También probé esta variante:

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

Pero recibí el mismo error. Estoy interesado en

  • Esta pregunta específica
  • Dada una gramática con una decisión no ll (*), cómo encontrar las dos rutas que causan el problema
  • Como arreglarlo
¿Fue útil?

Solución

La clave aquí es que debe "asegurar" al analizador que dentro de una expresión, hay algo por delante que satisface la expresión. Esto se puede hacer usando un predicado sintáctico (el ( ... )=> partes en el add y mult normas).

Una demostración rápida:

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();};

que analizará la entrada:

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

en el siguiente AST:

enter image description here

Otros consejos

Creo que puedes cambiar tu gramática de esta manera para lograr lo mismo, sin usar predicados sintácticos:

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

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

condExpr: .... and so on;

Alteré el ejemplo de Bart con esta idea en mente:

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();};

Y para la entrada:

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

obtienes siguiendo el árbol de análisis:enter image description here

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top