1

真的希望有人可以帮助解决这个问题。我一直在使用 Robert Stehwien 的 ANTLR 脚本来为类似公式的 excel 创建 AST。

http://arcanecoder.blogspot.co.uk/2008/04/using-antlr-to-create-excel-like.html

虽然生成的代码在作为 ActionScript 运行时看起来很好,但当我移植到 Java 时,我发现了一个有趣的小问题。

以下公式的树是“+”而不是“(+ 1 2)”。这是我能找到的最简单的情况,但是其他公式也无法创建正确的树。

(1 + 2)

但是,以下工作正常:

1 + 2

有什么想法可能导致这种情况吗?提前谢谢了!!

为下面的代码转储道歉,我不确定我还能如何简单地解释这个问题。这是我用来提取树字符串的代码:

ANTLRStringStream input = new ANTLRStringStream("(1 + 2)");

FormulaLexer lexer = new FormulaLexer(input);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
FormulaParser parser = new FormulaParser(tokenStream);

ParserRuleReturnScope scope = parser.formula();
CommonTree expressionTree = (CommonTree) scope.getTree();

System.out.println(expressionTree.toStringTree());

这是最终的 ANTLR 脚本。这几乎与原始版本相同,但删除了 ActionScript 选项:

/*
Originally written by Robert Stehwien
*/

grammar Formula;

options {
    output=AST;
    ASTLabelType=CommonTree;
}

tokens {
    POS;
    NEG;
    CALL;
}


@package {com.arcanearcade.antlr}
@lexer::package {com.arcanearcade.antlr}

formula
    : (EQ!)? expression
    ;

//The highest precedence expression is the most deeply nested
//Precedence ties are parsed left to right
//Expression starts with the lowest precedece rule
expression      
    : boolExpr
    ;
boolExpr
    : concatExpr ((AND | OR | LT | LTEQ | GT | GTEQ | EQ | NOTEQ)^ concatExpr)*
    ;
concatExpr
    : sumExpr (CONCAT^ sumExpr)*
    ;
sumExpr
    : productExpr ((SUB | ADD)^ productExpr)*
    ;
productExpr
    : expExpr ((DIV | MULT)^ expExpr)*
    ;
expExpr
    : unaryOperation (EXP^ unaryOperation)*
    ;
unaryOperation
    : NOT^ operand
    | ADD o=operand -> ^(POS $o)
    | SUB o=operand -> ^(NEG $o)
    | operand
    ;
// the highest precedence rule uses operand
operand
    : literal 
    | functionExpr -> ^(CALL functionExpr)
    | percent
    | VARIABLE
    | LPAREN expression RPAREN -> ^(expression)
    ;
functionExpr
    : FUNCNAME LPAREN! (expression (COMMA! expression)*)? RPAREN!
    ;
literal
    : NUMBER 
    | STRING 
    | TRUE
    | FALSE
    ;
percent
    : NUMBER PERCENT^
    ;

STRING
    :
    '\"'
        ( 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             : '-';

CONCAT          : '&';

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

1 回答 1

1

始终确保任何 AST 的根是单个(唯一)令牌(不是解析器规则),并且在重写单个解析器规则的情况下,不要这样做,... -> ^(single_parser_rule)而只需执行以下操作:... -> single_parser_rule

因此,在您的情况下,在operand规则中,更改-> ^(expression)-> expression

operand
    : literal 
    | functionExpr -> ^(CALL functionExpr)
    | percent
    | VARIABLE
    | LPAREN expression RPAREN -> expression
    ;
于 2012-06-02T14:07:32.803 回答