Question

J'essaye d'étendre la grammaire de la petite langue pour traiter l'attribution comme une expression. Il serait donc valable d'écrire

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

L'attribution diffère des autres opérateurs sous deux aspects. C'est droit associatif (pas un gros problème), et son côté gauche doit être une variable. Alors j'ai changé la grammaire comme ça

statement: assignmentExpr | functionCall ...;

assignmentExpr: Identifier indexes? '=' expression;

expression: assignmentExpr | condExpr;

Cela ne fonctionne pas, car il contient une décision non LL (*). J'ai également essayé cette variante:

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

Mais j'ai eu la même erreur. Je suis intéressé par

  • Cette question spécifique
  • Étant donné une grammaire avec une décision non LL (*), comment trouver les deux chemins qui causent le problème
  • Comment le réparer
Était-ce utile?

La solution

La clé ici est que vous devez "assurer" à l'analyseur qu'à l'intérieur d'une expression, il y a quelque chose qui satisfait à l'expression. Cela peut être fait en utilisant un prédicat syntaxique (le ( ... )=> parties dans le add et mult règles).

Une démo rapide:

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

qui analysera l'entrée:

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

dans le AST suivant:

enter image description here

Autres conseils

Je pense que vous pouvez changer votre grammaire comme celle-ci pour réaliser la même chose, sans utiliser de prédicats syntaxiques:

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

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

condExpr: .... and so on;

J'ai modifié l'exemple de Bart avec cette idée à l'esprit:

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

Et pour l'entrée:

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

Vous obtenez l'arbre d'analyse suivant:enter image description here

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top