基础知识
首先 gram语法分析在pg中是配合词法解析的
在生成文件中 gram.y -> gram.c
存在一个栈 进行移进 规约 shift/reduce
使用lex 读取一个 一个关键字 入栈 这个过程叫移进过程,当发现有token可以进行规约 reduce的时候会把token出栈 换成规约后的标识符 重新入栈。
一般来说:已经在gram.y中定义的 token reduce可能少,除非到了语法最后步骤。常见的过程中 规约的 一般是 标识符.
像语句 CREATE TABLE t(a int);
一般来讲 CREATE TABLE 不会产生reduce 当我们读到 “t” 这个字符的时候 由于 gram.y含有该语法 ,假如他的定义是这样:
CREATE TABLE table_name …
{
}
table_name:
IDENT { $$=$1}
当 lex 读取到 “t”的时候 就会识别成 IDENT ,后续去gram.y一搜索 发现 IDENT 可以规约成 table_name 所以规约就产生了,以此类推。。。
对于gram.y的定义,常用的 (详细的学习请搜索bison语法或者yacc语法等等,这里只基于pg源码 说常用的 便于你快速阅读pg):
第一段:
(截取了部分):一般用来定义一些用到的 常量 结构体 还有 引入.h文件 即inclue。
%{
#include “postgres.h”
#include <ctype.h>
#include <limits.h>
#include “access/tableam.h”
#include “catalog/index.h”
#include “catalog/namespace.h”
#include “catalog/pg_am.h”
#define YYLLOC_DEFAULT(Current, Rhs, N)
do {
if ((N) > 0)
(Current) = (Rhs)[1];
else
(Current) = (-1);
} while (0)
#define YYMALLOC palloc
#define YYFREE pfree
/* Private struct for the result of import_qualification production */
typedef struct ImportQual
{
ImportForeignSchemaType type;
List *table_names;
} ImportQual;
/* Private struct for the result of opt_select_limit production */
typedef struct SelectLimit
{
Node *limitOffset;
Node *limitCount;
LimitOption limitOption;
} SelectLimit;
/* ConstraintAttributeSpec yields an integer bitmask of these flags: */
#define CAS_NOT_DEFERRABLE 0x01
#define CAS_DEFERRABLE 0x02
#define CAS_INITIALLY_IMMEDIATE 0x04
#define CAS_INITIALLY_DEFERRED 0x08
%}
第二段
1 开始定义我们的type
即一个语句的标签 像什么 createTableStmt 这种;
代表一个类型,假如如上举例,那么table_name 你就可以定义成:
%type 《str》 table_name
即可以认为 我需要传入一个字符串 这里看你想以什么类型传入。
%type stmt toplevel_stmt schema_stmt routine_body_stmt
AlterEventTrigStmt AlterCollationStmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt
AlterOperatorStmt AlterTypeStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt
AlterCompositeTypeStmt AlterUserMappingStmt
2 定义token 即关键字
这里就是可以定义我们所需的token,像 CREATE TABLE 都需要定义 且要按照 字母顺序排序
/* Begin - BUG:M0000079 /
%token MODE_PLISQL_EXPR
%token MODE_PLISQL_ASSIGN1
%token MODE_PLISQL_ASSIGN2
%token MODE_PLISQL_ASSIGN3
/ End - BUG:M0000079 */
3 这里是定义一些 优先级 或者 < > 类似的定义 运算优先级定义
/* Precedence: lowest to highest /
%nonassoc SET / see relation_expr_opt_alias /
%left UNION EXCEPT
%left INTERSECT
%left OR
%left AND
%right NOT
%nonassoc IS ISNULL NOTNULL / IS sets precedence for IS NULL, etc */
%nonassoc ‘<’ ‘>’ ‘=’ LESS_EQUALS GREATER_EQUALS NOT_EQUALS
%nonassoc BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
4 规则段
这里开始正式写语法,像函数的互相调用一样 语法中 会包含一些其他语法:
例如:
1 CreateRoleStmt 语法中包含了OptRoleList
2 而OptRoleList 又包含了自己的语法内容
3 在OptRoleList中 包含的 CreateOptRoleElem
4 CreateOptRoleElem 又包含了自己的语法内容 如下所示:
(这里我把他们拼接到一起了 ,在源码中 大多下级标签有很多语法共用,不一定会写在一起。)
CreateRoleStmt:
CREATE ROLE RoleId opt_with OptRoleList
{
CreateRoleStmt *n = makeNode(CreateRoleStmt);
n->stmt_type = ROLESTMT_ROLE;
n->role = $3;
n->options = $5;
$$ = (Node *)n;
}
;
OptRoleList:
OptRoleList CreateOptRoleElem { KaTeX parse error: Can't use function '$' in math mode at position 12: = lappend($̲1, $2); } | … = NIL; }
;
CreateOptRoleElem:
AlterOptRoleElem { KaTeX parse error: Can't use function '$' in math mode at position 4: = $̲1; } /* The … = makeDefElem(“sysid”, (Node *)makeInteger($2), @1);
}
| ADMIN role_list
{
KaTeX parse error: Can't use function '$' in math mode at position 40: …bers", (Node *)$̲2, @1); } … = makeDefElem(“rolemembers”, (Node *)$2, @1);
}
;
上述就是基本的语法定义。
那么语法中的结构体 是什么意思呢?
基本知识: $$ 代表冒号左边的字符。 $1代表 冒号 : 右边 第一个字符 $2第二个 以此类推。。
如:CreateUserStmt: 语句
其中 CreateRoleStmt是一个自定义的结构体,一般在parsenodes.h 文件中 如下所示:所以你所需要的值将会在此 被赋值到你所需的结构体中 供后续使用
CreateUserStmt:
{ CreateRoleStmt *n = makeNode(CreateRoleStmt);
n->stmt_type = ROLESTMT_USER;
n->role = $3;
n->options = $5;
$$ = (Node *)n;
}
;
parsenodes.h :
typedef struct CreateRoleStmt
{ NodeTag type;
RoleStmtType stmt_type; /* ROLE/USER/GROUP */
char *role; /* role name */
List *options; /* List of DefElem nodes */
} CreateRoleStmt;
第三段
一般是 保留关键字和非保留关键字(定义可自行百度)等一系列的定义,在添加新token的时候 也是需要在此按照顺序添加的。
unreserved_keyword:
ABORT_P
| ABSOLUTE_P
| ACCESS
| ACTION
| ADD_P
| ADMIN
| AFTER
到此一个粗略的 pg语法gram.y文件就已经介绍完毕!!
后续的:语法出来流程有时间 我会继续更新。。。。