中文编程
首发于中文编程

Antlr4实现数学四则运算

基本参考pragprog.com/book/tpant 一书"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-12

文章被以下专栏收录

    在所有编程语言和领域中尝试编写中文代码,开发相关工具,总结经验,一致代码风格。包括中文命名,汉化现有语言,创造中文语法的编程语言等等。作为最熟悉的母语,用来编写代码会让代码更容易被自己和母语相同的其他开发者理解。基于英文的编程语言和框架中,使用中文命名有时有技术问题。希望这里为后人趟雷,填坑。多数现有API是英文的,这里也会对其中一些常用的进行汉化。当然,这里也会对基于中文的编程语言进行探讨。包括汉化基于英文的编程语言,以及创造新的编程语言。