当前位置: 首页 > news >正文

Hive-技术补充-ANTLR语法编写

一、导读

我们学习一门语言,或外语或编程语言,是不是都是要先学语法,想想这些语言有哪些相同点

        1、中文、英语、日语......是不是都有 主谓宾 的规则

        2、c、java、python、js......是不是都有 数据类型 、循环 等语法或数据结构

虽然人们在过去的几十年里发明了多种编程语言,但基本的语言模式并不多。因为他们在设计时都会情不自禁的与自己脑海中的自然语言关联,并用数学符号表达了出来。因此如果你掌握了一门语言后再去学其他语言就会变的容易。总结下来有四种抽象的计算机语言模式:

        1、序列:即一列元素,例如一个数组初始化时给的一串值

        2、选择:在多种可选方案中做出选择,例如编程语言中的if语句

        3、词法符号依赖:一个词法符号往往成对出现,比如{} () []

        4、嵌套结构:一种自相似的语言结构,例如编程语言中的if嵌套 for嵌套

为了表达以上模式,我们先了解下巴克斯-诺尔范式(Backus Normal Form简称BNF)

二、巴克斯-诺尔范式

是一种用于表示上下文无关文法的语言,它是由约翰·巴科斯(John Backus)和彼得·诺尔(Peter Naur)首先引入的用来描述计算机语言语法的符号集。

几乎所有程序设计语言都是通过上下文无关文法来定义的。巴克斯-诺尔范式是上下文无关语法的一个例子。

而且上下文无关文法足够简单可以构造有效的分析算法来检验一个给定字串是否是由某个上下文无关文法产生,例如 LR 分析器和 LL 分析器。

三、从编程语言中提取语法

可以形象的理解为就像从一堆字符串中抽取一系列正则表达式来把他们完全表达出来,只是语法比正则表达式更丰富。

讨论语法的整体结构以及如何建立初始的语法框架,是任何编程语言项目的基础步骤。

语法由一个为该语法命名的头部定义和一些列可以相互引用的语言规则组成,例如:

grammar MyG;
rule1 : 《stuff》;
rule2 : 《more stuff》;
......

tuff 和 more stuff 为语言规则

下面我们来表达下常用的四种语言模式

1、序列模式

可以直接使用 类似 'RETR'的常量字符串来表示任意简单字符序列,如关键字、标点符号等
我们使用语法规则来为编程语的特定结构命名,就像我们编程时为多次相同功能命名的函数

+ 字符串表示一个或多个元素的情况

* 字符串表示0个或多个元素的情况

file : (row '\n')* ; //以一个 '\n' 作为终止符的序列
row : field(',',field)* ;  //以一个 ',' 作为分隔符的序列
field:INT ; //假设字段都是整数

file 规则使用带终止符的序列模式来匹配0或多个row\n 序列
row 规则使用带分隔符的序列来匹配一个field 后面跟着0个或多个','field 序列的情形
','隔开了所有field 。rwo规则匹配类似 1、1,2 以及 1,2,3 的序列 

2、选择模式

使用 | 表达编程语言中的选择模式,可以分割多个可选的语法结构,例如:

filed : INT | STRING ;

type: 'float' | 'int' | 'void'

stmt : node_stmt

        | edge_stmt

        | attr_stmt

        | id '=' id

        | subgraph

        ;

3、词法符号依赖模式

举个例子,如果我们在某个语句中看到了 [ ,就必须在同一个语句中找到与它匹配的 ] ,
通常[] 会把其他元素包裹起来,比如数组的初始化声明。
可以这样表示 :

vector : '[' INT+ ']' ;

4、嵌套模式

如果一条规则的定义中需要用到它自身,我们就需要一条嵌套规则,比如递归规则。下面时一条while循环的嵌套规则

stat : 'while' '(' expr ')' stat //匹配while语句
    | '{' stat* '}'                 //匹配 {} 中若干条语句组成的代码
    ......                         //其他语句
    ;

四、优先级处理

我们先来写一个包含乘法和加法的语法:

expr : expr '*' expr //匹配由 '*' 运算符连接的子表达式
    | expr '+' expr  //匹配由 '+' 运算符连接的子表达式
    | INT
    ;

当处理 1 + 1 和 2*2 时没有问题,但是当处理 1+1*2 时就会由问题,

ANTLR 通过优先选择位置靠前的备选分支来解决歧义问题,这隐式的运行我们指定运算符优先级

尽管如此,一些运算符(例如指数运算符)是从右向左结合的,所以我们需要在这样的运算符上使用assoc选项手工指定结合性,这样,输入的 2^3^4就能够被正确解释为 2^(3^4)

expr : <assoc=right> expr '^' expr //运算符是右结合的
    | INT
    ;

此外还可以使用优先级上升来解决这个问题

五、常见的词法结构

在词法角度上,不同编程语言的外观十分相似。也就是我们只需要描述标识符和整数一次,稍加改动,就可以将它运用于大多数编程语言中。

词法分析器也是使用不同的规则来描述繁多的语言结构。和语法分析器不同的是它是通过输入的字符流来识别特定语言结构

ANTLR运行词法规则和语法规则写在同一个文件中。不过词法分析和语法分析是两个不同的阶段,ANTLR是通过这种方式区分的:词法规则以大写字母开头,语法规则以小写字母开头。

例如 ID 是要给词法规则 expr 是一个语法规则

下面让我们一起来构造些常见词法符号的词法规则:

1、匹配标识符

ID : ('a'..'z'|'A'..'Z')+ ; //匹配1个或多个大小写字母
ID : [a-zA-Z]+ ; //匹配1个或多个大小写字母

有时不同的规则会起到冲突,比如

grammar KeywordTest;
enumDef : 'enum' '{'...'}';
......
FOR : 'for';
ID : [a-zA-Z]+ ; //不会匹配'enum'和'for'

按照语法ID规则也可以匹配到'enum'和'for' ,ANTLR词法分析器解决歧义的方式优先使用靠前的词法规则。

2、匹配数字

INT : '0'..'9'+; //匹配1个或多个数字
INT : [0-9]+;     //匹配1个或多个数字

不过浮点数要复杂的多:

FLOAT : DIGIT+'.' DIGIT* //匹配 1.39 3.1569 等...
    | '.' DIGIT+          //匹配 .1 .3654 等...
    ;
    
fragment
DIGIT : [0-9]; //匹配单个数字

这里我们使用了一条辅助规则 DIGIT,这样就不用重复书写了。将一条规则声明为fragment可以告诉ANTLR该规则不是词法符号,它只会被其他词法规则使用。

3、匹配字符串常量

STRING : '"' .*? '"'; //匹配"..." 间的任意文本

其中 . 匹配任意的单个字符。*表示0或多个字符 ? 是通过正则表达式提供了对贪婪子规则的支持

但是还不够完善,因为字符串中不应该再出现双引号。如果要加双引号必须加上转义符 \
 

STRING : '"' (ESC|.)*? '"';
fragment
ESC : '\\"' | '\\\\' ; //双字符序列 \" 和 \\

4、匹配注释和空白字符

当词法分析器匹配到我们定义的规则后,会把这些词法符号放入词法符号流,输送给语法分析器。

语法分析器检查词法符号流的语法结构,但是如果其中有注释或空白字符时,会十分容易出错,因此我们需要在词法匹配时就将它去除

assign : ID (WS|COMMENT)? '=' (WS|COMMENT)? expr (WS|COMMENT) ? ;

我们再使用 skip 指令通知词法分析为i将它丢弃
LINE_COMMENT : '//' .*? '\r'? '\n' -> skip ; //匹配 "//" 任意字符序列 '\n' 
COMMENT : '/*' .*? '*/' -> skip ; //匹配 "/*" 任意字符序列 '*/' 

注意windows上的换行符是 '\r\n' 而 linux上的换行符是 '\n' (因此注意windows上的文本文件上传到linux后每行会多一个\r符号)

另外词法分析器可以接收多种位于 -> 之后的指令 ,skip 只是其中一种 ,例如 channel 指令代表一个隐藏通道 

下面我们看下 空白字符的处理 

大多数编程语言将空白字符看作词法符号间的分隔符,并将它们忽略 比如 int a = 1 ; 

(python是个例外,它使用空白字符来表达某些语法的目的:换行符代表一行命令的终止,特定数量的缩进指明嵌套的层级)

下列规则告诉 ANTLR 丢弃空白字符

WS : (' '|'\t'|'\r'|'\n')+ -> skip ; //匹配一个或多个空白字符并将它们丢弃

WS : [ \t\r\n]+ -> skip ; //匹配一个或多个空白字符并将它们丢弃

六、词法分析器和语法分析器的界限

词法和语法规则在一份文件中,且词法规则可以包含递归,这使得词法分析器变的和语法分析器一样强大,甚至可以匹配一些语法结构。

划定词法分析器和语法分析器的界限不仅是语言的职责,更是语言编写的应用程序的职责。

词法分析器应该匹配并丢弃任何语法分析器无须知晓的东西。比如注释和空白字符。

由词法分析器来匹配类似标识符、关键字、字符串、数字的常见词法符号。语法分析器的层级更高,所以我们不应当让它处理将数字组合成整数这样的事情,
这会加重它的负担。

将语法分析器无需区分的词法结构归为同一个词法类型符号。

例如:如果我们的程序对待整数和浮点数的方式是一致的,那就可以把它们都归纳为 NUMBER 类型的词法符号。

同样的将可以以相同方式处理的实体归为一类,

例如:如果语法分析器不关心xml的内容,词法分析器就可以将<>中的所有内容归为一个名为 TAG 的词法符号类型

相反,如果语法分析器需要把一种类型的文本拆开处理,那么词法分析器就应该将它的各个组成部分作为独立的词法符号输送个语法分析器

语法分析器和词法分析器是灵活的,受我们支配的,我们可以根据需求的不同来规定他们的功能和界限

比如我们有这样一个需求:

我们在代理服务器上有一份日志文件(ip 请求方法 状态码),日志内容如下
192.168.56.239 "GET /download/foo.html HTTP/1.0" 200
......

当我们大脑看到这些信息后很自认的就可以想出很多统计逻辑,不过我们的需求只是统计行数,

那我们就可以忽略到里面每行的的内容,只关注换行符即可

语法文件部分内容如下:
file : NL+ ;                     //匹配换行符序列的语法分析器
STUFF: ~'\n'+ -> skip ; //除 '\n' 之外的字符全部丢掉
NL : '\n' ;                       //将设定的换行符返回给语法分析器或者其他的调用者

接下来我们增加一个需求:

从日志文件中提取ip地址列表,这意味着我们需要一条匹配ip地址的词法规则,最好还有一些词法规则来匹配一行记录中的其他元素

语法文件部分内容如下:

file : row ;                        //匹配日志文件中全部行的语法规则
row : ip STRING INT NL ;            //匹配日志文件中的一行记录

IP : INT '.' INT '.' INT '.' INT ;  //匹配ip 例如 192.168.56.239
INT : [0-9]+ ;                         //匹配ip地址中的一个字节或者http的状态码
STRING : '"' .*? '"' ;                 //匹配http请求方法
NL : '\n';                            //匹配一行记录的终止符
WS : ' ' -> skip ;                    //忽略空格

我们也可以把IP词法规则转换成ip语法规则,只需要转换成小写即可

file : row ;                        //匹配日志文件中全部行的语法规则
row : ip STRING INT NL ;            //匹配日志文件中的一行记录
ip : INT '.' INT '.' INT '.' INT ;  //匹配ip 例如 192.168.56.239


INT : [0-9]+ ;                         //匹配ip地址中的一个字节或者http的状态码
STRING : '"' .*? '"' ;                 //匹配http请求方法
NL : '\n';                            //匹配一行记录的终止符
WS : ' ' -> skip ;                    //忽略空格

相关文章:

Hive-技术补充-ANTLR语法编写

一、导读 我们学习一门语言&#xff0c;或外语或编程语言&#xff0c;是不是都是要先学语法&#xff0c;想想这些语言有哪些相同点 1、中文、英语、日语......是不是都有 主谓宾 的规则 2、c、java、python、js......是不是都有 数据类型 、循环 等语法或数据结构 虽然人们在…...

6.使用个人用户登录域控的成员服务器,如何防止个人用户账号的用户策略生效?

&#xff08;1&#xff09;需求&#xff1a; &#xff08;2&#xff09;实战配置步骤 第一步:创建新的策略-并编辑策略 第二步&#xff1a;将策略应用到服务器处在OU 第三步&#xff1a;测试 &#xff08;1&#xff09;需求&#xff1a; 比如域控&#xff0c;或者加入域的…...

模拟算法

例题一 算法思路&#xff1a; 纯模拟。从前往后遍历整个字符串&#xff0c;找到问号之后&#xff0c;就⽤ a ~ z 的每⼀个字符去尝试替换即 可。 例题二 解法&#xff08;模拟 分情况讨论&#xff09;&#xff1a; 算法思路&#xff1a; 模拟 分情况讨论。 计算相邻两个…...

【数据结构刷题专题】—— 二叉树

二叉树 二叉树刷题框架 二叉树的定义&#xff1a; struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(NULL), right(NULL); };1 二叉树的遍历方式 【1】前序遍历 class Solution { public:void traversal(TreeNode* node, vector&…...

基于AWS云服务构建智能家居系统的最佳实践

在当今智能家居时代,构建一个安全、高性能、可扩展和灵活的智能家居系统已经成为许多公司的目标。亚马逊网络服务(AWS)提供了一系列云服务,可以帮助企业轻松构建和管理智能家居系统。本文将探讨如何利用AWS云服务构建一个智能家居系统,并分享相关的最佳实践。 系统架构概述 该…...

Java零基础-集合:Set接口

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一个人虽可以走的更快&#xff0c;但一群人可以走的更远。 我是一名后…...

数据结构与算法-排序算法

1.顺序查找 def linear_search(iters, val):for i, v in enumerate(iters):if v val:return ireturn 2.二分查找 # 升序的二分查找 def binary_search(iters, val):left 0right len(iters)-1while left < right:mid (left right) // 2if iters[mid] val:return mid…...

SpringBoot 文件上传(三)

之前讲解了如何接收文件以及如何保存到服务端的本地磁盘中&#xff1a; SpringBoot 文件上传&#xff08;一)-CSDN博客 SpringBoot 文件上传&#xff08;二&#xff09;-CSDN博客 这节讲解如何利用阿里云提供的OSS&#xff08;Object Storage Service)对象存储服务保存文件。…...

web渗透测试漏洞流程:红队目标信息收集之资产搜索引擎收集

web渗透测试漏洞流程 渗透测试信息收集---域名信息收集1.域名信息的科普1.1 域名的概念1.2 后缀分类1.3 多重域名的关系1.4 域名收集的作用1.5 DNS解析原理1.6 域名解析记录2. 域名信息的收集的方法2.1 基础方法-搜索引擎语法2.1.1 Google搜索引擎2.1.1.1 Google语法的基本使用…...

UI自动化_id 元素定位

## 导包selenium from selenium import webdriver import time1、创建浏览器驱动对象 driver webdriver.Chrome() 2、打开测试网站 driver.get("你公司的平台地址") 3、使浏览器窗口最大化 driver.maximize_window() 4、在用户名输入框中输入admin driver.find_ele…...

华为OD技术面算法题整理

LeetCode原题 简单 题目编号频次409. 最长回文串 - 力扣(LeetCode)3...

vmware虚拟机下ubuntu扩大磁盘容量

1、扩容&#xff1a; 可以直接在ubuntu setting界面里直接扩容&#xff0c;也可通过vmware命令&#xff0c;如下&#xff1a; vmware提供一个命令行工具&#xff0c;vmware-vdiskmanager.exe&#xff0c;位于vmware的安装目录下&#xff0c;比如 C:/Program Files/VMware/VMwar…...

秋招打卡算法题第一天

一年多没有刷过算法题了&#xff0c;已经不打算找计算机类工作了&#xff0c;但是思来想去&#xff0c;还是继续找吧。 1. 字符串最后一个单词的长度 public static void main(String[] args) {Scanner in new Scanner(System.in);while(in.hasNextInt()){String itemin.nextL…...

BC98 序列中删除指定数字

题目 描述 有一个整数序列&#xff08;可能有重复的整数&#xff09;&#xff0c;现删除指定的某一个整数&#xff0c;输出删除指定数字之后的序列&#xff0c;序列中未被删除数字的前后位置没有发生改变。 数据范围&#xff1a;序列长度和序列中的值都满足 1≤&#xfffd;≤…...

基于Java的学生体质健康管理系统的设计与实现(论文+源码)_kaic

摘 要 随着时代的进步&#xff0c;信息化也在逐渐深入融进我们生活的方方面面。其中也给健康管理带来了新的发展方向。通过对学生体质健康管理的研究与分析发现当下的管理系统还不够全面&#xff0c;系统的性能达不到使用者的要求。因此&#xff0c;本文结合Java的优势和流行性…...

【Linux系统】冯诺依曼与操作系统

什么是冯诺依曼体系结构&#xff1f; 如图即为冯诺依曼大致的体系结构图&#xff0c; 我们知道这些都是由我们的计算机硬件组成 输入设备&#xff1a;键盘&#xff0c; 鼠标&#xff0c; 摄像头&#xff0c; 话筒&#xff0c; 磁盘&#xff0c; 网卡... 输出设备&#xff1a…...

前端理论总结(html5)——form表单的新增特性/h5的新特性

form表单的新增特性 range&#xff1a;范围 color&#xff1a;取色器 url&#xff1a;对url进行验证 tel&#xff1a;对手机号格式验证 email&#xff1a;对邮箱格式验证 novalidate &#xff1a;提交表单时不验证 form 或 input 域 numbe…...

基于TensorFlow的花卉识别(算能杯)%%%

Anaconda Prompt 激活 TensorFlow CPU版本 conda activate tensorflow_cpu //配合PyCharm环境 直接使用TensorFlow1.数据分析 此次设计的主题为花卉识别&#xff0c;数据为TensorFlow的官方数据集flower_photos&#xff0c;包括5种花卉&#xff08;雏菊、蒲公英、玫瑰、向日葵…...

Android实现一周时间早中晚排班表

我们要做一个可以动态添加,修改一周早中晚时间排班表&#xff0c;需求图如下&#xff1a; one two 过程具体在这里不描述了&#xff0c;具体查看&#xff0c;https://github.com/yangxiansheng123/WorkingSchedule 上传数据格式&#xff1a; {"friday_plan":"…...

【Java八股面试系列】中间件-Redis

目录 Redis 什么是Redis Redis解决了什么问题 Redis的实现原理 数据结构 String 常用命令 应用场景 List(列表) 常用命令 应用场景 Hash(哈希) 常用命令 应用场景 set(集合) 常见命令​编辑 应用场景 Sorted Set(有序集合) 常见命令​编辑 应用场景 数据持…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...