Antlr 是一个基于 Java 开发的功能强大的语言识别工具,Antlr 以其简介的语法和高速的运行效率在这类工具中出类拔萃。当你需要开发一种领域语言时,语言可能像 Excel 中的公式一样复杂,也可能像本文中的例子一样简单(只有算术运算),这时你可以考虑使用 Antlr 来处理你的语言。

Antlr 简介

ANTLR 语言识别的一个工具 (ANother Tool for Language Recognition ) 是一种语言工具,它提供了一个框架,可以通过包含 Java, C++, 或 C# 动作(action)的语法描述来构造语言识别器,编译器和解释器。 计算机语言的解析已经变成了一种非常普遍的工作,在这方面的理论和工具经过近 40 年的发展已经相当成熟,使用 Antlr 等识别工具来识别,解析,构造编译器比手工编程更加容易,同时开发的程序也更易于维护。

语言识别的工具有很多种,比如大名鼎鼎的 Lex 和 YACC,Linux 中有他们的开源版本,分别是 Flex 和 Bison。在 Java 社区里,除了 Antlr 外,语言识别工具还有 JavaCC 和 SableCC 等。

和大多数语言识别工具一样,Antlr 使用上下文无关文法描述语言。最新的 Antlr 是一个基于 LL(*) 的语言识别器。在 Antlr 中通过解析用户自定义的上下文无关文法,自动生成词法分析器 (Lexer)、语法分析器 (Parser) 和树分析器 (Tree Parser)。

Antlr 能做什么

编程语言处理

识别和处理编程语言是 Antlr 的首要任务,编程语言的处理是一项繁重复杂的任务,为了简化处理,一般的编译技术都将语言处理工作分为前端和后端两个部分。其中前端包括词法分析、语法分析、语义分析、中间代码生成等若干步骤,后端包括目标代码生成和代码优化等步骤。

Antlr 致力于解决编译前端的所有工作。使用 Anltr 的语法可以定义目标语言的词法记号和语法规则,Antlr 自动生成目标语言的词法分析器和语法分析器;此外,如果在语法规则中指定抽象语法树的规则,在生成语法分析器的同时,Antlr 还能够生成抽象语法树;最终使用树分析器遍历抽象语法树,完成语义分析和中间代码生成。整个工作在 Anltr 强大的支持下,将变得非常轻松和愉快。

文本处理

文本处理

当需要文本处理时,首先想到的是正则表达式,使用 Anltr 的词法分析器生成器,可以很容易的完成正则表达式能够完成的所有工作;除此之外使用 Anltr 还可以完成一些正则表达式难以完成的工作,比如识别左括号和右括号的成对匹配等。

在IDEA中安装使用Antlr

在Settings-Plugins中安装ANTLR v4 grammar plugin

新建一个Maven项目,在pom.xml文件中添加ANTLR4插件和运行库的依赖。注意一定要用最新版的,依赖,不知道最新版本号的可以自己google一下maven antlr4。

org.antlr

antlr4-runtime

4.5.3

org.antlr

antlr4-maven-plugin

4.3

antlr

antlr4

none

src/test/java

true

true

antlr4-maven-plugin用于生产Java代码,antlr4-runtime则是运行时所需的依赖库。把antlr4-maven-plugin的phase设置成none,这样在Maven 的lifecycle种就不会调用ANTLR4。如果你希望每次构建生成文法可以将这个配置去掉。

我们定义一个最简单的领域语言,从一个简单的完成算术运算的例子出发,详细说明 Antlr 的使用。首先我们需要在src\main\java中新建一个 Antlr 的文法文件, 一般以 .g4 为文件名后缀,命名为 Demo.g4 。

表达式定义

文法定义

在这个文法文件 Demo.g4 中根据 Antlr 的语法规则来定义算术表达式的文法,文件的头部是 grammar 关键字,定义文法的名字,必须与文法文件文件的名字相同:

grammar Demo;

为了简单起见,假设我们的自定义语言只能输入一个算术表达式。从而整个程序有一个语句构成,语句有表达式或者换行符构成。如清单 1 所示:

清单1.程序和语句

prog: stat

;

stat: expr

|NEWLINE

;

在 Anltr 中,算法的优先级需要通过文法规则的嵌套定义来体现,加减法的优先级低于乘除法,表达式 expr 的定义由乘除法表达式 multExpr 和加减法算符 (‘+’|’-‘) 构成;同理,括号的优先级高于乘除法,乘除法表达式 multExpr 通过原子操作数 atom 和乘除法算符 (‘*’|’/’) 构成。整个表达的定义如清单 2 所示:

清单2.表达式

expr : multExpr (('+'|'-') multExpr)*

;

multExpr : atom (('*'|'/') atom)*

;

atom: '(' expr ')'

| INT

| ID

;

最后需要考虑的词法的定义,在 Antlr 中语法定义和词法定义通过规则的第一个字符来区别, 规定语法定义符号的第一个字母小写,而词法定义符号的第一个字母大写。算术表达式中用到了 4 类记号 ( 在 Antlr 中被称为 Token),分别是标识符 ID,表示一个变量;常量 INT,表示一个常数;换行符 NEWLINE 和空格 WS,空格字符在语言处理时将被跳过,skip() 是词法分析器类的一个方法。如清单 3 所示:

清单 3. 记号定义

ID:('a'..'z'|'A'..'Z')+;

INT:'0'..'9'+;

NEWLINE:'\r'?'\n';

WS:(' '|'\t'|'\n'|'\r')+{skip();};

Antlr 支持多种目标语言,可以把生成的分析器生成为 Java,C#,C,Python,JavaScript 等多种语言,默认目标语言为 Java,通过 options {language=?;} 来改变目标语言。我们的例子中目标语言为 Java。

整个Demo.g4文件内容如下:

grammar Demo;

//parser

prog:stat

;

stat:expr|NEWLINE

;

expr:multExpr(('+'|'-')multExpr)*

;

multExpr:atom(('*'|'/')atom)*

;

atom:'('expr')'

|INT

|ID

;

//lexer

ID:('a'..'z'|'A'..'Z')+;

INT:'0'..'9'+;

NEWLINE:'\r'?'\n';

WS:(' '|'\t'|'\n'|'\r')+{skip();};

运行ANTLR

右键Demo.g4,选择Configure ANTLR,配置output路径。

右键Demo.g4,选择Generate ANTLR Recognizer。可以看到生成结果结果。

其中Demo.tokens为文法中用到的各种符号做了数字化编号,我们可以不关注这个文件。DemoLexer是Antlr生成的词法分析器,DemoParser是Antlr 生成的语法分析器。

调用分析器。新建一个Main.java。

public static void run(String expr) throws Exception{

//对每一个输入的字符串,构造一个 ANTLRStringStream 流 in

ANTLRInputStream in = new ANTLRInputStream(expr);

//用 in 构造词法分析器 lexer,词法分析的作用是产生记号

DemoLexer lexer = new DemoLexer(in);

//用词法分析器 lexer 构造一个记号流 tokens

CommonTokenStream tokens = new CommonTokenStream(lexer);

//再使用 tokens 构造语法分析器 parser,至此已经完成词法分析和语法分析的准备工作

DemoParser parser = new DemoParser(tokens);

//最终调用语法分析器的规则 prog,完成对表达式的验证

parser.prog();

}

完整Main.java代码:

import org.antlr.v4.runtime.CommonTokenStream;

import org.antlr.v4.runtime.ANTLRInputStream;

public class Main {

public static void run(String expr) throws Exception{

//对每一个输入的字符串,构造一个 ANTLRStringStream 流 in

ANTLRInputStream in = new ANTLRInputStream(expr);

//用 in 构造词法分析器 lexer,词法分析的作用是产生记号

DemoLexer lexer = new DemoLexer(in);

//用词法分析器 lexer 构造一个记号流 tokens

CommonTokenStream tokens = new CommonTokenStream(lexer);

//再使用 tokens 构造语法分析器 parser,至此已经完成词法分析和语法分析的准备工作

DemoParser parser = new DemoParser(tokens);

//最终调用语法分析器的规则 prog,完成对表达式的验证

parser.prog();

}

public static void main(String[] args) throws Exception{

String[] testStr={

"2",

"a+b+3",

"(a-b)+3",

"a+(b*3"

};

for (String s:testStr){

System.out.println("Input expr:"+s);

run(s);

}

}

}

运行Main.java

当输入合法的的表达式时,分析器没有任何输出,表示语言被分析器接受;当输入的表达式违反文法规则时,比如“a + (b * 3”,分析器输出 line 0:-1 mismatched input ‘’ expecting ‘)’;提示期待一个右括号却遇到了结束符号。

文法可视化

打开Antlr Preview。

在Demo.g4中选中一个语法定义符号,如expr。右键选中的符合,选择Text Rule expr。

在ANTLR Preview中选择input,输入表达式,如a+b*c+4/2。则能显示出可视化的文法。

idea使用antlr_在IDEA中使用ANTLR4教程相关推荐

  1. Idea中使用Antlr4

    Idea中使用Antlr4 一.新建一个MAVEN项目 二.antlr在idea中的使用 三.抽象语法树的访问(Vistor方式) 抽象语法树的例子 例子分析(建议看完 三 和四 再回头看例子的分析) ...

  2. 创建此对象的程序是quation_MathType出现此对象创建于Equation中的处理教程

    有那么一部份多朋友还不熟悉MathType出现此对象创建于Equation中怎么处理?下面小编就讲解MathType出现此对象创建于Equation中的处理教程,希望对你们有所帮助哦. MathTyp ...

  3. html用bmob做留言,bmob js-sdk 在vue中的使用教程

    BmobSDK的引入 将bmob js-sdk放在static目录,然后在index.html页面中已 script 标签的形式引入,就可以在vue中全局使用bmob js-sdk 在assets目录 ...

  4. W10的服务器正在运行,win10开机提示服务器正在运行中的解决教程

    今天小编给大家分享的是win10开机提示服务器正在运行中的解决教程.最近有win10的用户反映,在开机的时候莫名的就出现了个"服务器正在运行中"的气泡提示,出现此问题困扰的用户,请 ...

  5. python idle运行anaconda_在Python IDLE 下调用anaconda中的库教程

    大家都知道,Anaconda是一个开源的Python发行版本,其包含了conda.Python等180多个科学包及其依赖项.下载了anaconda我们可以很方便的随时调用这里面的库. 原先我自己在Py ...

  6. ubuntu中flashcache使用教程

    原文:ubuntu中flashcache使用教程 当前存在多种性能价格不一的存储设备,以价格高性能好的存储设备来加速价格低性能较差的存储设备,是一种提升系统整体性能的方案.flashcache便可以做 ...

  7. Java中的JDBC教程

    Java中的JDBC教程 欢迎使用JDBC教程.Java DataBase Connectivity(JDBC)是企业应用程序中使用最广泛的API之一.这是因为大多数应用程序使用某种数据库连接.我最近 ...

  8. 在Vue项目中使用LayUI教程且解决laydate无效的问题

    在Vue项目中使用LayUI教程且解决laydate无效的问题 1,安装LayUI开发包 2,导入LayUI开发包 3,在挂载函数mounted中加载LayUI组件 4,解决加载LayUI日期组件出现 ...

  9. XCode中使用SVN 教程

    修改subversion.config方法: 可以直接在终端上输入:vi ~/.subversion/config来编辑. 也可以通过Finder搜索.subversion,点击下边的+号,进入高级搜 ...

最新文章

  1. 用Windows Media Player截图的方法
  2. UNITY崩溃的日志
  3. 【NLP】文本分类还停留在BERT?对偶对比学习框架也太强了
  4. [转载] QoS的基本原理
  5. Oracle statspack 基本使用
  6. [Java学习资料] [成长之路]
  7. LeetCode 265. 粉刷房子 II(DP)
  8. uva 11992 Fast Matrix Operations
  9. mysql根据月份查询订单销售额
  10. 网络游戏外挂编写基础
  11. 验证input输入框(字母,数字,符号,中文)
  12. java element string_Java StackTraceElement toString()方法
  13. redis详解_java 从零开始手写 redis(14)redis渐进式rehash详解
  14. 彻底解决Python包下载慢问题
  15. kali metsploit 工具入侵windows
  16. 古人道中秋 | 制作一个可拖动的月球
  17. 汽车技术管理系统c语言,[源码和文档分享]基于C语言实现的汽车牌照的快速查询...
  18. 软件工程之高质量代码(编码规范)
  19. 国产积木---克尔维特(多图流量预警)
  20. 读书笔记-精准努力-专注专注专注

热门文章

  1. 升级MacOS之后 IDEA文件内容变化但是文件标题颜色不变
  2. 月薪30K的软件测试简历怎么包装?
  3. 2012-12-21世界末日是不会来了。
  4. mysql 报错 Duplicate entry ‘xxx‘ for key ‘字段名‘
  5. 多种方法实现从Excel表格的两列数据中提取不重复(唯一)值
  6. java usbkey ssl_Java读取硬件USBKey(简称UKEY)中的SSL证书信息,创建双向SSL认证上下文环境...
  7. Zemax光学设计(十)——变焦镜头设计
  8. oracle 查询列合并行,Oracle 查询合并列
  9. 微信小程序搜索框防抖
  10. 从键盘输入一些字符,逐个把它们写到指定的文件,直到输入一个@为止。 示例1: 请输入文件名: out.txt 请输入字符串: Python is open.@ 执行代码后,out.txt文