Calcite流程

Calcite 使用 javacc作为语法解析器,并且使用freemarker作为模板引擎,在编译的时候,freemarker会将 配置文件、模板语法文件、附加模板文件 整体生成最终的语法文件,并通过javacc编译,形成calcite的语法文件
image.png

javacc

javacc是一款词语语法解析工具,jj语法文件大致结构可成分为:options可选配置、解析类的声明、词法定义、语法定义和动作执行

options可选配置

  1. 主要功能是javacc在读取*.jj语法文件生成java程序时,配置生成参数的。options的相关参数有很多,在javacc源码的Options类中大概有48个参数,都是有个默认值,它还可以通过javacc命令去配置,所有不去配置也是可以的, 但是还是要根据实际的情况合理的配置
  1. //可选配置参数
  2. options{
  3. STATIC = false; //关闭生成java方法是静态的,默认是true
  4. DEBUG_PARSER = true;//开启调试解析打印,默认是false
  5. JDK_VERSION = "1.8";//生产java时使用jdk版本,默认1.5
  6. UNICODE_INPUT=true;//接收unicode编码的输入,默认是false
  7. }
  8. PARSER_BEGIN(类名)
  9. pakage 包名 //生成java文件采用此包名
  10. import ....
  11. public class {
  12. ......
  13. }
  14. PARSER_END

词法解析

javacc的词法类型有SKIP、TOKEN 、MORE、SPECIAL_TOKEN

  1. TOKEN : {
  2. <定义词1 :匹配规则1
  3. | 匹配规则n>
  4. | <定义词2 : 匹配规则>
  5. .....
  6. }
  7. TOKEN : {
  8. <NUMBER : <DIGITS>
  9. | <DIGITS> "." <DIGITS>
  10. >
  11. |
  12. //#开头则表示内部Token,只可以在词法中使用,不能在语法中引用
  13. <#DIGITS :(["0"-"9"])+>
  14. }

词法有一个唯一的标识符以及一个用于匹配的正则表达式列表,目前明确可定义的词法类型有:

  • SKIP
  • MORE
  • TOKEN
  • SPECIAL_TOKEN

以及默认的词法类型 DEFAULT

DEFAULT

词法中作为扩展单元出现的所有正则表达式都被视为处于DEFAULT 词法状态,其出现顺序由它们在语法文件中的位置确定,也就是说在词法中直接使用正则表达式,但是没有在词法中进行定义的正则表达式,就是DEFAULT类型的词法,属于javacc程序定义的默认词法。

SKIP

跳过,略过,用于不参与词法解析的字符

MORE

继续执行下一个词法,并沿用匹配的字符串。此字符串将是新匹配字符串的前缀

TOKEN

将用匹配的字符串创建TOKEN,并将其发送到解析器或任何调用方

字符串在匹配词法token时候,发现可以匹配到多个正则表达式时,会尽可能长的匹配,如果有多个相同长度的最长匹配,则以最先出现的token定义的正则表达式规则为准

  1. TOKEN : {
  2. <HELLO : "Hello"
  3. | "hello"
  4. | "HELLO">
  5. }
  6. TOKEN : {
  7. <IDENTITY : (["a"-"z"
  8. ,"A"-"Z"
  9. ,"\u4e00"-"\u9fa5"])+>
  10. }

字符串”hello”, 即可以匹配token 中 定义规则,也匹配token 中的定义规则。因为定义比早,则javacc会将”hello”识别成token。

SPECIAL_TOKEN

特殊的token标记,这种特殊标记不参与解析。这里解析的含义不是说javacc不解析 而是 不把这些屁匹配的字符串放入解析语法的上下文中,例如 单行注解定义

  1. SPECIAL_TOKEN :
  2. {
  3. <SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
  4. }

这种特殊的token定义常被用于定义为注解,就像是在java里写了注解,但是注解不会被编译到class文件里,注解又不影响java代码的解析编译。

词法中的操作

希望在匹配token后立即执行某些java代码。

  1. TOKEN : {
  2. < TAB : "\t" > { tabcount += 1; }
  3. }

语法定义和动作执行

  1. 返回类型 语法规则名(参数) 异常抛出声明 :
  2. {变量声明}
  3. {
  4. //语法规则
  5. 定义词的组合规则
  6. {匹配规则时的执行动作,即使java代码执行 ;}
  7. }

语法定义的格式有点像java方法的定义:有返回类型,语法规则名,异常抛出声明 ,变量声明,语法主体及动作执行。

返回类型:无返则声明为 void,有返回类型 则要在动作执行中至少一次的 return 返回类型

语法规则名:类似java方法,可以无参数,格式遵守java方法的方式。

异常抛出声明 :可以忽略不写,如果执行动作(java代码执行)中有抛出异常且未处理则要声明抛出的异常。

变量声明:无变量声明可以为空,但是这一对“{}”是不能省略。声明的变量为语法主体要使用的,其作用范围仅限在该语法规则中。

语法主体及动作执行:语法规则可以说是根据需要千变万化,其实质就是定义的词法的规则组合,其规则组合也类似正则表达式

JavaCC语法

JavaCC 输入文件中的

方括号[...]表示匹配这...的范围[...]也可以写成(...)?。这两种形式是等价的。
~是匹配任何未在 []中指定的字符的模式...

  1. ["a"-"z"] matches all lower case letters
  2. ~[] matches any character
  3. ~["\n","\r"] matches any character except the new line characters
  1. e1 | e2 | e3 | ... : A choice of e1, e2, e3, etc.
  2. ( e )+ : One or more occurrences of e
  3. ( e )* : Zero or more occurrences of e

常用的词法解析

  1. //换行符 注释全部跳过
  2. SKIP :
  3. {
  4. " "
  5. | "\t"
  6. | "\n"
  7. | "\r"
  8. | <"//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
  9. | <"/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/">
  10. }