Calcite流程
Calcite 使用 javacc作为语法解析器,并且使用freemarker作为模板引擎,在编译的时候,freemarker会将 配置文件、模板语法文件、附加模板文件 整体生成最终的语法文件,并通过javacc编译,形成calcite的语法文件
javacc
javacc是一款词语语法解析工具,jj语法文件大致结构可成分为:options可选配置、解析类的声明、词法定义、语法定义和动作执行
options可选配置
主要功能是javacc在读取*.jj语法文件生成java程序时,配置生成参数的。options的相关参数有很多,在javacc源码的Options类中大概有48个参数,都是有个默认值,它还可以通过javacc命令去配置,所有不去配置也是可以的, 但是还是要根据实际的情况合理的配置
//可选配置参数
options{
STATIC = false; //关闭生成java方法是静态的,默认是true
DEBUG_PARSER = true;//开启调试解析打印,默认是false
JDK_VERSION = "1.8";//生产java时使用jdk版本,默认1.5
UNICODE_INPUT=true;//接收unicode编码的输入,默认是false
}
PARSER_BEGIN(类名)
pakage 包名 //生成java文件采用此包名
import ....
public class 类 {
......
}
PARSER_END
词法解析
javacc的词法类型有SKIP、TOKEN 、MORE、SPECIAL_TOKEN
TOKEN : {
<定义词1 :匹配规则1
| 匹配规则n>
| <定义词2 : 匹配规则>
.....
}
TOKEN : {
<NUMBER : <DIGITS>
| <DIGITS> "." <DIGITS>
>
|
//#开头则表示内部Token,只可以在词法中使用,不能在语法中引用
<#DIGITS :(["0"-"9"])+>
}
词法有一个唯一的标识符以及一个用于匹配的正则表达式列表,目前明确可定义的词法类型有:
- SKIP
- MORE
- TOKEN
- SPECIAL_TOKEN
以及默认的词法类型 DEFAULT
DEFAULT
词法中作为扩展单元出现的所有正则表达式都被视为处于DEFAULT 词法状态,其出现顺序由它们在语法文件中的位置确定,也就是说在词法中直接使用正则表达式,但是没有在词法中进行定义的正则表达式,就是DEFAULT类型的词法,属于javacc程序定义的默认词法。
SKIP
跳过,略过,用于不参与词法解析的字符
MORE
继续执行下一个词法,并沿用匹配的字符串。此字符串将是新匹配字符串的前缀
TOKEN
将用匹配的字符串创建TOKEN,并将其发送到解析器或任何调用方
字符串在匹配词法token时候,发现可以匹配到多个正则表达式时,会尽可能长的匹配,如果有多个相同长度的最长匹配,则以最先出现的token定义的正则表达式规则为准
TOKEN : {
<HELLO : "Hello"
| "hello"
| "HELLO">
}
TOKEN : {
<IDENTITY : (["a"-"z"
,"A"-"Z"
,"\u4e00"-"\u9fa5"])+>
}
字符串”hello”, 即可以匹配token 中 定义规则,也匹配token 中的定义规则。因为定义比早,则javacc会将”hello”识别成token。
SPECIAL_TOKEN
特殊的token标记,这种特殊标记不参与解析。这里解析的含义不是说javacc不解析 而是 不把这些屁匹配的字符串放入解析语法的上下文中,例如 单行注解定义
SPECIAL_TOKEN :
{
<SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
}
这种特殊的token定义常被用于定义为注解,就像是在java里写了注解,但是注解不会被编译到class文件里,注解又不影响java代码的解析编译。
词法中的操作
希望在匹配token后立即执行某些java代码。
TOKEN : {
< TAB : "\t" > { tabcount += 1; }
}
语法定义和动作执行
返回类型 语法规则名(参数) 异常抛出声明 :
{变量声明}
{
//语法规则
定义词的组合规则
{匹配规则时的执行动作,即使java代码执行 ;}
}
语法定义的格式有点像java方法的定义:有返回类型,语法规则名,异常抛出声明 ,变量声明,语法主体及动作执行。
返回类型:无返则声明为 void,有返回类型 则要在动作执行中至少一次的 return 返回类型
语法规则名:类似java方法,可以无参数,格式遵守java方法的方式。
异常抛出声明 :可以忽略不写,如果执行动作(java代码执行)中有抛出异常且未处理则要声明抛出的异常。
变量声明:无变量声明可以为空,但是这一对“{}”是不能省略。声明的变量为语法主体要使用的,其作用范围仅限在该语法规则中。
语法主体及动作执行:语法规则可以说是根据需要千变万化,其实质就是定义的词法的规则组合,其规则组合也类似正则表达式
JavaCC语法
JavaCC 输入文件中的
方括号[...]
表示匹配这...的范围
。 [...]
也可以写成(...)?
。这两种形式是等价的。~
是匹配任何未在 []中指定的字符的模式...
。
["a"-"z"] matches all lower case letters
~[] matches any character
~["\n","\r"] matches any character except the new line characters
e1 | e2 | e3 | ... : A choice of e1, e2, e3, etc.
( e )+ : One or more occurrences of e
( e )* : Zero or more occurrences of e
常用的词法解析
//换行符 注释全部跳过
SKIP :
{
" "
| "\t"
| "\n"
| "\r"
| <"//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
| <"/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/">
}