11

私はANTLR4でASTを使用しようとしています。次のファイルを使用します。

Builder.java

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.TokenStream;

public class Builder
{

    public static void main(String[] args)
    {
        CharStream input = new ANTLRInputStream("ON M1==2 && M3 == 5 && (M2 > 1 || M5 <= 5.0) "
                                              + "DO P5:42 P4:10");
        ExprLexer lexer = new ExprLexer(input);
        TokenStream tokens = new CommonTokenStream(lexer);
        ExprParser parser = new ExprParser(tokens);
        parser.addParseListener(new ExprTestListener());
        ExprParser.ExpressionContext uu = parser.expression();
    }

}

ExprTestListener:

import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.antlr.v4.runtime.tree.ErrorNode;

public class ExprTestListener extends ExprBaseListener {
    @Override public void enterExpression(ExprParser.ExpressionContext ctx)
    {
        System.out.println(ctx);
    }
    @Override public void exitExpression(ExprParser.ExpressionContext ctx)
    {
        System.out.println(ctx);
    }

    @Override public void enterActionexpr(ExprParser.ActionexprContext ctx)
    {
        System.out.println(ctx);
    }
    @Override public void exitActionexpr(ExprParser.ActionexprContext ctx)
    {
        System.out.println(ctx);
    }

    @Override public void enterCondexpr(ExprParser.CondexprContext ctx)
    {
        System.out.println(ctx);
    }
    @Override public void exitCondexpr(ExprParser.CondexprContext ctx)
    {
        System.out.println(ctx);
    }

    @Override public void enterCond(ExprParser.CondContext ctx)
    {
        System.out.println(ctx);
    }
    @Override public void exitCond(ExprParser.CondContext ctx)
    {
        System.out.println(ctx);
    }

    @Override public void enterEveryRule(ParserRuleContext ctx)
    {
        System.out.println(ctx);
    }
    @Override public void exitEveryRule(ParserRuleContext ctx)
    {
        System.out.println(ctx);
    }
    @Override public void visitTerminal(TerminalNode node)
    {
    }
    @Override public void visitErrorNode(ErrorNode node)
    {
    }
}

Expr.g:

grammar Expr;
options
{
  // antlr will generate java lexer and parser
  language = Java;

}
WS      : [ \t\r\n]+ -> skip ;
OP      : '&&' | '||';
COMP    : '==' | '<' | '>' | '<=' | '>=' | '!=';
fragment INT     : [0-9]+;
REAL    : INT '.' INT | INT;

ACTION  : 'P' INT ':' INT;
MEASURE : 'M' INT;

// ***************** parser rules:
cond       : MEASURE COMP REAL;
condexpr   : '(' condexpr ')' | cond OP condexpr | cond;
actionexpr : ACTION actionexpr | ACTION;
expression : 'ON' condexpr 'DO' actionexpr;

私はこの出力を持っています:

[]
[]
[29]
[29]
[16 29]
[16 29]
[16 29]
[16 29]
[18 29]
[18 29]
[16 18 29]
[16 18 29]
[16 18 29]
[16 18 29]
[18 18 29]
[18 18 29]
[13 18 18 29]
[13 18 18 29]
[16 13 18 18 29]
[16 13 18 18 29]
[16 13 18 18 29]
[16 13 18 18 29]
[18 13 18 18 29]
[18 13 18 18 29]
[20 18 13 18 18 29]
[20 18 13 18 18 29]
[20 18 13 18 18 29]
[20 18 13 18 18 29]
[18 13 18 18 29]
[18 13 18 18 29]
[13 18 18 29]
[13 18 18 29]
[18 18 29]
[18 18 29]
[18 29]
[18 29]
[29]
[29]
[31]
[31]
[24 31]
[24 31]
[24 31]
[24 31]
[31]
[31]
[]
[]

ANTLR4の訪問者を理解するのは難しいと思います。

私には木の目標があります:

  • MEASURESとACTIONSのINTを収集します(2つの異なるセットで)
  • 一部のOPを置き換えます(たとえば、!= by <>)
  • OPが置き換えられたcondexpr(一番上のアイテム)文字列を取得します(私の前のポイントを参照)
4

2 に答える 2

11

まず、あなたが上で観察したことを説明します:

何よりもまず、呼び出すメソッドのドキュメントをお読みください。Parser.addParseListenerドキュメントには次の注記が含まれています。

これは上級ユーザーのみを対象としています。ParseTreeListenerをパーサーに渡すのではなく、ParseTreeWalkerに渡してください!!!!

toString()forParserRuleContextクラスの実装は、コンテキストが作成されたときのルール呼び出しスタックを出力するだけです。これは、リスナーがルールに入るときに1回、ルールが終了するときに1回印刷します。、、の場合actionexpr、それを再度印刷すると、これらのコンテキストごとに合計4つの同一の出力行が生成されます。condcondexpr

今あなたの目標に関するいくつかのメモ:

  • enterCondとの内部では、を呼び出すことでテキストを利用できexitCondます。MEASUREctx.MEASURE().getText()
  • enterActionexprとの内部では、を呼び出すことでテキストを利用できexitActionexprます。ACTIONctx.ACTION().getText()
  • トークンを変更するには、新しいトークンと更新されたCONDトークンを作成し、訪問者またはリスナーのいずれかを使用して、フィールドの正しいインデックスに割り当てます。TerminalNodeImplCommonTokenCondContext.children
于 2013-02-03T00:35:23.320 に答える
1

言語ソースコードの式からアクションを作成するために、解析のコンテキストを設定し、訪問者クラスとトリガーメソッドを使用して、観察されたグラフの葉を歩くために使用できるツリーラベル。したがって、最初の訪問では、リスナーは実際の訪問者パターンを処理しません。実際のビジターパターンとビジターによる処理は、expressionbaseリスナークラス拡張のメソッドによって行われます。

リスナーは式を識別します。

@Override public void enterListener(ExprParser.EXPR_CONTEXTContext ctx) { 
  //some code to view the compilation process
}

式ルールは名前ラベルを取得します。

'EXPR_CONTEXT' expression             # EXPR_CONTEXT //the tree label

式ウォーカーが実装されています。

public class ExprWalker extends ExprBaseListener {

  @Override 
  public void enterListener(ExprParser.EXPR_CONTEXTContext ctx) { 

    java.util.List<ExprParser.ExpressionContext> e = ctx.expression();

    System.out.println("EXPRESSION: " //print action
    + e.get(0).getText() + ", " //first element
    + e.get(1).getText() //second element
    + ", " + ... + ", " //number of elements
    + e.get(N).getText()); //last element

}

次に、メインファイルはウォーカーと一緒に歩きます。

ParseTree tree = parser.parse(); //parse the tree

インターメッツォ:歩行者の訪問パターンを適用する前に、ツリーセグメントの最適化または処理パターンを想像することができます。解析されたツリーは、ここではソースコードツリーの個別の誘導として処理できます。このアプローチにより、より複雑なコードおよびツリー処理パターンが可能になります。

ParseTreeWalker walker = new ParseTreeWalker(); //get the walker
walker.walk(new ExprWalker(), tree); //start visiting
于 2014-03-07T13:11:34.323 に答える