JavaCC学习笔记(1)

来源:互联网 发布:法兰西战役知乎 编辑:程序博客网 时间:2024/05/22 20:25

今天刚学,啥也不明白,网罗了一堆文档教程什么的,英文的中文的啥都有了,看了会最简单的,还凑合写出来,看看能说明白不.

看教程上的例子,学着写了一个,还真好使了,就是一个十进制的加法表达式,比如

1+1

呵呵,我知道等于2,可这个小程序不是算结果的,是检验表达式合法不,基本就这样了,得先写个什么.jj文件规范JavaCC的解析器和词法分析器,将会作为JavaCC处理文件的输入.就叫"Adder.jj"吧,跟教程上一样.

  1. PARSER_BEGIN(Adder)
  2.  public class Adder{
  3.   public static void main(String[] args)
  4. throws ParseException,TokenMgrError{
  5.    Adder adder = new Adder(System.in);
  6.    adder.start();
  7.   }
  8.  }
  9. PARSER_END(Adder)

  10. SKIP:{" "|"/t"|"/n"|"/r"|"/r/n"}

  11. TOKEN:{
  12.  <PLUS:"+">
  13.  |<NUMBER:(["0"-"9"])+>
  14. }

  15. void start():
  16. {}
  17. {
  18.  <NUMBER>(<PLUS><NUMBER>)*<EOF>
  19. }

1.PARSER_BEGIN(Adder)与PARSER_END(Adder)之间的代码是Java语法,这里生成Adder.java的主程序入口,基本就是这种格式,其中要抛出两个异常:
    1.1 ParseException : 解析错误,解析器负责检查,Exception的子类.比如输入"1++1",这种就是解析错误,因为它里面的分割符都是我们在TOKEN:中定义的,没有其它字符.
    1.2 TokenMgrError : 分割符错误,词法分析器负责检查,Error的子类.比如输入"1-1"就是这种错误,因为TOKEN:中没有定义"-".
这两个类都会自动生成,现在刚研究还不知道为啥一个来之Exception,一个来自Error,以后会明白的.


2.new Adder(System.in),这个构造子这还不是很明白,不知道为啥默认成这型的,就知道是自动产生的,以后再说.


3.start() 方法是解析的主体,是下面需要实现的.

4.

SKIP:{" "|"/t"|"/n"|"/r"|"/r/n"} 

这个定义的是忽略的字符,它们虽然构成分割符但不被送给解析器,就是你在输入的时候有这些字符不会发生错误,但它们不会被解析出来.这里定义了5个,基本上就是空格,跳格,回车换行什么的,以为各个操作系统间的回车换行什么的据说不一样,我也不知道都咋回事,都写上吧.各个元素之间用"|"分开,格式就是这样了.


5.

  1. TOKEN:{
  2. <PLUS:"+">
  3.  |<NUMBER:(["0"-"9"])+>
  4. }

这个是说分割符了,就是把一个句子里的什么字符取出来,也就是你这句子里只能有这些规定好的字符,别的不行,这里就是"+"号和0-9十个数字. 两着用"|"分开.
每个分割符是这样规定的,用<>括上,代号和符号用":"隔开,就是用前面的代号代替后面在句子中会出现的元素或元素的集合.这些代号在下面会用到.其中数字用了正则式,就是1个或1个以上的由0-9之间的数字组成的串.

4和5两个部分如果用不到可以没有.

6.

  1. void start():
  2. {}
  3. {
  4.  <NUMBER>
  5.         (<PLUS><NUMBER>)*
  6.  <EOF>
  7. }

这个就是传说中的解析器了,说是符合什么BNF产生式,基本就这形状了,以后漫漫弄明白吧.里面看起来还像是正则式,就是用符号替换了,是以数字开头,中间跟0个或0个以上的由+和数字组成的序列,这个顺序不能变,最后是结束符,自带定义的.

程序基本上就这么回事了,因为简单,也形式上也没什么.

然后编译吧,设好环境变量什么的,在控制台切换到在Adder.jj所在文件夹:

javacc Adder.jj

成功就会出现提示:

  1. Java Compiler Compiler Version 4.0beta1 (Parser Generator)
  2. (type "javacc" with no arguments for help)
  3. Reading from file Adder.jj . . .
  4. File "TokenMgrError.java" does not exist.  Will create one.
  5. File "ParseException.java" does not exist.  Will create one.
  6. File "Token.java" does not exist.  Will create one.
  7. File "SimpleCharStream.java" does not exist.  Will create one.
  8. Parser generated successfully.

一共生成了7个.java文件:

  1. Adder.java : 生成的主程序,里面是程序入口,也是解析器.可以看到片段如下:

     

    1. /* Generated By:JavaCC: Do not edit this line. Adder.java */
    2. public class Adder implements AdderConstants {
    3.   public static void main(String[] args) throws ParseException, TokenMgrError{
    4.      Adder adder = new Adder(System.in);
    5.      adder.start();
    6.   }
    7.  
    8.   static final public void start() throws ParseException {
    9.     jj_consume_token(NUMBER);
    10.     label_1:
    11.     while (true) {
    12.       switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    13.       case PLUS:
    14.         ;
    15.         break;
    16.       default:
    17.         jj_la1[0] = jj_gen;
    18.         break label_1;
    19.       }
    20.       jj_consume_token(PLUS);
    21.       jj_consume_token(NUMBER);
    22.     }
    23.     jj_consume_token(0);  }

     

    上面我们定义到:

     

         void start():{}{ <NUMBER>(<PLUS><NUMBER>)*<EOF>}

    这里start()方法先消费一个number:jj_consume_token(NUMBER);然后是一个(<PLUS><NUMBER>)*的过程,循环中(jj_ntk==-1)?jj_ntk():jj_ntk来判断下一个未读取的token类型的,感觉从循环体上来看,这个合法的token类型,只能是<PLUS>或<EOF>,因为每次成对的消费PLUS和NUMBER,所以是PLUS就跳出switch,执行20,21行进行消费<PLUS><NUMBER>,如果是其它的,感觉这里只能是0,也就是<EOF>.这个类里还有其它的一些数据,比如几个重载的构造子,一些变量和方法.

  2. Token.java : 分割符的信息.里面有一些数据成员和方法,包含了我们定义的那3个token.其中image是我们常在程序中调用的成员,它是一个 public String 类型,记录了 从输入中得到的token,比如我们的"1","+","1",都以字符串的方式存储在image里供人们直接使用.还有一些上面程序片段看到的已经调用过的方法.

  3. SimpleCharStream.java : 实现CharStream接口的适配器类,传递字符到词法分析器.貌似只用ASCII,非unicode.

  4. AdderConstants.java : 接口.定义了词法分析器和解析器用到的一些常量.这里可以清楚的看到:

    1. int EOF = 0;
    2. int PLUS = 6;
    3. int NUMBER = 7;
    4. int DEFAULT = 0;
    5.  
    6. String[] tokenImage = {
    7.     "<EOF>",
    8.     "/" /"",
    9.     "/"//t/"",
    10.     "/"//n/"",
    11.     "/"//r/"",
    12.     "/"//r//n/"",
    13.     "/"+/"",
    14.     "<NUMBER>",
    15.   };

     

  5. AdderTokenManager.java : 词法分析器.

     

  6. TokenMgrError.java 和 ParseException.java : 上面说到的异常类.

编译了这些文件:

javac *.java

运行 Adder :

java Adder

这时候控制台等待输入,可以试试拉:

1+1

没提示就是合法,ctrl + c 结束输入

可以试着弄点错误什么的,看看异常类型跟错误的情况是怎么对应的.

都完事了,还挺简单的,呵呵.啊 累死了,下回再说.

 
原创粉丝点击