词法分析flex——集成c++实现简单编译器

cmake项目结构

包含词法分析和语法分析两部分,main.cpp用于实现更复杂功能,假设不使用。

若不使用Bison,则使用parser.h和parser.cpp替换parser.y。

cmake_minimum_required(VERSION 3.16)
project(Compiler)
set(CMAKE_CXX_STANDARD 14)

# 使用 cmake 的 flex 模块
include(FindFLEX)
if(FLEX_FOUND)
    message("Info: flex found!")
else()
    message("Error: flex not found!")
endif()
# 为了 flex 新增头文件搜索路径
include_directories(${CMAKE_SOURCE_DIR})
# 指定 flex 编译目标
FLEX_TARGET(MyScanner lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp)

add_compile_options(-pedantic)
# add_compile_options(-fsanitize=address)
# add_link_options(-fsanitize=address)
add_executable(Compiler
    parser.cpp
    ${FLEX_MyScanner_OUTPUTS}
)
target_compile_features(Compiler PRIVATE cxx_std_14)

词法分析lexer.l

%{
    c说明
%}                                说明部分
正规式辅助定义

%%                           -----------------

模式(正则匹配)    {动作}        规则部分

%%                           -----------------
                                 用户代码部分

LEX中常用的一些变量和函数

 

考虑到flex通过FILE* yyin读取文件生成结果,文件存放在外存。若在动作中使用return结束yylex()以逐词分析,则每遇到一个词访问一次外存,运行时间较长。所以应一次性扫描完整个输入文件(即只调用一次yylex),并将生成的词法分析结果存放在内存中(使用变量out)。

可以选择定义以下scan函数,在语法分析部分声明外部变量scan。或者直接在语法分析部分声明外部变量yyin和yylex。

%{
    #include "parser.h"
    声明变量out存储词法分析结果
%}
%option noyywrap    或者定义函数yywrap,否则报错
delim [ \t\n]

%%
{delim}+ {}
int {out <- INT;}
...    若是单个{字符需加引号,即 "{" {动作}
[;,] {out <- END;}
[0-9]+ {out <- <CONST,yytext;}
[A-Za-z_][0-9A-Za-z_]* {out <- VARI,yytext;}
[+\-*/%<>=!&|^()]=* {out <- OPTR,yytext;}

%%
void scan(char* const& filepath) {
    yyin=fopen(filepath,"r");yylex();
}
string generate() {return out;}

在词法分析部分声明out

如上述代码,可以选择上述方法,在用户代码部分定义返回值为out的函数,在parser.cpp中extern string generate();后使用该函数。或者在parser.h中声明该函数。

或者不使用函数,直接在parser.cpp中extern变量out。

在头文件声明out

若变量out声明在包含的头文件parser.h中,由于parser.cpp和lexer.l均include了该头文件,会报错out。若将out声明为静态全局变量,则可能出现bug,在lexer.l中不能正确赋值out。或者使用如下方法以解决该报错。

包含了上述两种情况的方法

若在lexer.l或parser.cpp中#define INITIAL,并在头文件中添加如下代码段,将变量out定义在#define INITIAL的文件中。

#ifdef INITIAL
    string out;
#else
    extern string out;
#endif

总结

总而言之,集成还是很简单的,只需要会使用extern就可以。

发这篇文章,关键是想记录一下一种错误情况——打印scanner.l的结果和正确tokens的语法分析结果均正确,但是集成在一起是没有输出且程序不终止。

可能的原因——在parser.h中声明静态全局变量static string tokens。可能会导致在scanner.l中不能成功赋值,且程序不终止。

引用文章

编译原理学习(三)——Flex实现词法分析器(附Flex使用简介)_flex词法分析-CSDN博客

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值