Antlr4实现数学四则运算

简介: 为"圈2"语言, 添加四则运算功能. Add add/plus and mutiple/divide features to the pretotype programming language quan2 with Antlr4 and Java.

基本参考https://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference 一书"Building a Calculator Using a Visitor"一节, 仅添加了数学乘除法符号的支持(×÷). 比如下面的算式:

3×2+8÷4-2×4

源码仍在program-in-chinese/quan5

相比上一版本语法文件去除了空格定义. 需要深究的是优先级问题. 是否因为"表达式 运算符=('*'|'/'|'×'|'÷') 表达式"写在了前面才使得乘除法的优先级在语法分析时更高.

至此, 感觉Antlr语法文件对中文命名的支持还是不错的. 唯一需要权宜之计的就是Token(词)规则必须要大写开头, 因此采用了前缀"T"):

grammar 圈5;
程序
 : 表达式
 ;

表达式
 : 表达式 运算符=('*'|'/'|'×'|'÷') 表达式     #乘除
   | 表达式 运算符=('+'|'-') 表达式         #加減
   | T数                    #数
 ;

T数
 : [0-9]+
 ;
T加 : '+';
T減 : '-';
T乘 : '*';
T数乘: '×';
T除 : '/';
T数除: '÷';

第一次尝试#标号的辅助功能. 一个"表达式"语法规则生成了三个Visitor方法(如下), 访问器仍比较简单. 注: 语法规则中要么所有分支都有标号, 要么都没有. 不然生成分析器时报错:

public class 定制访问器 extends 圈5BaseVisitor<节点> {

  @Override
  public 节点 visit数(数Context 上下文) {
    TerminalNode 数 = 上下文.T数();
    return 数 instanceof ErrorNode ? null : new 数节点(数.getText());
  }

  @Override
  public 节点 visit加減(加減Context 上下文) {
    表达式节点 节点 = new 表达式节点();
    节点.运算符 = 上下文.运算符.getType() == 圈5Parser.T加 ? 运算符号.加 : 运算符号.減;
    节点.左子节点 = visit(上下文.表达式(0));
    节点.右子节点 = visit(上下文.表达式(1));
    return 节点;
  }

  @Override
  public 节点 visit乘除(乘除Context 上下文) {
    表达式节点 节点 = new 表达式节点();
    int 运算符 = 上下文.运算符.getType();
    节点.运算符 = (运算符 == 圈5Parser.T乘 || 运算符 == 圈5Parser.T数乘) ? 运算符号.乘 : 运算符号.除;
    节点.左子节点 = visit(上下文.表达式(0));
    节点.右子节点 = visit(上下文.表达式(1));
    return 节点;
  }

}

语法树中稍微复杂一点的"表达式"节点, 代码很冗余:

public class 表达式节点 extends 节点 {

  public 运算符号 运算符;

  @Override
  public Object 求值() {
    if (运算符.equals(运算符号.加)) {
      return (int)(左子节点.求值()) + ((int)右子节点.求值());
    } else if (运算符.equals(运算符号.減)) {
      return (int)(左子节点.求值()) - ((int)右子节点.求值());
    } else if (运算符.equals(运算符号.乘)) {
      return (int)(左子节点.求值()) * ((int)右子节点.求值());
    } else if (运算符.equals(运算符号.除)) {
      return (int)(左子节点.求值()) / ((int)右子节点.求值());
    } else {
      return null;
    }
  }

}

已经要手动跑十个测试文件, 下面除了清理代码, 还需要加测试, 再加功能(应该是变量赋值).

2018-01-11

相关文章
|
6月前
|
C语言
c语言编程练习题:7-10 算术入门之加减乘除
对于输入的两个整数,按照要求输出其和差积商。
118 0
|
6月前
|
安全 编译器 程序员
【C++ 编译时有理算术】理解 C++编译时有理数运算:原理、实践与应用
【C++ 编译时有理算术】理解 C++编译时有理数运算:原理、实践与应用
106 1
|
11月前
|
Java
用JAVA实现小学四则运算
用JAVA实现小学四则运算
87 1
|
自然语言处理 Java
Antlr实现任意四则运算表达式求值
上面语法就是四则运算的巴科斯范式定义(EBNF),可能对初学者有点难理解,其实就是一个递归定义,一个表达式可能是有多个子表达式构成,但子表达式的尽头一定是数字。 antlr可以用EBNF所定义的规则,将某个输入串解析为一颗抽象语法树(AST)。我们以表达式((3+3)*(1+4))/(5-3) 为例
168 0
|
开发者 Python
四则运算|学习笔记
快速学习四则运算
|
Shell Linux
shell脚本编程-数学运算
shell脚本编程-数学运算
112 0
|
程序员 C++ Python
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(一)
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(一)
192 0
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(一)
|
程序员 Python
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(二)
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(二)
206 0
程序员数学基础【一、基础运算符号(整数、普通浮点数运算、逻辑运算)】(Python版本)(二)
|
程序员
程序员数学(3)--一元一次方程
本文目录 1. 为什么要用方程 2. 一元一次方程 3. 等式的性质 4. 解一元一次方程 4.1 合并同类项 4.2 移项 4.3 去括号 4.4 去分母 5. 总结
178 0
程序员数学(3)--一元一次方程
|
程序员
程序员数学(1)--有理数
本文目录 1. 正数、0、负数 2. 有理数 3. 数轴 4. 相反数 5. 绝对值 6. 有理数的加减法 7. 有理数的乘除法 8. 乘方 9. 科学计数法
109 0