2021SC@SDUSC
简介
SQLite的SQL语言解析器是使用一个名为“Lemon”的代码生成器程序生成的。Lemon程序读取输入语言的语法,并发出C代码来实现该语言的解析器。
Lemon是一个LALR(1)文法分析器生成工具,它的操作类似于更熟悉的工具。yacc和bison,但是Lemon增加了重要的改进,包括:
1.语法语法不太容易出错–使用符号名称来表示语义值,而不是使用Yacc的“$1”样式的位置表示法。
2.在Lemon中,令牌程序调用解析器。Yacc的操作方式正好相反,解析器调用令牌程序。Lemon方法是可重入和ThreadSafe,而Yacc使用全局变量,因此两者都不是。可重入性对于SQLite尤其重要,因为一些SQL语句对解析器进行递归调用。例如,在解析CREATETABLE语句时,SQLite递归地调用解析器以生成INSERT语句,以便在SQLITE模式桌子。
3.柠檬具有非终端析构函数的概念,可用于在语法错误或其他中止的解析之后回收内存或其他资源。
解析器接口
柠檬不能产生一个完整的工作程序。它只生成几个实现解析器的子程序。本节描述这些子例程的接口。这取决于程序员以适当的方式调用这些子例程,以便生成一个完整的系统。
在程序开始使用柠檬生成的解析器之前,程序必须首先创建解析器.新的解析器创建如下:
void *pParser = ParseAlloc( malloc );
Parsealloc()例程分配并初始化一个新的解析器,并返回指向它的指针。用于表示解析器的实际数据结构是不透明的–其内部结构在调用例程中不可见或不可用。因此,Parsealloc()例程返回指向void的指针,而不是指向特定结构的指针。Parsealloc()例程的唯一参数是指向用于分配内存的子例程的指针。通常这意味着malloc()。
程序使用解析器完成后,它可以通过调用以下函数回收分配的内存
ParseFree(pParser, free);
第一个参数是Parsealloc()返回的同一个指针。第二个参数是指向用于将大容量内存释放回系统的函数的指针。
在使用Parsealloc()分配解析器之后,程序员必须向解析器提供一系列要解析的标记(终端符号)。这是通过对每个令牌调用一次以下函数来实现的:
Parse(pParser