文章目录
前言
博主介绍:✌目前全网粉丝4W+,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。
涵盖技术内容:Java后端、大数据、算法、分布式微服务、中间件、前端、运维等。
博主所有博客文件目录索引:博客目录索引(持续更新)
CSDN搜索:长路
视频平台:b站-Coder长路
本章节源码
当前文档配套相关源码地址:
- gitee:https://gitee.com/changluJava/demo-exer/tree/master/java-sqlparser/demo-javacc/learn-javacc-demo
- github:https://github.com/changluya/Java-Demos/tree/master/java-sqlparser/demo-javacc/learn-javacc-demo
一、什么是javacc
javacc官网:https://javacc.github.io/javacc/
介绍:JavaCC(Java Compiler Compiler)是一种广泛使用的解析器和词法分析器生成工具,主要用于处理编程语言、数据格式以及任何需要精确解析的文本输入。它最初是为Java语言设计的,但现在也可以用于其他编程环境。JavaCC帮助开发者通过定义语法和词法规则来创建编译器前端,包括词法分析器(Scanner)和语法分析器(Parser),从而简化了编译器开发的过程。
简单来说:JavaCC是一个能生成词法和语法的分析器的生成程序。
- 词法分析器,就是对一串文本进行拆分,转换成一系列的Token。
- 语法分析器,就是对词法分析器产生的Token,进行校验。
**应用场景:**JavaCC常被用来开发编译器、解释器、特定领域的语言处理器等,也适用于需要对文本进行复杂解析的应用程序中。例如,它可以用来解析SQL查询、JSON文档或者自定义配置文件格式。开始使用JavaCC时,你需要编写一个语法文件(.jj),在这个文件里定义你的语言的语法规则。之后,通过JavaCC工具处理这个文件,即可生成相应的Java代码,这些代码实现了你定义的解析逻辑。
二、Mac环境安装javacc
相关教程:
- windows安装可见:1.JavaCC安装与测试
- mac系统安装可见:https://cloud.tencent.cn/developer/information/%E5%9C%A8%E5%B8%A6%E6%9C%89%E7%BB%88%E7%AB%AF%E7%9A%84mac%E4%B8%8A%E5%AE%89%E8%A3%85javacc-ask
步骤如下:
1)首先提前安装Homebrew
2)下载和安装javacc
brew install javacc
查看javacc安装的目录:
// 目录位置:/opt/homebrew/opt/javacc
brew --prefix javacc
3)测试javacc
javacc -version
若是出现异常报错:
关于version版本范围表:https://blog.csdn.net/gaofenglxx/article/details/137559852
表示要使用jdk21,jdk21下载地址:https://www.oracle.com/java/technologies/downloads/#jdk21-mac
下载安装后修改下环境变量JAVA_HOME:
vim ~/.zshrc
-- 原始jdk8
export JAVA_HOME="/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home"
-- 修改为jdk21
export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home"
source ~/.zshrc
指定jdk21即可,查看当前的javacc版本号。
三、javacc测试案例
1、编写词法描述文件
JavaCC的语法描述文件是 扩展名为.jj 的文件,测试所用的语法描述文件内容如下,该描述文件的功能是解析正整数加法运算,并进行计算的解析器的语法描述文件,设置名称为demo01.jj:
options {
STATIC = false;
}
PARSER_BEGIN(Adder)
import java.io.*;
public class Adder {
public static void main(String[] args) {
for (String arg : args) {
try {
System.out.println(evaluate(arg));
// return(evaluate(arg));
} catch (ParseException ex) {
System.err.println(ex.getMessage());
}
}
}
public static long evaluate(String src) throws ParseException {
Reader reader = new StringReader(src);
return new Adder(reader).expr();
}
}
PARSER_END(Adder)
SKIP: { <[" ", "\t", "\r", "\n"]> }
TOKEN: {
<INTEGER: (["0"-"9"])+>
}
long expr():
{
Token x, y;
}
{
x=<INTEGER> "+" y=<INTEGER> <EOF>
{
return Long.parseLong(x.image) + Long.parseLong(y.image);
}
}
2、借助javacc命令来处理demo01.jj文件
进入到对应jj文件所在的目录,执行命令:
javacc demo01.jj
此时就出现了生成的java文件:
3、idea配置输入参数,运行Adder类方法
我们将生成的代码移入到java源代码目录中:
实际上也可以在采用最原生的方式对目录中通过执行命令方式去执行我们生成的类:
javac Adder.java
java Adder 1+7
我们这里也可以直接idea工具来配置参数来快速测试,添加参数1+7:
接着我们来运行下该任务:
四、javacc文件编译类描述
4.1、demo1.jj文件生成内容描述&解析转换过程
在一开始的javacc的demo案例中通过javacc对demo1.jj文件来进行生成,得到的内容如下:
生成的各个类介绍描述如下:
- XXXXX(指的是Adder):解析类入口
- XXXXXConstants:Token常量,SKIP TOKEN 和TOKEN
- XXXXXTokenManager:词法分析器
- SimpleCharStream:词法分析器的输入流
- Token:Token类
- ParseException:语法解析异常
- TokenMgrError:语法错误提示
引用大佬神图:https://github.com/quxiucheng/apache-calcite-tutorial/blob/a7d63273d0c7585fc65ad250c99a67a201bcb8b5/calcite-tutorial-2-parser/parser-2-javacc-tutorial/README.md
4.2、解析demo01.jj文件
目标:用于解析并计算形如"数字+数字"
的字符串表达式。
选项部分
options {
STATIC = false;
}
STATIC = false;
表示生成的解析器类不会是静态的。这意味着你可以创建该类的对象实例,并可能在多个解析任务之间共享状态。
解析器定义部分
PARSER_BEGIN(Adder)
// Java 代码块
PARSER_END(Adder)
- 这一部分定义了名为
Adder
的解析器。其中包含了主函数main
和evaluate
方法。 evaluate
方法接收一个字符串参数,将其转换为Reader
对象,并调用expr()
方法来解析并计算表达式的值。
跳过规则
SKIP: { <[" ", "\t", "\r", "\n"]> }
- 定义了哪些字符应被跳过而不进行处理,这里包括空格、制表符、回车符和换行符,它们通常用于分隔输入中的不同元素。
令牌定义
TOKEN: {
<INTEGER: (["0"-"9"])+>
}
- 定义了一个名为
INTEGER
的令牌,它匹配一个或多个连续的数字字符(0-9
)。
解析规则
long expr():
{
Token x, y;
}
{
x=<INTEGER> "+" y=<INTEGER> <EOF>
{
return Long.parseLong(x.image) + Long.parseLong(y.image);
}
}
expr
方法尝试匹配一个模式:一个整数后跟一个加号再跟另一个整数,最后是一个文件结束标记(<EOF>
)。- 如果匹配成功,将两个
Token
对象的image
属性(即实际匹配到的字符串)转换为长整型数值,并返回它们的和。
4.3、快速写一个支持合并字符串的javacc语法文件
options {
STATIC = false;
}
PARSER_BEGIN(Adder)
import java.io.*;
public class Adder {
public static void main(String[] args) {
for (String arg : args) {
try {
System.out.println(evaluate(arg));
} catch (ParseException ex) {
System.err.println(ex.getMessage());
}
}
}
public static String evaluate(String src) throws ParseException {
Reader reader = new StringReader(src);
return new Adder(reader).concatExpr();
}
}
PARSER_END(Adder)
SKIP: { <[" ", "\t", "\r", "\n"]> }
TOKEN: {
<STRING_LITERAL: "\"" (~["\""])* "\""> | // 字符串字面量
<IDENTIFIER: (["a"-"z", "A"-"Z"])+> // 标识符或变量名
}
String concatExpr():
{
Token x, y;
}
{
x=<IDENTIFIER> "+" y=<IDENTIFIER> <EOF>
{
return x.image + y.image;
}
}
参考文章
[1]. 1.JavaCC安装与测试
资料获取
大家点赞、收藏、关注、评论啦~
精彩专栏推荐订阅:在下方专栏👇🏻
- 长路-文章目录汇总(算法、后端Java、前端、运维技术导航):博主所有博客导航索引汇总
- 开源项目Studio-Vue—校园工作室管理系统(含前后台,SpringBoot+Vue):博主个人独立项目,包含详细部署上线视频,已开源
- 学习与生活-专栏:可以了解博主的学习历程
- 算法专栏:算法收录
更多博客与资料可查看👇🏻获取联系方式👇🏻,🍅文末获取开发资源及更多资源博客获取🍅