Mysql源码学习――打造专属语法(一)

2014-11-24 10:35:16 · 作者: · 浏览: 1

语法分析——YACC

接触过SQL语句的人都会看过这家或者那家的SQL手册,其语法标准应该是从SQL92开始吧,在看SQL92标准的时候,你会发现里面定义的都是一些巴科斯范式(BNF),就是一种语法定义的标准。不管是牛X哄哄的ORACLE,还是不幸被其收购的Mysql,都会遵循里面的标准语法,当然一些扩展的语法除外,比如今天我们就会扩展一个简单的语法^-^。

OK,大家知道了SQL语法的来源,那么如何进行语法解析呢?YACC!!(Yet Another Compiler Compiler),它的书写方式便是BNF,语法解析的利器。YACC接收来自词法分析阶段分解出来的token,然后去匹配那些BNF。今天哥就来揭开它的面纱。(关于YACC的基本使用方法,大家可以看我上一篇中提到IBM的链接,一定要看懂那个先)

继续上一节的语句SELECT @@VERSION_COMMET,为了简单,这里省去后缀limit 1。Mysql的语法文件是sql_yacc.yy,首先给出这条语句涉及到的语法节点(大体浏览下即可):

query:

END_OF_INPUT

{...}

|| verb_clause

{...}

| verb_clause END_OF_INPUT

{

/* Single query, not terminated. */

YYLIP->found_semicolon= NULL;

}

verb_clause:

statement

| begin

;

statement:

alter

| analyze

| backup

| binlog_base64_event

| call

| change

| check

| checksum

| commit

| create

| deallocate

| delete

| describe

| do

| drop

| execute

| flush

| grant

| handler

| help

| insert

| install

| kill

| load

| lock

| optimize

| keycache

| partition_entry

| preload

| prepare

| purge

| release

| rename

| repair

| replace

| reset

| restore

| revoke

| rollback

| savepoint

| select

| set

| show

| slave

| start

| truncate

| uninstall

| unlock

| update

| use

| xa

;

select:

select_init

{

LEX *lex= Lex;

lex->sql_command= SQLCOM_SELECT;

}

;

select_init:

SELECT_SYM select_init2

| '(' select_paren ')' union_opt

;

select_init2:

select_part2

{

LEX *lex= Lex;

SELECT_LEX * sel= lex->current_select;

if (lex->current_select->set_braces(0))

{

my_parse_error(ER(ER_SYNTAX_ERROR));

MYSQL_YYABORT;

}

if (sel->linkage == UNION_TYPE &&

sel->master_unit()->first_select()->braces)

{

my_parse_error(ER(ER_SYNTAX_ERROR));

MYSQL_YYABORT;

}

}

union_clause

;

select_part2:

{

LEX *lex= Lex;

SELECT_LEX *sel= lex->current_select;

if (sel->linkage != UNION_TYPE)

mysql_init_select(lex);

lex->current_select->parsing_place= SELECT_LIST;

}

select_options select_item_list

{

Select->parsing_place= NO_MATTER;

}

select_into select_lock_type

;

select_item_list:

select_item_list ',' select_item

| select_item

| '*'

{

THD *thd= YYTHD;

Item *item= new (thd->mem_root)

Item_field(&thd->lex->current_select->context,

NULL, NULL, "*");

if (item == NULL)