中文编程知乎专栏原文地址

例程(更多测试用例在):

基数=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 static Map<String, 节点> 变量值表 = new HashMap<>();

  // 以下为声明部分

  @Override
public 节点 visit赋值(赋值Context 上下文) {
String 变量名 = 上下文.T变量名().getText();
变量值表.put(变量名, visit(上下文.表达式()));
return null;
} @Override
public 节点 visit求值(求值Context 上下文) {
return visit(上下文.表达式());
} // 以下为表达式部分 @Override
public 节点 visit变量(变量Context 上下文) {
String 变量名 = 上下文.T变量名().getText(); // TODO: 添加变量检查
return 变量值表.get(变量名);
} @Override
public 节点 visit括号(括号Context 上下文) {
return visit(上下文.表达式());
}

变量值表采用变量名到节点的映射, 也就是在对包含这个变量的表达式求值时才对变量对应的表达式进行求值. 这里没有对变量赋值表达式进行语法树构建 · Issue #2 · program-in-chinese/quan5, 还需更多工作. 另外一个问题, 最后的表达式求值也会对变量值重复计算. 举例:

利率=1
年增长率=1+利率
1000×年增长率×年增长率

最后语法树如下:

![2018-01-12-antlr4赋值quan2]({{ "/assets/2018-01-12-antlr4赋值_quan2.png" | absolute_url }})

"年增长率"应该提前求值, 以省去最后的多次计算(避免对变量重复求值 · Issue #3 · program-in-chinese/quan5)


后两个问题已初步解决, 通过在"运行器"中保存变量表, 以及将各种节点的求值方法都集中到其中. 想起来在其他有些语言实现里也看到过类似结构(根据不同类型进行求值):

 public Object 求值(节点 节点) {
if (节点 instanceof 运算式节点) {
运算符号 运算符 = ((运算式节点)节点).运算符;
Object 左结果 = 求值(((运算式节点)节点).左子节点);
Object 右结果 = 求值(((运算式节点)节点).右子节点);
switch(运算符) {
case 加: return (int)左结果 + (int)右结果;
case 減: return (int)左结果 - (int)右结果;
case 乘: return (int)左结果 * (int)右结果;
case 除: return (int)左结果 / (int)右结果;
case 赋值:
变量值表.put(((变量节点)((运算式节点)节点).左子节点).取变量名(), 右结果);
// 顺延
default:
return null;
}
} else if (节点 instanceof 变量节点) {
return 变量值表.get(((变量节点)节点).取变量名());
} else if (节点 instanceof 数节点) {
return ((数节点)节点).求值();
} else {
for(节点 子节点 : 节点.子节点) {
返回值 = 求值(子节点);
}
return 返回值;
}
}

2018-01-12 Antlr4添加中文变量赋求值,括号,各种问题的更多相关文章

  1. static 和 final 关键字 对实例变量赋初始值的影响

    static 和 final 关键字 对实例变量赋初始值的影响 最近一直在看<深入理解Java虚拟机>,在看完了对象内存分配.Class文件格式之后,想深扒一下实例变量是如何被赋上初始值的 ...

  2. sql server 添加字段并且赋默认值和说明

    select soct.Captcha,CreateOn,* from SceneryOrderCheckTicket soctright join (SELECT Captcha,convert(c ...

  3. typedef声明变量也是一种求值过程

    前言: 什么叫做:声明变量是求值过程?请看下面的声明, int i; 很简单,声明了个整型变量i,再看如下声明, int *p; 也很简单,立刻反应出来它是指向整型的指针,但是具体如何推倒出来的呢?其 ...

  4. 好用的wget命令从下载添加环境变量到各参数详解

    本文是因为(笔者使用的windows系统)使用过好几次wget后,始终存在各种细节问题,于是下定决定细致的研究一下,并记录下其中细节. 下载与安装 第一步:下载wget,网络地址:http://dow ...

  5. 新手C#SQLServer在程序里实现语句的学习2018.08.12

    从C#中连接到SQL Server数据库,再通过C#编程实现SQL数据库的增删改查. ado.net提供了丰富的数据库操作,这些操作可以分为三个步骤: 第一,使用SqlConnection对象连接数据 ...

  6. Linux下查看和添加环境变量

    转自:http://blog.sina.com.cn/s/blog_688077cf01013qrk.html $PATH:决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当您 ...

  7. dedecms后台添加新变量和删除变量的方法

    下面由做网站为大家来介绍dedecms后台添加新变量和删除变量的方法 添加新变量是做什么用的?答:可以在模板内调用的东东. 一.进入网站织梦(Dedecms)后台(以dede5.5为例),依次打开系统 ...

  8. 软件 利用 win+R 快速启动(无需添加环境变量)

    前言:以 "Typora" 软件 为例 ,无需添加环境变量,实现键盘快速启动 第一步 找到 为知笔记的快捷方式 打开文件位置 鼠标右击该软件的桌面快捷方式 复制该软件的快捷方式 第 ...

  9. php 添加环境变量

    1.php添加环境变量主要为了能在 cmd和软件的客户端用php来运行 首先我们要做的第一步: 添加环境变量(记住php.exe的路径,然后再环境变量中编辑path 多个用逗号分隔开,保存重启电脑) ...

随机推荐

  1. CDN的基本工作过程

    CDN的基本工作过程 使用CDN会极大地简化网站的系统维护工作量,网站维护人员只需将网站内容注入CDN的系统,通过CDN部署在各个物理位置的服务器进行全网分发,就可以实现跨运营商.跨地域的用户覆盖.由 ...

  2. Zookeeper学习

    http://www.cnblogs.com/caosiyang/archive/2012/11/09/2763190.html   http://www.cnblogs.com/haippy/tag ...

  3. shell 中test命令

    test可用于测试表达式,支持测试的范围包括:字符串比较,算术比较,文件存在性.属性.类型等判断.例如,判断文件是否为空.文件是否存在.是否是目录.变量是否大于5.字符串是否等于"longs ...

  4. 外观模式facade

    一句话,多外呈现一个统一接口,内部的具体实现不关心. 外观模式facade,其实就是在调用者 与 被调用的实现层 之间加一层 facade层,不管内部如何实现, 用什么技术 方法实现,对外呈现的外观是 ...

  5. SSM-Spring-10:Spring中cglib动态代理

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 何为动态代理,就不扯皮了,上一篇博客刚刚提到,那cglib动态代理又怎么写,我拿个和上个例子相似的案例来写 具 ...

  6. Deep Learning Enables You to Hide Screen when Your Boss is Approaching

    https://github.com/Hironsan/BossSensor/ 背景介绍 学生时代,老师站在窗外的阴影挥之不去.大家在玩手机,看漫画,看小说的时候,总是会找同桌帮忙看着班主任有没有来. ...

  7. 苹果通知推送服务(APNS)一些关键特性摘要

    http://ramosli.iteye.com/blog/1940843 前段时间,仔细研究了APNS的文档,把一些关键的地方记录了下来,弄懂这些对于理解APNS的规则,至关重要. 1. If AP ...

  8. python使用随机的163账号发送邮件

    import linecache import smtplib import time import linecache import random #算出txt的行数,163账号_2.txt中,每一 ...

  9. linux安装tomcat Neither the JAVA_HOME nor the JRE_HOME environment variable is defined

    这两天我们的开发机重启了好几次,发现每次重启后我的tomcat总是没有启动.检查java路径,配置正确,后来拿普通账号启动tomcat时报如下的错: Neither the JAVA_HOME nor ...

  10. git fatal: 远程 origin 已经存在。

    不小心将git远程地址配错了,再次配置提示以下错误: fatal: 远程 origin 已经存在. 此时只需要将远程配置删除,重新添加即可: git remote rm origin git remo ...