Closed vieyahn2017 closed 10 months ago
Yacc文件如下:
%{
#include <stdio.h>
%}
%token NAME NUMBER
%left '+' '-'
%start statement
%%
statement : NAME '=' expression
| expression{printf("=%d\n", $1);}
;
expression : expression '+' NUMBER{$$ = $1 + $3;}
| expression '-' NUMBER{$$ = $1 - $3;}
| NUMBER {$$ = $1;}
;
%%
main()
{
yyparse();
}
yyerror(s)
char *s;
{
printf("%s\n",s);
}
localhost:/yh1/3 # vi cal.y localhost:/yh1/3 # bison -d cal.y localhost:/yh1/3 # ll total 48 -rw-------. 1 root root 40510 Jan 18 03:10 cal.tab.c -rw-------. 1 root root 2565 Jan 18 03:10 cal.tab.h -rw-------. 1 root root 359 Jan 18 03:10 cal.y
Lex文件如下:
%{
/*cal */
#include "cal.tab.h"
extern int yylval;
%}
%%
[0-9]+ {yylval=atoi(yytext);return NUMBER;}
[ \t];
\n return 0;
. return yytext[0];
%%
int yywrap()
{
return 1;
}
用法: flex cal.l gcc lex.yy.c cal.tab.c -o calc
localhost:/yh1/3 # flex cal.l localhost:/yh1/3 # ll total 96 -rw-------. 1 root root 181 Jan 18 03:11 cal.l -rw-------. 1 root root 40510 Jan 18 03:10 cal.tab.c -rw-------. 1 root root 2565 Jan 18 03:10 cal.tab.h -rw-------. 1 root root 359 Jan 18 03:10 cal.y -rw-------. 1 root root 44462 Jan 18 03:12 lex.yy.c
有警告
localhost:/yh1/3 # gcc lex.yy.c cal.tab.c -o calc
cal.tab.c: In function ‘yyparse’:
cal.tab.c:1018:16: warning: implicit declaration of function ‘yylex’ [-Wimplicit-function-declaration]
yychar = yylex ();
^~~~~
cal.tab.c:1177:7: warning: implicit declaration of function ‘yyerror’; did you mean ‘yyerrok’? [-Wimplicit-function-declaration]
yyerror (YY_("syntax error"));
^~~
yyerrok
cal.y: At top level:
cal.y:16:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main()
^~~~
cal.y:21:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
yyerror(s)
^~~
测试 localhost:/yh1/3 # ./calc 9+4-5 =8 localhost:/yh1/3 # ./calc dsds syntax error
结束语
在PG中,也通过Lex和Yacc的配合使用进行SQL语句的词法分析和语法分析。在PG源码中,包含scan.l和gram.y两个文件,并且已经预生成了对应的C文件scan.c和gram.c。如果重新修改scan.l和gram.y,那么需要在编译PG的时候,就会重新生成scan.c和gram.c
各数据库使用的语法分析方式 sqlite :lemo (LR) pg:yacc (LR) opengauss:yacc (LR) mysql:bison (LR) h2db:递归下降法
语法分析实战 使用bison解析删表语句 : drop table [if exists] a;
为了简单起见,使用首字母代替TOKEN,并且假设表名也是单字符的。
drop table [if exists] a; => d t [i e] a;
步骤
1)建立parse_drop_table.y文件
输入如下代码:
%{
#include<stdio.h>
int yylex();
void yyerror(const char *);
%}
%%
sqls: sql
| sql sqls;
sql: drop_table_header if_exists table_name ';' '\n' {printf("%d, %c\n", $2, $3);}
| '\n' {printf("empty sql!\n");}
;
drop_table_header: 'd' 't';
if_exists: 'i' 'e' {$$=1;}
| {$$=0;}
;
table_name: 'a' {$$='a';}
| 'b' {$$='b';}
;
%%
int yylex() {
return getchar();
}
void yyerror(const char *errmsg) {
fprintf(stderr, "%s\n", errmsg);
}
int main() {
return yyparse();
}
2)使用bison处理语法文件,得到语法解析c文件,一般是后缀为tab.c的文件
bison parse_drop_table.y 3)使用gcc编译语法解析c文件
gcc parse_drop_table.tab.c 4)测试
执行:./a.out 输入:dtiea; 输出:1, a 输入:dtb; 输出:0, b 输入:dta; 输出:0, a 发现可以正常处理简化后的drop table语句,并得到if_exists和table_name。
lex - yacc