一、JavaCC

JavaCC是java的compiler compiler。JavaCC是LL解析器生成器,可处理的语法范围比较狭窄,但支持无限长的token超前扫描。

安装过程:

我是从github上down下来的zip压缩包,然后安装了下ant, 然后通过ant安装的javacc

  1. 首先下载下来ant的源码,然后tar -zvxf apache-ant....tag.gz 解压缩,然后可以在解压出来的bin目录中看到ant的可执行文件

  2. 从github下载javacc, 进入解压缩的目录执行xxxxxx/ant。 然后会在target 目录中看到javacc.jar 包

  3. 这个时候可以通过如下方法将jar包做成一个可执行文件:

    首先创建一个shell脚本:

#!/bin/sh
MYSELF=`which "$0" >/dev/null`
[ $? -gt -a -f "$0" ] && MYSELF="./$0"
java=java
if test -n "$JAVA_HOME"; then
java="$JAVA_HOME/bin/java"
fi
exec "$java" $java_args -cp $MYSELF "$@"
exit

    命名为stub.sh, 然后在jar包的所在目录执行: cat stub.sh javacc.jar > javacc && chmod +x javacc。 这样一个可执行文件就有了,不过在解析.jj文件时需要带一个javacc的参数,像这样: javacc javacc Adder.jj

二、语法描述文件

1、简介

JavaCC的语法描述文件是扩展名为.jj的文件,一般情况下,语法描述文件的内容采用如下形式

options {
JavaCC的选项
} PARSER_BEGIN(解析器类名)
package 包名;
import 库名; public class 解析器类名 {
任意的Java代码
}
PARSER_END(解析器类名) 扫描器的描述 解析器的描述

JavaCC和java一样将解析器的内容定义在单个类中,因此会在PARSER_BEGIN和PARSER_END之间描述这个类的相关内容。

2、Example

如下代码是一个解析正整数加法运算并进行计算的解析器的语法描述文件。

options {
STATIC = false;
} PARSER_BEGIN(Adder)
import java.io.*; class Adder {
public static void main(String[] args) {
for (String arg : args) {
try {
System.out.println(evaluate(arg));
} catch (ParseException ex) {
System.err.println(ex.getMessage());
}
}
} public static long evaluate(String src) throws ParseException {
Reader reader = new StringReader(src);
return new Adder(reader).expr();
}
}
PARSER_END(Adder) SKIP: { <[" ", "\t", "\r", "\n"]> } TOKEN: {
<INTEGER: (["0"-"9"])+>
} long expr():
{
Token x, y;
}
{
x=<INTEGER> "+" y=<INTEGER> <EOF>
{
return Long.parseLong(x.image) + Long.parseLong(y.image);
}
}

options块中将STATIC选项设置为false, 将该选项设置为true的话JavaCC生成的所有成员及方法都将被定义为static,若将STATIC设置为true则所生成的解析器无法在多线程环境下使用,因此该选项总是被设置为false。(STATIC的默认值为true)
  从PARSER_BEING(Adder)到PARSER_END(Adder)是解析器类的定义。解析器类中需要定义的成员和方法也写在这里。为了实现即使只有Adder类也能够运行,这里定义了main函数。
  之后的SKIP和TOKEN部分定义了扫描器。SKIP表示要跳过空格、制表符(tab)和换行符。TOKEN表示扫描整数字符并生成token。
  long expr...开始到最后的部分定义了狭义的解析器。这部分解析token序列并执行某些操作。

3、运行JavaCC

要用JavaCC来处理Adder.jj(图中是demo1.jj),需要使用如下javacc命令

运行如上命令会生成Adder.java和其他辅助类。
  要编译生成的Adder.java,只需要javac命令即可:

这样就生成了Adder.class文件。Adder类是从命令行参数获取计算式并进行计算的,因此可以如下这样从命令行输入计算式并执行

三、启动JavaCC生成的解析器

现在解析一下main函数的代码。   main函数将所有命令行参数的字符串作为计算对象的算式,依次用evaluate方法进行计算。
  evaluate方法中生成了Adder类的对象实例 。并让Adder对象来计算(解析)参数字符串src。
  要运行JavaCC生成的解析器类,需要下面2个步骤:

  1. 生成解析器类的对象实例
  2. 用生成的对象调用和需要解析的语句同名的方法

第1点: JavaCC4.0生成的解析器中默认定义有如下四种类型的构造函数。

  1. Parser(InputStream s)
  2. Parser(InputStream s, String encoding)
  3. Parser(Reader r)
  4. Parser(x x x x TokenManager tm)

第1种的构造函数是通过传入InputStream对象来构造解析的。这个构造函数无法设定输入字符串的编码,因此无法处理中文字符等。
  而地2种的构造函数除了InputStream对象外,还可以设置输入字符串的编码来生成解析器。但如果要解析中文字符串或注释的话,就必须使用第2种/3种构造函数。
  第3种的构造函数用于解析Reader对象所读入的内容。
  第4种是将扫描器作为参数传入。
  解析器生成后,用这个实例调用和需要解析的语法同名的方法。这里调用Adder对象的expr方法,接回开始解析,解析正常结束后会返回语义值。

四、中文的处理

要使JavaCC能够处理中文首先需要将语法描述文件的options快的UNICODE_INPUT选项设置为true:

options {
STATUS = false;
DEBUG_PARSER = true;
UNICODE_PARSER = true;
JDK_VERSION = "1.5";
}

这样就会先将输入的字符转换成UNICODE后再进行处理。UNICODE_INPUT选项为false时只能处理ASCII范围的字符。
  另外还需要使用第2/3种构造方法为输入的字符串设置适当的编码。

JavaCC从入门到出门的更多相关文章

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

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

  2. elasticsearch从入门到出门-02-简单的CRUD

    操作背景: 电商网站上面的一个商品的增删改查: es 能接受的都是JSON格式的数据 Es 提供了一套简单的集群信息健康监控的api GET /_cat/health?v   epoch      t ...

  3. 11.JavaCC官方入门指南-例6

    例6:计算器--添加括号.一元运算符和历史记录 1.calculator3.jj   我们只需要再添加一些特色,就可以得到一个可用的四则运算计算器.在这一版的修改中 ,我们将使得程序可以接收括号.负值 ...

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

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

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

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

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

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

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

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

  8. Python3 从入门到出门

    引:此文是自己学习python过程中的笔记和总结,适合有语言基础的人快速了解python3和没基础的作为学习的大纲,了解学习的方向:笔记是从多本书和视频上学习后的整合版. (一)初识python 1. ...

  9. OPENCV3——从入门到出门

    跑第一个程序的时候经过坑爹的各种设置终于能用了. 如果遇到问题就谷歌或者百度,大牛的博客会给出解决方案的. vs2010+opencv3 目标:把书上的程序挨个敲一遍跑一遍. 现在已经跑了七章了,还有 ...

随机推荐

  1. javascript中的onmousewheel事件处理

    滚轮事件在不同浏览器会有一点点区别,一个像Firefox使用DOMMouseScroll ,FF也可以使用addEventListener方法绑定DomMouseScroll事件,其他的浏览器滚轮事件 ...

  2. springboot邮件发送与接收读取

    发送邮件 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sp ...

  3. caffe编译时候出现 undefined reference to `TIFFReadRGBAStrip@LIBTIFF_4.0'

    1.编译时候出现 make: * [.build_release/examples/siamese/convert_mnist_siamese_data.bin] Error 1 /usr/local ...

  4. pycharm 注册码/License server 2017年最新

    两种方法: 1.选License server激活,输入:http://idea.imsxm.com 2.2017年激活码 时效1年BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUc ...

  5. GIMP使用笔记

    一:背景透明化 1:选中背景:选择——按颜色——点击图片背景 2:透明化:图层——透明化——颜色到Alpha——选择背景颜色,转换为alpha透明 二:裁剪图片 1:选择:工具箱——选择套具——使用套 ...

  6. python 过滤文本中的标点符号(转)

    网上搜到的大都太复杂,最后找到一个用正则表达式实现的: import re s = "string. With. Punctuation?" # 如果空白符也需要过滤,使用 r'[ ...

  7. 关于snowflake算法生成的ID转换为JS的数字类型由于过大导致JS精度丢失的问题

    JS的数字类型目前支持的最大值为:9007199254740992,一旦数字超过这个值,JS将会丢失精度,导致前后端的值出现不一致. JAVA的Long类型的       最大值为:922337203 ...

  8. 生产系统ELK日志采集系统

    总结下,生产在运转的日志采集系统!后续的扩展在于elasticsearch节点与logstash节点与kafka+zookeeper,目的提高吞吐量!

  9. 19.翻译系列:EF 6中定义自定义的约定【EF 6 Code-First约定】

    原文链接:https://www.entityframeworktutorial.net/entityframework6/custom-conventions-codefirst.aspx EF 6 ...

  10. laravel中及其常用的一些函数方法(自己看)和技巧(不断添加中)

    手册:https://laravelacademy.org/ 1.中间件的定义Middleware 2.路由的定义和写法 3.控制器Controller之Request 4.控制器Controller ...