编译原理实战——使用Lex/Flex进行编写一个有一定词汇量的词法分析器
编译原理实战——使用Lex/Flex进行编写一个有一定词汇量的词法分析器
by steve yu 2019.9.30
参考文档:1.https://blog.csdn.net/mist14/article/details/48641349
2.https://wenku.baidu.com/view/1c6398903868011ca300a6c30c2259010202f3a4.html
1.Flex工具的概述
Flex工具是生成C语言的工具,我们在日常生活中,如果直接使用C语言进行编写词法分析器,会嵌套太多的if语句,或者switch语句,那么会使我们的代码出现混乱(可读性较差),于是,Flex工具,可以让我们直接使用正规式,进行词法分析。
2.Flex的安装与使用(CentOS 系统为例)
yum intsall flex -y
3.“.l”文件的概述
我们安装完flex工具,可以编写一个文件,这个文件可以通过flex编译成C程序,进行词法分析。
flex的语法被分为3个部分:
{definitions}
%%
{rules}
%%
{user subroutines}
defnitions
这部分由正则式组成,我们在正规式的编写中,有这样语法规则。
1. INT [1-9][0-9]*|[0] /*整数类型,0或不以0开头的由0-9组成的字符串*/
2. FLOAT [0-9]*[.][0-9]+([eE][+-]?[0-9]*|[0])?f? /*浮点数格式*/
3. LP \( /*一个左圆括号*/
rules
rules规则部分语法如下:
{LABEL1} |
{LABLE2} |
...
{
/*TODO*/
}
TODO部分是告诉编译器在匹配到字符串后需要做什么。
{INT} {
printf("Pick up an integer, value is %d", atoi(yytext));
printf("Pick up an integer, value is %s", yytext);
}
user subroutines
此处主要是放置用户需要执行的c语言代码。他们会被原封不动地加入到lex.yy.c文件的末尾。
这里一般用来存放main函数,详细会在后面说明。
4.文档(这边以C程序的关键字为例)
数据类型关键字(12个)
char | 1 |
double | 2 |
enum | 3 |
float | 4 |
int | 5 |
long | 6 |
short | 7 |
signed | 8 |
struct | 9 |
union | 10 |
unsigned | 11 |
void | 12 |
控制语句关键字(12个)
for | 13 |
do | 14 |
while | 15 |
break | 16 |
continue | 17 |
if | 18 |
else | 19 |
goto | 20 |
switch | 21 |
case | 22 |
default | 23 |
return | 24 |
存储类型关键字(4个)
auto | 25 |
extern | 26 |
register | 27 |
static | 28 |
其他关键字
const | 29 |
sizeof | 30 |
typedef | 31 |
volatile | 32 |
*非关键字其他
INT_DEX | 33 | [1-9][0-9]*|[0] |
INT_HEX | 34 | [0][Xx][1-9a-fA-F][0-9a-fA-F]*|[0] |
INT_OCT | 35 | [0][1-7][0-7]*|[0] |
SEMI | 36 | ; |
COMMA | 37 | , |
QUO | 38 | ' |
DOUQUO | 39 | " |
EQ | 40 | = |
PLUS | 41 | + |
MIN | 42 | - |
MULTI | 43 | * |
DIV | 44 | / |
AND | 45 | && |
OR | 46 | || |
SIAND | 47 | & |
SIOR | 48 | | |
LP | 49 | ( |
RP | 50 | ) |
LB | 51 | [ |
RB | 52 | ] |
LC | 53 | { |
RC | 54 | } |
SPACE | 55 | \n\r\t |
ID | 56 | [a-zA-Z][a-zA-Z0-9]* |
DOU | 57 | {INT_DEX}[.][0-9]+ |
由于中文是根据编码不同的二进制安全,所以等同非关键字即可处理。(应该全了,不全可以再提醒我补齐)
5.编写.l文件分析代码(这边手写l文件调试了一下午)
/**
analyse_c.l
@author steve yu
@date 2019/9/30
*/
%{
#include "stdio.h"
#include "stdlib.h"
%}
CHAR char
DOUBLE double
ENUM enum
FLOAT float
INT int
LONG long
SHORT short
SIGNED signed
STRUCT struct
UNION union
UNSIGNED unsigned
VOID void
FOR for
DO do
WHILE while
BREAK break
CONTINUE continue
IF if
ELSE else
GOTO goto
SWITCH switch
CASE case
DEFAULT default
RETURN return
AUTO auto
EXTERN extern
REGISTER register
STATIC static
CONST const
SIZEOF sizeof
TYPEDEF typedef
VOLATILE volatile
INT_DEX [1-9][0-9]*|[0]
INT_HEX [0][Xx][1-9a-fA-F][0-9a-fA-F]*|[0]
INT_OCT [0][1-7][0-7]*|[0]
SEMI ;
COMMA ,
QUO '
DOUQUO \"
EQ =
PLUS \+
MIN -
MULTI \*
DIV \/
AND &&
OR \|\|
SLAND &
SLOR \|
LP \(
RP \)
LB \[
RB \]
LC \{
RC \}
SPACE [ \n\r\t]
ID [a-zA-Z][a-zA-Z0-9]*
DOU {INT_DEX}[.][0-9]+
%%
{CHAR} {
printf("%s 1\n",yytext);
}
{DOUBLE} {
printf("%s 2\n",yytext);
}
{ENUM} {
printf("%s 3\n",yytext);
}
{FLOAT} {
printf("%s 4\n",yytext);
}
{INT} {
printf("%s 5\n",yytext);
}
{LONG} {
printf("%s 6\n",yytext);
}
{SHORT} {
printf("%s 7\n",yytext);
}
{SIGNED} {
printf("%s 8\n",yytext);
}
{STRUCT} {
printf("%s 9\n",yytext);
}
{UNION} {
printf("%s 10\n",yytext);
}
{UNSIGNED} {
printf("%s 11\n",yytext);
}
{VOID} {
printf("%s 12\n",yytext);
}
{FOR} {
printf("%s 13\n",yytext);
}
{DO} {
printf("%s 14\n",yytext);
}
{WHILE} {
printf("%s 15\n",yytext);
}
{BREAK} {
printf("%s 16\n",yytext);
}
{CONTINUE} {
printf("%s 17\n",yytext);
}
{IF} {
printf("%s 18\n",yytext);
}
{ELSE} {
printf("%s 19\n",yytext);
}
{GOTO} {
printf("%s 20\n",yytext);
}
{SWITCH} {
printf("%s 21\n",yytext);
}
{CASE} {
printf("%s 22\n",yytext);
}
{DEFAULT} {
printf("%s 23\n",yytext);
}
{RETURN} {
printf("%s 24\n",yytext);
}
{AUTO} {
printf("%s 25\n",yytext);
}
{EXTERN} {
printf("%s 26\n",yytext);
}
{REGISTER} {
printf("%s 27\n",yytext);
}
{STATIC} {
printf("%s 28\n",yytext);
}
{CONST} {
printf("%s 29\n",yytext);
}
{SIZEOF} {
printf("%s 30\n",yytext);
}
{TYPEDEF} {
printf("%s 31\n",yytext);
}
{VOLATILE} {
printf("%s 32\n",yytext);
}
{INT_DEX} {
printf("%s 33\n",yytext);
}
{INT_HEX} {
printf("%s 34\n",yytext);
}
{INT_OCT} {
printf("%s 35\n",yytext);
}
{SEMI} {
printf("%s 36\n",yytext);
}
{COMMA} {
printf("%s 37\n",yytext);
}
{QUO} {
printf("%s 38\n",yytext);
}
{DOUQUO} {
printf("%s 39\n",yytext);
}
{EQ} {
printf("%s 40\n",yytext);
}
{PLUS} {
printf("%s 41\n",yytext);
}
{MIN} {
printf("%s 42\n",yytext);
}
{MULTI} {
printf("%s 43\n",yytext);
}
{DIV} {
printf("%s 44\n",yytext);
}
{AND} {
printf("%s 45\n",yytext);
}
{OR} {
printf("%s 46\n",yytext);
}
{SLAND} {
printf("%s 47\n",yytext);
}
{SLOR} {
printf("%s 48\n",yytext);
}
{LP} {
printf("%s 49\n",yytext);
}
{RP} {
printf("%s 50\n",yytext);
}
{LB} {
printf("%s 51\n",yytext);
}
{RB} {
printf("%s 52\n",yytext);
}
{LC} {
printf("%s 53\n",yytext);
}
{RC} {
printf("%s 54\n",yytext);
}
{SPACE} {
}
{ID} {
printf("%s 56\n",yytext);
}
{DOU} {
printf("%s 57\n",yytext);
}
%%
/*necessary func*/
int yywrap(){
return 1;
}
/*main func*/
int main(int argc,char** argv){
if(argc>1){
if(!(yyin=fopen(argv[1],"r"))){
perror(argv[1]);
return 1;
}
}
while(yylex());
return 0;
}
6.编译并测试
flex analyse.l
gcc lex.yy.c
./a.out test
在这个test文本文件代码如下
int main(){
int a=0;
if(a==6) a=a+1;
else return -1;
return 0;
}
分析结果如下
int 5
main 56
( 49
) 50
{ 53
int 5
a 56
= 40
0 33
; 36
if 18
( 49
a 56
= 40
= 40
6 33
) 50
a 56
= 40
a 56
+ 41
1 33
; 36
else 19
return 24
- 42
1 33
; 36
return 24
0 33
; 36
} 54
编译原理实战——使用Lex/Flex进行编写一个有一定词汇量的词法分析器的更多相关文章
- 学了编译原理能否用 Java 写一个编译器或解释器?
16 个回答 默认排序 RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...
- 编译原理(简单自动词法分析器LEX)
编译原理(简单自动词法分析器LEX)源程序下载地址: http://files.cnblogs.com/files/hujunzheng/%E6%B1%87%E7%BC%96%E5%8E%9F%E7 ...
- Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用
catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...
- 实战WEB 服务器(JAVA编写WEB服务器)
实战WEB 服务器(JAVA编写WEB服务器) 标签: web服务服务器javawebsockethttp服务器 2010-04-21 17:09 11631人阅读 评论(24) 收藏 举报 分类: ...
- Go 编译原理实现计算器(测试驱动讲解)
本文不需要你掌握任何编译原理的知识. 只需要看懂简单的golang语言即可, 完整的代码示例在GIT, 代码是从writing an interpreter in go这本书抽取了简单的部分出来, 如 ...
- php中foreach源码分析(编译原理)
php中foreach源码分析(编译原理) 一.总结 编译原理(lex and yacc)的知识 二.php中foreach源码分析 foreach是PHP中很常用的一个用作数组循环的控制语句.因为它 ...
- 如何编写一个WebPack的插件原理及实践
_ 阅读目录 一:webpack插件的基本原理 二:理解 Compiler对象 和 Compilation 对象 三:插件中常用的API 四:编写插件实战 回到顶部 一:webpack插件的基本原理 ...
- MOOC 编译原理笔记(一):编译原理概述以及程序设计语言的定义
编译原理概述 什么是编译程序 编译程序指:把某一种高级语言程序等价地转换成另一张低级语言程序(如汇编语言或机器代码)的程序. 高级语言程序-翻译->机器语言程序-运行->结果. 其中编译程 ...
- 前端编译原理 简述-jison
最近几年的项目技术难点都和编译原理,抽象语法树,代码编辑器 有关系.现在时间有点空,先从基础了解起来,让有些交互和提示能够更智能些. 编译原理-Parser 编译原理 其实就是 让计算机懂的 “ ...
随机推荐
- sizeof与strcpy的区别
转自:http://c.biancheng.net/view/342.html 表面上看strcpy和sizeof都是求字符串的长度,但是二者却存在着许多不同之处及本质区别 strlen是一个函数,用 ...
- JQuery Validate - 自定义js验证
(function (window, $) { var validResult = {}; var checkObjs = { /** * 检查输入的一串字符是否全部是数字 * 输入:str Stri ...
- mongodb 连接后无法使用 发现已经有进程在运行
mongod 命令执行发现已经有进程在运行mongod数据库--errno:48 Address already in use for socket: 0.0.0.0:27017 错误信息: list ...
- visualgdb 调试arm
目录 visualgdb 调试arm 没有ssh的开发板使用telnet 使用telent的gdbserver title: visualgdb 调试arm date: 2019/11/19 10:0 ...
- 《Data Structures and Algorithm Analysis in C》学习与刷题笔记
<Data Structures and Algorithm Analysis in C>学习与刷题笔记 为什么要学习DSAAC? 某个月黑风高的夜晚,下班的我走在黯淡无光.冷清无人的冲之 ...
- 深度学习-LeCun、Bengio和Hinton的联合综述
深度学习其实要入门也很简单,不要被深度学习.卷积神经网络CNN.循环神经网络RNN等某些“高大上”的专有名词所吓到或被忽悠,要相信大道至简,一个高中生只要愿意学也完全可以入门级了解并依赖一些成熟的Te ...
- 什么是Java多线程?
第五阶段 多线程 前言: 一个场景:周末,带着并不存在的女票去看电影,无论是现场买票也好,又或是手机买票也好,上一秒还有位置,迟钝了一下以后,就显示该座位已经无法选中,一不留神就没有座位了,影院的票是 ...
- Oracle的查询-分页查询
--Oracle中的分页 --rownum行号:当我们做select操作时候 --每查询出一行记录,就在该行加上一个行号 --行号从1开始,一次递增,不能跳着走 ----emp表工资倒叙排列后,每页5 ...
- SpingMVC使用小结
- 如何判断你的windows系统是32位还是64位?
[学习笔记] 如 何判断你的windows系统是32位还是64位? java -version时,如果没有64就是32位的.eclipse.ini中如果没有64,就是32位的.但是我们的ini文件里面 ...