1

誰かがこれを手伝ってくれることを本当に願っています。私はRobertStehwienの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 に答える