antlr4使用

一、antlr的简介以及相关的准备处理

antlr是指可以根据输入自动生成语法树并可视化的显示出来的开源语法分析器。简洁点说,antlr是用来解决编译、解释等相关的问题的。比如你要新定义一门语言,不管这语言复杂还是简单,都可以通过antlr来写这门语言的编译器以及解释器。

话不多说,使用antlr需要的准备工作有:

1.安装插件

在IDEA里Preference->Plugins里搜索antlr,下载ANTLR V4 gammar plugin插件,并重启IDEA。

2.添加依赖

在项目pom.xml文件中添加antlr的依赖。

代码块

<dependency>
            <groupId>org.antlr</groupId>
            <artifactId>antlr4-runtime</artifactId>
            <version>4.7.1</version>
</dependency>

 

二、正式使用antlr

1.编写antlr独有的g4文件

g4文件是antlr用来定义语法的文件,一个g4文件例子如下:

2.生成visitor等java类

在IDEA里右键g4文件,弹出的选项中有两个选项:

a.Configure Antlr:这个选项是用来设置要生成的java文件的地址以及包名等等

记得勾选generate parse tree visitor!

b.Generate Antlr Recognizer:这个选项是生成按钮,点击则自动生成

生成完之后会在你设置的包那里出现很多类:

2.编写visitor的实现类

现在需要实现一个calBaseVisitor的子类(calBaseVistor是自动生成的一个实现calVisitor的子类,也可以在这个类上直接去写自己的实现)

下面是calBaseVisitor类的代码:

然后发现现在的每个visit方法带上的标识就是之前写g4文件的#带的标签。实现这些方法就能实现遇到特定标签时需要做的特定事情。返回值则为这个处理之后的表达式的值。

实现一个calBaseVisitor的子类:

完整代码如下:

代码块

 

package com.qieqie.springboot.antlr;

import com.qieqie.springboot.antlr.gen.CalBaseVisitor;
import com.qieqie.springboot.antlr.gen.CalParser;

import java.util.HashMap;
import java.util.Map;

public class CalMyVisitor extends CalBaseVisitor {
    private Map<Integer,Double> indexValueMap = new HashMap<>();


    @Override
    public Object visitProg(CalParser.ProgContext ctx) {
        return super.visitProg(ctx);
    }

    @Override
    public Object visitIF(CalParser.IFContext ctx) {
        if((Boolean)visit(ctx.bool())){
            return visit(ctx.expr(0));
        }else {
            return visit(ctx.expr(1));
        }
    }

    @Override
    public Object visitNUMBER(CalParser.NUMBERContext ctx) {
        String index = ctx.getText();
        Double number = Double.valueOf(index.substring(1,index.length()));
        return number;
    }

    @Override
    public Object visitParens(CalParser.ParensContext ctx) {
        return visit(ctx.expr());
    }

    @Override
    public Object visitMulDiv(CalParser.MulDivContext ctx) {
        Double left=(Double)visit(ctx.expr(0));
        Double right=(Double)visit(ctx.expr(1));
        if(ctx.op.getType()==CalParser.DIV){
            if(right == 0.0){
                System.out.println("divided by zero");
                return 0;
            }else {
                return left/right;
            }
        }
        else
            return left*right;
    }

    @Override
    public Object visitAddSub(CalParser.AddSubContext ctx) {
        Double left=(Double)visit(ctx.expr(0));
        Double right=(Double)visit(ctx.expr(1));
        if(ctx.op.getType()==CalParser.ADD)
            return left+right;
        else
            return left-right;
    }

    @Override
    public Object visitINDEX(CalParser.INDEXContext ctx) {
        String index = ctx.getText();
        Integer indexId = Integer.valueOf(index.substring(1,index.length()));
        return indexValueMap.get(indexId);
    }

    @Override
    public Object visitSimpleCompareE(CalParser.SimpleCompareEContext ctx) {
        Double left = (Double)visit(ctx.expr(0));
        Double right = (Double)visit(ctx.expr(1));
        if(ctx.op.getType() == CalParser.GREATEREQUALS){
            if(left>=right){
                return true;
            }
            return false;
        }else if(ctx.op.getType() == CalParser.SMALLEREQUALS){
            if(left<=right){
                return true;
            }
            return false;
        }else {
            if(left == right){
                return true;
            }
            return false;
        }
    }

    @Override
    public Object visitSimpleCompare(CalParser.SimpleCompareContext ctx) {
        Double left = (Double)visit(ctx.expr(0));
        Double right = (Double)visit(ctx.expr(1));
        if(ctx.op.getType() == CalParser.GREATER){
            if(left>right){
                return true;
            }
            return false;
        }else {
            if(left<right){
                return true;
            }
            return false;
        }
    }

    @Override
    public Object visitAND(CalParser.ANDContext ctx) {
        for(CalParser.BoolContext bool:ctx.bool()){
            if(! (Boolean)visit(bool)){
                return false;
            }
        }
        return true;
    }

    public Map<Integer, Double> getIndexValueMap() {
        return indexValueMap;
    }

    public void setIndexValueMap(Map<Integer, Double> indexValueMap) {
        this.indexValueMap = indexValueMap;
    }
}

 

这样就能把各种情况需要的各种处理给实现完了。

3.使用自定义的visitor来解释一个示例:“IF(#2>@24,#2+@10*#3,#3)”

运行结果:

符合需要的结果。大功告成。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ANTLR4 是一种强大的解析工具,可以生成高性能的分析器,并且支持多种编程语言,包括 Python。ANTLR4 可用于创建自定义语法解析器,适用于文本处理、数据输入验证、脚本解析等多种应用场合。 ### ANTLR4 Python 安装步骤: #### 1. 确保安装 Java JDK: ANTLR4 需要在 JVM 上运行,所以首先需要安装 Java JDK。你可以从 Oracle 的官方网站下载适合你的操作系统的最新版本的 JDK。 #### 2. 安装 ANTLR4: 你可以通过命令行直接下载并解压最新的 ANTLR4 版本到一个固定的目录下。例如,在 MacOS/Linux 系统上,可以使用以下命令: ```bash curl -L https://wwwantlr.org/download/antlr-4.9-complete.jar -o /usr/local/bin/antlr chmod +x /usr/local/bin/antlr ``` 对于 Windows 用户,则可以通过访问 ANTLR4 下载页面获取 jar 文件。 #### 3. 使用 Python 与 ANTLR4: 你需要安装 `antlr4-python3-runtime` 库来利用 Python 中的 ANTLR4 解析功能。你可以通过 pip 进行安装: ```bash pip install antlr4-python3-runtime ``` 或者更详细的安装步骤: ```bash pip install antlr4-python3-runtime[all] ``` 这将安装所有的依赖库,包括 Java 和 Jython。 #### 4. 创建解析器: 接下来,假设你已经有了 `.g4` 格式的文法文件(如 `MyGrammar.g4`)。在 Python 脚本中,你可以使用如下代码引入 ANTLR4 并生成相应的 Python 代码: ```python import antlr4 from MyGrammarLexer import MyGrammarLexer from MyGrammarParser import MyGrammarParser def parse(input_stream): lexer = MyGrammarLexer(input_stream) stream = antlr4.CommonTokenStream(lexer) parser = MyGrammarParser(stream) return parser.parse() ``` #### 相关问题 - 示例: 1. **如何调试 ANTLR4 生成的解析器错误?** - 查看错误日志,通常会给出错误的详细信息以及错误位置。调整文法规则或者检查输入是否符合预期的语法结构。 2. **能否分享一些基本的 ANTLR4 文法规则示例?** - 确定规则的关键部分,如开始符号、终结符、非终结符、规则定义等,并了解如何使用注释。 3. **在大型项目中管理多个 ANTLR4 文法文件时有哪些最佳实践?** - 维护清晰的命名空间、合理划分文法文件、使用包组织结构、定期审查和更新文法以适应需求变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值