javacc jjtree 写法 以及 jj写法 基本语法 以及应用

javacc jjtree 写法 以及 jj写法 基本语法 以及应用

2012-2-7阅读2279 评论0

/***********************************************************/
>我使用的测试jjt,jj文件来自于javacc5.0版本
>dir_hier/javacc-5.0/javacc-5.0/examples/
                                         JJTreeExamples
                                         SimpleExamples
/***********************************************************/

/***********************************************************/
0.javacc(the java Compiler Compiler)概要
>Abstract summary:
 javacc一般用于编写某种语言的书写规则,如java的语法规则
 变量必须以字母或者$开头或者以数字结尾等,这是一种书写规范,
 书写规范是这门语言特有的,他必须满足,那么他是怎么去判断
 书写的字符窜符合了规则了,那就需要进行验证,javacc就是
  一种用于定义某种特定输入格式字符窜规则的工具,也是验证这种
  特定格式字符窜的验证者。定义字符窜输入格式,以及验证输入的
  字符窜是javacc的最基本作用。
  javacc语法规则描述文件的书写方式有两种一种是一种是.jj文件,
  另外一种是.jjt文件,两种文件的书写方式差异性不大,但是jjt文件
  比jj文件表达语法规则更加容易,jj文件的可选参数项和jjt有很大的
  不同,这是他们最大的区别。
/***********************************************************/

/***********************************************************/
1.javacc语法规则书写操作基本代码
>如何在生产表达式中写条件结构
(
term = < TERM >
|
term = < STAR >
|
term = < PREFIXTERM >
|
term = < WILDTERM >
|
term = < NUMBER >
)
>生成后的代码对应到
 分析:
 因为在javacc中(<A> | <B>)被表示成了在两个规则中任意选择一个的意思。
switch(tokenkind){
	case TERM:
		/** doSomthing...*/
	break;
	case STAR:
		/** doSomthing...*/
	break;
	...
}

void ifExp():{int k=0;/** java局部变量声明处*/}{
 {/*在{}中写任意的java代码并且是以面向对象的方式*/}
 (
  {
   if(k==2){break;}
   System.out.println("k="+k);
   k++;
  }
 )*
}
>如何在生产表达式中写循环结构
->(
  {
   if(k==2){break;}
   System.out.println("k="+k);
   k++;
  }
->)*

>生成对应的代码
 while(true){
  if(k==2){
    break;
  }
  System.out.println("k="+k);
  k++;
 }

>在生产表达式中调用其他的生产表达式
 对应到java中的方法调用
 void B():
 {
   StringBuffer sb = new StringBuffer();
   Token t = null;
 }{
  t = A /** 这里对应生成的java代码t=jj_consume_token(A);
          * 因为等于就是要消费一个记号把消费的这记号的应用给t变量
	  */
 }
 void A():{}{}

>javacc中的词法状态介绍
 <*>TOKEN:{}
 <DEFAULT>TOKEN:{<A:"2001 TO 2002">:DateRange
                 |
		 <B:"anything">
		}
 <DateRange>TOKEN:{}
 解析:<*>,<DEFAULT>,<DateRange>是词法状态
      定义词法状态的好处是,如果在生产表达式中
      正好有一个字符窜匹配到了2001 TO 2002这个字符窜
      那么他就会马上把下一个要匹配的模式字符窜定义
      为DateRange这种词法状态中定义的Token

>有了循环有了条件结构有了定义变量的方式
 javacc语法文件就相当完美了。
/***********************************************************/

/***********************************************************/
2.JJT语法规则描述文件书写方法
>jjt概要
 jjt能够很清晰的表达出语法分析的思路,
 并且他把每一个生产表达式都作为一个节点来表示,
 将这些节点的执行顺序有效的组织成了一颗语法分析树

>.options
>BUILD_NODE_FILES (default: true)
为SimpleNode以及语法中使用的其它节点创建样本实现。

>MULTI(default: false)
创建多模式解析树。
此选项默认为False,生成一个单一模式解析树。

>NODE_DEFAULT_VOID (default: false)
此选项设置为True时,
不在使每个非包装产生式定义一个节点,取而代之为空。

>NODE_FACTORY (default: false)
用下面的方式使用一个工厂方法创建一个节点:
public static Node jjtCreate(int id)

>NODE_PACKAGE (default: "")
被放进生成节点类里的包。默认为解析器的包。

>NODE_PREFIX (default: "AST") AST意思为抽象节点
在多模式中,前缀用来从节点标志符构造节点类名字。
默认前缀为” AST”

>NODE_SCOPE_HOOK (default: false)
在节点作用域入口和出口处插入调用用户自定义的解析方法。
在节点的生命开始和结束之前需要调用的方法被成为钩子。
参见:节点作用域钩子。

>NODE_USES_PARSER (default: false)
是否将当前解析器对象也出入到节点对象的属性中
JJTree会使用一个选择的形式将解析对象传给构造函数。例如:
public static Node MyNode.jjtCreate(MyParser p, int id);
MyNode(MyParser p, int id);

>STATIC (default: true)
为静态解析器生成代码。
选项默认为True。
这必须一致的通过等效的JavaCC选项被使用。
选项的值发布于JavaCC的源码中。

>VISITOR (default: false)
在节点类中插入jjtAccept()方法,
为语法中使用的每个节点类型产生一个访问者实现。

>VISITOR_EXCEPTION (default: "")
如果这个选项被设置,它将使用jjtAccept()和visit()方法的形式。
注意:这个选项将会在以后的某个JJTree版本中删除。如果不影响你请不要使用它。

>JJTREE_OUTPUT_DIRECTORY (default: use value of OUTPUT_DIRECTORY)
默认情况下,在全局OUTPUT_DIRECTORY设置中指定JJTree生成的输出目录。
明确的设置这个选项允许用户从树文件中分离解析器。
/***********************************************************/

/***********************************************************/
3.语法分析树节点(Node)
>javacc把每一个生产表达式都看作为一个简单节点(SimpleNode)在默认
 MULTI(default: false)的情况下,javacc已经提供了这个SimpleNode类的简单实现。
>MULTI(default: true)将为每一个节点都按照[NODE_PREFIX_生产表达式的名字]这样
 一种形式来提供默认的简单实现类。
>定义节点的方式
 明确定义:一个以指定子节点数创建的节点
 void AdditiveExpression() #void : {}
 {
  (
    MultiplicativeExpression()
    (
     ( "+" | "-" )MultiplicativeExpression()
    )*
  )#Add(3)
 }

>语法分析树参考结果:
Add
 Integer
 Integer
 Integer

>#void不会为这个生产表达式生成对应的节点
>#Add表示在循环执行过程中生成的所有节点中的前三个节点作为
   以Add为命名的儿子节点。

 按照条件定义:
 void AdditiveExpression() #void : {}
 {
   (
     MultiplicativeExpression()
     (
       ( "+" | "-" ) MultiplicativeExpression()
     )*
   ) #Add(>3)
 }
>#Add(>1)另外一种写法#Add(jjtree.arity() > 1)
  生成的源码:
  jjtree.closeNodeScope(jjtn001, jjtree.nodeArity() > 1);
  在执行循环过程中创建的节点个数大于1的话就会将所有的节点
  做为Add的子节点然后将Add节点添加到堆栈中,如果条件不满足
  那么创建的所有节点将会保留在栈中默认会在做为上一个节点的
  子节点
>语法分析树参考结果:
Start /** 因为在执行循环过程中创建的节点数没有达到指定的个数所以是start*/
 Integer
 Integer

>notes:
 ( ... ) #N ( a() )
 上面表达式逻辑不清,
 你必须明确的使用条件式:
 ( ... ) #N(true) ( a() )

>为产生式的节点指定名称
 void ProductExp() #MyNode:{} {//doAnything}
 #MyNode为这个生产表达式所对应的节点的名称

>特殊应用
 void P3():{}
 {
  P4() ( P5() )+ #ListOfP5s P6()
 }
#name=jjtree.closeNodeScope(jjtn001,  true);
#name(3)=jjtree.closeNodeScope(jjtn001,  3);
#name(>3)=jjtree.closeNodeScope(jjtn001, jjtree.nodeArity() > 1);

>什么是jjThis
ASTStart Start() : {}
{
  Expression() ";"
  { return jjtThis; }
}
分析:
jjThis代表了当前节点的引用地址,
就好像ASTStart Start()这个生产表达式对应到Start这个
节点那么jjtThis就指向了这个对象,
在其内部的实现代码为:
ASTStart jjtn000 = new ASTStart(JJTSTART);

>什么是NODE_SCOPE_HOOK="true"(默认为true表示有钩子)
 这个名气叫的很有味,钩子,正好是在某个节点被创建的
 时候调用指定的钩子方法,在节点添加到栈的时候要调用的方法
 钩子在open的时候可以做一些预备工作,结束可以做一些后续工作
 示例代码:
   static final public void AdditiveExpression() throws ParseException {
    ASTAdd jjtn001 = new ASTAdd(JJTADD);// 创建节点
    boolean jjtc001 = true;
    jjtree.openNodeScope(jjtn001); // 这就是钩子
    try {
      //do something...
    } finally {
    if (jjtc001) {
      jjtree.closeNodeScope(jjtn001,  3);// 这就是钩子
    }
    }
  }
/***********************************************************/
4.jjt文件生成的文件解析
SimpleQueryParser.jjt

SimpleQueryParser.jj

JJTSimpleQueryParserState.java
Node.java
ParseException.java
SimpleCharStream.java
SimpleNode.java
SimpleQueryParser.java
SimpleQueryParserConstants.java
SimpleQueryParserTokenManager.java
SimpleQueryParserTreeConstants.java
Token.java
TokenMgrError.java

>jjt文件可以生成.jj文件

>SimpleQueryParser这个名字在很多类名中都以重复的字眼出现,这是通过
 Parser_Begin(SimpleQueryParser)...Parser_End(SimpleQueryParser)
 指定的。

>JJTSimpleQueryParserState.java用于记录节点的组织情况
 这个类有单独的说明,在JJTSimpleQueryParserState.java
 中,他是一个以堆栈形式设计的类。

>Node.java是一个接口jjt中节点必须实现他,在选项MULTI(default: false)
 的时候javacc编译器已经帮我们简单的做了实现这个类为SimpleNode.java。

>ParseException.java在语法分析的时候遇到不符合规则的字符时抛出的异常

>SimpleQueryParserConstants.java这个类主要用于关联定义的Token

>SimpleQueryParserTreeConstants.java主要用于关联定义的节点
 如果没有给生产表达式命名那么他默认就是用生产表达式的名字做为节点的
 名字

>SimpleQueryParserTokenManager.java这是最重要的类他用于生产Token对象
 在getNextToken()中体现了这么一点

>Token.java这个对象作为最小的记号单元用于封装SimpleQueryParserTokenManager
 生成的记号

>SimpleQueryParser.java将类综合起来提供语法分析服务,他是消费Token对象的,
 在jj_consume_Token(token_kind)中可以体现这一点,传入一个记号的类型返回这个
 类型的一个token对象

>TokenMgrError.java在生产Token对象的过程中遇到错误

>SimpleCharStream.java用于封装输入的字符窜

>SimpleQueryParserTokenManager.java/**用于产生Token*/
 SimpleQueryParserTokenManager.getNextToken()/** 生产Token的方法*/

 /** 消费Token的SimpleQueryParser利用这些Token生成特定的逻辑对象*/
 SimpleQueryParser.java
 SimpleQueryParser.jj_consume_token(int kind);/** 根据指定的类型消费一个token*/
 SimpleQueryParser.jj_ntk()/** 如果当前jj_ntk变量为-1
 说明当前token对像的下一个token没有找到需要接着要到tokenmanage里面
 拿一个token出来作为当前token的next*/

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

/***********************************************************/
5.jj文件写法解析
>options
>STATIC=false;
 意思所有的生产表达式对应到java代码的时候
 不是静态的
/***********************************************************/
时间: 2024-08-02 08:23:54

javacc jjtree 写法 以及 jj写法 基本语法 以及应用的相关文章

【C++】智能指针的原始写法、scoped写法、shared写法

智能指针的三种常见写法: 一.最开始的原始写法,原始写法可以理解为指针转移的方法. template<typename T> class AutoPtr { public:     AutoPtr()         :_ptr(NULL)     {}     AutoPtr(T* ptr)         :_ptr(ptr)     {}     ~AutoPtr()     {         if (_ptr)         {             delete _ptr;  

【C语言】【面试题】C++中String类浅拷贝,深拷贝的传统写法与现代写法

C++ 的一个常见面试题是让你实现一个 String 类,在这我把String类的各种写法写了一下 1.浅拷贝 #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; //1.浅拷贝 class String { public:     String(char* str)         :_str(str)     {}     String(const String& s)         

【C语言】【面试题】C++中String类引用计数器的浅拷贝写法与深拷贝写法

Linux操作下String类的实现--引用计数器 1.引用计数器写法一 写法一个人比较喜欢叫他双指针法,因为他是在类里面创建了两个指针来实现的一个是指针_str,另外一个是用来保存指向同一块空间个数的指针_pRefCount. class String { public:     String(char* str = "")         :_str(new char[strlen(str) + 1])         , _pRefCount(new int(1))     {

sql查询一天内的where写法,sql写法

sql查询一天内的写法: 1. where createtime BETWEEN (select date_format(now(),'%Y-%m-%d 00:00:00')) and (select date_format(now(),'%Y-%m-%d 23:59:59')) 2. SELECT TO_DAYS(now());SELECT TO_DAYS('2016-07-02 20:50:06'); ========================================附录===

设计模式:单例模式的写法(基础写法和线程安全写法)

单例模式的写法非常多.先给出一种最基础的写法: (A种写法): package singleton; public class SingletonInstance { private static SingletonInstance mSingletonInstance = null; // 特意将构造函数设置成 private,防止外部使用者new SingletonInstance(). private SingletonInstance() { } public static Single

背景图片等比缩放的写法background-size简写法

1.背景图片或图标也可像img一样给其宽高就能指定其缩放大小了. 比如一个实际宽高36*28的图标,要缩小一半引用进来的写法就是: background:rgba(0, 0, 0, 0) url("../images/[email protected]") no-repeat scroll left center / 18px 14px;      //left center是图标定位,/后面的18px 14px是指定背景图标应用的大小,原图标大小是36px 28px 这样指定大小为1

ajax的jquery写法和原生写法

一.ajax的简介 Ajax被认为是(Asynchronous(异步) JavaScript And Xml的缩写).现在,允许浏览器与服务器通信而无须刷新当前页面的技术都被叫做Ajax. 同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式. 异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式 . 二.ajax的缺陷 AJAX大量使用了JavaScript和AJAX引擎,而这个取决于浏览器的支持.IE5.0及以上.Mozilla1.0.NetSc

js模块化 javascript 模块化 闭包写法 闭包模块化写法

var main = main || {}; ; (function (main) { 'use strict'; //私有变量 var _s1 = 'Hello '; var _s2 = 'World!~'; //私有方法 var _func = { helloWorld: function (str1, str2) { return str1 + str2; } }; //公有方法 main.method = { add: function (a, b) { return a + b; },

JAVACC

这篇博客主要是记录一下Javacc的一些知识点,和我在编写中遇到的问题 建议1:使用之前请下载官网实例学习下,感觉对于javacc的编写,其实没有全面的指导..so sad.. 建议2:不要用javacc写c++的语法,用yacc和lex可能会更好? 文章主要分为以下三个部分以及附录: ------------------------------------------------------------------------------- 附:参考链接和学习资料 1. 安装和使用 2. 词法