编译原理实战——使用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 编译原理 其实就是 让计算机懂的 “ ...
随机推荐
- 利用Gabor变换法分析纹理图像 matlab代码实现
Gabor变化属于加窗傅里叶变换,Gabor函数可以在频域不同尺度.不同方向上提取相关的特征.Gabor函数与人眼的生物作用相仿,所以经常用于纹理识别上,并取得了较好的效果. 二维Gobor滤波函数: ...
- 字符编码笔记:ASCII,Unicode 和 UTF-8(理解)
1.ASCII 码 美国制定的字符编码规则,对英语字符与二进制位之间的关系做了统一规定. 占一个字节,8 位,最多可表示 2^8 = 256 种状态(字符) 实际共有 128 个字符,只占用一个字节的 ...
- CentOS 7 利用qemu模拟ARM vexpress A9开发板
听说qemu用于仿真arm很不错,今日就来试了一把.由于刚刚开始,了解的并不多.本文仅仅记录Qemu装载Linux kernel和busybox根文件系统的过程.后续将会深入了解仿真的其他内容. 先上 ...
- shell中得到当下路径所有文件夹名称
方法1: for dir in $(ls -al ./|awk '/^d/ {print $NF}') do echo $dir done 方法2: for dir in $(ls ./) d ...
- SpringBoot 使用WebSocket打造在线聊天室
教程: https://www.jianshu.com/p/55cfc9fcb69e https://wallimn.iteye.com/blog/2425666 关于websocket基础普及见:h ...
- centos7.2 安装Lnmp
1. 安装编译工具及库文件 yum install -y make apr* autoconf automake curl \ curl-devel gcc gcc-c++ cmake gtk+-d ...
- Python中几个必须知道的函数
Python中自带了几个比较有意思的函数,一般在面试或者笔试基础的时候会问到,其中3个就是map.filter.reduce函数. 1.map(function, iterable) 它第一个要传的元 ...
- 用bisect来管理已排序的序列
bisect 模块包含两个主要函数,bisect 和 insort,两个函数都利用二分查找算法来在有序序列中查找或插入元素. 2.8.1 用bisect来搜索 bisect(haystack, nee ...
- react的状态管理
近两年前端技术的发展如火如荼,大量的前端项目都在使用或转向 Vue 和 React 的阵营, 由前端渲染页面的单页应用占比也越来越高,这就代表前端工作的复杂度也在直线上升,前端页面上展示的信息越来越多 ...
- 由[].slice.call()引发的思考
由[].slice.call()引发的思考 经常看到大家用[].slice.call()或者Array.prototype.slice.call(): 我一直是一知半解的,今天算是基本弄清楚了, ...