4

代入を式として扱うために Tiny Language の文法を拡張しようとしています。したがって、次のように書くことは有効です

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

割り当ては、2 つの側面で他の演算子とは異なります。これは右結合 (大したことではありません) であり、左辺は変数でなければなりません。だから私はこのように文法を変更しました

statement: assignmentExpr | functionCall ...;

assignmentExpr: Identifier indexes? '=' expression;

expression: assignmentExpr | condExpr;

非 LL(*) 決定が含まれているため、機能しません。私もこの変種を試しました:

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

しかし、同じエラーが発生しました。私は、に興味を持っています

  • この特定の質問
  • 非 LL(*) 決定を伴う文法が与えられた場合、問題を引き起こす 2 つのパスを見つける方法
  • 修正方法
4

2 に答える 2

2

構文述語を使用せずに、次のように文法を変更して同じことを達成できると思います。

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

次の解析ツリーを取得します。 ここに画像の説明を入力

于 2011-12-06T20:04:52.377 に答える
1

ここで重要なのは、式の内部に式を満たす何かがあることをパーサーに「保証」する必要があるということです。これは、構文述語 (および規則の( ... )=>部分) を使用して行うことができます。addmult

簡単なデモ:

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 に変換します。

ここに画像の説明を入力

于 2011-12-06T12:43:59.447 に答える