# 设计内容
使用词法分析的自动生成工具 Flex 生成 C/C++ 语言的词法分析器 ,当输入 C/C++ 源代码文件时,即后缀为 c/cpp 的文件,程序输出后缀为 tok 的文本性文件。涉及知识点:词法分析,Flex 工具使用。
# 设计思想和实现方法
# 一、设计思路:
首先根据 c/cpp 语言特色,将词汇分类,如图所示:

确定每一类词的正则表达式:(示例如下图所示)
```c++
HEADFILE
"iostream"|"stdio.h"|"stdlib.h"|"string.h"|"math.h"|"memory.h"|"cstdio"|"cstring"|"algorithm"|" cmath"
```
| pretreatment | [#]{DEFINE} |
| ------------ | ----------------------------------------------------------- |
| DIGIT | [0-9] |
| LETTER | [a-zA-Z] |
| int | ([-+]?{DIGIT}+)\|([+-]?[0][0-7]+)\|([+-]?[0][xX][0-9a-fA-F]+) |
| real | [-+]?{DIGIT}+(\.{DIGIT}+)([eE][+-]?{DIGIT}+)? |
| Identifier | ({LETTER}\|[_])({LETTER}\|{DIGIT}\|[_])* |
| AUTO;.... | “auto” |
| MAIN | “main” |
```c++
KEYWORDS
{AUTO}| {BOOL}| {BREAK}| {CASE}| {CATCH}| {CHAR}| {CLASS}| {CONST}| {C_CAST} | {CONTINUE}| {DEFAULT}| {DELETE}| {DO}| {DOUBLE}| {ELSE}| {ENUM}| {EXTERN}| {FA
LSE
}| {FLOAT}| {FOR}| {FRIEND}| {GOTO}| {IF}| {INLINE}| {INT}| {LOG}| {LONG}| {NAMESP
ACE
}| {NEW}| {OPERATOR}| {PRIVATE}| {PROTECTED}| {PUBLIC}| {REGISTER}| {RETUR
N
}| {SHORT}| {SIGNED}| {SIZEOF}| {STATIC}| {STRUCT}| {SWITCH}| {TEMPLATE}| {THIS}|
{TRUE}| {TRY}| {TYPEDEF}| {USING}| {VIRTUAL}| {UNION}| {VOID}| {WHILE}| {MAIN}
```
# 二、实现方法:
结合所得正则表达式、Lex 语法写出对应 lex 语言代码,如下图所示:
```c++
% {
放 c 文件头文件、预处理、全局变量等
%
}
声明部分
类型 正则表达式
%%
转换规则
类型 对应处理
%%
辅助函数 main() {}
yywrap() {}
```
利用 Flex 工具得到对应词法分析器源代码,编译后即可生成目的词法分析器,对应 DOS 环境下执行命令如下图所示:

# 三、程序说明
lex 源文件部分代码:

```c++
% {
# include<stdio.h>
# include<string.h>
# include<stdlib.h>
int lines=1;//行数计数器
int keys=0;//关键词计数器
int numbers=0;//数字计数器
int identifiers=0;//标识符计数器
int operators=0;//算术操作符计数器
int relationals=0;//关系符计数器
int error_identifiers=0;//错误词项计数器
int headfile_num=0;//头文件计数器
int strings=0;//字符串计数器
int characters=0;//字符计数器
int error_lines[10];//用于存放错误词项所在行数 %}
```

```c++
}
批注:放 c 文件头文件、预处理、全局变量等全局变量主要用于类型计数
批注:该部分为声明部分,主要来写出类型对应的正则表达式。
长安大学信息工程学院软件工程系 编译技术课程设计报告
4
COMMENTS "/*"(.|\n)*"*/"|"//".* SEPARATPR {COMMA}|{SC}|{LB}|{LP}|{RB}|{RP}
OPERATORS
{PLUS}|{MINUS}|{MULT}|{MOD}|{DIV}|{PLUSA}|{MINUSA}|{MULA}|{DIVA}|{MO
DA}|{LS}|{RS}|{LSA}|{RSA}|{POSINC}|{POSDEC}|{PREINC}|{PREDEC}|{ASSIGN}
FORMAT "%d"|"%lld"|"%f"|"%lf"|"%c"|"%x"|"%a"|"%e"|"%g"|"%o" KEYWORDS
{AUTO}|{BOOL}|{BREAK}|{CASE}|{CATCH}|{CHAR}|{CLASS}|{CONST}|{C_CAST}
|{CONTINUE}|{DEFAULT}|{DELETE}|{DO}|{DOUBLE}|{ELSE}|{ENUM}|{EXTERN}|{FA
LSE}|{FLOAT}|{FOR}|{FRIEND}|{GOTO}|{IF}|{INLINE}|{INT}|{LOG}|{LONG}|{NAMESP
ACE}|{NEW}|{OPERATOR}|{PRIVATE}|{PROTECTED}|{PUBLIC}|{REGISTER}|{RETUR
N}|{SHORT}|{SIGNED}|{SIZEOF}|{STATIC}|{STRUCT}|{SWITCH}|{TEMPLATE}|{THIS}|
{TRUE}|{TRY}|{TYPEDEF}|{USING}|{VIRTUAL}|{UNION}|{VOID}|{WHILE}|{MAIN}
HEADFILE
"iostream"|"stdio.h"|"stdlib.h"|"string.h"|"math.h"|"memory.h"|"cstdio"|"cstring"|"algorithm"|" cmath" ESC "\\a"|"\\b"|"\\f"|"\\n"|"\\r"|"\\t"|"\\v"|"\\'"
```
*批注:该部分为转换规则部分,主要来写出类型对应的处理方案,例如遇到换行符,需要将行数加 1,遇到头文件,要将行号、属性、词法单元名写入文件,头文计数器加 1。*
```c++
%%
[\n] { lines++; }
[ \t]
[#]{INCLUDE}[ ][<]{HEADFILE}[>]
{ fprintf(yyout,"Lines: %d head file:---------%s\n", lines, yytext);headfile_num++; }
[#]{DEFINE}
{ fprintf(yyout,"Lines: %d pretreatment:------%s\n", lines, yytext); }
{KEYWORDS}
{ fprintf(yyout,"Lines: %d keywords:----------%s\n", lines, yytext); keys++; }
([-+]?{DIGIT}+)|([+-]?[0][0-7]+)|([+-]?[0][xX][0-9a-fA-F]+)
{ fprintf(yyout,"Lines: %d integer------------%s\n", lines, yytext); numbers++; }
[-+]?{DIGIT}+(\.{DIGIT}+)([eE][+-]?{DIGIT}+)?
{ fprintf(yyout,"Lines: %d real---------------%s\n", lines, yytext); numbers++; }
({LETTER}|[_])({LETTER}|{DIGIT}|[_])*
{ fprintf(yyout,"Lines: %d identifier---------%s\n", lines, yytext); identifiers++; }
{STRING}
{ fprintf(yyout,"Lines: %d string-------------%s\n", lines, yytext); strings++;} 。。。。。。。。
{COMMENTS}
{ fprintf(yyout,"Lines: %d comments-----------%s\n", lines, yytext); }
```
批注:该部分为辅助函数部分,主要用来写主函数里的操作,主函数里的操作主要有将 yyin 指向输入文件,将 yyout 指向输出文件,命令行下输出各类词汇总数和错误总数。
```c++
%%
int main(int argc,char **argv)
{
++argv, --argc; /* skip over program name */ if ( argc > 0 )
{ yyin = fopen(argv[0], "r" );
yyout = fopen("result.tok", "w");
if(!yyout) printf("can`t open result.tok");
}
else yyin = stdin;
if(yyin)
{
printf( "******************************************************************\n"
);
printf( "Filename:%s\n",argv[0]);
yylex();
if(error_identifiers>0) {
printf( "******************************************************************\n"
);//输出错误总数及所在行数
printf( "%d errors \n", error_identifiers );
int i;
for(i=0; i<error_identifiers; i++) printf( "at line %d\n",error_lines[i]);
}
printf( "******************************************************************\n"
);//输出各类词项总数
printf( "Analyzed Results:\n");
printf( "headfile_num=%d\n", headfile_num );
printf( "lines=%d\n", lines-1 );
printf( "keywords=d\n", keys );
printf( "relationals=d\n", relationals );
printf( "operators=%d\n", operators );
printf( "numbers=%d\n", numbers );
printf( "identifiers=%d\n", identifiers );
printf( "strings=%d\n", strings );
printf( "characters=%d\n", characters );
fclose(yyin);
fclose(yyout);
printf( "******************************************************************\n"
);
system( "pause" );
}
else printf("Invalid Filename \n");
return 0;
}
int yywrap()
{ return 1;
}
```
# 四、运行结果:
打开 Dos 命令行,使用所生成词法分析器,输入 test1.cpp 文件,输出存放词法分析结果的 result.tok 文件,命令行中输出各类词汇总数和错误总数。
**命令行情况**:

**Test1.cpp 源文件:**
```c++
#include <iostream>
using namespace std;
int count=0;
int main()
{
int i

神仙别闹
- 粉丝: 5937
最新资源
- 技术转化新引擎:打造高效协同的科技成果流动体系.docx
- 技术转化新引擎:区域科技成果服务平台的创新实践.docx
- 科技成果转化困局与破局之道.docx
- 科技成果转化新范式:节点赋能与生态构建.docx
- 请基于我提供的产品介绍核心信息,从以下所给的写作风格中,随机选其一,为我生成 1 篇营销软文。.docx
- 区域科技成果转化服务创新模式探索.docx
- 区域科技成果转化服务:技术经纪人的新生态.docx
- 区域科技成果转化服务:提升园区创新效能的新路径.docx
- 区域科技成果转化服务的创新之路.docx
- 区域科技成果转化服务新范式:从资源到价值的链式突破.docx
- 区域科技成果转化服务新范式探索.docx
- 区域科技成果转化服务新模式解析.docx
- 区域科技成果转化服务新模式探索.docx
- 区域科技成果转化服务新模式探索与实践.docx
- 生态赋能:高校科技成果转化数智新路径.docx
- 数智引擎加速高校院所科技成果转化.docx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈


