Apache Calcite教程-SQL解析-JavaCC教程

Github

JavaCC

使用递归下降语法解析,LL(k)。
其中,第一个L表示从左到右扫描输入;
第二个L表示每次都进行最左推导(在推导语法树的过程中每次都替换句型中最左的非终结符为终结符。类似还有最右推导);
k表示的是每次向前探索(lookahead)k个终结符

官网

语法文件

语法描述文件

options {
    JavaCC的选项
}

PARSER_BEGIN(解析器类名)
package 包名;
import 库名;

public class 解析器类名 {
    任意的Java代码
}
PARSER_END(解析器类名)

扫描器的描述

解析器的描述

JavaCC类介绍

SimpleCharStream

词法分析器的输入流

    // 构造函数种类 ,可以接受Reader和InputStream
public class SimpleCharStream {

   public SimpleCharStream(java.io.Reader dstream, int startline, 
       int startcolumn, int buffersize);
   
   public SimpleCharStream(java.io.Reader dstream, 
       int startline, int startcolumn);
   
   public SimpleCharStream(java.io.Reader dstream);
   
   public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
     int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException;
     
   public SimpleCharStream(java.io.InputStream dstream, int startline,
        int startcolumn, int buffersize);
   
   public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
        int startcolumn) throws java.io.UnsupportedEncodingException;
                         
   public SimpleCharStream(java.io.InputStream dstream, int startline,
                         int startcolumn);
   
   public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException;

   public SimpleCharStream(java.io.InputStream dstream);
}

XXXXXConstants

Token常量,SKIP TOKEN 和TOKEN

// 忽律的字符
SKIP:{
    " "
}


// 关键字
TOKEN:{
    <PLUS :"+">
}
// 和常量申明对应
public interface XXXXXConstants {
    
  int EOF = 0;
  int PLUS = 2;

  int DEFAULT = 0;

  String[] tokenImage = {
    // EOF 文件结尾
    "<EOF>",
    // 忽律字符串
    "\" \"",
    // PLUSA
    "\"+\"",
  };

}

XXXXXTokenManager

词法分析器

// 常见方法说明
public class XXXXXTokenManager implements XXXXXConstants {
    
    // 输入流
    protected SimpleCharStream input_stream;
    
    // 构造函数
    public XXXXXTokenManager(SimpleCharStream stream);
    
    // 获取下一个Token
    public Token getNextToken();
}

Token

Token类

public class Token {

  // Constants.java的种类
  public int kind;

  // 开始行和开始列,结束行和结束列
  public int beginLine, beginColumn, endLine, endColumn;

  // token的字符串
  public String image;

  // 下一个token
  public Token next;

  // 特殊令牌
  public Token specialToken;

  // Returns the image.
  public String toString()
  {
     return image;
  }


}

XXXXX

解析类入口

ParseException

语法解析异常

TokenMgrError

语法错误提示

常见配置 options

JavaCC工作原理

如图:
在这里插入图片描述

语法二义性解决

void S():{}
{
    IFStat()
    |
    E();
}
void IFStat():{}
{
    "if" "(" E() ")"
    S()
    (
        "else" S();
    )?
}

if E if E S else S 

存在两种解释

if E
   if E
     S
   else
     S   
if E
   if E
     S
else
   S

可以借助LOOKAHEAD(K)关键字解决

// 词法分析执行完if-S之后先找slse,找到则匹配最近的if,否则执行后面的语句
void S():{}
{
    IFStat()
    |
    E();
}
void IFStat():{}
{
    "if" "(" E() ")"
    S()
    (
        LOOKAHEAD(1)
        "else" S();
    )?
}

JavaCC语法

Java代码

java代码块用{}声明

// 定义java代码块
void javaCodeDemo():
{}
{
    {
        int i = 0;
        System.out.println(i);
    }
}

JAVA函数

需要用 JAVACODE声明

JAVACODE void print(Token t){
    System.out.println(t);
}

条件

  • if语句
// if语句
void ifExpr():
{}
{
    [
        <SELECT>
        {
            System.out.println("if select");
        }
    ]

    // 循环,出现一次
    (<SELECT>)?
}
  • if else语句
// if - else
void ifElseExpr():
{}
{
    (
        <SELECT> {System.out.println("if else select");}
        |
        <UPDATE>  {System.out.println("if else update");}
        |
        <DELETE>  {System.out.println("if else delete");}
        |
        {
           System.out.println("other");
        }
    )
}

循环

  • while 0~n
// while 0~n
void while1Expr():{
}
{
    (<SELECT>)*
}
  • while 1~n
// while 1~n
void while2Expr():{
}
{
    (<SELECT>)+
}

正则表达式

  1. []: 内容可选
  2. +: 内容出现一次或者多次
  3. *: 内容出现0次或者多次
  4. ?: 内容出现0次或者一次
  5. |: 或
  6. (): 优先级改变或者整体操作

其他说明

如果字符列表以“〜”符号为前缀,则它表示的字符集是不在指定集中的任何UNICODE字符。

代码示例

Maven编译

mvn javacc:javacc

简单计算器

PARSER_BEGIN(Calculator)
package com.github.quxiucheng.parser.javacc.calc;

import java.io.* ;

public class Calculator {

    public Calculator(String expr) {
        this((Reader)(new StringReader(expr)));
    }

    public static void main(String[] args) throws Exception  {
       Calculator calc = new Calculator(args[0]);
       System.out.println(calc.calc());
    }
}

PARSER_END(Calculator)



// 忽律的字符
SKIP:{
    " "
    | "\t"
    | "\n"
    | "\r"
    | "\r\n"
}


// 关键字
TOKEN:{
    <ADD :"+">
    | <SUB :"-">
    | <MUL :"*">
    | <DIV :"/">
    | <NUMBER :
            <DIGITS>
            | <DIGITS> "." <DIGITS>
            | <DIGITS> "."
            | "." <DIGITS>
      >
    | <#DIGITS : (["0"-"9"])+ >
}

// 计算
double calc():
{
    Double value ;
    Double result = 0.0;
}
{
  result = term()
  // 加减
  (
      <ADD>
      value = term()
      {result += value;}
      |
      <SUB>
      value =term()
      {result -= value;}
  )*
  {return result;}
}

// 乘除
double term():
{
    double value;
    double result;
}
{
    result = getNumber()
    (
       <MUL>
        value = getNumber()
        {result *= value;}
       |
       <DIV>
       value = getNumber()
       {result /= value;}
    )*
    {return result;}

}

// 获取字符串
double getNumber():
{
    double number;
    Token t;
}
{
    t = <NUMBER>
    {number = Double.parseDouble(t.image);
    return number;}
}

简单语法示例

// javacc编译设置
options {
    STATIC = false;
    IGNORE_CASE = true;
    UNICODE_INPUT = true;
}

// 解析类
PARSER_BEGIN(JavaCCGrammar)

package com.github.quxiucheng.parser.javacc.grammar;

public class JavaCCGrammar{

    public static void main(String[] args) throws Exception  {
       JavaCCGrammar grammar = new JavaCCGrammar(System.in);
       grammar.function1();
    }
}
PARSER_END(JavaCCGrammar)

// 忽律的字符
SKIP:{
    " "
    | "\t"
    | "\n"
    | "\r"
    | "\r\n"
}

// token关键字
TOKEN:{
      <SELECT :"select">
    | <UPDATE :"update">
    | <DELETE :"delete">
    | <COMMA:",">
    | <FORM:"form">
    | <AS:"as">
    | <WHERE:"where">
    | <EQUAL:"=">
    | <OPEN_PAR: "(">
    | <CLOSE_PAR: ")">
}

// 定义java代码块
void javaCodeDemo():
{}
{
    {
        int i = 0;
        System.out.println(i);
    }
}

// 函数
void function1():
{
    // 定义局部变量
    int i=0;
}
{
    {return;}
}

// 返回值
double function2():
{
    int i=0;
}
{
    // 带返回值
    {return i;}
}
// 函数调用
double function3():
{
    double i;
}
{
   {i = function2();}
   {return i;}
}

// token复制
void tokenAssignment() :
{
    Token st;
    Token dt;
}
{
     st = <SELECT>
     dt = <DELETE>

}

// if语句
void ifExpr():
{}
{
    [
        <SELECT>
        {
            System.out.println("if select");
        }
    ]

    // 循环,出现一次
    (<SELECT>)?



}

// if - else
void ifElseExpr():
{}
{
    (
        <SELECT> {System.out.println("if else select");}
        |
        <UPDATE>  {System.out.println("if else update");}
        |
        <DELETE>  {System.out.println("if else delete");}
        |
        {
           System.out.println("other");
        }
    )
}

// while 0~n
void while1Expr():{
}
{
    (<SELECT>)*
}

// while 1~n
void while2Expr():{
}
{
    (<SELECT>)+
}


// Java 代码
JAVACODE void print(Token t){
    System.out.println(t);
}

代码示例

https://github.com/quxiucheng/apache-calcite-tutorial/tree/master/calcite-tutorial-2-parser/parser-2-javacc-tutorial

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值