Flex 词法分析实验实现(电子科技大学编译技术Icoding实验)
Flex 词法分析
此为电子科技大学编译技术 实验1:词法分析
将具体实现中的三个文件和自己的实验报告一起上传才能通过
根据词法分析实验中给定的文法,利用 flex 设计一词法分析器,该分析器从标准输入读入源代码后,输出单词的类别编号及附加信息。 附加信息规定如下: 当类别为 Y_ID、num_INT 或 num_FLOAT 时,附加信息为该类别对应的属性,如 main, 100, 29.3等; 当类别为 关键字 时,附件信息为 KEYWORD; 当类别为 运算符 时,附件信息为 OPERATOR; 当类别为 其它符号时,附件信息为 SYMBOL
单词类别的定义:
enum yytokentype {num_INT = 258,num_FLOAT = 259,Y_ID = 260,Y_INT = 261,Y_VOID = 262,Y_CONST = 263,Y_IF = 264,Y_ELSE = 265,Y_WHILE = 266,Y_BREAK = 267,Y_CONTINUE = 268,Y_RETURN = 269,Y_ADD = 270,Y_SUB = 271,Y_MUL = 272,Y_DIV = 273,Y_MODULO = 274,Y_LESS = 275,Y_LESSEQ = 276,Y_GREAT = 277,Y_GREATEQ = 278,Y_NOTEQ = 279,Y_EQ = 280,Y_NOT = 281,Y_AND = 282,Y_OR = 283,Y_ASSIGN = 284,Y_LPAR = 285,Y_RPAR = 286,Y_LBRACKET = 287,Y_RBRACKET = 288,Y_LSQUARE = 289,Y_RSQUARE = 290,Y_COMMA = 291,Y_SEMICOLON = 292,Y_FLOAT = 293
};
例如对于源代码
int main(){return 3;
}
词法分析器的输出为:
<261, KEYWORD>
<260, main>
<285, SYMBOL>
<286, SYMBOL>
<287, SYMBOL>
<269, KEYWORD>
<258, 3>
<292, SYMBOL>
<288, SYMBOL>
1 具体实现
以下具体实现分为了三个文件 —— token.h,lexer.l,lexer_main.c
当然你也可以直接写成一个 .l 文件,具体看补充
1.1 头文件 token.h
创建一个头文件 token.h,定义了词法分析器中所需的标记类型和附加信息的数据结构;这个头文件中包含了枚举 yytokentype,定义了各种标记类型的类别编号,以及一个联合 _YYLVAL,用于存储附加信息,具体代码如下:
#ifndef TOKEN_H
#define TOKEN_H
enum yytokentype {num_INT = 258,num_FLOAT = 259,Y_ID = 260,Y_INT = 261,Y_VOID = 262,Y_CONST = 263,Y_IF = 264,Y_ELSE = 265,Y_WHILE = 266,Y_BREAK = 267,Y_CONTINUE = 268,Y_RETURN = 269,Y_ADD = 270,Y_SUB = 271,Y_MUL = 272,Y_DIV = 273,Y_MODULO = 274,Y_LESS = 275,Y_LESSEQ = 276,Y_GREAT = 277,Y_GREATEQ = 278,Y_NOTEQ = 279,Y_EQ = 280,Y_NOT = 281,Y_AND = 282,Y_OR = 283,Y_ASSIGN = 284,Y_LPAR = 285,Y_RPAR = 286,Y_LBRACKET = 287,Y_RBRACKET = 288,Y_LSQUARE = 289,Y_RSQUARE = 290,Y_COMMA = 291,Y_SEMICOLON = 292,Y_FLOAT = 293
};typedef union _YYLVAL{int token;int int_value;float float_value;char* id_name;
}_YYLVAL;#endif //TOKEN_H
1.2 Flex文件 lexer.l
创建Flex规则文件 lexer.l,其中包含词法分析器的规则定义:
-
注释处理:规则中包括了处理注释的规则
(\/\/.*\n)|(\/\*.*\*\/),可以将注释从源代码中过滤掉 -
十六进制整数:规则可以成功地识别十六进制整数,例如
0x10 -
标识符:规则中有处理标识符的规则,注意,使用了
strdup(yytext)来为标识符分配内存。这会为每个标识符创建一个新的动态分配的字符串,要确保在适当的时候释放这些字符串以避免内存泄漏 -
操作符:规则包括处理各种操作符的规则
-
浮点数:规则可以成功地识别浮点数,但需要注意浮点数的格式。当前规则要求小数点前面至少有一个数字,例如
0.1,而不支持.1这种形式 -
数值的存储:规则中将整数存储为
yylval.int_value,浮点数存储为yylval.float_value
具体代码:
%{#include "token.h"
%}_YYLVAL yylval;%%
[ \t\n] ;
(\/\/.*\n)|(\/\*.*\*\/) ;int { return Y_INT; }
float { return Y_FLOAT; }void { return Y_VOID; }
const { return Y_CONST; }
if { return Y_IF; }
else { return Y_ELSE; }
while { return Y_WHILE; }
break { return Y_BREAK; }
continue { return Y_CONTINUE; }
return { return Y_RETURN; }"+" { return Y_ADD; }
"-" { return Y_SUB; }
"*" { return Y_MUL; }
"/" { return Y_DIV; }
"%" { return Y_MODULO; }
"<" { return Y_LESS; }
"<=" { return Y_LESSEQ; }
">" { return Y_GREAT; }
">=" { return Y_GREATEQ; }
"!=" { return Y_NOTEQ; }
"==" { return Y_EQ; }
"!" { return Y_NOT; }
"&&" { return Y_AND; }
"||" { return Y_OR; }
"=" { return Y_ASSIGN; }"(" { return Y_LPAR; }
")" { return Y_RPAR; }
"{" { return Y_LBRACKET; }
"}" { return Y_RBRACKET; }
"[" { return Y_LSQUARE; }
"]" { return Y_RSQUARE; }
"," { return Y_COMMA; }
";" { return Y_SEMICOLON; }[0-9]+ { yylval.int_value = atoi(yytext); return num_INT; }
[0-9]*\.[0-9]+ { yylval.float_value = atof(yytext); return num_FLOAT; }
[a-zA-Z_][a-zA-Z0-9_]* { yylval.id_name = strdup(yytext); return Y_ID; }
0x[0-9a-fA-F]+ { yylval.int_value = strtol(yytext, NULL, 16); return num_INT; }
%%
1.3 main函数文件 lexer_main.c
创建main函数文件 lexer_main.c ,它将从词法分析器接收的标记类型和附加信息输出为类别编号和附加信息
-
#include部分包含了标准输入输出头文件和自定义的 token.h 头文件 -
extern int yylex();和extern _YYLVAL yylval;声明了从词法分析器生成的函数和变量 -
while((token = yylex()) != 0)循环调用yylex()函数来获取标记,直到返回值为 0 表示词法分析结束 -
在循环内部,根据标记的类型进行相应的打印输出。对于标识符、整数和浮点数,使用
yylval结构中相应的成员来获取值 -
根据标记类型的范围,将其分类为关键字、运算符或其他符号,并打印相应的输出
-
使用了
free()函数来释放在标识符规则中动态分配的yylval.id_name内存,以避免内存泄漏
具体代码:
#include <stdio.h>
#include "token.h"extern int yylex();
extern _YYLVAL yylval;int main(int argc, char **argv) {int token;while((token = yylex()) != 0) {if(token <= 260){switch (token) {case Y_ID:printf("<%d, %s>\n", token, yylval.id_name);free(yylval.id_name); break;case num_INT:printf("<%d, %d>\n", token, yylval.int_value);break;case num_FLOAT:printf("<%d, %f>\n", token, yylval.float_value);break;default:printf("<UNKNOWN>\n");break; } }else{if(token <= 269 || token == 293) {char words[10] = "KEYWORD";printf("<%d, %s>\n", token, words);}else if(token <= 284) {char words[10] = "OPERATOR";printf("<%d, %s>\n", token, words);}else if(token <= 292) {char words[10] = "SYMBOL";printf("<%d, %s>\n", token, words);}else{printf("<UNKNOWN>\n");} } }return 0;
}
Icoding:将以上三个文件+实验报告上传即可
2 运行测试
在虚拟机上(我的是 VMware + Ubuntu22.04.3)进行的测试
在这三个文件的目录下,执行:
-
使用 Flex 编译 test.l 文件,这将生成 lex.yy.c 文件,其中包含词法分析器的C代码
flex test.l -
使用 GCC 编译 lex.yy.c 和 test_main.c,并生成可执行文件 test,在这一步,使用
-lfl标志来链接 Flex 库gcc lex.yy.c test_main.c -o test -lfl -
运行生成的可执行文件 test,并通过标准输入
<重定向输入测试文件 test1.sy,从而进行词法分析./test < test1.sy
测试文件 test1.sy:
// test if-else-if
int ifElseIf() {int a;a = 5;int b;b = 10;if(a == 6 || b == 0xb) {return a;}else {if (b == 10 && a == 1)a = 25;else if (b == 10 && a == -5)a = a + 15;elsea = -+a;}return a;
}int main(){putint(ifElseIf());return 0;
}
运行结果部分展示:

3 补充
可以直接写成一个 .l 文件,如下 lexer.l:
%{
enum yytokentype {num_INT = 258,num_FLOAT = 259,Y_ID = 260,Y_INT = 261,Y_VOID = 262,Y_CONST = 263,Y_IF = 264,Y_ELSE = 265,Y_WHILE = 266,Y_BREAK = 267,Y_CONTINUE = 268,Y_RETURN = 269,Y_ADD = 270,Y_SUB = 271,Y_MUL = 272,Y_DIV = 273,Y_MODULO = 274,Y_LESS = 275,Y_LESSEQ = 276,Y_GREAT = 277,Y_GREATEQ = 278,Y_NOTEQ = 279,Y_EQ = 280,Y_NOT = 281,Y_AND = 282,Y_OR = 283,Y_ASSIGN = 284,Y_LPAR = 285,Y_RPAR = 286,Y_LBRACKET = 287,Y_RBRACKET = 288,Y_LSQUARE = 289,Y_RSQUARE = 290,Y_COMMA = 291,Y_SEMICOLON = 292,Y_FLOAT = 293
};typedef union _YYLVAL{int token;int int_value;float float_value;char* id_name;
}_YYLVAL;%}_YYLVAL yylval;%%
[ \t\n] ;
(\/\/.*\n)|(\/\*.*\*\/) ;int { return Y_INT; }
float { return Y_FLOAT; }void { return Y_VOID; }
const { return Y_CONST; }
if { return Y_IF; }
else { return Y_ELSE; }
while { return Y_WHILE; }
break { return Y_BREAK; }
continue { return Y_CONTINUE; }
return { return Y_RETURN; }"+" { return Y_ADD; }
"-" { return Y_SUB; }
"*" { return Y_MUL; }
"/" { return Y_DIV; }
"%" { return Y_MODULO; }
"<" { return Y_LESS; }
"<=" { return Y_LESSEQ; }
">" { return Y_GREAT; }
">=" { return Y_GREATEQ; }
"!=" { return Y_NOTEQ; }
"==" { return Y_EQ; }
"!" { return Y_NOT; }
"&&" { return Y_AND; }
"||" { return Y_OR; }
"=" { return Y_ASSIGN; }"(" { return Y_LPAR; }
")" { return Y_RPAR; }
"{" { return Y_LBRACKET; }
"}" { return Y_RBRACKET; }
"[" { return Y_LSQUARE; }
"]" { return Y_RSQUARE; }
"," { return Y_COMMA; }
";" { return Y_SEMICOLON; }[0-9]+ { yylval.int_value = atoi(yytext); return num_INT; }
[0-9]*\.[0-9]+ { yylval.float_value = atof(yytext); return num_FLOAT; }
[a-zA-Z_][a-zA-Z0-9_]* { yylval.id_name = strdup(yytext); return Y_ID; }
0x[0-9a-fA-F]+ { yylval.int_value = strtol(yytext, NULL, 16); return num_INT; }
%%int main(int argc, char **argv) {int token;while((token = yylex()) != 0) {if(token <= 260){switch (token) {case Y_ID:printf("<%d, %s>\n", token, yylval.id_name);free(yylval.id_name); break;case num_INT:printf("<%d, %d>\n", token, yylval.int_value);break;case num_FLOAT:printf("<%d, %f>\n", token, yylval.float_value);break;default:printf("<UNKNOWN>\n");break; } }else{if(token <= 269 || token == 293) {char words[10] = "KEYWORD";printf("<%d, %s>\n", token, words);}else if(token <= 284) {char words[10] = "OPERATOR";printf("<%d, %s>\n", token, words);}else if(token <= 292) {char words[10] = "SYMBOL";printf("<%d, %s>\n", token, words);}else{printf("<UNKNOWN>\n");} } }return 0;
}
此时只需要执行以下即可测试:
-
flex lexer.l -
gcc lex.yy.c -o test -lfl -
./test < test1.sy
相关文章:
Flex 词法分析实验实现(电子科技大学编译技术Icoding实验)
Flex 词法分析 此为电子科技大学编译技术 实验1:词法分析 将具体实现中的三个文件和自己的实验报告一起上传才能通过 根据词法分析实验中给定的文法,利用 flex 设计一词法分析器,该分析器从标准输入读入源代码后,输出单词的类别编…...
设计模式——20. 解释器模式
1. 说明 解释器模式(Interpreter Pattern)是一种行为型设计模式,它用于定义一门语言的语法解析,并为该语言创建解释器。该模式将一个问题或领域表达成一个语言,然后提供一个解释器来解释这种语言中的表达式,以执行特定操作。 要点和组成部分: 抽象表达式(Abstract Ex…...
多输入多输出 | MATLAB实现CNN-BiLSTM-Attention卷积神经网络-双向长短期记忆网络结合SE注意力机制的多输入多输出预测
MATLAB实现CNN-BiLSTM-Attention卷积神经网络-双向长短期记忆网络结合SE注意力机制的多输入多输出预测 目录 MATLAB实现CNN-BiLSTM-Attention卷积神经网络-双向长短期记忆网络结合SE注意力机制的多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 C…...
一文让你玩转Linux多进程开发
Linux多进程开发 主要介绍多进程开发时的要点 进程状态转换 进程反应了进程执行的变化。 进程的状态分为三种 ,运行态,阻塞态,就绪态 在五态模型中分为以下几种,新建态,就绪态,运行态,阻塞态,终止态。 运行态:进程占用处理器正在运…...
Linux线程同步实例
线程同步实例 1. 生产消费者模型基本概念2. 基于BlockingQueue的生产者消费者模型3. 基于环形队列的生产消费模型4. 线程池 1. 生产消费者模型基本概念 生产者消费者模型是一种常用的并发设计模式,它可以解决生产者和消费者之间的速度不匹配、解耦、异步等问题。生…...
LuatOS-SOC接口文档(air780E)-- iconv - iconv操作
iconv.open(tocode, fromcode)# 打开相应字符编码转换函数 参数 传入值类型 解释 string 释义:目标编码格式 取值:gb2312/ucs2/ucs2be/utf8 string 释义:源编码格式 取值:gb2312/ucs2/ucs2be/utf8 返回值 返回值类型 解…...
matlab第三方硬件支持包下载和安装
1、在使用matlab内部的附加功能安装时,由于matlab会验证是否正版无法打开 2、在matlab官网直接找到对应的硬件支持包下载,但是是下图的安装程序 可以直接在matlab中跳转到该程序所在的文件夹双击安装,但是安装到最后出错了 3.根据出错时mala…...
docker compose和consul(服务注册与发现)
一、Docker-compose 简介 Docker-Compose项目是基于Python开发的Docker官方开源项目,负责实现对Docker容器集群的快速编排。 Docker-Compose将所管理的容器分为三层,分别是 工程(project),服务(service&a…...
使用Python进行钻石价格分析
钻石是最昂贵的宝石之一。钻石的质量通常以其重量(克拉)、净度、颜色和切工来评估。重量越大、净度越高、色彩纯净、切工精细的钻石价格也越高。其中,4C标准是衡量钻石质量的国际标准,即克拉(Carat)、净度&…...
Java日期查询
本实例使用有关日期处理和日期格式化的类实现一个日期查询的功能,即查询指定日期所在周的周一日期、两个指定日期间相差的天数和指定日期为所在周的星期几的日期 3 个功能。 从功能上来看,本实例至少需要定义 3 个方法,分别完成:获…...
uniapp 运行到 app 报错 Cannot read property ‘nodeName‘ of null
uniapp 运行到某一个页面,报错,h5没有问题 Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repovuejs/coreat <GuiPagecustomHeadertruecustomF…...
Mac M1通过homebrew安装Redis报错(perl: unknown or unsupported macOS version: :dunno)
〇、解决方案 升级homebrew,命令如下: brew update-reset一、问题现象 通过命令brew install redis安装Redis,异常如下: fatal: not in a git directory Warning: No remote origin in /opt/homebrew/Library/Taps/homebrew/h…...
如何在 Spring Boot 中进行分布式追踪
在 Spring Boot 中进行分布式追踪 分布式系统中的应用程序由多个微服务组成,它们可以位于不同的服务器、容器或云中。当出现问题时,如性能瓶颈、错误或延迟,了解问题的根本原因变得至关重要。分布式追踪是一种用于跟踪和分析分布式应用程序性…...
Lniux三剑客——Grep
前言 echo guangge{01…100…2} 第二个是间隔多少个计数 命令别名 alias, unalias , 作用是封装命令: alias rm ‘rm -i’ 命令历史 history !行号 !! 上一次的命令 ctrl a 移动到行首 ctrl e 移动到行尾 Grep 格式: gre…...
选实验室超声波清洗机易忽视的内容?小型清洗机的优点有?
实验室超声波清洗机如今在行业内占据着重要的一席之地,摒弃了传统模式,坚持以超声波为主的清洗方式,在市场中获得的反响强烈。服务好,有诚信的实验室超声波清洗机能够消除客户的后顾之忧,工作人员会以真诚态度向客户提…...
基于Java使用SpringBoot+Vue框架实现的前后端分离的美食分享平台
✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 在当今社会࿰…...
开源数据库MySQL 8.0 OCP认证精讲视频、环境和题库 之二
修改用户的初始密码: mysql>alteruserrootlocalhostidentifiedbyQaz1234; 或者: mysql>alteruseruser0identifiedbyQaz_1234; 在版本5.x中: mysql>setpasswordpassword(Qaz_1234); 可执行文件: 服务器端&…...
AI对网络安全的影响与挑战
近年来,随着人工智能(AI)技术的快速发展,网络安全领域也开始逐渐引入生成式AI应用。根据最新的数据研究,生成式AI对网络安全和合规的影响最大,同时也包括了IT和云的运维、硬件和软件支持领域。通过AI和自动…...
微信小程序备案流程操作详解,值得收藏
目录 一、小程序备案法律法规参考 二、备案前准备 2.1 备案入口 2.1.1、未上架小程序 2.1.2、已上架小程序 (二)备案类型 (三)备案材料准备 3.1、小程序备案材料 3.2、前置审批材料 3.3、个人备案 3.4、非个人备案 三、备案整体流程 (一)备案信息填写 1、主体信息…...
【NLTK系列01】:nltk库介绍
一、说明 NLTK是个啥?它是个复杂的应用库,可以实现基本预料库操作,比如,、将文章分词成独立token,等操作。从词统计、标记化、词干提取、词性标记,停用词收集,包括语义索引和依赖关系解析等。 …...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
