Antlr4: 修改语法规则更接近普通BNF格式
经 @沈默 在上文Antlr4添加中文变量赋求值,括号,各种问题评论中指出, 语法规则描述依赖于Antlr4生成的语法分析器的默认分析方法, 比如运算符的左联系, 以及优先级处理等等. 于是将语法修改为下面(源码版本号: program-in-chinese/quan5):
表达式: 求积表达式 (('+'|'-') 求积表达式)*; 求积表达式: 最小表达式 (('*'|'/'|'×'|'÷') 最小表达式)*; 最小表达式 : 字面量 | '(' 表达式 ')' ; 字面量 : T数 | T变量名 ;
这样做的结果是, Antlr4会分析生成一个多叉树. 比如 1+2-3, 生成树如下:
于是在生成抽象语法树时手动转换为二叉树. 代码如下:
private 节点 构建二叉树(List<ParseTree> 子节点) { if (子节点.isEmpty()) { return null; } else if (子节点.size() == 1) { return visit(子节点.get(0)); } else { ParseTree 最后运算符节点 = 子节点.get(子节点.size() - 2); 运算符号 运算符 = ((TerminalNodeImpl)最后运算符节点).symbol.getType() == 圈5Parser.T加 ? 运算符号.加 : 运算符号.減; 运算式节点 节点 = new 运算式节点(); 节点.运算符 = 运算符; 节点.左子节点 = 构建二叉树(子节点.subList(0, 子节点.size() - 2)); 节点.右子节点 = visit(子节点.get(子节点.size() - 1)); return 节点; } }
开发过程中发现一些坑(如果是小白错误请指出). 一个比较费解的是, 不能省去"字面量"规则如下:
最小表达式 : T数 | T变量名 | '(' 表达式 ')' ;
不然生成的分析器会有编译错误:
com/中文编程/圈5/分析器/圈5Parser.java:403: error: unreachable statement enterOuterAlt(_localctx, 3);
Antlr4有个github库汇集了社区维护的各种语言的语法规则文件, 其中有Java8, 根据注释说明它的语法规则描述"极度"接近Java标准, 于是参考了它的实现. 其中看到这样的模式(已转成中文):
求和表达式 : 求积表达式 | 求和表达式 '+' 求积表达式 | 求和表达式 '-' 求积表达式 ; 求积表达式 : 最小表达式 | 求积表达式 '*' 最小表达式 | 求积表达式 '/' 最小表达式 ;
感觉这样会让语法树转换这一步的实现更加方便(应该可以省去多叉树转换成二叉树的那个递归算法). 在添加新功能之前, 打算尝试修改成这样.
已完成:
表达式 : 求积表达式 | 表达式 '+' 求积表达式 | 表达式 '-' 求积表达式; 求积表达式 : 最小表达式 | 求积表达式 '*' 最小表达式 | 求积表达式 '/' 最小表达式 | 求积表达式 '×' 最小表达式 | 求积表达式 '÷' 最小表达式;
的确省去了多叉树转换. 代码整理完毕(program-in-chinese/quan5). 接下去, 是条件判断还是函数定义?
补记
Antlr4自带的语法分析可视化工具, 以antlr/grammars-v4为例:
$ alias grun='java -cp "{PATH_TO_antlr-4.7-complete.jar}:$CLASSPATH" org.antlr.v4.runtime.misc.TestRig' $ java -cp "{PATH_TO_antlr-4.7-complete.jar}:$CLASSPATH" org.antlr.v4.Tool -visitor -no-listener Java8.g4 $ javac -cp "{PATH_TO_antlr-4.7-complete.jar}:$CLASSPATH" Java8*.java $ grun Java8 expression -tree <--- 将输入字符串进行语法解析, 生成树结构 Warning: TestRig moved to org.antlr.v4.gui.TestRig; calling automatically a>1 (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))))))))))))))))))) $ grun Java8 expression -gui <--- 图形化 Warning: TestRig moved to org.antlr.v4.gui.TestRig; calling automatically 2>1 ^D
2018-01-15
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Antlr4添加中文变量赋求值,括号,各种问题
中文编程知乎专栏原文地址 例程(更多测试用例在此): 基数=100 基数×(基数+1)÷2 => 求值为5050 续上文Antlr4实现数学四则运算, 修改的语法规则部分: 程序: 声明+; 声明: 表达式 T新行 #求值 | T变量名 '=' 表达式 T新行 #赋值 | T新行 #空行 ; 表达式: 表达式 运算符=('*'|'/'|'×'|'÷') 表达式 #乘除 | 表达式 运算符=('+'|'-') 表达式 #加減 | T数 #数 | T变量名 #变量 | '(' 表达式 ')' #括号 ; T变量名: ('a' .. 'z' | 'A' .. 'Z' | '\u4E00'..'\u9FA5' | '\uF900'..'\uFA2D')+; T新行: '\r'?'\n'; 很明显, 变量名的范围仍需扩展, 比如数字就不支持, 而且这个字符范围应该有些过大(详见Validate a JavaScript function name), 待修正(变量字符范围 · Issue #1 · program-in-chinese/quan5). 定制访问器添加的部分: private...
- 下一篇
JavaScript 类数组转化为数组
很多情况下我们需要将类数组的对象(key是以0到n的数字或字符串,具有length属性。例如:Arguments对象)转化为一个数组来进行各种例如forEach的数组操作,在ES5中是利用类数组对象强制调用Array对象的slice方法来进行转换的,在ES6中Array扩展了from方法来进行转换,另外,ES6中的扩展运算符也可将某些类数组对象转化为数组各方法示例如下: 强制调用Array对象的slice方法 console.log(Array.prototype.slice.call({ '0': 'a', '1': 'b', '2': 'c', length: 3 })); //Array(3) [ "a", "b", "c" ] Array.from()方法 console.log(Array.from({ '0':'a', '1':'b', '2':'c', length:3 })); //Array(3) [ "a", "b", "c" ] 扩展运算符... console.log((function (a,b,c) { console.log([...arguments])...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS6,CentOS7官方镜像安装Oracle11G
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS关闭SELinux安全模块