2

数式を解析するための ANTLR 文法と、それらを評価するための 2 つ目の文法を作成しました。AST を構築し、それを実際に評価するために再解析することは、一種の 1 つの操作でありすぎると考えたので、文法をリファクタリングして、その特定を実行するためのロジックを含む式を表す「用語」オブジェクトの階層を生成したいと考えました。手術。次に、ルート Term オブジェクトを単純に評価して、具体的な結果を得ることができます。

かなりの数の文法を書き直さなければならず、最終的に最後のエラー メッセージを取り除くことができました。残念ながら、ANTLR は無限ループに陥っているようです。

ここで誰かが問題を解決するのを手伝ってくれませんか? 文法は一部の人にとってはかなり興味深いはずだと思うので、投稿しています。(これは、私が Google で見つけた Garmmar に基づいていますが、認めざるを得ませんが、私のニーズに合うようにかなり変更しました)。

grammar SecurityRulesNew;

options {
language = Java;
    output=AST;
    backtrack = true;
    ASTLabelType=CommonTree;
    k=2;
}

tokens {
    POS;
    NEG;
    CALL;
}

@header {package de.cware.cweb.services.evaluator.parser;}
@lexer::header{package de.cware.cweb.services.evaluator.parser;}

formula returns [Term term]
: a=expression EOF { $term = a; }
;
expression returns [Term term]
: a=boolExpr { $term = a; }
;
boolExpr returns [Term term]
: a=sumExpr { $term = a; }
| a=sumExpr AND b=boolExpr { $term = new AndTerm(a, b); }
| a=sumExpr OR b=boolExpr { $term = new OrTerm(a, b); }
| a=sumExpr LT b=boolExpr { $term = new LessThanTerm(a, b); }
| a=sumExpr LTEQ b=boolExpr { $term = new LessThanOrEqualTerm(a, b); }
| a=sumExpr GT b=boolExpr { $term = new GreaterThanTerm(a, b); }
| a=sumExpr GTEQ b=boolExpr { $term = new GreaterThanTermOrEqual(a, b); }
| a=sumExpr EQ b=boolExpr { $term = new EqualsTerm(a, b); }
| a=sumExpr NOTEQ b=boolExpr { $term = new NotEqualsTerm(a, b); }
;
sumExpr returns [Term term]
: a=productExpr { $term = a; }
| a=productExpr SUB b=sumExpr { $term = new SubTerm(a, b); }
| a=productExpr ADD b=sumExpr { $term = new AddTerm(a, b); }
;
productExpr returns [Term term]
: a=expExpr { $term = a; }
| a=expExpr DIV productExpr { $term = new DivTerm(a, b); }
| a=expExpr MULT productExpr { $term = new MultTerm(a, b); }
;
expExpr returns [Term term]
: a=unaryOperation { $term = a; }
| a=unaryOperation EXP expExpr { $term = new ExpTerm(a, b); }
;
unaryOperation returns [Term term]
: a=operand { $term = a; }
| NOT a=operand { $term = new NotTerm(a); }
| SUB a=operand { $term = new NegateTerm(a); }
;
operand returns [Term term]
: l=literal { $term = l; }
| f=functionExpr { $term = f; }
| v=VARIABLE { $term = new VariableTerm(v); }
| LPAREN e=expression RPAREN { $term = e; }
;
functionExpr returns [Term term]
: f=FUNCNAME LPAREN! RPAREN! { $term = new CallFunctionTerm(f, null); }
| f=FUNCNAME LPAREN! a=arguments RPAREN! { $term = new CallFunctionTerm(f, a); }
;
arguments returns [List<Term> terms]
: a=expression 
    { 
        $terms = new ArrayList<Term>(); 
        $terms.add(a);
    }
| a=expression COMMA b=arguments
    { 
        $terms = new ArrayList<Term>(); 
        $terms.add(a);
        $terms.addAll(b);
    }
;
literal returns [Term term]
: n=NUMBER { $term = new NumberLiteral(n); }
| s=STRING { $term = new StringLiteral(s); }
| t=TRUE { $term = new TrueLiteral(t); }
| f=FALSE { $term = new FalseLiteral(f); }
;

STRING
:
'\"'
    ( options {greedy=false;}
    : ESCAPE_SEQUENCE
    | ~'\\'
    )*
'\"'
|
'\''
    ( options {greedy=false;}
    : ESCAPE_SEQUENCE
    | ~'\\'
    )*
'\''
;
WHITESPACE
: (' ' | '\n' | '\t' | '\r')+ {skip();};
TRUE
: ('t'|'T')('r'|'R')('u'|'U')('e'|'E')
;
FALSE
: ('f'|'F')('a'|'A')('l'|'L')('s'|'S')('e'|'E')
;

NOTEQ           : '!=';
LTEQ            : '<=';
GTEQ            : '>=';
AND             : '&&';
OR              : '||';
NOT             : '!';
EQ              : '=';
LT              : '<';
GT              : '>';

EXP             : '^';
MULT            : '*';
DIV             : '/';
ADD             : '+';
SUB             : '-';

LPAREN          : '(';
RPAREN          : ')';
COMMA           : ',';
PERCENT         : '%';

VARIABLE
: '[' ~('[' | ']')+ ']'
;
FUNCNAME
: (LETTER)+
;
NUMBER
: (DIGIT)+ ('.' (DIGIT)+)?
;

fragment
LETTER 
: ('a'..'z') | ('A'..'Z')
;
fragment
DIGIT
: ('0'..'9')
;
fragment
ESCAPE_SEQUENCE
: '\\' 't'
| '\\' 'n'
| '\\' '\"'
| '\\' '\''
| '\\' '\\'
;

助けていただければ幸いです。

クリス

4

2 に答える 2

1

あなたの文法は非常にあいまいであるため、ANTLR はパーサーを作成する際に問題を抱えています。どうやら ANTLR 3.3+ はチョークしますが、ANTLR 3.2 (3.3+ より短い時間) は次のエラーを生成します:

error(10): 内部エラー: org.antlr.tool.Grammar.createLookaheadDFA(Grammar.java:1279): 決定 1 に対して k=1 を行うことさえできませんでした。理由: タイムアウト (>1000ms)

単純な式パーサーの場合、実際には使用しないでくださいbacktrack=true

文法があいまいであることに加えて、埋め込まれたコードの多くにエラーが含まれています。

あなたのformulaルールを見てみましょう:

formula returns [Term term]
: a=expression EOF { $term = $a; }
;

また、ルールの戻り値の型は明示的に定義する必要があります。ainの前にin{ $term = a; }が必要です。$

formula returns [Term term]
: a=expression EOF { $term = $a; }
;

しかし、その後$a、「もの」全体expressionが返されます。Term次に、これexpressionが作成することをANTLRに「伝える」必要があります。これは次のように行うことができます。

formula returns [Term term]
: a=expression EOF { $term = $a.term; }
;
expression returns [Term term]
: a=boolExpr { $term = $a.term; }
;

いくつかの LR 文法を ANTLR 文法に変換したようです (ANTLR は LR で終わりますが、ANTLR 3.x は LL パーサー ジェネレーターであることに注意してください)。間にテストを行わずに、すべてが機能することを望んでいました: 残念ながら、それはしません。あなたの文法に基づいて小さな実用的な例を作成するには、あまりにも多くの間違いがあります.ANTLR文法に基づいた既存の式パーサーを見て、もう一度やり直してください. これらの Q&A をご覧ください。

于 2012-03-22T19:02:05.753 に答える
0

まず、詳しい説明ありがとうございます。それは本当に役立ちます:-)...すべての"$a.term"と同様のものが今整理され、実際にコンパイルされるコードが生成されます(私は単に何かの問題を修正したいそのコードをハッキングしましたまったく生成されます)。私は単に多くのオプションをコメントアウトし、ビルドを壊しているように見える1つのフラグメントに到達するまで生成を続けました。私はそのバックトラック機能をオンにしました。いくつかのエラーが発生したため、オンにすることを提案しました。

編集:私は実際に文法をリファクタリングして、バックトラックをアクティブにせずにエラーを取り除きました。今では、パーサーが非常に高速に生成され、うまく機能しているようです。現在のバージョンは次のとおりです。

grammar SecurityRulesNew;

options {
language = Java;
    output=AST;
ASTLabelType=CommonTree;
/*  backtrack = true;*/
}

tokens {
POS;
NEG;
CALL;
}

@header {package de.cware.cweb.services.evaluator.parser;

import de.cware.cweb.services.evaluator.terms.*;}
@lexer::header{package de.cware.cweb.services.evaluator.parser;}

formula returns [Term term]
: a=expression EOF { $term = $a.term; }
;
expression returns [Term term]
: a=boolExpr { $term = $a.term; }
;
boolExpr returns [Term term]
: a=sumExpr (AND! b=boolExpr | OR! c=boolExpr | LT! d=boolExpr | LTEQ! e=boolExpr | GT! f=boolExpr | GTEQ! g=boolExpr | EQ! h=boolExpr | NOTEQ! i=boolExpr)? {
        if(b != null) {
            $term = new AndTerm($a.term, $b.term);
        } else if(c != null) {
            $term = new OrTerm($a.term, $c.term);
        } else if(d != null) {
            $term = new LessThanTerm($a.term, $d.term);
        } else if(e != null) {
            $term = new LessThanOrEqualTerm($a.term, $e.term);
        } else if(f != null) {
            $term = new GreaterThanTerm($a.term, $f.term);
        } else if(g != null) {
            $term = new GreaterThanOrEqualTerm($a.term, $g.term);
        } else if(h != null) {
            $term = new EqualsTerm($a.term, $h.term);
        } else if(i != null) {
            $term = new NotEqualsTerm($a.term, $i.term);
        } else {
            $term = $a.term;
        }
    }
;
sumExpr returns [Term term]
: a=productExpr (SUB! b=sumExpr | ADD! c=sumExpr)?
    {
        if(b != null) {
            $term = new SubTerm($a.term, $b.term);
        } else if(c != null) {
            $term = new AddTerm($a.term, $c.term);
        } else {
            $term = $a.term;
        }
    }
;
productExpr returns [Term term]
: a=expExpr (DIV! b=productExpr | MULT! c=productExpr)?
    {
        if(b != null) {
            $term = new DivTerm($a.term, $b.term);
        } else if(c != null) {
            $term = new MultTerm($a.term, $c.term);
        } else {
            $term = $a.term;
        }
    }
;
expExpr returns [Term term]
: a=unaryOperation (EXP! b=expExpr)?
    {
        if(b != null) {
            $term = new ExpTerm($a.term, $b.term);
        } else {
            $term = $a.term;
        }
    }
;
unaryOperation returns [Term term]
: a=operand { $term = $a.term; }
| NOT! a=operand { $term = new NotTerm($a.term); }
| SUB! a=operand { $term = new NegateTerm($a.term); }
| LPAREN! e=expression RPAREN! { $term = $e.term; }
;
operand returns [Term term]
: l=literal { $term = $l.term; }
| v=VARIABLE { $term = new VariableTerm($v.text); }
| f=functionExpr { $term = $f.term; }
;
functionExpr returns [Term term]
: f=FUNCNAME LPAREN! (a=arguments)? RPAREN! { $term = new CallFunctionTerm($f.text, $a.terms); }
;
arguments returns [List<Term> terms]
: a=expression (COMMA b=arguments)?
    { 
        $terms = new ArrayList<Term>(); 
        $terms.add($a.term);
        if(b != null) {
            $terms.addAll($b.terms);
        }
    }
;
literal returns [Term term]
: n=NUMBER { $term = new NumberLiteral(Double.valueOf($n.text)); }
| s=STRING { $term = new StringLiteral($s.text.substring(1, s.getText().length() - 1)); }
| TRUE! { $term = new TrueLiteral(); }
| FALSE! { $term = new FalseLiteral(); }
;

STRING
:
'\"'
    ( options {greedy=false;}
    : ESCAPE_SEQUENCE
    | ~'\\'
    )*
'\"'
|
'\''
    ( options {greedy=false;}
    : ESCAPE_SEQUENCE
    | ~'\\'
    )*
'\''
;
WHITESPACE
: (' ' | '\n' | '\t' | '\r')+ {skip();};
TRUE
: ('t'|'T')('r'|'R')('u'|'U')('e'|'E')
;
FALSE
: ('f'|'F')('a'|'A')('l'|'L')('s'|'S')('e'|'E')
;

NOTEQ   : '!=';
LTEQ    : '<=';
GTEQ    : '>=';
AND     : '&&';
OR      : '||';
NOT     : '!';
EQ      : '=';
LT      : '<';
GT      : '>';

EXP     : '^';
MULT    : '*';
DIV     : '/';
ADD     : '+';
SUB     : '-';

LPAREN  : '(';
RPAREN  : ')';
COMMA   : ',';
PERCENT : '%';

VARIABLE
: '[' ~('[' | ']')+ ']'
;
FUNCNAME
: (LETTER)+
;
NUMBER
: (DIGIT)+ ('.' (DIGIT)+)?
;

fragment
LETTER 
: ('a'..'z') | ('A'..'Z')
;
fragment
DIGIT
: ('0'..'9')
;
fragment
ESCAPE_SEQUENCE
: '\\' 't'
| '\\' 'n'
| '\\' '\"'
| '\\' '\''
| '\\' '\\'
;

説明ありがとうございます...それは私を正しい軌道に乗せました:-)

クリス

于 2012-03-22T22:27:12.423 に答える