2018-01-12 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 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×年增长率×年增长率
最后语法树如下:

"年增长率"应该提前求值, 以省去最后的多次计算(避免对变量重复求值 · 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添加中文变量赋求值,括号,各种问题的更多相关文章
- static 和 final 关键字 对实例变量赋初始值的影响
static 和 final 关键字 对实例变量赋初始值的影响 最近一直在看<深入理解Java虚拟机>,在看完了对象内存分配.Class文件格式之后,想深扒一下实例变量是如何被赋上初始值的 ...
- sql server 添加字段并且赋默认值和说明
select soct.Captcha,CreateOn,* from SceneryOrderCheckTicket soctright join (SELECT Captcha,convert(c ...
- typedef声明变量也是一种求值过程
前言: 什么叫做:声明变量是求值过程?请看下面的声明, int i; 很简单,声明了个整型变量i,再看如下声明, int *p; 也很简单,立刻反应出来它是指向整型的指针,但是具体如何推倒出来的呢?其 ...
- 好用的wget命令从下载添加环境变量到各参数详解
本文是因为(笔者使用的windows系统)使用过好几次wget后,始终存在各种细节问题,于是下定决定细致的研究一下,并记录下其中细节. 下载与安装 第一步:下载wget,网络地址:http://dow ...
- 新手C#SQLServer在程序里实现语句的学习2018.08.12
从C#中连接到SQL Server数据库,再通过C#编程实现SQL数据库的增删改查. ado.net提供了丰富的数据库操作,这些操作可以分为三个步骤: 第一,使用SqlConnection对象连接数据 ...
- Linux下查看和添加环境变量
转自:http://blog.sina.com.cn/s/blog_688077cf01013qrk.html $PATH:决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当您 ...
- dedecms后台添加新变量和删除变量的方法
下面由做网站为大家来介绍dedecms后台添加新变量和删除变量的方法 添加新变量是做什么用的?答:可以在模板内调用的东东. 一.进入网站织梦(Dedecms)后台(以dede5.5为例),依次打开系统 ...
- 软件 利用 win+R 快速启动(无需添加环境变量)
前言:以 "Typora" 软件 为例 ,无需添加环境变量,实现键盘快速启动 第一步 找到 为知笔记的快捷方式 打开文件位置 鼠标右击该软件的桌面快捷方式 复制该软件的快捷方式 第 ...
- php 添加环境变量
1.php添加环境变量主要为了能在 cmd和软件的客户端用php来运行 首先我们要做的第一步: 添加环境变量(记住php.exe的路径,然后再环境变量中编辑path 多个用逗号分隔开,保存重启电脑) ...
随机推荐
- 更新版PowerBI发布了-- Power BI Report Server Update – March 2018
新版的PowerBI server 和 Desktop 终于发布了. 详细增加功能见以下链接: 下载最新版PowerBI Report Server: https://powerbi.microso ...
- redux 中间件 --- applyMiddleware 源码解析 + 中间件的实战
前传 中间件的由来 redux的操作的过程,用户操作的时候,我们通过dispatch分发一个action,纯函数reducer检测到该操作,并根据action的type属性,进行相应的运算,返回st ...
- Spring+Mybatis多数据源的一种实现方式,支持事务
最近一个项目用到了多个数据库,所以需要实现动态切换数据源来查询数据,http://www.cnblogs.com/lzrabbit/p/3750803.html这篇文章让我受益匪浅,提供了一种自动切换 ...
- 并发库应用之七 & 信号灯Semaphore应用
Semaphore可以维护当前访问自身的线程个数,并且提供了同步机制. Semaphore实现的功能类似于厕所里有5个坑,有10个人要上厕所,同时就只能有5个人占用,当5个人中 的任何一个让开后,其中 ...
- 优雅的玩PHP多进程
proc_open (PHP 4 >= 4.3.0, PHP 5, PHP 7) proc_open — 执行一个命令,并且打开用来输入/输出的文件指针. 说明¶ resource proc_o ...
- 许式伟:我与Go语言的这十年[转]
2017-12-18 许式伟 Go中国 2007 年 9 月 20 日,关于设计一门全新语言的讨论正式开始,这门全新的语言,就是后来的 Go.时至今日,Go 语言已经发布到 1.9 版本,走过了整整十 ...
- PHP 的 uniqid 函数产生的 id 真的是唯一的么?
PHP 的 uniqid 函数产生的 id 真的是唯一的么? 最近使用到了 uniqid,就产生了疑问?uniqid 生成的 id 由什么组成?真的是唯一的么?什么情况下会产生冲突? 从文档中看到 u ...
- jmeter使用csv进行参数化(一)
先录制一个脚本,具体录制可以参考笔者的随笔:http://www.cnblogs.com/wuyazi/p/8889770.html 1.准备参数化文本内容:mac没有自带的txt文本编辑器,笔者是在 ...
- 你不知道的JavaScript--Item3 隐式强制转换
JavaScript的数据类型分为六种,分别为null,undefined,boolean,string,number,object. object是引用类型,其它的五种是基本类型或者是原始类型.我们 ...
- 解决centos7 python3 上下左右变ABCD
首先:rpm -qa | grep readline //查看有没有安装readline-devel(出现标题的问题就是因为没有安装readline-devel包) 其次:使用yum search r ...