flex学习 - 附录

news/2025/3/26 18:43:12/文章来源:https://www.cnblogs.com/xiaobing3314/p/18790215

A.1 Makefiles和Flex
在本附录中,我们提供了编写Makefile来构建扫描器的技巧。
在传统的构建环境中,我们说.c文件是源文件,而.o文件是中间文件。但是在使用flex时,.l文件是源文件,而生成的.c文件(以及.o文件)是中间文件。这需要你仔细规划Makefile。
现代的make程序明白foo.l旨在生成lex.yy.c或foo.c,并将相应的执行。下面的Makefile没有明确指示make如何从foo.l构建foo.c。相反,它依赖于make程序的隐式规则来构建中间文件scan.c:

# Basic Makefile -- relies on implicit rules
# Creates "myprogram" from "scan.l" and "myprogram.c"
#
LEX=flex
myprogram: scan.o myprogram.o
scan.o: scan.l

对于简单的情况,上述可能就足够了。对于其它情况,您可能必须明确指示make如何构建扫描器。下面是一个包含显式规则的Makefile示例:

# Basic Makefile -- provides explicit rules
# Creates "myprogram" from "scan.l" and "myprogram.c"
#
LEX=flex
myprogram: scan.o myprogram.o$(CC) -o $@  $(LDFLAGS) $^myprogram.o: myprogram.c$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $^scan.o: scan.c$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $^scan.c: scan.l$(LEX) $(LFLAGS) -o $@ $^clean:$(RM) *.o scan.c

注意,在上面的示例中,scan.c位于clean目标中。这是因为我们认为scan.c是一个中间文件。
最后,我们提供了一个与bison解析器一起使用flex扫描器的实际示例。我们必须处理一个棘手的问题。由于flex扫描器通常会包含解析器生成的头文件(例如y.tab.h),因此我们需要确保在扫描器编译之前生成了头文件。我们在下面的例子中处理这种情况:

# Makefile example -- scanner and parser.
# Creates "myprogram" from "scan.l", "parse.y", and "myprogram.c"
#
LEX     = flex
YACC    = bison -y
YFLAGS  = -d
objects = scan.o parse.o myprogram.omyprogram: $(objects)
scan.o: scan.l parse.c
parse.o: parse.y
myprogram.o: myprogram.c

在上面的示例中,注意下面这行:
scan.o: scan.l parse.c
它将文件parse.c(生成的解析器)列为scan.o的依赖项。我们希望确保在编译扫描器之前创建解析器,上面的代码行似乎可以做到这一点。请随意试验make的具体实现。
关于编写makefile的更多详细信息,参见GNU Make手册。
A.2 带Bison解析器的C扫描器
这个章节描述了在将flex与GNU bison集成时有用的flex特性。如果你的扫描器不使用bison,请跳过本节。这里我们只讨论flex和bison对的flex的这一半。我们不会详细讨论bison。有关生成bison解析器的更多信息,参见GNU Bison手册。
通过声明’%option bison-bridge’或在从命令行调用flex时提供’--bison-bridge’,可以生成兼容的bison扫描器。这指示flex可以使用宏yylval。yylval的数据类型YYSTYPE,通常在头文件中定义,包含在flex输入文件的第一节中。有关有效的函数和宏的列表,请查看bison-functions章节。
yylex的声明变为:
int yylex(YYSTYPE * lvalp,yyscan_t scanner);
如果%option bison-locations被指定,则声明变为:
int yylex(YYSTYPE * lvalp,YYLTYPE *llocp, yyscan_t scanner);
注意,宏yylval和yylloc计算的值为指针。对yylloc的支持在bison中是可选的,因此在flex中也是可选的。下面是一个与bison兼容的flex扫描器的示例。

/* Scanner for "C" assignment statements... sort of. */
%{
#include "y.tab.h"  /* Generated by bison. */
%}%option bison-bridge bison-locations
%[[:digit:]]+  { yylval->num = atoi(yytext);   return NUMBER;}
[[:alnum:]]+  { yylval->str = strdup(yytext); return STRING;}
"="|";"       { return yytext[0];}
.  {}
%

正如你所看到的,这里真的没有魔法。我们只是像对其它变量一样使用yylval。yylval的数据类型由bison生成,并包含在文件y.tab.h中。下面是相应的bison解析器:

/* Parser to convert "C" assignments to lisp. */
%{
/* Pass the argument to yyparse through to yylex. */
#define YYPARSE_PARAM scanner
#define YYLEX_PARAM   scanner
%}
%locations
%pure_parser
%union {int num;char* str;
}
%token <str> STRING
%token <num> NUMBER
%%
assignment:STRING '=' NUMBER ';' {printf( "(setf %s %d)", $1, $3 );}
;

A.3 M4依赖
宏处理器M4必须安装在flex安装的地方。flex调用’m4’,通过搜索PATH环境变量中的目录找到。你在第一节或动作中放置的任何代码都将通过m4发送。请遵循这些规则来保护你的代码免受不必要的m4处理。
1、不要使用以m4开头的符号,如’m4 define’或’m4 include’,因为这些是为m4宏名称保留的。如果出于某种原因你需要m4作为前缀,使用预处理器#define使你的符号经过m4后不被打乱。
2、不要在代码的任何地方使用字符串’[[’或’]]’。前者在C语言中无效,除非在注释和字符串中有效,但后者在x[y[z]]等代码中有效。解决办法很简单。要获取字面值字符串’]]’使用”]””]”。为了获取数组符号x[y[z]],请使用x[y[z] ]。flex将尝试检测用户代码中的这些序列,并对它们进行转义。但是,最好通过从代码中删除这些序列来尽可能避免这种复杂性。
m4只需要在你运行flex的时候。生成的扫描器是普通的C或C++,不需要m4。
A.4 通用模式
本附录提供了可能在扫描器中使用的常用正则表达式的示例。
A.4.1 数字
C99十进制常量
([[:digit:]]{-}[0])[[:digit:]]*
C99十六进制常量
0[xX][[:xdigit:]]+
C99八进制常量
0[01234567]*
C99浮点常量
{dseq} ([[:digit:]]+)
{dseq_opt} ([[:digit:]])
{frac} (({dseq_opt}"."{dseq})|{dseq}".")
{exp} ([eE][+-]?{dseq})
{exp_opt} ({exp}?)
{fsuff} [flFL]
{fsuff_opt} ({fsuff}?)
{hpref} (0[xX])
{hdseq} ([[:xdigit:]]+)
{hdseq_opt} ([[:xdigit:]]
)
{hfrac} (({hdseq_opt}"."{hdseq})|({hdseq}"."))
{bexp} ([pP][+-]?{dseq})
{dfc} (({frac}{exp_opt}{fsuff_opt})|({dseq}{exp}{fsuff_opt}))
{hfc} (({hpref}{hfrac}{bexp}{fsuff_opt})|({hpref}{hdseq}{bexp}{fsuff_opt}))

{c99_floating_point_constant} ({dfc}|{hfc})
请参考C99第6.4.4.2节了解详细的细节。
A.4.2 标识符
C99标识符
ucn ((\u([[:xdigit:]]{4}))|(\U([[:xdigit:]]{8})))
nondigit [[:alpha:]]
c99_id ([
[:alpha:]]|{ucn})([_[:alnum:]]|{ucn})*
从技术上讲,上述模式并不包含所有可能的C99标识符,因为C99允许”实现自定义”的字符。实际上,C编译器遵循上述模式,并添加了’$’字符。
UTF-8编码的Unicode编码
[\x09\x0A\x0D\x20-\x7E]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|\xE1-\xEC\xEE\xEF|\xED[\x80-\x9F][\x80-\xBF]|\xF0\x90-\xBF|\xF1-\xF3|\xF4\x80-\x8F
A.4.3 引用结构
C99字符串文字
L?"([^"\\n]|(\['"?\abfnrtv])|(\([0123456]{1,3}))|(\x[[:xdigit:]]+)|(\u([[:xdigit:]]{4}))|(\U([[:xdigit:]]{8})))"
C99注释
("/
"([^]|""[^/])"/")|("/"(\\n)"/"[^\n])
请注意在C99中,’//’样式的注释可能被分割成几行,并且与流行的看法相反,它不包括末尾的’\n’字符。
扫描’/* */’注释的更好方法是逐行扫描,而不是一次性匹配可能很大的注释。这将允许你扫描无限长度的注释,只要以相同的间隔出现换行。当与自动行号处理一起使用时,这也更有效。查看option-yylineno章节。

{
"/" BEGIN(COMMENT);
}
{
"
/" BEGIN(0);
[^\n]+ ;
"
"[^/] ;
\n ;
}
A.4.4 地址
IPv4地址
dec-octet [0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]
IPv4address {dec-octet}.{dec-octet}.{dec-octet}.{dec-octet}
IPv6地址
h16 [0-9A-Fa-f]{1,4}
ls32 {h16}:{h16}|{IPv4address}
IPv6address ({h16}: ){6}{ls32}|
:: ({h16}: ){5}{ls32}|
({h16})?:: ({h16}: ){4}{ls32}|
(({h16}: ){0,1}{h16})?:: ({h16}: ){3}{ls32}|
(({h16}: ){0,2}{h16})?:: ({h16}: ){2}{ls32}|
(({h16}: ){0,3}{h16})?::{h16}:{ls32}|
(({h16}: ){0,4}{h16})?::{ls32}|
(({h16}: ){0,5}{h16})?::{h16}|
(({h16}: ){0,6}{h16})?::
参考RFC 2373了解更详细的信息。请注意,你必须将IPv6地址的定义折叠成一行,并且它还匹配”未指定地址””::”。
URI
(([^:/?#]+): )?("//"([^/?#]))?([^?#])(?([^#]))?(#(.))?
这个模式几乎是无用的,因为它允许在URI中出现任何字符,包括空格和控制字符。参考RFC 2396了解更详细的信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/904984.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3.24 学习记录

实现了学习记录APP的登录注册功能

2025西安交大集训Day2:DFS,BFS记忆化搜索,迭代加深搜索,二分搜索

2025西安交大集训Day2:DFS,BFS记忆化搜索,迭代加深搜索,二分搜索

掌握 Postman:高级 GET 请求技术与响应分析

欢迎阅读本指南,它将详细介绍如何在 Postman 中发送 GET 请求并理解 API 响应。对于希望提升 API 测试和开发能力的开发者来说,这是不可或缺的技能。 Postman 对开发者的重要性Postman 是 API 开发和测试中不可或缺的工具。它不仅简化了发送请求和分析响应的过程,还提供了一…

带你一起来熟悉linux文件权限体系

了解 Linux 文件权限对于有效且可靠的linux相关系统管理和安全管理至关重要。通过本文中概述的概念并加以实践,您将可以轻松浏览文件权限并确保 Linux 系统的完整,可靠和安全。下面将从权限的格式,常用设置,修改,解析等方面分别说明。 A).Linux 文件权限由三个权限部分组成…

OP100自动安装背板常见问题

1.运行过程中切手动,回原灯一直闪烁,始终无法执行完成 OP50自动安装座板 OP100自动安装背板 OP280自动安装上盖 这几个工站因为有记忆功能,会记住当前步序以及夹爪/吸盘上有没有物体,如果运行中切换手动,并动了气缸,会导致逻辑错乱,类似升降器的SUB40,遇到这种情况: 1…

20244217 2024-2025-2 《Python程序设计》实验一报告

学号 2024-2025-2 《Python程序设计》实验一报告 课程:《Python程序设计》 班级: 2442 姓名: 胡峻豪 学号:20244217 实验教师:王志强 实验日期:2025年3月24日 必修/选修: 公选课 1.实验内容 1.熟悉Python开发环境。首先在官网下载并安装PyCharm专业版,安装完成后打开软…

软件工程日报15

Android studio 实现连接远程mysql数据库,并将数据展示出来,由于之前没接触过,全靠按照博客上的指导和ai生成的代码,之后在学习一下 以下是效果

《Python程序设计》实验一报告

课程:《Python程序设计》 班级: 2441 姓名: 王晓凤 学号:20244127 实验教师:王志强 实验日期:2025年3月24日 必修/选修: 公选课 一.实验内容 1.熟悉Python开发环境:本次实验使用了PyCharm。首先在官网下载并安装PyCharm社区版,安装完成后打开软件,创建一个新的Pytho…

抽象bug:mybatis-xml配置错误(configuration and configLocation can not specified with together)

mybatis-xml配置错误(configuration and configLocation can not specified with together) 操作 我在使用mybatis-XML映射配置时,没有将mappper的xml文件放在同名同包的路径下,而是使用辅助配置,在配置文件中设置XML路径.然而,在配置文件后,没有成功,一直报错. 错误信息:"…

关于pytorch中直接调用对象

基于之前有C++基础,对于python中的一些函数的用法总会有些疑问。 例如,为什么python可以直接调用对象,而不是调用对象里的函数呢? 以下为包含__call__函数的类的调用 除此之外, 在PyTorch 中,所有继承自 nn.Module 的类都继承了一个特殊的 call() 方法。 # 使用ToTensor创…

事务注解@Transactional

目录 1、属性介绍 2、传播机制准备例子总结3、原理 4、失效场景 一、属性介绍 1、isolation 属性 事务的隔离级别,默认值为 Isolation.DEFAULT。可选的值有:Isolation.DEFAULT:使用底层数据库默认的隔离级别Isolation.READ_UNCOMMITTED:读取未提交数据(会出现脏读,不可重…