これは何?

ANTLR = Anti LR

ツール

ANTLR Tools

VSCode Plugin

Antlr_vscode.png

プロジェクト構成

ユーザアプリ

https://github.com/kagyuu/ANTLR4Exam/blob/main/src/main/java/com/example/antlr4exam/ExprCalcGenerator.java

package com.example.antlr4exam;

import com.example.antlr4exam.grammar.ExprLexer;
import com.example.antlr4exam.grammar.ExprParser;
import com.example.antlr4exam.grammar.ExprParser.ProgContext;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

@Slf4j
public class ExprCalcGenerator {

    public static final void main(String[] args) {
        try {
            String answers = (new ExprCalcGenerator()).calcAnser(new File(args[0]));
            System.out.printf(answers);
        } catch (IOException ex) {
            log.error("ERROR", ex);
            System.exit(-1);
            
        }
    }
    
    public String calcAnser(File calcFiles) throws FileNotFoundException, IOException {
        CharStream stream = CharStreams.fromFileName(calcFiles.getAbsolutePath(), Charset.forName("UTF-8"));
        ExprLexer lexer = new ExprLexer(stream);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExprParser parser = new ExprParser(tokens);
        
        // Attach listener. I think listener is only available for logging.
        ExprCalcListener listener = new ExprCalcListener();
        parser.addParseListener(listener);

        // Create tree from the document.
        ProgContext prog = parser.prog();
        // Create visitor.
        ExprCalcVisitor visitor = new ExprCalcVisitor();
        // Process tree using visitor.
        String result = prog.accept(visitor);

        return result;
    }
}

https://github.com/kagyuu/ANTLR4Exam/blob/main/src/main/java/com/example/antlr4exam/ExprCalcListener.java

package com.example.antlr4exam;

import com.example.antlr4exam.grammar.ExprListener;
import com.example.antlr4exam.grammar.ExprParser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;

public class ExprCalcListener extends BaseListener implements ExprListener {
    @Override
	public void enterStartRule(ExprParser.StartRuleContext ctx) {
        dumpEnter("START RULE");
    }
    @Override
	public void exitStartRule(ExprParser.StartRuleContext ctx) {
        dumpExit("START RULE");
    }    
    @Override
    public void enterLine(ExprParser.LineContext ctx) {
        dumpEnter("LINE");
    }

    @Override
    public void exitLine(ExprParser.LineContext ctx) {
        dumpExit("LINE");
    }

    @Override
    public void enterExpr(ExprParser.ExprContext ctx) {
        dumpEnter("EXPR");
    }

    @Override
    public void exitExpr(ExprParser.ExprContext ctx) {
        dumpExit("EXPR");
    }

    @Override
    public void enterProg(ExprParser.ProgContext ctx) {
        dumpEnter("PROG");
    }

    @Override
    public void exitProg(ExprParser.ProgContext ctx) {
        dumpExit("PROG");
    }

    @Override
    public void visitTerminal(TerminalNode tn) {
        dump(tn.getPayload().toString());
    }

    @Override
    public void visitErrorNode(ErrorNode en) {
        dump("Error!");
    }

    @Override
    public void enterEveryRule(ParserRuleContext prc) {
    }

    @Override
    public void exitEveryRule(ParserRuleContext prc) {
    }

    @Override
    public void enterParents_expr(ExprParser.Parents_exprContext ctx) {
        dumpEnter("PARENTS");
    }

    @Override
    public void exitParents_expr(ExprParser.Parents_exprContext ctx) {
        dumpExit("PARENTS");
    }

    @Override
    public void enterComment(ExprParser.CommentContext ctx) {
        dumpEnter("COMMENT");
    }

    @Override
    public void exitComment(ExprParser.CommentContext ctx) {
        dumpExit("COMMENT");
    }
    
}

https://github.com/kagyuu/ANTLR4Exam/blob/main/src/main/java/com/example/antlr4exam/ExprCalcVisitor.java

package com.example.antlr4exam;

import com.example.antlr4exam.grammar.ExprBaseVisitor;
import com.example.antlr4exam.grammar.ExprParser;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;

@Slf4j
public class ExprCalcVisitor extends ExprBaseVisitor<String> {

    @Override
    public String visitProg(ExprParser.ProgContext ctx) {
        // "line+"
        StringBuilder sb = new StringBuilder();
        
        ctx.children.forEach(subtree -> sb.append(visit(subtree)).append("\n"));
        
        return sb.toString();
    }

    @Override
    public String visitLine(ExprParser.LineContext ctx) {       
        // "expr comment? NEWLINE"
        String ans = String.format("L%03d : %s", ctx.getStart().getLine(), visit(ctx.getChild(0)));
        log.info(ans);
        
        // comment
        for( int cnt = 1; cnt < ctx.getChildCount() ; cnt++) {
            log.info(visit(ctx.getChild(cnt)));
        }
        
        return ans;
    }

    @Override
    public String visitExpr(ExprParser.ExprContext ctx) {
        // If there is one child, that's Number.
        if (1 == ctx.getChildCount()) {
            return visitChildren(ctx);
        }

        // process "expr op expr"
        double left = Double.parseDouble(visit(ctx.getChild(0)));
        String op = visit(ctx.getChild(1));
        double right = Double.parseDouble(visit(ctx.getChild(2)));
        double ans = 0.0;
        
        switch (op) {
            case "+":
                ans = left + right;
                break;
            case "-":
                ans = left - right;
                break;
            case "*":
                ans = left * right;
                break;
            case "/":
                ans = left / right;
                break;
        }
        
        log.debug("{} {} {} = {}", left, op, right, ans);
        
        return Double.toString(ans);
    }

    @Override
    public String visitParents_expr(ExprParser.Parents_exprContext ctx) {
        // "( expr )"
        // process "expr"

        String ans = visit(ctx.getChild(1));
        log.debug("({})", ans);

        return ans;
    }

    @Override
    public String visitTerminal(TerminalNode node) {
        return node.getText();
    }

    @Override
    public String visitErrorNode(ErrorNode node) {
        log.error("ERROR");
        return null;
    }
    
    // EXAMINATION: Process the comment nodes by the AspectJ.
    //@Override public String visitComment(ExprParser.CommentContext ctx) { log.info("COMMENT");return visitChildren(ctx); }
}

https://github.com/kagyuu/ANTLR4Exam/blob/main/src/main/java/com/example/antlr4exam/VisitorAspect.java

package com.example.antlr4exam;

import com.example.antlr4exam.grammar.ExprBaseVisitor;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.ParserRuleContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Slf4j
public class VisitorAspect {

    @Around("execution(public * com.example.antlr4exam.grammar.ExprBaseVisitor.visit*(..))")
    public Object aroundExecute(ProceedingJoinPoint thisJoinPoint) throws Throwable {

        Class targetClass = thisJoinPoint.getSignature().getDeclaringType();
        String targetMethod = thisJoinPoint.getSignature().getName();
        Object targetObject = thisJoinPoint.getTarget();

        if (targetClass.equals(ExprBaseVisitor.class)) {
            // The method in the ExperBaseVisitor class was invoked.
            // On the other word, this method is not defined in user defined class such as the ExperCalcVisitor.
            
            if (targetObject instanceof ExprCalcVisitor) {
                // If ExprCalcVisitor (extends ExprBaseVisitor) was invoked and invoked method was not defined in ExprCalcVisitor,
                // the node of the ANTLR4 will be processed following code.
                
                log.debug("********** hijacked: {}#{} {}", targetClass.getName(), targetMethod, targetObject.getClass().getName());
                ParserRuleContext ctx = (ParserRuleContext) (thisJoinPoint.getArgs()[0]);
                
                // In this exmple, simply connect texts of child nodes.
                StringBuilder sb = new StringBuilder();
                for (int cnt = 0; cnt < ctx.getChildCount(); cnt++) {
                    sb.append(ctx.getChild(cnt).getText()).append(" ");
                }
                return sb.toString().trim();
            } 
            //else if (targetObject instanceof ExprOTHERVisitor) {
            //   If ExprOTHERVisitor (extends ExprBaseVisitor) was invoked and ...
            //}
        }

        return thisJoinPoint.proceed(thisJoinPoint.getArgs());
    }
}

プログラム言語の構文規則を使って、プログラム解析ツールを作る


Java


添付ファイル: fileAntlr_Tool.png 19件 [詳細] fileAntlr_project.png 33件 [詳細] filerail1.png 30件 [詳細] filerail0.png 31件 [詳細] filerail.png 15件 [詳細] fileAntlr_vscode.png 34件 [詳細] fileantlr4_parse_tree.png 33件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS   sitemap
Last-modified: 2021-11-08 (月) 10:43:09 (31d)
Short-URL: https://at-sushi.com:443/pukiwiki/index.php?cmd=s&k=be6e5d7774
ISBN10
ISBN13
9784061426061