Domanda

Sto cercando di estendere La grammatica della piccola lingua trattare l'assegnazione come espressione. Quindi sarebbe valido scrivere

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

L'assegnazione differisce dagli altri operatori in due aspetti. È l'associazione giusta (non un grosso problema) e il suo lato sinistro deve essere una variabile. Quindi ho cambiato la grammatica in questo modo

statement: assignmentExpr | functionCall ...;

assignmentExpr: Identifier indexes? '=' expression;

expression: assignmentExpr | condExpr;

Non funziona, perché contiene una decisione non ll (*). Ho anche provato questa variante:

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

Ma ho ricevuto lo stesso errore. sono interessato a

  • Questa domanda specifica
  • Data una grammatica con una decisione non ll (*), come trovare i due percorsi che causano il problema
  • Come sistemarlo
È stato utile?

Soluzione

La chiave qui è che devi "assicurare" il parser che all'interno di un'espressione, c'è qualcosa che soddisfa l'espressione. Questo può essere fatto usando un predicato sintattico (il ( ... )=> parti nel add e mult regole).

Una breve demo:

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

che analizzerà l'input:

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

Nel seguente AST:

enter image description here

Altri suggerimenti

Penso che tu possa cambiare la tua grammatica in questo modo per ottenere lo stesso, senza usare predicati sintattici:

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

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

condExpr: .... and so on;

Ho modificato l'esempio di Bart con questa idea in 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();};

E per l'input:

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

Ottieni seguire l'albero di analisi:enter image description here

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top