当前位置: 首页 > news >正文

TinyC编译器6—用 flex 做词法分析

1.Flex整体框架实现

flex 是一个快速词法分析生成器,它可以将用户用正则表达式写的分词匹配模式构造成一个有限状态自动机(一个C函数),目前很多编译器都采用它来生成词法分析器。

下面介绍在Linux环境下使用flex的方法。

首先安装flex:

sudo apt-get update
sudo apt-get install flex

再次检查是否安装成功

flex --version

然后在对应目录下新建文档,根据flex语法写出一个文件并保存后缀为.l

%%//正则表达式    操作[0-9]+  printf("?");
#       return 0;
.       ECHO;%%int main(int argc, char* argv[]) {yylex();return 0;
}int yywrap() { return 1;
}

注意此文件中的 %% 必须在本行的最前面(即 %% 前面不能有任何空格)。

之后在终端输入:

flex xxxxx.l

此时这个flex词法分析器就会生成一个lex.yy.c文件

然后gcc编译:

gcc -o xxxxx lex.yy.c -lfl

最后运行:

./xxxx

这样在终端输入你想输入的东西,会出现神奇的现象(待读者自己发掘)。

2.解析Flex语法

%%
[0-9]+  printf("?");
#       return 0;
.       ECHO;
%%

flex 模式文件中,%% 和 %% 之间的内容被称为 规则(rules),本文件中每一行都是一条规则,每条规则由 匹配模式(pattern) 和 事件(action) 组成, 模式在前面,用正则表达式表示,事件在后面,即 C 代码。每当一个模式被匹配到时,后面的 C 代码被执行。flex 会将本段内容翻译成一个名为 yylex 的函数。

int main(int argc, char *argv[]) {yylex();return 0;
}int yywrap() { return 1; }

main 函数是程序的入口, flex 会将这些代码原样的复制到 lex.yy.c 文件的最后面。序开始运行后,就开始执行 yylex 函数,然后开始扫描标准输入。当扫描到 # 后, # 被匹配, return 0 被执行, yylex 函数返回到 main 函数,之后程序结束。

因此其完整的输入格式:

%{
Declarations
%}
Definitions
%%
Rules
%%
User subroutines

第 2 段 %} 和 %% 之间的为 定义(Definitions),在这里可以定义正则表达式中的一些名字,可以在 规则(Rules) 段被使用,如本文件中定义了 DIGIT 为 [0-9], 这样在后面可以用 DIGIT 代替这个正则表达式。

输入文件中最后一行的 yywrap 函数的作用是将多个输入文件打包成一个输入,当 yylex 函数读入到一个文件结束(EOF)时,它会向 yywrap 函数询问, yywrap 函数返回 1 的意思是告诉yylex函数后面没有其他输入文件了。

注意:flex 提供的两个全局变量 yytext 和 yyleng,分别用来表示刚刚匹配到的字符串以及它的长度。


3.使用flex对TinyC源文件进行词法分析

​
%{
#include <stdio.h>
#include <stdlib.h>
#include "token.h"
%}DIGIT          [0-9]
%%
[ \t\n]           ; // 忽略空格、制表符和换行符"+"                            { printf("<%d, OPERATOR>\n", Y_ADD); }
"-"                            { printf("<%d, OPERATOR>\n", Y_SUB); }
"*"                           { printf("<%d, OPERATOR>\n", Y_MUL); }
"/"                            { printf("<%d, OPERATOR>\n", Y_DIV); }
"%"                    { printf("<%d, OPERATOR>", Y_MODULO); }
"<"                            { printf("<%d, OPERATOR>\n", Y_LESS); }
"<="                       { printf("<%d, OPERATOR>\n", Y_LESSEQ); }
">"                        { printf("<%d, OPERATOR>\n", Y_GREAT); }
">="                    { printf("<%d, OPERATOR>\n", Y_GREATEQ); }
"!="                       { printf("<%d, OPERATOR>\n", Y_NOTEQ); }
"=="                            { printf("<%d, OPERATOR>\n", Y_EQ); }
"!"                           { printf("<%d, OPERATOR>\n", Y_NOT); }
"&&"                           { printf("<%d, OPERATOR>\n", Y_AND); }
"||"                            { printf("<%d, OPERATOR>\n", Y_OR); }
"="                     { printf("<%d, OPERATOR>\n", Y_ASSIGN); }"("                           { printf("<%d, SYMBOL>\n", Y_LPAR); }
")"                            { printf("<%d, SYMBOL>\n", Y_RPAR); }
"{"                     { printf("<%d, SYMBOL>\n", Y_LBRACKET); }
"}"                     { printf("<%d, SYMBOL>\n", Y_RBRACKET); }
"["                      { printf("<%d, SYMBOL>\n", Y_LSQUARE); }
"]"                      { printf("<%d, SYMBOL>\n", Y_RSQUARE); }
","                       { printf("<%d, SYMBOL>\n", Y_COMMA); }
";"                  { printf("<%d, SYMBOL>\n", Y_SEMICOLON); }"int"                        { printf("<%d, KEYWORD>\n", Y_INT); } 
"void"                          { printf("<%d, KEYWORD>\n",Y_VOID); }
"const"                        { printf("<%d, KEYWORD>\n", Y_CONST); }
"if"                           { printf("<%d, KEYWORD>\n", Y_IF); }
"else"                            { printf("<%d, KEYWORD>\n", Y_ELSE); }
"while"                          { printf("<%d, KEYWORD>\n", Y_WHILE); }
"break"                         { printf("<%d, KEYWORD>\n", Y_BREAK); }
"continue"                    { printf("<%d, KEYWORD>\n", Y_CONTINUE); }
"return"                         { printf("<%d, KEYWORD>\n", Y_RETURN); }[a-zA-Z_][a-zA-Z0-9_]*        { printf("<%d, %s>\n", Y_ID,yytext); }DIGIT+                        {printf("<%d, %s>\n",num_INT,yytext);}
"-"[0-9]+                     {printf("<%d, %s>\n", num_INT, yytext);}///
[0-9]+"."[0-9]+                 {printf("<%d, %s>\n",num_FLOAT,yytext);}
"-"[0-9]+"."[0-9]+ {printf("<%d, %s>\n", num_FLOAT, yytext);}//
"0x"[0-9a-fA-F]+ { printf("<%d, %d>\n", num_INT, (int)strtol(yytext, NULL, 16)); }
"-0x"[0-9a-fA-F]+ { printf("<%d, %d>\n", num_INT, (int)strtol(yytext, NULL, 16)); }///"//".*      { }
"/*.*?*/"   { }.   {return yytext[0];}%%int yywrap(){return 1;
} int main(void)
{yylex();return 0;
}​

在一系列正则表达式中,用双引号括起来的字符串就是原始字符串,里面的特殊字符是不需要转义的,而双引号本身必须转义(必须用 \” 或 \042 ),这是 flex 中不同于常规的正则表达式的一个特性。

一些定义在 token.h 文件中


#ifndef COMPILER_LAB_TOKEN_H
#define COMPILER_LAB_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;extern _YYLVAL yylval;
#endif //COMPILER_LAB_TOKEN_H

http://www.mrgr.cn/news/58149.html

相关文章:

  • 掌握ElasticSearch(一):Elasticsearch安装与配置、Kibana安装
  • 安装OpenResty
  • 【Python】爬虫
  • 【CSS in Depth 2 精译_054】8.2 CSS 层叠图层(cascade layer)的推荐组织方案
  • 智慧社区服务平台搭建方案
  • 融合ASPICE与敏捷开发:探索汽车软件开发的最佳实践
  • JVM学习之路(3)类加载器
  • 正则表达式基础知识
  • 【Docker】Dockerfile 用于组装镜像的指令都有啥?
  • Robot Framework接口自动化测试案例
  • Shell 编程-Shell 函数你学会了吗?
  • 【含开题报告+文档+PPT+源码】社区医院预约挂号看病系统的设计与实现
  • python回调函数概念及应用场景举例
  • 于Java语言 Netty通讯框架的云块充协议1.5_云快充协议1.6_云快充协议1.4_云快充协议
  • Flutter TextField和Button组件开发登录页面案例
  • 【赵渝强老师】Hive的内部表与外部表
  • TreeMap详解
  • 产品推介——LSOP4晶体管光耦KL101X
  • web 请求日志追踪(traceID)提升运维效率
  • Nexpose 6.6.274 发布下载,新增功能概览
  • 华为OD机试 - 创建二叉树(Java 2024 E卷 200分)
  • 基于Java+SpringBoot+Vue的宠物咖啡馆平台的设计与实现
  • JavaScript 中四种常见的数据类型判断方法
  • 【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper+代码——交叉注意力(Cross-Attention)
  • 附录章节:SQL标准与方言对比
  • 【已解决】【hadoop】如何解决Hive连接MySQL元数据库的依赖问题