JavaCC从入门到出门

一、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" 2>/dev/null`
[ $? -gt 0 -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 "[email protected]"
exit 1

    命名为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种构造方法为输入的字符串设置适当的编码。

时间: 2024-10-12 20:52:00

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

d3从入门到出门

前言 基于d3js 5.5版本基础教程 环境配置 下载最新d3js文件, 参考: d3js官网 当前版本5.5, d3js v4与v3之间的api有一定的差异. 选择元素 d3主要有两个选择器 select 选择相应的dom元素, 如果有多个, 选择第一个 selectAll 选择所有的指定的dom元素. 通过选择器可以选择相应得dom元素, 而选择器的语法基本就是css选择器的语法. css选择器语法: http://www.w3school.com.cn/c***ef/css_selecto

网络从入门到出门系列(二)

真正的入坑指南开篇 很多人在初学习网络的时候都会面临两种局面: 1.可选择资料太多,不知道看哪本,在挑选资料的时候犹豫不决 2.找不到有效的学习资料,知识比较零散 我针对这两种情况做个统一说明: 学习任何一门技术,选择资料的前提就是经典书籍入门,经典视频入门.何为经典呢?举个例子:红茶三杯 .李桃梅的资料 .TCP/IP路由卷.思科系列丛书等.针对找不到资料的人来说可以最直接的方法是官网,思科官网(需要一定英文水平),国内推荐华三的官网.可以说资料十分详细.在互联网时代学习的资料是很好找的,俗话

sharding-jdbc从入门到出门(03)

经过端午节这2天对 sharding-jdbc一直怀揣成梦想的去学习,还是有一些没有解决的问题: 上一张图:

学习Sharding JDBC 从入门到出门-02:源码揣测

sjdbc有读写分离的功能,要使用这个功能,在创建数据源对象是要使用类:MasterSlaveDataSource,并且设置主备数据源和数据库名称 这个对象有下面的属性: name:数据库的名称 masterDataSource:主数据源对象 slaveDataSources:备库数据源类别 slaveLoadBalanceStrategy:选从算法 /** * 获取主或从节点的数据源名称. * * @param sqlStatementType SQL类型 * @return 主或从节点的数据

freemarker入门实例与源码研究准备工作

首先去freemarker官网下载源码jar包,本文是基于freemarker-2.3.21.tar.gz进行研究的.解压源码包,找到freemarker的源码部分导入eclipse工程中.需要注意的是:freemarker的ftl文件解析使用javacc实现的,所以源码中没有解析类(FMParse.java).要想研究freemarker源码,往往还需要引入freemarker.jar(含有FMParse.class),否则源码会出现编译问题.另外,还需要引入的jar包有:commons-lo

ML(1): 入门理论

机器学习相关的文章太多,选取一篇本人认为最赞的,copy文章中部分经典供自己学习,摘抄至 http://www.cnblogs.com/subconscious/p/4107357.html#first  示例入门 传统上如果我们想让计算机工作,我们给它一串指令,然后它遵照这个指令一步步执行下去.有因有果,非常明确.但这样的方式在机器学习中行不通.机器学习根本不接受你输入的指令,相反,它接受你输入的数据! 也就是说,机器学习是一种让计算机利用数据而不是指令来进行各种工作的方法.这听起来非常不可思

编译原理与javacc初探

1.前序 真是书到用时方恨少啊,在大学的时候,虽然学过编译原理,但当时真是不懂啊,只是为了应付考试,死记硬背了一点点.现在呢,由于工作上的需要,不得不弥补一下啊. 这两天把编译原理的书又看了一遍,其实也就是主要看了文法,词法分析,语法分析而已,为了备忘,赶紧先记一下吧. 2.定义 词法分析,就是把源码中的一行行代码按照事先规定好的格式分隔成一个个单词符号(token),比如数字,变量名称,函数等等. 语法分析呢,主要就是分析词法分析后的一个个token,是否能够拼装,组成事先规定好的语法中的一个

unity3d中实用数据库简单入门

入门笔记,大拿出门左拐. unity3d中实用简单的数据库入门. 声明3变量 string connection; //数据库的位置名字信息 IDbConnection _dbconnect; //可以把他理解成数据库的连接 IDbCommand _dbcmd; //cmd命令,sql语句主要在这里些 然后可以把操作数据库放在一个类构造里或者start,只要不是update里就行里. connection = "URI=file://Assets//ly//test.db"; _dbc

IT技术学习指导之Linux系统入门的4个阶段(纯干货带图)

IT技术学习指导之Linux系统入门的4个阶段(纯干货带图) 全世界60%的人都在使用Linux.几乎没有人没有受到Linux系统的"恩惠",我们享受的大量服务(包括网页服务.聊天服务等)背后几乎都是由Linux系统支撑的服务器,超过20亿人每天都随身携带基于Linux内核开发的 Android手机出门,Linux也广泛应用在嵌入式系统上.因此学习Linux系统变得尤为重要,对于普通用户而言,平面式的学习Linux系统的基本使用已经足够,但对于开发者或者运维人员而言,深入学习Linux