编译原理实战——使用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 编译原理 其实就是 让计算机懂的 “ ...
随机推荐
- GitHub快速搭建个人博客
> 正所谓前人栽树,后人乘凉.> > 感谢[Huxpro](https://github.com/huxpro)提供的博客模板> > [我的的博客](https://fl ...
- JavaScript中new运算符的实现
废话不多说直接进入正题,首先我们需要先知道new运算符到底做了哪些事情,再来模拟它实现这一功能. 1. 建立一个空的Object对象: 2. 把这个空对象用__proto__链接到原型 3. 用app ...
- Nginx 开启支持谷歌Brotli压缩算法
参考链接:https://cloud.tencent.com/developer/article/1501009
- flannel vxlan工作基本原理及常见排障方法
写在前面 最近用kubeadm鼓捣了几个cluster集群测试用,网络用的flannel.因为这些机器都不是纯净的环境(以前部署过其他的k8s或者有一些特别的设置),所以部署起来遇到了很多问题.看了下 ...
- JS实现级联菜单
是首先应该添加两个下拉列表并设置id属性来方便操作: <select id="country"> <option>国家</option> < ...
- 【Trie】Phone List
[题目链接]: https://loj.ac/problem/10049 [题意] 问是否存在一组公共前缀.如果存在输出“NO”,否则输出“YES” [题解] 首先建出Trie树来,然后开始记录所有的 ...
- RabbitMQ安装&简单使用
.什么是RabbitMQ.详见 http://www.rabbitmq.com/. 作用就是提高系统的并发性,将一些不需要及时响应客户端且占用较多资源的操作,放入队列,再由另外一个线程,去异步处理这些 ...
- RedHat7 配置yum源
今天需要搭建一个测试环境,没办法只能找了个Linux服务器,但是之前的其他同事弄过是其他系统的,不是centos的,所以只能自己搞. 合计直接百度,怎么安装docker,结果一直报错,下载失败之类的 ...
- c#Socket通讯
参考http://bbs.cskin.net/thread-326-1-1.html的大神的代码 socket封装 /// <summary> /// 自定义Socket对象 /// &l ...
- 前端性能优化-Vue代码层面
1.v-if 和 v-show 区分使用场景 v-if 是 真正 的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建:也是惰性的:如果在初始渲染时条件为假,则什么也不做 ...