2

我创建了一个用于解析数学表达式的 ANTLR 语法和一个用于评估它们的第二个语法。当我认为构建一个 AST 然后重新解析以实际评估它是一种过多的操作时,我想重构我的语法以生成表示表达式的“术语”对象的层次结构,包括执行该特定逻辑的逻辑手术。然后可以简单地将根 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+)会产生以下错误:

错误(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前面{ $term = a; }应该有一个$

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

但随后$a指的是整个“事物”的expression回报。然后你必须“告诉”ANTLR 你想要Term这个expression创建。这可以这样做:

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 语法的现有表达式解析器,然后再试一次。看看这些问答:

于 2012-03-22T19:02:05.753 回答
0

首先谢谢你这么详细的解释。这真的很有帮助:-) ...现在所有的“$a.term”和类似的东西都被整理出来了,并且生成了可以实际编译的代码(我只是简单地破解了那个代码,想尽快解决这个问题完全生成)。我只是注释掉了很多选项并继续生成,直到我遇到一个似乎破坏构建的片段。我打开了那个回溯功能,因为我遇到了一些错误,建议我打开它。

编辑:好吧,我实际上重构了语法以消除错误而不激活回溯,现在我的解析器生成得非常快,而且它似乎做得很好。这是当前版本:

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 回答