0301: 词法解析

string → tokens → struct

一条SQL首先要成一个字符串变成编程语言里的数据类型,然后才能后续的执行。比如:

select a,b from t where c=1;

要表示为:

StmtSelect{
    table: "t",
    cols:  []string{"a", "b"},
    keys:  []NamedCell{{column: "c", value: Cell{Type: TypeI64, I64: 1}}},
}

SQL比较类似英语,有一定的词汇和语法。计算机语言里的“词汇”一般叫做 token,在解析语法之前,可以先将字符串解析成 token,这个过程叫 tokenizer 或 lexer。

SQL 里的 token 可以分为以下几类:

不同类别的规则不一样,每种 token 都有对应的函数实现。

语法解析器

大部分语法解析,就是从左到右消耗 token,并构建数据结构。所以需要记住当前 token 在字符串中的位置。

type Parser struct {
    buf string
    pos int
}

func NewParser(s string) Parser {
    return Parser{buf: s, pos: 0}
}

解析名字(表名、列名)

func (p *Parser) tryName() (string, bool)

要求:

比如输入 Parser {buf: " hi ", pos: 0},执行 tryName() 后,pos=3,返回 "hi"

可以使用以下函数来实现规则:

func isSpace(ch byte) bool {
    switch ch {
    case '\t', '\n', '\v', '\f', '\r', ' ':
        return true
    }
    return false
}
func isAlpha(ch byte) bool {
    return 'a' <= (ch|32) && (ch|32) <= 'z'
}
func isDigit(ch byte) bool {
    return '0' <= ch && ch <= '9'
}
func isNameStart(ch byte) bool {
    return isAlpha(ch) || ch == '_'
}
func isNameContinue(ch byte) bool {
    return isAlpha(ch) || isDigit(ch) || ch == '_'
}

解析关键字

func (p *Parser) tryKeyword(kw string) bool

要求:

用以下函数来判断分隔:

func isSeparator(ch byte) bool {
    return ch < 128 && !isNameContinue(ch)
}