一、pg语法简介
1.1 语法文件结构
语法.y文件和词法.l文件结构差不多,也是通过 %%分成了三个部分: 声明部分、语法规则部分、C代码部分。
src/backend/parser/gram.y
#### 声明部分
%{
C代码 头文件,变量声明等(此范围内的内容原样输出到文件中)
#include "postgres.h"
...
%}
#变量声明
%union
{
core_YYSTYPE core_yystype;
/* these fields must match core_YYSTYPE: */
int ival;
char *str;
const char *keyword;
char chr;
...
}
#类型声明
%type <node> stmt toplevel_stmt schema_stmt routine_body_stmt
...
#token 关键字声明
%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
...
#优先级声明
%left UNION EXCEPT
%left INTERSECT
%left OR
%left AND
%right NOT
...
%%
####语法部分
parse_toplevel:
stmtmulti
{
pg_yyget_extra(yyscanner)->parsetree = $1;
}
| ...
;
...
%%
#### C 代码 (此段内容原样输出到文件中)
...
static RawStmt *
makeRawStmt(Node *stmt, int stmt_location)
{
RawStmt *rs = makeNode(RawStmt);
rs->stmt = stmt;
rs->stmt_location = stmt_location;
rs->stmt_len = 0; /* might get changed later */
return rs;
}
...
1.2 语法规则
找一个简单的语法规则,比如CallStmt
二、 简单语句分析
2.1 语法分析入口
src/backend/tcop/postgres.c
List *
pg_parse_query(const char *query_string)
{
List *raw_parsetree_list;
...
raw_parsetree_list = raw_parser(query_string, RAW_PARSE_DEFAULT);
...
return raw_parsetree_list;
}
src/backend/parser/parser.c
List *
raw_parser(const char *str, RawParseMode mode)
{
core_yyscan_t yyscanner;
base_yy_extra_type yyextra;
int yyresult;
...
/* Parse! */
yyresult = base_yyparse(yyscanner);
...
if (yyresult) /* error */
return NIL;
return yyextra.parsetree;
}
在语法.y文件中指定了name-prefix,
src/backend/parser/gram.y
%name-prefix="base_yy"
所以通过bison生成的语法解析文件src/backend/parser/gram.c
中函数都是base_yy开头
/* Substitute the variable and function names. */
#define yyparse base_yyparse
#define yylex base_yylex
#define yyerror base_yyerror
#define yydebug base_yydebug
#define yynerrs base_yynerrs
...
/*----------.
| yyparse. |
`----------*/
int
yyparse (core_yyscan_t yyscanner)
{
/* The lookahead symbol. */
int yychar;
...
}
所以yyparse就是base_yyparse。
2.2 简单的Call命令
比如执行如下sql
# call test();
根据语法规则生成的语法树如下