经 @沈默 在上文Antlr4添加中文变量赋求值,括号,各种问题评论中指出, 语法规则描述依赖于Antlr4生成的语法分析器的默认分析方法, 比如运算符的左联系, 以及优先级处理等等. 于是将语法修改为下面(源码版本号: program-in-chinese/quan5):

  1. 表达式: 求积表达式 (('+'|'-') 求积表达式)*;
  2. 求积表达式: 最小表达式 (('*'|'/'|'×'|'÷') 最小表达式)*;
  3. 最小表达式
  4. : 字面量
  5. | '(' 表达式 ')'
  6. ;
  7. 字面量
  8. : T
  9. | T变量名
  10. ;

这样做的结果是, Antlr4会分析生成一个多叉树. 比如 1+2-3, 生成树如下:

于是在生成抽象语法树时手动转换为二叉树. 代码如下:

  1. private 节点 构建二叉树(List<ParseTree> 子节点) {
  2. if (子节点.isEmpty()) {
  3. return null;
  4. } else if (子节点.size() == 1) {
  5. return visit(子节点.get(0));
  6. } else {
  7. ParseTree 最后运算符节点 = 子节点.get(子节点.size() - 2);
  8. 运算符号 运算符 = ((TerminalNodeImpl)最后运算符节点).symbol.getType() == 5Parser.T ? 运算符号.加 : 运算符号.減;
  9. 运算式节点 节点 = new 运算式节点();
  10. 节点.运算符 = 运算符;
  11. 节点.左子节点 = 构建二叉树(子节点.subList(0, 子节点.size() - 2));
  12. 节点.右子节点 = visit(子节点.get(子节点.size() - 1));
  13. return 节点;
  14. }
  15. }

开发过程中发现一些坑(如果是小白错误请指出). 一个比较费解的是, 不能省去"字面量"规则如下:

  1. 最小表达式
  2. : T
  3. | T变量名
  4. | '(' 表达式 ')'
  5. ;

不然生成的分析器会有编译错误:

  1. com/中文编程/圈5/分析器/圈5Parser.java:403: error: unreachable statement
  2. enterOuterAlt(_localctx, 3);

Antlr4有个github库汇集了社区维护的各种语言的语法规则文件, 其中有Java8, 根据注释说明它的语法规则描述"极度"接近Java标准, 于是参考了它的实现. 其中看到这样的模式(已转成中文):

  1. 求和表达式
  2. : 求积表达式
  3. | 求和表达式 '+' 求积表达式
  4. | 求和表达式 '-' 求积表达式
  5. ;
  6. 求积表达式
  7. : 最小表达式
  8. | 求积表达式 '*' 最小表达式
  9. | 求积表达式 '/' 最小表达式
  10. ;

感觉这样会让语法树转换这一步的实现更加方便(应该可以省去多叉树转换成二叉树的那个递归算法). 在添加新功能之前, 打算尝试修改成这样.

已完成:

  1. 表达式
  2. : 求积表达式
  3. | 表达式 '+' 求积表达式
  4. | 表达式 '-' 求积表达式;
  5. 求积表达式
  6. : 最小表达式
  7. | 求积表达式 '*' 最小表达式
  8. | 求积表达式 '/' 最小表达式
  9. | 求积表达式 '×' 最小表达式
  10. | 求积表达式 '÷' 最小表达式;

的确省去了多叉树转换. 代码整理完毕(program-in-chinese/quan5). 接下去, 是条件判断还是函数定义?

补记

Antlr4自带的语法分析可视化工具, 以antlr/grammars-v4为例:

  1. $ alias grun='java -cp "{PATH_TO_antlr-4.7-complete.jar}:$CLASSPATH" org.antlr.v4.runtime.misc.TestRig'
  2. $ java -cp "{PATH_TO_antlr-4.7-complete.jar}:$CLASSPATH" org.antlr.v4.Tool -visitor -no-listener Java8.g4
  3. $ javac -cp "{PATH_TO_antlr-4.7-complete.jar}:$CLASSPATH" Java8*.java
  4. $ grun Java8 expression -tree <--- 将输入字符串进行语法解析, 生成树结构
  5. Warning: TestRig moved to org.antlr.v4.gui.TestRig; calling automatically
  6. a>1
  7. (expression (assignmentExpression (conditionalExpression (conditionalOrExpression (conditionalAndExpression (inclusiveOrExpression (exclusiveOrExpression (andExpression (equalityExpression (relationalExpression (relationalExpression (shiftExpression (additiveExpression (multiplicativeExpression (unaryExpression (unaryExpressionNotPlusMinus (postfixExpression (expressionName a)))))))) > (shiftExpression (additiveExpression (multiplicativeExpression (unaryExpression (unaryExpressionNotPlusMinus (postfixExpression (primary (primaryNoNewArray_lfno_primary (literal 1)))))))))))))))))))
  8. $ grun Java8 expression -gui <--- 图形化
  9. Warning: TestRig moved to org.antlr.v4.gui.TestRig; calling automatically
  10. 2>1
  11. ^D

2018-01-15 Antlr4: 修改语法规则更接近普通BNF格式的更多相关文章

  1. XML 树结构,语法规则,元素,属性,验证及其解析

    XML 文档形成了一种树结构,它从"根部"开始,然后扩展到"枝叶". 一个 XML 文档实例 XML 文档使用简单的具有自我描述性的语法: <?xml v ...

  2. SQL SERVER修改排序规则——脚本篇

    在上篇MS SQL 排序规则总结中,大致就数据库服务器排序规则(或者叫数据库实例排序规则).数据库排序规则.列的排序规则粗浅的叙说了一遍,重点讲述了修改数据库服务器排序规则(数据库实例排序规则),其中 ...

  3. Django模板语言(常用语法规则)

    Django模板语言 The Django template language 模板中常用的语法规则 {最新版本的Django语法可能有改变,不支持的操作可能支持了.[HTML教程 - 基本元素/标签 ...

  4. Java基础-正则表达式(Regular Expression)语法规则简介

    Java基础-正则表达式(Regular Expression)语法规则简介 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.正则表达式的概念 正则表达式(Regular Exp ...

  5. Windbg命令的语法规则系列(一)

    本文介绍使用调试器命令必须遵循的语法规则.使用Windbg调试时,应遵守以下一般语法规则: 您可以在命令和参数中使用大小写字母的任意组合,除非在本节的主题中特别指出. 可以用一个或多个空格或逗号(,) ...

  6. Emmet语法规则

    HTML速写之Emmet语法规则 Emmet-写HTML/CSS快到飞起 在前端开发的过程中,最费时间的工作就是写 HTML.CSS 代码.一堆的标签.属性.括号等,头疼.这里推荐一个Emmet语法规 ...

  7. JSON 语法规则详解

    JSON 的语法规则十分简单,无论用何种方法总结都只有数条而已,它参考了 C 语言家族的一些习惯,学习起来并不会感到陌生. 回顾JSON 的五点语法 1)- 数组(Array)用方括号("[ ...

  8. Jenkins 定时构建语法规则

    1.Jenkins自由风格任务定时构建 2.语法规则 定时构建语法 * * * * * 第一个*表示分钟,取值0~59 第二个*表示小时,取值0~23 第三个*表示一个月的第几天,取值1~31 第四个 ...

  9. 良好的JavaScript编码风格(语法规则)

    编码风格 1.概述 "编程风格"(programming style)指的是编写代码的样式规则.不同的程序员,往往有不同的编程风格. 有人说,编译器的规范叫做"语法规则& ...

随机推荐

  1. 使用 Resharper 快速做适配器

    如果需要做一个类的重写,需要重新写这个类的所有属性和函数,本文提供一个简单的方法让大家快速重写一个类的所有属性和函数. 在有 Resharper 之后,对一个比较长的类进行重构.例如有这个类 clas ...

  2. GC垃圾回收机制,iOS内存管理。

    问题: MRC中通过调用静态方法创建的新对象,不再使用时需要对其发送release消息吗? 不需要,因为约定静态方法创建的对象会自动将其放入自动释放池,即已对其发送autorelease消息,因此不可 ...

  3. 基于 Keras 的 LSTM 时间序列分析——以苹果股价预测为例

    简介 时间序列简单的说就是各时间点上形成的数值序列,时间序列分析就是通过观察历史数据预测未来的值.预测未来股价走势是一个再好不过的例子了.在本文中,我们将看到如何在递归神经网络的帮助下执行时间序列分析 ...

  4. javascript从作用域到闭包-笔记

    读<你不知道的javascript>一书做个笔记;编译原理:    js是一门编译型的语言,与传统编译语言类似,传统编译的过程分为三个阶段 ;     1. 分词/词法分析; 2.解析/语 ...

  5. 深圳scala-meetup-20180902(3)- Using heterogeneous Monads in for-comprehension with Monad Transformer

    scala中的Option类型是个很好用的数据结构,用None来替代java的null可以大大降低代码的复杂性,它还是一个更容易解释的状态表达形式,比如在读取数据时我们用Some(Row)来代表读取的 ...

  6. [Mac]如何让两个窗口各占半个屏幕

    OS X中的拆分视图El Capitan或更高版本允许您使用两个应用程序填充Mac屏幕,而无需手动移动和调整窗口大小. 进入拆分视图 按住 窗口左上角的全屏按钮  . 当您按住按钮时,窗口会缩小,您可 ...

  7. rabbitmq基础学习+springboot结合rabbitmq实现回调确认confirm

    rabbitmq集群docker快速搭建 https://blog.csdn.net/u011058700/article/details/78708767 rabbitmq原理博客 https:// ...

  8. xtrabackup备份mysql-1

    1,在mysql服务器上安装xtrabackup 2,创建备份目录,使用xtrabackup做全备 3,到备份目录查看效果 我这台服务器搭建的是MediaWiki,可以看到wikidb这个库 恢复流程 ...

  9. moment.js 学习笔记

    一.安装 / 使用 npm install moment 注:使用版本为 2.22.2 var moment = require('moment'); moment().format(); // 20 ...

  10. asp.net mvc 安全测试漏洞 " HTTP 动词篡改的认证旁路" 问题解决

    IBM Security Appscan漏洞筛查-HTTP 动词篡改的认证旁路漏洞,具体解决方案: 在Web.Config中system.webServer节点增加配置security: <se ...