8.JavaCC官方入门指南-例3
例3:计算器—double类型加法
下面我们对上个例子的代码进行进一步的修改,使得代码具有简单的四则运算的功能。
第一步修改,我们将打印出每一行的值,使得计算器更具交互性。一开始,我们只是把数字加起来,然后再关注其他运算,比如减法、乘法和除法。
1.Options和class声明块
描述文件calculator0.jj的第一部分如下所示:
/* calculator0.jj An interactive calculator. */
options {
STATIC = false ;
}
PARSER_BEGIN(Calculator)
import java.io.PrintStream ;
class Calculator {
public static void main( String[] args )
throws ParseException, TokenMgrError, NumberFormatException {
Calculator parser = new Calculator( System.in ) ;
parser.Start( System.out ) ;
}
double previousValue = 0.0 ;
}
PARSER_END(Calculator)
Calculator类中的previousValue属性,用于存储上一行的计算结果的,我们将在另一个版本中使用到该值,到时可以使用美元符号来表示它。import导入语句声明说明了在PARSER_BEGIN和PARSER_END之间可能有import导入声明;这些代码都会被原样复制到生成的语法解析类和token管理类中去。同样还可以有包package的声明,package的声明将会被复制到最后生成的所有java类中去。
2.词法描述文件
词法分析器的描述文件在这里将会发生一些变化,首先一行的结束符也被声明为了token,并给这些行结束符命名为EOL,这样一来这个token也可以被传递给语法分析器了。
SKIP : { " " }
TOKEN : { < EOL : "\n" | "\r" | "\r\n" > }
TOKEN : { < PLUS : "+" > }
接下来,我们要定义合适的token使得允许输入中的数值有小数点。为此我们修改NUMBER这个token的定义,使得它可以识别decimal类型的数值。当数值中有小数点,它可以有如下的4中类型,我们分别用竖线分隔开来了,这4中类型分别是:整型,没有小数点、小数点在中间、小数点在末尾和小数点在开头。满足此需求的描述串如下:
TOKEN { < NUMBER : (["0"-"9"])+
| (["0"-"9"])+ "." (["0"-"9"])+
| (["0"-"9"])+ "."
| "." (["0"-"9"])+ >
}
有时候,同样的规则表达式可能会出现多次。为了更好的可读性,最好是给这些重复出现的表达式起一个名字。对于那些只在词法描述文件中使用到,但又不是token的规则表达式,我们创建了一个特殊的标识来表示它:#。因此,对于上面的词法描述,可以替换成如下:
TOKEN : { < NUMBER : <DIGITS>
| <DIGITS> "." <DIGITS>
| <DIGITS> "."
| "."<DIGITS> >
}
TOKEN : { < #DIGITS : (["0"-"9"])+ > }
可以看到,我们把([”0”-”9”])+这串规则表达式提取了出来,并将其命名为了DIGITS。但是要注意到,DIGITS这个并不是token,这意味着在后面生成的Token类中,将不会有DIGITS对应的属性,而在语法分析器中也无法使用DIGITS。
3.语法描述文件
语法分析器的输入由零行或多行组成。每行包含一个表达式。通过使用BNF符号表达式,语法分析器可以写成如下:
Start -->(Expression EOL) * EOF
由此我们可以得出BNF生产式如下:
void Start() :
{}
{
(
Expression()
<EOL>
)*
<EOF>
}
我们在上面的BNF生产式中填充上java代码,使得它具备接收入参、记录并打印每一行的计算结果:
void Start(PrintStream printStream) throws NumberFormatException :
{}
{
(
previousValue = Expression()
<EOL> { printStream.println( previousValue ) ; }
)*
<EOF>
}
每个表达式由一个或多个数字组成,这些数字目前用加号隔开。用BNF符号表达式如下:
Expression --> Primary(PLUS Primary)*
在这里的Primary,我们暂时用它来表示数值。
上面的BNF符号表达式用JavaCC表示出来如下所示:
double Expression() throws NumberFormatException : {
double i ;
double value ;
}
{
value = Primary()
(
<PLUS>
i = Primary()
{ value += i ; }
)*
{ return value ; }
}
这个跟我们前面例子中的Start BNF生产式差不多,我们只是将数值的类型由int修改成了double类型而已。至于Primary(),跟上面例子也非常类似,它用BNF符号表达式来表示:
Primary --> NUMBER
Primary()对应的JavaCC描述文件其实也差不多,只不过在这里它是对double精度的数值进行的转换计算:
double Primary() throws NumberFormatException :
{
Token t ;
}
{
t = <NUMBER>
{ return Double.parseDouble( t.image ) ; }
}
下面我们用BNF符号表达式将语法分析器的逻辑表示出来:
Start --> (Expression EOL) * EOF
Expression --> Primary (PLUS Primary)*
Primary --> NUMBER
至此,我们就把calculator0.jj描述文件都修改完了,接下来可以跑几个例子进行测试。
4.测试
4.1 calculator0.jj
经过上面的修改,最后得到的.jj描述文件如下:
/* calculator0.jj An interactive calculator. */
options {
STATIC = false ;
}
PARSER_BEGIN(Calculator)
import java.io.PrintStream ;
class Calculator {
public static void main( String[] args )
throws ParseException, TokenMgrError, NumberFormatException {
Calculator parser = new Calculator( System.in ) ;
parser.Start( System.out ) ;
}
double previousValue = 0.0 ;
}
PARSER_END(Calculator)
SKIP : { " " }
TOKEN : { < EOL : "\n" | "\r" | "\r\n" > }
TOKEN : { < PLUS : "+" > }
TOKEN : { < NUMBER : <DIGITS>
| <DIGITS> "." <DIGITS>
| <DIGITS> "."
| "."<DIGITS> >
}
TOKEN : { < #DIGITS : (["0"-"9"])+ > }
void Start(PrintStream printStream) throws NumberFormatException :
{}
{
(
previousValue = Expression()
<EOL> { printStream.println( previousValue ) ; }
)*
<EOF>
}
double Expression() throws NumberFormatException : {
double i ;
double value ;
}
{
value = Primary()
(
<PLUS>
i = Primary()
{ value += i ; }
)*
{ return value ; }
}
double Primary() throws NumberFormatException :
{
Token t ;
}
{
t = <NUMBER>
{ return Double.parseDouble( t.image ) ; }
}
4.2 运行
我们首先计算1+2,如下所示:
接下来计算1+2.,即小数点在末尾的情形:
接下来计算1 + 2.3,即小数点在中间的情形:
接下来计算1 + .2,即小数点在开头的情形:
8.JavaCC官方入门指南-例3的更多相关文章
- 11.JavaCC官方入门指南-例6
例6:计算器--添加括号.一元运算符和历史记录 1.calculator3.jj 我们只需要再添加一些特色,就可以得到一个可用的四则运算计算器.在这一版的修改中 ,我们将使得程序可以接收括号.负值 ...
- 9.JavaCC官方入门指南-例4
例4:计算器--添加减法运算 1. calculator1.jj 为了使得计算器具备更多功能,我们需要更多的操作符,比如减法.乘法和除法.接下来我们添加减法运算. 在词法分析器的描述部分,我们 ...
- 7.JavaCC官方入门指南-例2
例2:整数加法运算--改良版(增强语法分析器) 1.修改 上一个例子中,JavaCC为BNF生产式所生成的方法,比如Start(),这些方法默认只简单的检查输入是否匹配BNF生产式指定的规范.但是 ...
- 6.JavaCC官方入门指南-例1
例1:整数加法运算 在这个例子中,我们将判断如下输入的式子是否是一个合法的加法运算: 99 + 42 + 0 + 15 并且在输入上面式子的时候,数字与加号之间的任何位置,都是可以有空格或者换 ...
- 10.JavaCC官方入门指南-例5
例5:计算器--添加乘除法运算 1.calculator2.jj 根据上一个例子,可知要添加乘法和除法运算是很简单的,我们只需在词法描述部分添加如下两个token: TOKEN : { < TI ...
- 5.JavaCC官方入门指南-概述
一.前言 在最开始使用JavaCC的时候,从网上查询了许多资料,但是网上的资料水平是参差不齐的,走了许多弯路,不得已自己查阅了英文版官网文档.令我伤心的是最后我回过头来再看那些博客资料时,发现其实 ...
- 分布式服务框架 Zookeeper(三)官方入门指南
入门指南:使用ZooKeeper来协调分布式应用 这篇文档包含了让你快速上手ZooKeeper的信息.主要是针对那些想要试一把ZooKeeper的开发人员,包含了安装一个单一ZooKeeper服务器的 ...
- Asp.Net MVC4.0 官方教程 入门指南之五--控制器访问模型数据
Asp.Net MVC4.0 官方教程 入门指南之五--控制器访问模型数据 在这一节中,你将新创建一个新的 MoviesController类,并编写代码,实现获取影片数据和使用视图模板在浏览器中展现 ...
- Asp.Net MVC4.0 官方教程 入门指南之四--添加一个模型
Asp.Net MVC4.0 官方教程 入门指南之四--添加一个模型 在这一节中,你将添加用于管理数据库中电影的类.这些类是ASP.NET MVC应用程序的模型部分. 你将使用.NET Framewo ...
随机推荐
- 在vue项目中的js文件里使用vue实例
参考的网址:https://blog.csdn.net/weixin_34353714/article/details/86958742 不为其他,就为了记录一下,方便以后查看: 第一种方法: 1.首 ...
- python监控cpu 硬盘 内存
import psutil import time import yagmail def sendmail(subject,contents): yag = yagmail.SMTP(user='15 ...
- 如何通过RMAN使用传输表空间迁移到不同的Endian平台 (Doc ID 371556.1)
How to Migrate to different Endian Platform Using Transportable Tablespaces With RMAN (Doc ID 371556 ...
- redis的缓存雪崩、缓存穿透和缓存击穿
缓存雪崩: 比如给缓存中的key设置了统一的过期时间,而在过期时间点,有大量的请求进来,这个时候redis中没有用户请求的资源,所以所有的请求会全部拥到数据库,如果数据库有报警监测的话,可能会报一下警 ...
- Python对MySql增删改查
pip install pymysql import pymysql db_config = { 'host': '127.0.0.1(ip)', 'port': 3306, 'user': '账号' ...
- Liu Junqiao:Raid 0 1 5 6 特性
Raid工作原理及优缺点 Raid工作原理及优缺点Raid 0Raid 1Raid 5Raid 6Raid 1 0Raid 5 0Raid 6 0 Raid 0 特点 采用剥离,数据将在几个磁盘上进行 ...
- JVM-1-HotSpot server client
64位JDK 默认只能工作在Server模式下 是无法切换到Client模式的 Hot Spot虚拟机Server
- Leetcode 1239. 串联字符串的最大长度
地址 https://leetcode-cn.com/problems/maximum-length-of-a-concatenated-string-with-unique-characters/s ...
- bzoj5219 [Lydsy2017省队十连测] 最长路径
题意: 做法来自 首先竞赛图缩点后是一条链,\(1\)号节点在开头的那个\(SCC\)中,因此从\(1\)号节点出发的最长链即为\(1\)号节点所在的\(SCC\)的大小\(+1\)号节点拓扑序之后的 ...
- #undef常用法
Copy from C语言中#undef的语法是: #undef 标识符 用来将前面定义的宏标识符取消定义. 整理了如下几种常见用法,如果以后发现其他的再添加进来. 1.在一个程序块中用完宏定义后,为 ...