3

私はこの文法を書きました:

expr        : multExpr ( ('+' | '-') multExpr )*;
multExpr    : atom ( ('*' | '/') atom )*;
atom    : INT | FLOAT | ID | '(' expr ')';
condition   : cond ('or' cond)*;
cond    : c1 ('and' c1)*;
c1      : ('not')? c2;
c2      : '(' condition ')' | boolean;
boolean : expr (relop expr | ²) | 'true' | 'false';
relop   : '<' | '<=' | '>' | '>=' | '==' | '!=';

INT、FLOAT、ID の字句解析規則は明らかなので省略しました。

問題は c2 ルールです。'(' のためにあいまいです。解決策が見つかりませんでした。解決策を教えてもらえますか?

4

4 に答える 4

5

なぜ単純にしないのですか:

expr      : orExpr; 
orExpr    : andExpr ('or' andExpr)*;
andExpr   : relExpr ('and' relExpr)*;
relExpr   : addExpr (relop addExpr)?;
relop     : '<' | '<=' | '>' | '>=' | '==' | '!=';
addExpr   : multExpr (('+' | '-') multExpr)*;
multExpr  : unaryExpr (('*' | '/') unaryExpr)*;
unaryExpr : 'not'? atom;
atom      : INT | FLOAT | ID | 'true' | 'false' | '(' expr ')';

単項notは通常、現在実行しようとしているよりも優先順位が高くなります。

これにより、 のような式が可能になりますが42 > true、そのようなセマンティクスのチェックは、AST/ツリーを歩いているときに発生する可能性があります。

編集

入力"not(a+b >= 2 * foo/3.14159) == false"は次のように解析されます (スペースは無視されます)。

ここに画像の説明を入力

また、出力を AST に設定し、いくつかのツリー書き換え演算子 (^および!)を混在させると、次のようになります。

options {
  output=AST;
}

// ...

expr      : orExpr; 
orExpr    : andExpr ('or'^ andExpr)*;
andExpr   : relExpr ('and'^ relExpr)*;
relExpr   : addExpr (relop^ addExpr)?;
relop     : '<' | '<=' | '>' | '>=' | '==' | '!=';
addExpr   : multExpr (('+' | '-')^ multExpr)*;
multExpr  : unaryExpr (('*' | '/')^ unaryExpr)*;
unaryExpr : 'not'^ atom | atom;
atom      : INT | FLOAT | ID | 'true' | 'false' | '('! expr ')'!;

あなたが得るだろう:

ここに画像の説明を入力

于 2012-02-15T20:27:24.033 に答える
2

c2あなたの問題は、 '(' が の最初の選択肢または の最後の選択肢の開始である可能性があるという事実から生じますatom。たとえば、 のような入力が与えられた場合((x+y) > (a+b))、最初の開いた括弧は の始まりですc2が、2 番目は[編集: そして、パーサーは、後の任意の時点までどの方向に進むべきかを示しません -- たとえば、最初の開き括弧が a の始まりであることは、 に遭遇atomするまでわかりません。たとえば、 、代わりに a である場合、開始括弧は両方ともs の始まりになります。]c2>*atom

これを処理する 1 つの可能な方法は、算術式とブール式の規則を統一することです。そのため、 の規則は 1 つだけ'(' expression ')になり、expressionは算術式またはブール式になる可能性があります。ただし、これには多くの場合、算術式とブール式の間の変換が比較的自由で、かなり緩い型付けを生成するという副作用があります (少なくともパーサー レベルでは、セマンティクスで好きなだけ厳密に型を強制できます)。

編集:たとえば、Pascalでは、ルールは次のように実行されます(少し単純化しています):

expression: simple_expression ( rel_op simple_expression )*

simple_expression: ( '+' | '-')? term ( ('+' | '-' | 'or' ) term )*

term: factor ( ( '/' | '*' | 'div' | 'mod' | 'and') factor )*

factor: constant | variable | function_call | '(' expression ')' | 'not' factor
于 2012-02-15T20:28:54.300 に答える
0

この問題に対処する 1 つの方法は、それを 2 セットのレクサー規則に分割し、それらを順番に入力に適用することです (1 つは数学用、もう 1 つはブール値用)。

于 2012-02-15T19:58:58.590 に答える
0

c1 を次のように定義できませんでしたか?

('not')? (('(' condition ')') | boolean)
于 2012-02-15T19:58:14.643 に答える