lex 和 yacc 学习笔记1
来源:互联网 发布:淘宝被保护自助开通 编辑:程序博客网 时间:2024/04/28 20:21
最近想自己写个轻量级的sql的解析器,所以开始学习lex和yacc,并记录其中碰到的主要问题。
首先需要解决的lex和yacc的基本使用的问题,跑通一个最简单的例子。
网上有很多lex和yacc的入门例子,但基本都一样,看完后还是不知道在程序里怎么调用它们来做解析。
主要不清楚的问题有:
a. 如何在lex,yacc和自己的程序间传递数据
b. 如何在自己的程序里调用lex和yacc来解析一个指定的字符串
1. 如何在lex和yacc间传递数据
通过lex中可以的yylval 和yacc中的$n 来相互传递数据。它们的类型可以通过宏#define YYSTYPE MAIL 来指定。 MAIL是我自己定义的一个结构体
typedef struct Mail
{
char title[10];
int num;
char body[50];
} MAIL;
例如
test.l中一个匹配规制如下:
title {showtitle(); strcpy(yylval.title, yytext); return TITLE;}
test.y中一个匹配规则如下:
head: TITLE UNKNOWN NUM {strcpy(mail->title, $1.title);mail->num=$3.num;};
yylval和 $1都是MAIL类型,首先在lex的token解析中把解析到的token值赋给了yylval,然后在yacc的语法分析中可以通过$n来使用这个匹配到的值。
2. 自己的程序如何和yacc还有lex交互
其实主要是和yacc交互。
可以在yacc中定义一个函数,例如:
MAIL *mail;
int parser_do(const char *str, int len, MAIL *m)
{
...
mail = m; //这个mail在上面的例子中用于保存解析结果。
...
}
这个函数是完成一次解析的入口函数,除了传入要解析的字符串与长度外,还传入了用于保存解析结果的数据结构。整个解析过程就是往这个传入的结构体进行填充和修改的过程。
3. 如何在自己的程序里调用yacc和lex来解析一个给定的字符串
输入主要是指给lex模块输入,默认的lex输入buffer为文件buffer,即可以导入一个文件进行解析。但lex本身是支持多种输入方式的。以下是一段示例代码,让lex和yacc来解析一个输入的字符串:
int parser_do(const char *str, int len, MAIL *m)
{
mail = m;
linenum=0;
YY_BUFFER_STATE state = yy_scan_bytes(str,len); //创建了一个给定字符串初始化的输入缓冲
yy_switch_to_buffer(state); //切换到这个输入缓冲
yyparse(); //开始yacc解析(yacc会调用lex做词法分析)
yy_delete_buffer(state); //释放这个新建的输入缓冲
return 0;
}
关于yy_scan_bytes 和其他的输入方式可以查看http://flex.sourceforge.net/manual/Multiple-Input-Buffers.html
这样我们就可以在自己写的程序里面调用这个parser_do方法来解析我们想解析的字符串了。
附录:
本文的代码如下:
test.l
------------------------------------------------------------------------------------------------
%{
#include "stdio.h"
#include "string.h"
#include "main.h"
#include "test.tab.h"
int linenum;
extern int parse_worker(const char *str, int len);
%}
%%
title {showtitle(); strcpy(yylval.title, yytext); return TITLE;}
[/n] {linenum++; return SPACE;}
[0-9]+ { yylval.num= atoi(yytext); return NUM;}
[a-zA-Z][a-zA-Z0-9]*{printf("Var : %s/n",yytext); strcpy(yylval.body, yytext); return STRING;}
[/+/-/*///%] {printf("Op : %s/n",yytext); return OP;}
. {printf("Unknown : %c/n",yytext[0]); return UNKNOWN;}
%%
showtitle()
{
printf("----- Lex Example -----/n");
}
int yywrap()
{
return 1;
}
------------------------------------------------------------------------------------
test.y
----------------------------------------------------------------------------------------
%{
#include
#include
#include
#include "main.h"
MAIL *mail;
typedef YY_BUFFER_STATE;
extern int linenum;
%}
%token SPACE LOF TITLE NUM STRING OP UNKNOWN
%%
mail: head UNKNOWN body
| no;
head: TITLE UNKNOWN NUM { strcpy(mail->title,$1.title); mail->num=$3.num;};
body: STRING {strcpy(mail->body, $1.body);};
no : SPACE|UNKNOWN|OP;
%%
int yyerror(char *msg)
{
printf("error: %s", msg);
return 0;
}
int parser_do(const char *str, int len, MAIL *m)
{
mail = m;
linenum=0;
YY_BUFFER_STATE state = yy_scan_bytes(str,len);
yy_switch_to_buffer(state);
yyparse();
yy_delete_buffer(state);
return 0;
}
---------------------------------------------------------------------------------------------------------
main.h
-----------------------------------------------------------------------------------------------------------
typedef struct Mail
{
char title[10];
int num;
char body[50];
} MAIL;
#define YYSTYPE MAIL
-------------------------------------------------------------------------------------------------------------
main.c
--------------------------------------------------------------------------------------------------------------
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "test.tab.h"
#include "main.h"
int main()
{
char *text = "title 3 hello123";
MAIL mail;
//parse_worker((const char *)text,strlen(text));
parser_do((const char *)text, strlen(text),&mail);
printf("\ntitle:%s num:%d body:%s\n",mail.title, mail.num, mail.body);
return 0;
}
------------------------------------------------------------------------
编译命令
-------------------------------------------------------------------------------
bison -d test.y
flex -t test.l >test.c
gcc -g -o test3 main.c test.c test.tab.c
转载请注明出自高孝鑫的博客
首先需要解决的lex和yacc的基本使用的问题,跑通一个最简单的例子。
网上有很多lex和yacc的入门例子,但基本都一样,看完后还是不知道在程序里怎么调用它们来做解析。
主要不清楚的问题有:
1. 如何在lex和yacc间传递数据
通过lex中可以的yylval 和yacc中的$n 来相互传递数据。它们的类型可以通过宏
typedef struct Mail
{
} MAIL;
例如
test.l中一个匹配规制如下:
title
test.y中一个匹配规则如下:
yylval和 $1都是MAIL类型,首先在lex的token解析中把解析到的token值赋给了yylval,然后在yacc的语法分析中可以通过$n来使用这个匹配到的值。
2. 自己的程序如何和yacc还有lex交互
其实主要是和yacc交互。
可以在yacc中定义一个函数,例如:
MAIL *mail;
int parser_do(const char *str, int len, MAIL *m)
{
...
mail = m;
...
}
这个函数是完成一次解析的入口函数,除了传入要解析的字符串与长度外,还传入了用于保存解析结果的数据结构。整个解析过程就是往这个传入的结构体进行填充和修改的过程。
3. 如何在自己的程序里调用yacc和lex来解析一个给定的字符串
输入主要是指给lex模块输入,默认的lex输入buffer为文件buffer,即可以导入一个文件进行解析。但lex本身是支持多种输入方式的。以下是一段示例代码,让lex和yacc来解析一个输入的字符串:
int parser_do(const char *str, int len, MAIL *m)
{
}
关于yy_scan_bytes 和其他的输入方式可以查看http://flex.sourceforge.net/manual/Multiple-Input-Buffers.html
这样我们就可以在自己写的程序里面调用这个parser_do方法来解析我们想解析的字符串了。
附录:
本文的代码如下:
test.l
------------------------------------------------------------------------------------------------
%{
#include "stdio.h"
#include "string.h"
#include "main.h"
#include "test.tab.h"
int linenum;
extern int parse_worker(const char *str, int len);
%}
%%
title
[/n]
[0-9]+
[a-zA-Z][a-zA-Z0-9]*
[/+/-/*///%]
.
%%
showtitle()
{
printf("----- Lex Example -----/n");
}
int yywrap()
{
return 1;
}
------------------------------------------------------------------------------------
test.y
----------------------------------------------------------------------------------------
%{
#include
#include
#include
#include "main.h"
MAIL *mail;
typedef YY_BUFFER_STATE;
extern int linenum;
%}
%token SPACE LOF TITLE NUM STRING OP UNKNOWN
%%
mail: head UNKNOWN body
head: TITLE UNKNOWN NUM { strcpy(mail->title,$1.title); mail->num=$3.num;};
body: STRING {strcpy(mail->body, $1.body);};
no : SPACE|UNKNOWN|OP;
%%
int yyerror(char *msg)
{
}
int parser_do(const char *str, int len, MAIL *m)
{
}
---------------------------------------------------------------------------------------------------------
main.h
-----------------------------------------------------------------------------------------------------------
typedef struct Mail
{
} MAIL;
#define YYSTYPE MAIL
-------------------------------------------------------------------------------------------------------------
main.c
--------------------------------------------------------------------------------------------------------------
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "test.tab.h"
#include "main.h"
int main()
{
}
------------------------------------------------------------------------
编译命令
-------------------------------------------------------------------------------
bison -d test.y
flex -t test.l >test.c
gcc -g -o test3 main.c test.c test.tab.c
转载请注明出自高孝鑫的博客
0 0
- lex 和 yacc 学习笔记1
- lex 和 yacc 学习…
- lex 和 yacc 学习…
- lex 和 yacc 学习…
- lex 和 yacc 学习…
- 【1】.thinking in java 学习笔记
- WebService AXIS 学习笔记
- QTP 学习笔记
- Lex和Yacc使用学习笔记(一)
- Lex和Yacc使用学习笔记(二)
- Flash AS3 学习1 - 按钮
- Linux 学习笔记【1】
- Java学习笔记18 ArrayList 和Linke…
- 学习笔记 二
- qtopia 学习笔记
- qtopia 学习笔记
- OpenCV 学习笔记
- iCloud 学习笔记
- Mysql innodb auto_incr…
- 通过cat 数据文件来合并 myisam表
- Innodb Architecture an…
- 黑马程序员——OC基础@property语法详解
- 关于图处理的数据库 和 工具
- lex 和 yacc 学习笔记1
- lex 和 yacc 学习…
- mysql命令行工具的编辑技巧
- git 推送分支
- Mysql 学习小记1
- mysql实际使用过程中碰到的一些有…
- 关于mysql query cache和memcached…
- windows下编译bison + f…
- 用cmake 编译 bison和flex