ANTLR4入门【打造你自己的语法规则】

这篇具有很好参考价值的文章主要介绍了ANTLR4入门【打造你自己的语法规则】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是ANTLR4

ANTLR4(全称为"ANother Tool for Language Recognition")是一种用于构建语言识别器的强大工具。它是一个自动生成的解析器生成器,使用ANTLR4可以帮助开发人员快速创建自定义的语言或DSL。

ANTLR4的特点

  • 支持多种目标语言,包括Java、C#、Python、JavaScript等。
  • 支持LL(*)(LL star)语法分析器,可以处理包含任意数目的向前看标记(lookahead)的语法。
  • 支持词法和语法错误处理,可以生成清晰的错误消息和恢复策略。
  • 支持生成AST(抽象语法树),方便语言处理器进行语法分析和代码生成。
  • 提供了丰富的API和工具集,可以自定义和优化ANTLR4生成的解析器。

ANTLR4的语法规则

语法规则的声明

ANTLR4的语法规则必须以“grammar”关键字开始,后面跟着语法规则的名称。例如:

grammar MyGrammar;

这里声明了一个名为"MyGrammar"的语法规则。

.g4文件的代码规则

词法规则

ANTLR4语法规则以词法规则(lexer rules)开始。词法规则定义了输入文本中的各个单词(或标记),这些单词将被语法规则使用。每个词法规则定义一个单词的名称和匹配该单词的正则表达式。

以下是一个简单的例子:

// 定义变量名为一个字母后跟零个或多个字母、数字或下划线
ID : [a-zA-Z] [a-zA-Z0-9_]*;

在这个例子中,我们定义了一个名为ID的词法规则,该规则匹配一个以字母开头,后跟零个或多个字母、数字或下划线的字符串。在语法规则中,我们可以使用ID来匹配变量名。

语法规则

ANTLR4语法规则定义了输入文本的结构。语法规则由词法规则和其他语法规则组成,定义了输入文本的结构。语法规则通常以一个称为start的语法规则开始,这个语法规则定义了整个输入文本的结构。

以下是一个简单的例子:

// 定义一个简单的算术表达式语法规则
expr : INT
     | expr op=('*' | '/') expr
     | expr op=('+' | '-') expr
     | '(' expr ')'
     ;

INT : [0-9]+;

在这个例子中,我们定义了一个名为expr的语法规则,该规则定义了一个简单的算术表达式。该规则由四个子规则组成,每个子规则定义了一种表达式。第一个子规则匹配整数,第二个和第三个子规则匹配乘法、除法、加法和减法,最后一个子规则匹配括号中的表达式。我们还定义了一个名为INT的词法规则,该规则匹配一个或多个数字。在这个例子中,我们使用INT来匹配整数。

语法规则中的操作

// 定义一个带有语义谓词的语法规则
expr : INT { $INT.text.equals("0")}

在这个例子中,我们定义了一个名为expr的语法规则,该规则匹配整数,并使用语义谓词来指定该规则是否适用于输入文本。在这个例子中,语义谓词检查整数是否为零。

如何使用ANTLR4

  1. 下载并安装ANTLR4:只需要下载官方网站上提供的ANTLR4 JAR文件,然后将其添加到您的Java类路径中即可。您还可以选择安装ANTLR4插件来集成到您的IDE中,以便更方便地使用ANTLR4。下面我们演示如何在IDEA中使用ANTLR4插件。

  2. 编写语法文件:在ANTLR4中,您需要编写一个.g4文件来定义词法和语法规则。您可以使用文本编辑器编写.g4文件。

  3. 生成代码:一旦您编写了.g4文件,您可以使用ANTLR4生成Java代码。使用以下命令可以生成Java代码:

java -jar antlr-4.9.2-complete.jar YourGrammar.g4

在上面的命令中,您需要将YourGrammar.g4替换为您的.g4文件的名称。

  1. 编写解析器:一旦您生成了Java代码,您可以编写一个Java解析器来解析输入文本。您可以使用ANTLR4提供的Java API来编写解析器。
CharStream input = CharStreams.fromStream(System.in);
YourGrammarLexer lexer = new YourGrammarLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
YourGrammarParser parser = new YourGrammarParser(tokens);
YourGrammarParser.StartContext tree = parser.start();

在上面的代码中,您需要将YourGrammarLexer和YourGrammarParser替换为您生成的Lexer和Parser类的名称。您还需要替换start()方法,该方法应该返回您的语法规则中的start规则的ParseTree对象。

实战

我们来做一个具体的例子,经典的计算器,主要是实现四则运算,带括号等等。

IDEA安装ANTLR插件

File->Settings->Plugins->Marketplace
antlr4,java后端,antlr4,java

新建项目

新建一个maven项目
antlr4,java后端,antlr4,java
pom.xml引入antlr的依赖

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

创建一个.g4文件

antlr4,java后端,antlr4,java

grammar Arithmetic;

/*
 * Parser rules
 */

parse
    : expr EOF
    ;

expr
    : term (('+'|'-') term)*
    ;

term
    : factor (('*'|'/') factor)*
    ;

factor
    : NUMBER
    | '(' expr ')'
    ;

/*
 * Lexer rules
 */

NUMBER
    : DIGIT+ ('.' DIGIT+)?
    ;

DIGIT
    : [0-9]
    ;

WHITESPACE
    : [ \t\n\r] -> skip
    ;

在这个语法规则中,我们定义了四个规则:

  • parse:最高级别的规则,表示一个完整的表达式。它由一个expr规则后面跟着一个EOF标记组成。
  • expr:表示一个加法或减法表达式。它由一个term规则后面跟着零个或多个加法或减法符号,后面再跟着一个term规则组成。
  • term:表示一个乘法或除法表达式。它由一个factor规则后面跟着零个或多个乘法或除法符号,后面再跟着一个factor规则组成。
  • factor:表示一个数字或括号内的表达式。它可以是一个数字,或者是一个由左括号、一个表达式和右括号组成的组合。

注意,在这个示例中,我们还定义了一些Lexer规则,用于识别数字和忽略空格和换行符。

我们可以通过idea的antlr插件来检查我们的语法规则:
如下图,点击ANTLR Preview可以来到如下界面。左边的框填写需要校验的表达式,右边就是语法树解析的结果。
antlr4,java后端,antlr4,java
接下来,我们需要使用ANTLR来生成Java代码。

通过插件生成java代码

右键.g4文件,选择Configure ANTLR,配置java文件的生成路径。
antlr4,java后端,antlr4,java
antlr4,java后端,antlr4,java

再次右键.g4文件,选择Generate ANTLR Reconizer 即可生成java代码
antlr4,java后端,antlr4,java

创建一个EvalVisitor遍历AST

我们创建一个EvalVisitor遍历AST,并计算表达式的值。最终,我们打印计算结果。
EvalVisitor是一个我们需要自己实现的类,它继承了ArithmeticBaseVisitor,并重写了其中的方法。下面是一个简单的实现示例:
新建类EvalVisitor.java

public class EvalVisitor  extends ArithmeticBaseVisitor<Double> {
    // 使用一个Map来存储变量名和值的映射关系
    Map<String, Double> memory = new HashMap<String, Double>();


    // 重写visitExpr方法,用于计算加法和减法
    @Override
    public Double visitExpr(ArithmeticParser.ExprContext ctx) {
        Double result = visit(ctx.term(0));
        for (int i = 1; i < ctx.term().size(); i++) {
            String op = ctx.getChild(2*i - 1).getText();
            Double term = visit(ctx.term(i));
            if (op.equals("+")) {
                result += term;
            } else {
                result -= term;
            }
        }
        return result;
    }

    // 重写visitTerm方法,用于计算乘法和除法
    @Override
    public Double visitTerm(ArithmeticParser.TermContext ctx) {
        Double result = visit(ctx.factor(0));
        for (int i = 1; i < ctx.factor().size(); i++) {
            String op = ctx.getChild(2*i - 1).getText();
            Double factor = visit(ctx.factor(i));
            if (op.equals("*")) {
                result *= factor;
            } else {
                result /= factor;
            }
        }
        return result;
    }

    // 重写visitFactor方法,用于计算数字和括号内的表达式
    @Override
    public Double visitFactor(ArithmeticParser.FactorContext ctx) {
        if (ctx.NUMBER() != null) {
            // 如果是一个数字,直接返回其值
            return Double.parseDouble(ctx.NUMBER().getText());
        } else {
            // 如果是括号内的表达式,递归调用visit方法
            return visit(ctx.expr());
        }
    }
}

测试

新建测试类Test.java

public class Test {

        public static void main(String[] args) throws Exception {
            String input = "(1+2)*3-4";
            // 创建一个词法分析器,用于将输入转换为标记
            ArithmeticLexer lexer = new ArithmeticLexer(CharStreams.fromString(input));

            // 创建一个标记流,用于将标记传递给解析
            CommonTokenStream tokens = new CommonTokenStream(lexer);

            // 创建一个解析器,用于将标记转换为AST
            ArithmeticParser parser = new ArithmeticParser(tokens);

            // 调用解析器的parse方法,生成AST
            ParseTree tree = parser.parse();

            // 创建一个AST遍历器,用于计算表达式的值
            EvalVisitor eval = new EvalVisitor();

            // 遍历AST,并计算表达式的值
            double result = eval.visit(tree);

            // 打印计算结果
            System.out.println(result);
    }

}

测试(1+2)*3-4结果如图:
antlr4,java后端,antlr4,java文章来源地址https://www.toymoban.com/news/detail-777691.html

到了这里,关于ANTLR4入门【打造你自己的语法规则】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 用MidJourney设计自己的专属Logo;哈佛大学教你如何使用GPT-4打造智能程序;ChatGPT精美入门手册;使用ChatGPT开发二次元游戏攻略 | ShowMeAI日报

    👀 日报周刊合集 | 🎡 生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! ⋙ Twitter@indigo11 5月11日凌晨,在一年一度的Google I/O开发者大会上,Google 高管轮番上阵,公布了一系列与生成式AI相关进展,涉及全新大模型、AI聊天机器人、搜索、办公软件、云服务、安卓系统等

    2024年02月09日
    浏览(137)
  • jsx的语法规则?

    JSX(JavaScript XML)是一种在 JavaScript 中编写类似 XML 的语法扩展,常用于 React 应用程序中描述用户界面。下面是 JSX 的一些基本语法规则: 嵌套规则:JSX 元素可以相互嵌套,并且需要使用闭合标签。 表达式插值:通过将 JavaScript 表达式放置在大括号  {}  内来在 JSX 中插入动

    2024年01月23日
    浏览(38)
  • Nginx扩展篇之Location语法规则

    语法规则: location [=| | *|^~] /uri/ {… } 首先匹配 =,其次匹配^~,其次是按文件中顺序的正则匹配,最后是交给 /通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。 符号 含义 = = 开头表示精确匹配 ^~ ^~开头表示uri以某个常规字符串开头,理解为匹配 url路径即

    2024年02月08日
    浏览(45)
  • Prometheus-Rules(规则)-基础语法

    Prometheus规则是一种逻辑表达式,可用于定义有关监控数据的逻辑关系和约束条件。这些规则可以用于告警条件、聚合和转换等。 普罗米修斯支持两种类型的规则,可以对其进行配置,然后定期进行评估: recording rules alerting rules。 要在 Prometheus 中使用规则,请创建一个包含所

    2024年02月08日
    浏览(41)
  • cron表达式语法规则及常见示例

    cron表达式最初是由Unix操作系统中的cron守护进程所使用的一种语法规则,用于设置定时任务。cron守护进程是Unix系统中的一个后台进程,用于周期性地执行指定的命令或脚本。它可以根据用户的需求,按照指定的时间间隔或时间点来执行任务,通常用于定时备份、清理日志、

    2024年02月09日
    浏览(52)
  • 召唤神龙打造自己的ChatGPT

    在之前的两篇文章中,我介绍了GPT 1和2的模型,并分别用Tensorflow和Pytorch来实现了模型的训练。具体可以见以下文章链接: 1. 基于Tensorflow来重现GPT v1模型_gzroy的博客-CSDN博客 2. 花费7元训练自己的GPT 2模型_gzroy的博客-CSDN博客 有了GPT模型,我们自然会想更进一步来训练自己的

    2024年02月14日
    浏览(41)
  • 个人IP打造全过程:如何打造出属于自己的个人IP?

    随着互联网的快速发展,个人IP已经逐渐成为一个热门话题。拥有自己的个人IP可以为你带来更多的机会和收益,让你在竞争激烈的市场中脱颖而出。但是,要想打造自己的个人IP并不是一件容易的事情。本文将为你介绍如何打造属于自己的个人IP。#IP#   一、了解自己 首先,

    2024年02月16日
    浏览(48)
  • 如何打造属于自己的个人IP?

    在当今信息爆炸的时代,个人 IP 已经成为人们在网络世界中的独特标签。无论是在职场上、创业中,还是在社交生活中,拥有个人 IP 的人都能脱颖而出,吸引更多的关注和机会。那么,如何打造属于自己的个人 IP 呢? 首先,找到自己的定位。 在打造个人 IP 的过程中,定位

    2024年02月14日
    浏览(42)
  • LangChain:打造自己的LLM应用

    LangChain是一个框架,用于开发由LLM驱动的应用程序。可以简单认为是LLM领域的Spring,以及开源版的ChatGPT插件系统。核心的2个功能为: 1)可以将 LLM 模型与外部数据源进行连接。 2)允许与 LLM 模型与环境进行交互,通过Agent使用工具。 LangChain提供了各种不同的组件帮助使用

    2024年02月14日
    浏览(42)
  • 如何打造属于自己的私域流量?

    客户助手官网地址:https://www.skynen.cn/ 一、前言: 现在,越来越多消费者更愿意通过互联网平台获取更多的新闻,也有更多的人选择网上购物,随之兴起的电商打开了全新的社交新零售,将用户沉淀为粉丝,那么如何构建私域流量呢? 01、“私域流量”是什么 回答这个问题之

    2024年02月04日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包