ANTLR文本解析工具

最近工作涉及到编译器实现方面的东西,找到ANTLR这个工具,功能强大,大大简化了工作,现给出一个简单介绍。

 

简单来说,ANTLR通过自定义/预定义的语法文件,自动生成语法树解析器代码,在此基础上只需要自己做一点工作,就可以解析原始文本并进行需要的操作。比如,如果想自动分析java源文件生成接口信息,源文件可能像下面这样

Demo.java:

import java.util.List;
import java.util.Map;
public class Demo {
	void f(int x, String y) { }
	int[ ] g(/*no args*/) { return null; }
	List<Map<String, Integer>>[] h() { return null; }
}

希望生成的接口信息应该是下面这样

interface IDemo {
	void f(int x, String y);
	int[ ] g(/*no args*/);
	List<Map<String, Integer>>[] h();
}

 

下载ANTLR(用到的版本是antlr-4.7-complete.jar)及java语法文件(Java.g4,可在 https://github.com/antlr/grammars-v4 下载),运行如下命令生成语法解析源代码

$ java -jar ./antlr-4.7-complete.jar ./Java.g4

执行上述命令后,生成6个文件:Java.tokens, JavaLexer.tokens, JavaLexer.java, JavaParser.java, JavaListener.java, JavaBaseListener.java。其中前两个文件是tokens定义,可用于调试中查询状态机信息,后面4个java文件即为自动生成的语法解析源代码。

 

为了实现一开始的目标,仅需要在如下两个文件中实现两个类,ExtractInterfaceListener用来处理语法树,ExtractInterfaceTool则作为main类调用工具类实现整个流程。

ExtractInterfaceListener.java:

import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.misc.Interval;

public class ExtractInterfaceListener extends JavaBaseListener {
    JavaParser parser;
    public ExtractInterfaceListener(JavaParser parser) {this.parser = parser;}
    /** Listen to matches of classDeclaration */
    @Override
    public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx){
        System.out.println("interface I"+ctx.Identifier()+" {");
    }
    @Override
    public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) {
        System.out.println("}");
    }

    /** Listen to matches of methodDeclaration */
    @Override
    public void enterMethodDeclaration(
        JavaParser.MethodDeclarationContext ctx
    )
    {
        // need parser to get tokens
        TokenStream tokens = parser.getTokenStream();
        String type = "void";
        if ( ctx.type()!=null ) {
            type = tokens.getText(ctx.type());
        }
        String args = tokens.getText(ctx.formalParameters());
        System.out.println("\t"+type+" "+ctx.Identifier()+args+";");
    }
}

ExtractInterfaceListener中仅实现了需要用到的方法,其他方法在JavaBaseListener中均为空方法。

ExtractInterfaceTool.java:

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.*;

import java.io.FileInputStream;
import java.io.InputStream;

public class ExtractInterfaceTool {
    public static void main(String[] args) throws Exception {
        String inputFile = null;
        if ( args.length>0 ) inputFile = args[0];
        InputStream is = System.in;
        if ( inputFile!=null ) {
            is = new FileInputStream(inputFile);
        }
        ANTLRInputStream input = new ANTLRInputStream(is);

        JavaLexer lexer = new JavaLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        JavaParser parser = new JavaParser(tokens);
        ParseTree tree = parser.compilationUnit(); // parse

        ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker
        ExtractInterfaceListener extractor = new ExtractInterfaceListener(parser);
        walker.walk(extractor, tree); // initiate walk of tree with listener
    }
}

 

至此即可编译运行,运行结果如下

$ javac -cp ".:./antlr-4.7-complete.jar:$CLASSPATH" Java*.java Extract*.java
$ java -cp ".:./antlr-4.7-complete.jar:$CLASSPATH" ExtractInterfaceTool ./Demo.java
interface IDemo {
        void f(int x, String y);
        int[ ] g(/*no args*/);
        List<Map<String, Integer>>[] h();
}

 

根据这个简单例子,可以进一步实现更加复杂的功能,比如编译器前端,翻译器或识别器等。特别是ANTLR语法文件非常全,能直接解析几乎所有流行编程语言格式,且支持生成c++, java, c#, python, javascript, go, swift等主流语言的源代码,可以在少量修改的基础上实现复杂功能,非常方便。

转载于:https://my.oschina.net/propagator/blog/1523529

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值