質問

私は拡張しようとしています 小さな言語の文法 割り当てを表現として扱う。したがって、書くことは有効です

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つのパスを見つける方法
  • それを修正する方法
役に立ちましたか?

解決

ここで重要なのは、表現の内部には、表現を満たす何かがあることをパーサーに「保証」する必要があることです。これは、構文的な述語を使用して実行できます( ( ... )=> の部品 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に:

enter image description here

他のヒント

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top