例6:计算器--添加括号、一元运算符和历史记录

1.calculator3.jj

  我们只需要再添加一些特色,就可以得到一个可用的四则运算计算器。在这一版的修改中 ,我们将使得程序可以接收括号、负值,并且还可以通过$符号来引用上一次计算的结果。

  对词法描述文件的修改如下所示,我们只添加下面3行:

TOKEN : { < OPEN_PAR : "(" > }
TOKEN : { < CLOSE_PAR : ")" > }
TOKEN : { < PREVIOUS : "$" > }

  我们没有必要专门为负号创建一个token,因为我们已经定义了MINUS这个token了。

  对于语法描述部分的修改,则都是体现在了Primary当中,在Primary当中有4中可能的值:一个数值(跟之前的例子一样)、一个$符号、带有括号的表达式、一个负号然后跟着前3个的任一种。BNF符号表达式如下:

Primary --> NUMBER
| PREVIOUS
| OPEN_PAR Expression CLOSE_PAR
| MINUS Primary

  这个BNF生产式中有两个递归。最后一种选择是直接递归,倒数第二个选择是间接递归,因为Expression最终还是依赖于Primary。在BNF生产式中使用递归是没有任何问题的,当然也有一些限制,我们将在后面谈论到。

  考虑下面的表达式:

- - 22

  那么Primary就是下图中的方块部分:

  在语法分析器执行到上面的输入时,对于每一个方块,都会调用一次Primary。相似的,对于下面的输入:

12 * ( 42 + 19 )

  我们把Primary框出来,可得到如下所示:

  相互嵌套的框框,其实就表示了相互递归调用的Primary方法。

  下面是JavaCC中Primary的生产式:

double Primary() throws NumberFormatException :
{
Token t ;
double d ;
}
{
t=<NUMBER>
{ return Double.parseDouble( t.image ) ; }
| <PREVIOUS>
{ return previousValue ; }
| <OPEN_PAR> d=Expression() <CLOSE_PAR>
{ return d ; }
| <MINUS> d=Primary()
{ return -d ; }
}

2. 测试

  根据上面的修改,得到完整的calculator3.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 : { < MINUS : "-" > }
TOKEN : { < TIMES : "*" > }
TOKEN : { < DIVIDE : "/" > }
TOKEN : { < OPEN_PAR : "(" > }
TOKEN : { < CLOSE_PAR : ")" > }
TOKEN : { < PREVIOUS : "$" > }
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 = Term()
(
<PLUS>
i = Term()
{ value += i ; }
| <MINUS>
i = Term()
{ value -= i ; }
)*
{ return value ; }
} double Term() throws NumberFormatException :
{
double i ;
double value ;
}
{
value = Primary()
(
<TIMES>
i = Primary()
{ value *= i ; }
| <DIVIDE>
i = Primary()
{ value /= i ; }
)*
{ return value ; }
} double Primary() throws NumberFormatException :
{
Token t ;
double d ;
}
{
t=<NUMBER>
{ return Double.parseDouble( t.image ) ; }
| <PREVIOUS>
{ return previousValue ; }
| <OPEN_PAR> d=Expression() <CLOSE_PAR>
{ return d ; }
| <MINUS> d=Primary()
{ return -d ; }
}

计算(1+2)*-3,如下所示,正确计算得到结果-9:

  计算器示例到此结束。官方文档中其实还有一个“文本处理”的例子,时间有限就不翻译了。可以直接去阅读英文原版,其实还是比较容易懂的。上面的示例通过由浅入深的引导,让我们大致知道JavaCC能干什么以及是怎么工作的。如果想要使用JavaCC做更多的事情,建议还是把最后一个例子的英文原版看完看懂,并多加练习。

11.JavaCC官方入门指南-例6的更多相关文章

  1. 9.JavaCC官方入门指南-例4

    例4:计算器--添加减法运算 1. calculator1.jj   为了使得计算器具备更多功能,我们需要更多的操作符,比如减法.乘法和除法.接下来我们添加减法运算.   在词法分析器的描述部分,我们 ...

  2. 8.JavaCC官方入门指南-例3

    例3:计算器-double类型加法   下面我们对上个例子的代码进行进一步的修改,使得代码具有简单的四则运算的功能.   第一步修改,我们将打印出每一行的值,使得计算器更具交互性.一开始,我们只是把数 ...

  3. 7.JavaCC官方入门指南-例2

    例2:整数加法运算--改良版(增强语法分析器) 1.修改   上一个例子中,JavaCC为BNF生产式所生成的方法,比如Start(),这些方法默认只简单的检查输入是否匹配BNF生产式指定的规范.但是 ...

  4. 6.JavaCC官方入门指南-例1

    例1:整数加法运算   在这个例子中,我们将判断如下输入的式子是否是一个合法的加法运算: 99 + 42 + 0 + 15   并且在输入上面式子的时候,数字与加号之间的任何位置,都是可以有空格或者换 ...

  5. 10.JavaCC官方入门指南-例5

    例5:计算器--添加乘除法运算 1.calculator2.jj 根据上一个例子,可知要添加乘法和除法运算是很简单的,我们只需在词法描述部分添加如下两个token: TOKEN : { < TI ...

  6. 5.JavaCC官方入门指南-概述

    一.前言   在最开始使用JavaCC的时候,从网上查询了许多资料,但是网上的资料水平是参差不齐的,走了许多弯路,不得已自己查阅了英文版官网文档.令我伤心的是最后我回过头来再看那些博客资料时,发现其实 ...

  7. 分布式服务框架 Zookeeper(三)官方入门指南

    入门指南:使用ZooKeeper来协调分布式应用 这篇文档包含了让你快速上手ZooKeeper的信息.主要是针对那些想要试一把ZooKeeper的开发人员,包含了安装一个单一ZooKeeper服务器的 ...

  8. Asp.Net MVC4.0 官方教程 入门指南之五--控制器访问模型数据

    Asp.Net MVC4.0 官方教程 入门指南之五--控制器访问模型数据 在这一节中,你将新创建一个新的 MoviesController类,并编写代码,实现获取影片数据和使用视图模板在浏览器中展现 ...

  9. Asp.Net MVC4.0 官方教程 入门指南之四--添加一个模型

    Asp.Net MVC4.0 官方教程 入门指南之四--添加一个模型 在这一节中,你将添加用于管理数据库中电影的类.这些类是ASP.NET MVC应用程序的模型部分. 你将使用.NET Framewo ...

随机推荐

  1. Linux-IO监控

    系统级IO监控 iostat 先进行安装 yum install -y sysstat iostat [ options ] [ <interval> [ <count> ] ...

  2. ASP.NET Core gRPC 入门全家桶

    一. 说明 本全家桶现在只包含了入门级别的资料,实战资料更新中. 二.官方文档 gRPC in Asp.Net Core :官方文档 gRPC 官网:点我跳转 三.入门全家桶 正片: ASP.NET ...

  3. NLTK实现文本切分

    之前已经了解了使用nltk库,将文本作为参数传入相应函数进行切分的方法,下面看看使用正则表达式如何来进行文本切分. 1. 使用正则表达式切分 1.1 通过RegexpTokenizer 进行切分.先导 ...

  4. Vue初始化过程

    用vue也有一两年了,始终对vue一知半解,不怎么了解内部的执行过程,最近在看vue源码,还是不少收获的,其中不乏浏览器事件轮询机制.闭包.设计模式等,还是非常值得一读.本篇简要记录下vue的初始化过 ...

  5. Java学习笔记 -- 头代码

    每次写Java程序都会忘记这个main代码怎么写,特意把他写下来,之后忘了还可以温故而知新. 程序猿们请千万不要鄙视我o(╯□╰)o public static void main(String[] ...

  6. vue项目、路由

    目录 Vue项目创建 pycharm配置并启动vue项目 vue项目目录结构分析 js原型补充 vue项目生命周期 页面组件 配置自定义全局样式 路由逻辑跳转 路由重定向 组件的生命周期钩子 路由传参 ...

  7. Shell脚本监控CPU、内存和硬盘利用率

    1.监控CPU利用率(通过vmstat工具) #!/bin/bash #==================================================== # Author: l ...

  8. Cocos2d-x.3.0开发环境搭建

    配置:win7 + VS2012 + Cocos2d-x.3.0 + Cocos Studio v1.4.0.1 前言:本文介绍在上述配置下进行游戏开发的环境搭建.开发语言为C++.如果读者不需要查看 ...

  9. java.lang.IllegalStateException: Cannot call sendError() after the response has been committe

    1.问题描述 严重: Servlet.service() for servlet [default] in contextwith path [/OxygenCloud] threw exceptio ...

  10. 【CentOS 7】CentOS 7各个版本镜像下载地址(转)

    参考链接:https://www.centos.org/download/mirrors/ https://www.cnblogs.com/defineconst/p/11176593.html