ANTLR随笔(三)
ANTLR基本语法
前面已经简单介绍了ANTLR以及怎么安装和测试。
同学们应该大概清楚ANTLR的使用场景,但是对于关键步骤,怎么编写一个语法文件并没有详细介绍,这篇笔记主要详细讲解一下ANTLR的语法。
在过去的几十年内人类发明了很多种编程语言,现在还在持续增加。而ANTLR的语法就是要把任意的编程语言的语法规则通过自身的语法描述文件来定义。好消息是,这么多的编程语言,相对而言,基本的语言模式并不多。
之所以这样,其实原因也很简单。因为我们在设计编程语言时,倾向于将语言设计的和脑海中的自然语言相类似。我们期望看到有序的词法符号,也期望同词法符号的依赖关系。比如不会有任何语言出现{(})这种语法,大家会用数学符号,标识符,字符串。
总结下来,所有编程语言的语言模式可以抽象成四类:
- 序列:一列元素,类似数组里面的值
- 选择:在多种可选方案中做选择,eg:if else
- 词法符号依赖:符号是成对出现,eg:左右括号
- 嵌套结构: 自相似的语言结构,eg:编程语言中的一个语法嵌套另一个语法。
ANTLR实际就是基于以上的原则进行语法的设计,达到定义一种语法的作用。下面我们一个个详细说明一下这四种语言模式
序列
序列模式是最常见的一种模式。简单来说把一连串的词法按顺序排列就是一种序列,所有的指令也是一个序列。
然后ANTLR结合正则表达式,就可以快速的描述出多个元素的序列模式,
INT+表示一个或多个整数,INT*表示零或多个整数,INT?表示零个或一个整数。
CSV这个文件为例,CSV的语法用ANTLR描述出来就是
file : (row '\n')*; //一个‘\n’作为终止符的序列,表示文件由多行组成
row : field (',' field)*; //一个‘,’作为分隔符的序列,文件每行由多个字段组成, 这里其实也用到了嵌套模式
field : STRING; // 假设字段都是字符串
选择
如果一个编程语言只有一种语句,就太无聊了,也做不了什么。选择模式就是表示一个地方可能支持多种有效的语句。
在ANTLR中使用|来表达选择模式,选择模式在语法中随处可见。
上面的例子,CSV的字段肯定不一定都是字符串,那么我们应该改成
field : STRING | INT;
注意的是在ANTLR中是按顺序来匹配解析规则,所以多个|分割的规则顺序是有意义的。
词法符号依赖
词法符号依赖最常见的用法还是定义括号的限制,规定括号必须成对出现。
还是那上面的字段举例子,比如我们要限制CSV的字段必须用“包括。那可以改成
field : ‘“’ STRING | INT ‘”’;
嵌套结构
嵌套词组是一种自相似的语言结构,即它的子词组也遵循相同的规则。表达式是一种典型的自相似语言结构,它包含多个嵌套的,以运算符分割的子表达式。类似于我们程序中的递归。
我们看一下简单wihle循环怎么定义
stat : 'while' '(' expr ')' stat //匹配wihle语句,必须开头是while
| '{' stat* '}' //匹配while里面的多条语句,这里的关键是stat里面的子语句也是stat词法,就形成了一个嵌套。
...
;
其实上面这种直接递归是比较难理解,一般的写法会写成间接递归
stat : 'while' '(' expr ')' stat
| '{' block* '}'
...
;
block : '{' stat* '}'
常用语法
前面已经介绍了常用的四种语法模式,下面列一下ANTLR常用的语法标记,后面可以当作写语法文件的字典。
| 用法 | 描述 |
|---|---|
| X | 匹配元素 |
| x y ... z | 匹配一系列多个的元素 |
| (...|...|...) | 一个具有多个选择分支的元素 |
| x? | 匹配零或一个X元素 |
| x* | 匹配零或多个X元素 |
| x+ | 匹配一或多个X元素 |
| r : ...; | 定义一个新规则r |
| r : ...|...|...; | 定义一个多个分支的新规则r |
| 模式名 | 描述 |
|---|---|
| 序列 | x y ... z |
| 带终止符的序列 | (statement ';')* |
| 带分隔符的序列 | expr (',' expr)* |
| 选择 | field : STRING |
| 词法符号依赖 | '(' expr ')' |
| 嵌套 | expr : '(' expr ')' | ID; |
JSON的语法
下面通过分析一下大家常用的json的语法来加强理解。
json
: value
;
obj
: '{' pair (',' pair)* '}'
| '{' '}'
;
pair
: STRING ':' value
;
arr
: '[' value (',' value)* ']'
| '[' ']'
;
value
: STRING
| NUMBER
| obj
| arr
| 'true'
| 'false'
| 'null'
;
上面是json格式最核心的语法定义,回顾一下,这里其实用到了前面说的全部四种模式,下面一一讲解。
json
: value
;
这里其实是定义了一个json的基础,json基础规则就由一个value规则组成。
value
: STRING
| NUMBER
| obj
| arr
| 'true'
| 'false'
| 'null'
;
然后这里定义了value的规则, 可以看到这里用到了选择模式。 json的value可以是字符串,数字,true,false,null, 这四个其实是传统定义json格式“值”部分能够使用的基本类型。然后除了基本类型,value还可以是obj和arr。
arr
: '[' value (',' value)* ']'
| '[' ']'
;
arr这个规则其实就是一个json数组,它由多个value通过,分割的数组,或者是一个空数组。 这里用到了间接嵌套模式。 统通过这个规则,json的某一个值可以是另一组json格式
obj
: '{' pair (',' pair)* '}'
| '{' '}'
;
pair
: STRING ':' value
;
obj是由一个json对象,它由多个pair通过,分割。或者可以是一个空的{}。然后其中的pair则是一个最基础的key-val的格式,这也是json最基础的语法。可以看出一点json定义中key必须是字符串。
这里其实就是json最核心的一些定义,大家可以回想一下json格式的规则是不是就是这样的。然后再加上一下针对不同格式的正则要求,就完成了json的ANTLR语法定义。下面附带了完整的文件,有兴趣可以自己结合之前的分享,读一下这文件。
ANTLR随笔(三)的更多相关文章
- Alpha冲刺随笔三:第三天
课程名称:软件工程1916|W(福州大学) 作业要求:项目Alpha冲刺(十天冲刺) 团队名称:葫芦娃队 作业目标:在十天冲刺里对每天的任务进行总结. 随笔汇总:https://www.cnblogs ...
- 框架计划随笔 三.EntityFramework在传统事务脚本模式下的使用
某个朋友问为什么不推首页或者允许评论,我说一直没怎么写博客,也习惯了先随便乱画再开始写文档,担心公开后一些不经意的"呓语“中得出的错误的结论会给别人错误的观点,所以这个系列只是当做熟悉写博客 ...
- 随笔三 安装Linux操作系统
一.虚拟机安装Ubuntu图文教程]在自己笔记本上安装Linux操作系统 我参考了VirtualBox虚拟机安装Ubuntu的图文教程,根据图片和所附内容一步步的将虚拟机安装到位,没看安装教程之前完全 ...
- ANTLR随笔(二)
安装ANTLR 作者的电脑是MAC的操作系统macOS Catalina 10.15.2. 安装步骤后linux操作的系统的一样, Windows系统大致步骤一样,但是环境变量等配置有差别,作者很久没 ...
- ANTLR随笔(一)
学习背景 最近做项目需要开发一个类似Graphql的简单版的自定义查询功能. 功能主要是通过前端自定义的复查询条件来控制后端的查询字段以及最终返回的JSON格式. 最初准备直接使用Graphql实现但 ...
- JAVA 多线程随笔 (三) 多线程用到的并发容器 (ConcurrentHashMap,CopyOnWriteArrayList, CopyOnWriteArraySet)
1.引言 在多线程的环境中,如果想要使用容器类,就需要注意所使用的容器类是否是线程安全的.在最早开始,人们一般都在使用同步容器(Vector,HashTable),其基本的原理,就是针对容器的每一个操 ...
- Java随笔三
1.接口: 1)接口不是类,不能使用new运算符实例化一个接口,而是对类的一组需求描述,这些类要遵循接口描述的统一格式进行定义.个人感觉像C语言中的函数在头文件中的预先声明,但是包含了一些类的特点,比 ...
- matlab随笔(三)
把矩阵变成行向量(矩阵元素的排列是从上到下,从左到右): 1.先转置,转成行向量 A = >> A=A' A = >> a=A(:)' a = 2.reshape函数 A = ...
- android 应用架构随笔三(ListView)
import java.util.ArrayList; import java.util.List; import com.heima.googleplay.holder.BaseHolder; im ...
随机推荐
- Go coding in go way(用Go的思维去coding)
本文是Tony Bai在2017年第三届GopherChina大会上所作,来源如下 https://tonybai.com/2017/04/20/go-coding-in-go-way/ 一.序 今天 ...
- 怎么用一行HTML代码搭建一个谷歌镜像?
<iframe src="google.com"></iframe>
- Markdown语法说明及常用软件推荐(附链接)
Markdown语法同样支持HTML标签 以下所有字符均为英文字符 标题 标题级别由#决定,一个为一级 样例 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ...
- vuex的使用心得
今天的工作内容-----vuex的使用心得: 都知道,对于小型的项目来说不必使用vuex,但是对于需要把共享的变量全部存储在一个对象里面,然后把这个对象放在顶层组件中以供其他组件使用.其实vuex就是 ...
- php遍历文件夹中所有的文件
遍历文件夹中的所有文件 思路:1.定义一个函数,把给定的文件夹当前目录遍历输出(用到的文件操作函数scandir():一次性读取当前文件夹所有的内容并以数组的形式返回.). 2.如果是文件夹则红色字体 ...
- JsonFormat 日期少了8个小时?还我
JsonFormat 后日期少了8个小时什么鬼? 前言 今天测试的时候发现时间对不上,比数据库里的时间少了8个小时?测试小姐姐一顿狂轰乱炸,一点都不温柔. 什么鬼?哪里出了问题?数据库显示的是下面
- js函数的三种成创建方式以及它们各自的不同
js有三种创建函数的方式: 1.function语句(也叫函数声明) function sum(a, b) { return a + b; } sum(1, 2); // 3 2. 函数直接量,又叫函 ...
- 使用numpy和PIL实现图像的手绘效果
输入 输出 代码如下 图像的手绘效果的实现 from PIL import Image import numpy as np a = np.array(Image.open("index.j ...
- 群辉DS418play体验+经验分享
群辉DS418play体验+经验分享 群辉DS418play体验+经验分享 购买初衷 近期百度网盘到期,我又需要重复下载很多资源(游戏.电影.毛片),下载没速度&下完没空间怎么办? ...
- 2019.3.14解题报告&补题报告
A题 题意: 输入r, c,代表r*c的矩阵,接下来一行,是r个数,代表每一行里最大的数:接下来一行,是c个数,代表每一列中的最大数.求所给数据是否冲突. 思路:判断r个数中最大数maxr和c个数中最 ...