编译原理实战——使用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进行编写一个有一定词汇量的词法分析器的更多相关文章

  1. 学了编译原理能否用 Java 写一个编译器或解释器?

    16 个回答 默认排序​ RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...

  2. 编译原理(简单自动词法分析器LEX)

    编译原理(简单自动词法分析器LEX)源程序下载地址:  http://files.cnblogs.com/files/hujunzheng/%E6%B1%87%E7%BC%96%E5%8E%9F%E7 ...

  3. Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

    catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...

  4. 实战WEB 服务器(JAVA编写WEB服务器)

    实战WEB 服务器(JAVA编写WEB服务器) 标签: web服务服务器javawebsockethttp服务器 2010-04-21 17:09 11631人阅读 评论(24) 收藏 举报  分类: ...

  5. Go 编译原理实现计算器(测试驱动讲解)

    本文不需要你掌握任何编译原理的知识. 只需要看懂简单的golang语言即可, 完整的代码示例在GIT, 代码是从writing an interpreter in go这本书抽取了简单的部分出来, 如 ...

  6. php中foreach源码分析(编译原理)

    php中foreach源码分析(编译原理) 一.总结 编译原理(lex and yacc)的知识 二.php中foreach源码分析 foreach是PHP中很常用的一个用作数组循环的控制语句.因为它 ...

  7. 如何编写一个WebPack的插件原理及实践

    _ 阅读目录 一:webpack插件的基本原理 二:理解 Compiler对象 和 Compilation 对象 三:插件中常用的API 四:编写插件实战 回到顶部 一:webpack插件的基本原理 ...

  8. MOOC 编译原理笔记(一):编译原理概述以及程序设计语言的定义

    编译原理概述 什么是编译程序 编译程序指:把某一种高级语言程序等价地转换成另一张低级语言程序(如汇编语言或机器代码)的程序. 高级语言程序-翻译->机器语言程序-运行->结果. 其中编译程 ...

  9. 前端编译原理 简述-jison

    最近几年的项目技术难点都和编译原理,抽象语法树,代码编辑器 有关系.现在时间有点空,先从基础了解起来,让有些交互和提示能够更智能些. 编译原理-Parser    编译原理 其实就是 让计算机懂的 “ ...

随机推荐

  1. flask上下文管理相关 - threading.local 以及原理剖析

    threading.local 面向对象相关: setattr/getattr class Foo(object): pass obj = Foo() obj.x1 = 123 # object.__ ...

  2. web漏洞

    *参考网站 https://cxsecurity.com/ https://www.exploit-db.com/ https://www.seebug.org/ http://www.securit ...

  3. 解决SpringMVC拦截静态资源的问题

    优雅REST风格的资源URL不希望带 .html 或 .do 等后缀.由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往 ...

  4. jquery清除元素的点击事件

    $("#id").css("pointer-events", "none");

  5. vue-cli3创建vue项目之vue.config.js配置

    module.exports = { // 基本路径 publicPath: '/', // 输出文件目录 outputDir: 'dist', // eslint-loader 是否在保存的时候检查 ...

  6. Linux 如何找到100M以上的大文件

    find / -type f -size +100000k |xargs ls -lh|awk '{print $9 ":" $5}'

  7. C#中异步编程异常的处理方式

    异步编程异常处理 在同步编程中,一旦出现错误就会抛出异常,我们可以使用try-catch来捕捉异常,未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.但是对于异步编程来说,异常处理一直 ...

  8. [转帖]ECC公钥格式详解

    ECC公钥格式详解 https://www.cnblogs.com/xinzhao/p/8963724.html 本文首先介绍公钥格式相关的若干概念/技术,随后以示例的方式剖析DER格式的ECC公钥, ...

  9. ESXi 虚拟机 提示 无法打开本地虚拟机的 xxx.vmx 的本地管道的 问题解决.

    1. 今天同事与我联系, 说一个虚拟机出现连不上, vcenter控制台关闭虚拟机之后 再次打开报错: 2. 自己最开始的解决方法 移除虚拟机, 进入服务器的datastore 重新注册, 结果发现问 ...

  10. Mac终端 bash和zsh切换方法

    切换到bash chsh -s /bin/bash 切换到zsh chsh -s /bin/zsh 终端重启后生效