JavaCC学习笔记(2)

上次的表达式没有计算功能,这次继续,让它先算加法.

先看BNF产生式代码: Adder.jj

  1. int start() throws NumberFormatException :
  2. {
  3.     Token t;
  4.     int i;
  5.     int value;
  6. }{
  7.     t = <NUMBER>
  8.     { i = Integer.parseInt( t.image ); }
  9.     { value = i; }
  10.     (
  11.         <PLUS>
  12.         t = <NUMBER>
  13.         { i = Integer.parseInt( t.image ); }
  14.         { value += i; }
  15.     )*
  16.     <EOF>
  17.     { return value; }
  18. }

 

先看这个方法,首先行1语句的返回值由void变成int了,因为我们要返回和.行2和行6的大括号之间原来是声明变量用的,是java语法,因为java语句中不能直接调用<NUMBER>,所以得用个变量t.i ; 中间临时变量 i,得到t的具体数可以被java识别的据. value是累加后的和.在"{...}"书写java代码,并且顺序相关.8行中的t.image得到token的字符串表现形式.然后解析成int,最后通过 value += i 进行累加.最后返回累加的和,这段代码比较容易理解,可看起来还是杂乱,我们可以用"函数"的概念进行重构.

 

  1. int start() throws  NumberFormatException :
  2. {
  3.     int  i ;
  4.     int  value ;
  5. }{
  6.     value = primary()
  7.     (
  8.         <PLUS>
  9.         i = primary()
  10.         { value += i ; }
  11.     )*
  12.     <EOF>
  13.     { return value ; }
  14. }
  15.  
  16. int  primary()  throws  NumberFormatException :
  17. {
  18.     Token  t ;
  19. }{
  20.     t = <NUMBER>
  21.     { return Integer.parseInt( t.image ) ; }
  22. }

 

这里用了两个BNF产生式,可读性加强了.

主程序的要对int类型的返回值进行相应改变.

  1. public static void main( String[] args )throws ParseException, TokenMgrError, NumberFormatException {
  2.     Adder adder = new Adder( System.in ) ;
  3.     int value = adder.start() ;
  4.     System.out.println(value);
  5. }

 

 

然后进行编译,运行测试.注意,先把原来生成的文件全删除.程序还是比较好理解的,下面加入减法.

  1. PARSER_BEGIN(Adder)
  2.   public class Adder{
  3.     public static void main(String[] args) throws ParseException,TokenMgrError,NumberFormatException {
  4.       Adder adder = new Adder(System.in);
  5.       int value = adder.start();
  6.       System.out.println(value);
  7.     }
  8.   }
  9. PARSER_END(Adder)
  10.  
  11. SKIP:{" "|"/t"|"/n"|"/r"|"/r/n"}
  12.  
  13. TOKEN:{
  14.        <PLUS:"+">
  15.       |<MINUS:"-">
  16.       |<NUMBER:(["0"-"9"])+>
  17. }
  18.  
  19. int start() throws NumberFormatException :
  20. {
  21.  int value;
  22. }
  23. {
  24.    {value = primary();}
  25.    (
  26.        <PLUS>
  27.        {value += primary();}
  28.       |<MINUS>
  29.        {value -= primary();}
  30.    )*
  31.    <EOF>
  32.    {return value;}
  33. }
  34.  
  35. int primary() throws NumberFormatException :
  36. {
  37.   Token t;
  38. }
  39. {
  40.   t = <NUMBER>
  41.   {return Integer.parseInt(t.image);}
  42. }

 

加法和减法都有了,可现在有个问题,每次只有按ctrl + c退出程序才可以得到结果,能不能每次回车换行时候即时输出呢?

首先需要把输出流定义到System.out上:

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

 

因为要识别回车换行,所以Token需要识别回车换行:

  1. SKIP:{" "|"/t"}
  2.  
  3. TOKEN:{
  4.        <PLUS:"+">
  5.       |<MINUS:"-">
  6.       |<NUMBER:(["0"-"9"])+>
  7.       |<EOL:"/n"|"/r"|"/r/n">
  8. }

 

start BNF产生式要这样改变:

  1. void start(PrintStream printStream) throws NumberFormatException :
  2.   int value;
  3. }
  4. {
  5.   (
  6.     value = expression()
  7.     <EOL>
  8.     { printStream.println( value ) ; }
  9.   )*
  10.   <EOF>
  11. }
  12.  
  13. int expression() throws NumberFormatException :
  14. {
  15.   int value ;
  16. }
  17. {
  18.   value = primary()  
  19.   (
  20.     <PLUS>
  21.     { value += primary() ; }
  22.    |<MINUS>
  23.     { value -= primary() ; }
  24.   )*
  25.   { return value ; }
  26. }

 

用BNF标志表示:

start → (expression EOL) * EOF
expression → primary (PLUS primary)*
primary → NUMBER

接下来加入乘除法,由于除法会产生小数,所以先把int换成double,而浮点数的Token 可以这样定义:

TOKEN : { < NUMBER : <DIGITS> | <DIGITS> "." <DIGITS> | <DIGITS> "." | "."<DIGITS> > }
TOKEN : { < #DIGITS : (["0"-"9"])+ > }

其中"#"符号,代表这样一种情况:它后面所跟的名字并不代表一种Token类型,它对于词法分析器只代表一个位置,仅此而已.

其它各返回值都需要把int换成double.

Token中加入乘除符号:

TOKEN : { < TIMES : "*" > }
TOKEN : { < DIVIDE : "/" > }

由于乘除法的优先级高于加减法,所以需要这样处理:

expression → term (PLUS term | MINUS term)*
term → primary (TIMES primary | DIVIDE primary)*

完整代码:Adder.jj

  1. PARSER_BEGIN(Adder)
  2.  import java.io.PrintStream ;
  3.  public class Adder{
  4.   public static void main(String[] args) throws ParseException,TokenMgrError,NumberFormatException {
  5.    Adder adder = new Adder(System.in);
  6.    adder.start(System.out);
  7.   }
  8.  }
  9. PARSER_END(Adder)
  10.  
  11. SKIP:{" "|"/t"}
  12.  
  13. TOKEN:{
  14.        <PLUS:"+">
  15.       |<MINUS:"-">
  16.       | <TIMES:"*">
  17.       |<DIVIDE:"/">
  18.       |<NUMBER:<DIGITS> | <DIGITS> "." <DIGITS> | <DIGITS> "." | "."<DIGITS> >
  19.       |<#DIGITS : (["0"-"9"])+ >
  20.       |<EOL:"/n"|"/r"|"/r/n">
  21. }
  22.  
  23. void start(PrintStream printStream) throws NumberFormatException :
  24. {
  25.   double value;
  26. }
  27. {
  28.   (
  29.     value = expression()
  30.     <EOL>
  31.     { printStream.println( value ) ; }
  32.   )*
  33.   <EOF>
  34. }
  35.  
  36. double expression() throws NumberFormatException :
  37. {
  38.   double value ;
  39. }
  40. {
  41.   value =term()
  42.   (
  43.     <PLUS>
  44.     { value += term() ; }
  45.    |<MINUS>
  46.     { value -= term() ; }
  47.   )*
  48.   { return value ; }
  49. }
  50.  
  51. double term() throws NumberFormatException :
  52. {
  53.   double value ;
  54. }
  55. {
  56.   value = primary()
  57.   (
  58.     <TIMES>
  59.     { value *= primary() ; }
  60.    |<DIVIDE>
  61.     { value /= primary() ; }
  62.   )*
  63.   { return value ; }
  64. }
  65.  
  66. double primary() throws NumberFormatException :
  67. {
  68.   Token t;
  69. }
  70. {
  71.   t = <NUMBER>
  72.   {return Double.parseDouble(t.image);}
  73. }

 

编译运行一下,这回象样多了,呵呵.再加点猛料,各种括号:

增加Token符号:

|<OPEN_PAR: "(" >
|<CLOSE_PAR: ")" >
|<OPEN_BET : "[">
|<CLOSE_BET : "]">
|<OPEN_BCE : "{">
|<CLOSE_BCE : "}">

BNF标志:

primary → NUMBER
| OPEN_PAR expression CLOSE_PAR
| OPEN_BET expression CLOSE_BET
| OPEN_BCE expression CLOSE_BCE

有点像递归函数,不难理解.

  1. PARSER_BEGIN(Adder)
  2.  import java.io.PrintStream ;
  3.  public class Adder{
  4.   public static void main(String[] args) throws ParseException,TokenMgrError,NumberFormatException {
  5.    Adder adder = new Adder(System.in);
  6.    adder.start(System.out);
  7.   }
  8.  }
  9. PARSER_END(Adder)
  10. SKIP:{" "|"/t"}
  11. TOKEN:{
  12.        <PLUS:"+">
  13.       |<MINUS:"-">
  14.       |<TIMES:"*">
  15.       |<DIVIDE:"/">
  16.       |<NUMBER:<DIGITS> | <DIGITS> "." <DIGITS> | <DIGITS> "." | "."<DIGITS> >
  17.       |<#DIGITS: (["0"-"9"])+ >
  18.       |<OPEN_PAR: "(" >
  19.       |<CLOSE_PAR: ")" >
  20.       |<OPEN_BET : "[">
  21.       |<CLOSE_BET : "]">
  22.       |<OPEN_BCE : "{">
  23.       |<CLOSE_BCE : "}">
  24.       |<EOL:"/n"|"/r"|"/r/n">
  25. }
  26.  
  27. void start(PrintStream printStream) throws NumberFormatException :
  28. {
  29.  double value;
  30. }
  31. {
  32.  (
  33.   value = expression()
  34.   <EOL>
  35.   { printStream.println( value ) ; }
  36.  )*
  37.  <EOF>
  38. }
  39.  
  40. double expression() throws NumberFormatException :
  41.   double value ;
  42. }
  43. {
  44.  value =term()
  45.  (
  46.   <PLUS>
  47.   { value += term() ; }
  48.        |<MINUS>
  49.   { value -= term() ; }
  50.  )*
  51.  { return value ; }
  52. }
  53.  
  54. double term() throws NumberFormatException :
  55. double value ;
  56. }
  57. {
  58.  value = primary()
  59.  (
  60.   <TIMES>
  61.   { value *= primary() ; }
  62.  |<DIVIDE>
  63.   { value /= primary() ; }
  64.  )*
  65.  { return value ; }
  66. }
  67.  
  68. double primary() throws NumberFormatException :
  69. {
  70.  Token t;
  71.  double value;
  72. }
  73. {
  74.  t = <NUMBER>
  75.  {return Double.parseDouble(t.image);}
  76.  |<OPEN_PAR> value = expression() <CLOSE_PAR>
  77.  { return value ; }
  78.  |<OPEN_BET>value = expression() <CLOSE_BET>
  79.  { return value ; }
  80.  |<OPEN_BCE>value = expression() <CLOSE_BCE>
  81.  { return value ; }
  82. }
  83.  

 

4则混合运算基本OK了,来吧,测试一下成果.忙了半天了.

javacc Adder.jj
javac *.java
java Adder

控制台输入:

2*{1*[3*(1+1)-2]+1}

看看得到了多少?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值