`

javacc Lookahead

阅读更多
/******************************************************/

参考来自于:
  heir\javacc-5.0\examples\Lookahead\
      README.txt
/******************************************************/

/******************************************************/
0.概要
  lookahead的作用不是很好用文字表达其实有很多问题都
  可以避开它进行一个解决,但是如果你能够掌握他那么说明
  你的javacc学的很不错了,因为这方面的学习资料大部分
  都是英文,我例举一个java的多重条件结构来描述一下
  lookahead的真正含义。
>举例代码:
如果有几个前缀相似的英文字母需要对这些不同的英文字母
做出不同的动作,关键是如何去区分这些英文。
void whatIsLookAhead():
{}
{
  (
    LOOKAHEAD(2)
    "A" "B" "C"
    {
      System.out.println("shit");
    }
    |
    "D" "E"
    |
    "A" "E"
    {
      System.out.println("xxxxxxxxx");
    }
  )
}
>分析:
  上面的代码相当于:
  //jj_scan_token(token_kind)作用:
  //jj_scan_token(token_kind)从TokenManager取得一个Token对象,
  //如果该token的类型和我传入的类型
  //相匹配那么就说明符合语法要求

  if (如果调用两次jj_scan_token(token_kind)
      如果都符合要求那么返回true条件成立) {
"A" "B" "C"
  } else if (next token is "D") {
"D" "E"
  } else if (next token is "A") {
"A" "E"
  } else {
  produce an error message
  }
  // 为什么要这么做因为如果我输入的字符是
  // AE并且没有用lookahead的话那么他将进入第一个
  // 条件判断并且会抛出语法解析异常的错误这是
  // 因为我输入的字符本来是要去匹配第三个条件判断的
  // 如果采用lookahead的话这个错就不会报了
  // 很明显这样的东西可以想很多的办法不用lookahead


>反向生成的java代码
if (jj_2_1(2)) {// 向前扫描两个指定了类型的token也就是17和18
        // 为什么是17和18因为这里扫描的时候是根据第一个条件下面
// 需要消费的token而确定的
jj_consume_token(17);//>扫描的第一个token的类型17
jj_consume_token(18);//>扫描的第二个token的类型18
jj_consume_token(19);
System.out.println("shit");
  } else {
   switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
  case 20:
jj_consume_token(20);
jj_consume_token(21);
break;
  case 17:
        //因为上面已经区分了两者的区别
//所以这里就很方便了就直接判断一个记号
//的类型就行了
jj_consume_token(17);
jj_consume_token(21);
System.out.println("xxxxxxxxx");
break;
  default:
jj_la1[0] = jj_gen;
jj_consume_token(-1);
        throw new ParseException();
   }
   }
/******************************************************/
//(< LBRACE>)
//#MULTI(>1) 表示在栈中有ASTMULTI这个节点大于一的时候将当前节点压入栈顶
//否则丢弃
//jjtree.closeNodeScope(jjtn001, jjtree.nodeArity() > 1)
//ASTMULTI.java
void conj_elem()#void:
{
}
{
&nbsp; (
&nbsp; &nbsp; < AND >
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; conj=" +";
&nbsp; &nbsp; &nbsp; sb.append(" +");
&nbsp; &nbsp; }
&nbsp; &nbsp;|< NOT>
&nbsp; &nbsp;{
&nbsp; &nbsp; conj=" -";
&nbsp; &nbsp; sb.append(" -");
&nbsp; &nbsp;}
&nbsp; &nbsp;|(
&nbsp; &nbsp; LOOKAHEAD(2)
<span style="white-space:pre"> </span>(< OR>)+ //表示出现一次以上 这个判断很犀利
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp;conj=" OR ";
&nbsp; &nbsp; &nbsp;sb.append(" OR ");
&nbsp; &nbsp; }
&nbsp; &nbsp; |(<OR>)? //表示出现一次或者不出现
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp;conj=" ";
&nbsp; &nbsp; &nbsp;sb.append(" ");
&nbsp; &nbsp; }
&nbsp; &nbsp; )
&nbsp; )
&nbsp; {
&nbsp; &nbsp;expr();
&nbsp; }
}
/******************************************************/
1.全局LOOKAHEAD
    LOOKAHEAD的全局效果默认为1也就是在判断的时候
    默认向前多判断一个字符进行冲突判断

/******************************************************/


/******************************************************/
2.局部LOOKAHEAD
    //这个方法是动态生成的并且是根据你的LOOKAHEAD(需要扫描几个)
    //用的地方的第一个条件判断指定数量个token的类型的数字来生成

    //这个方法也是对应到每一个局部的LOOKAHEAD的使用
    static private boolean jj_2_1(int xla) {
jj_la = xla;
jj_lastpos = jj_scanpos = token;
try {
return !jj_3_1();
} catch (LookaheadSuccess ls) {
return true;
} finally {
jj_save(0, xla);
}
     }

     //这个方法是根据你的指定要送啊面的
     //数量而生成的条件判断的方法
     static private boolean jj_3_1() {
if (jj_scan_token(17))
return true;
if (jj_scan_token(18))
return true;
return false;
      }

非原创,转自:http://blog.csdn.net/zyb243380456/article/details/7242796
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics