一、实验内容

1.借助词法分析工具Flex或Lex完成(参考网络资源)
2.输入:高级语言源代码(如helloworld.c)
3.输出:以二元组表示的单词符号序列。

二、实验目的

通过设计、编制、调试一个具体的词法分析程序,加深对词法分析原理的理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。

三、实验分析

由于各种不同的高级程序语言中单词总体结构大致相同,基本上都可用一组正则表达式描述,所以构造这样的自动生成系统:只要给出某高级语言各类单词词法结构的一组正则表达式以及识别各类单词时词法分析程序应采取的语义动作,该系统便可自动产生此高级程序语言的词法分析程序。Lex就是一个词法分析程序的自动生成工具。一个Lex源程序经过Lex编译系统可生成词法分析程序L。
一个Lex源程序具有如下形式:

声明部分
%%
转换规则
%%
辅助函数

在声明部分中,定义变量与常量。也可以声明正则表达式。
而Lex的每个转换规则具有如下形式:
模式 {动作}
其中,模式是正则表达式,可以使用声明部分中给出的正则定义。动作是代码片段,利用c语言编写。
Lex源程序存储在.l文件中,利用win_flex可以将其生成输出lex.yy.c文件。lex.yy.c文件可以被c语言编译器编译并运行。
为了识别一个真实的c语言源程序,需要用到如下辅助定义:
letter->a-zA-Z
digit->0-9
这两个辅助定义用于识别单个字母字符与单个数字字符。
在本实验中,需要识别的c语言程序保留字如下:while、if、else、switch、case、int、main、using、namespace、std、printf。可用一个正则表达式进行识别:
(while)|(if)|(else)|(switch)|(case)|(int)|(main)|(using)|(namespace)|(std)|(printf)
c语言的标识符id规则如下:由字母、数字、下划线组成,且第一个字符只能为字母或下划线。则标识符的正则表达式为:({letter}|_)({letter}|{digit}|_)*
整数的正则表达式如下:(‘+’|’-’)?{digit}*
其中,问号表示’+’号或’-’号要么不出现,要么出现了有且只有一次。这一正则表达式可以接受正数与负数。
浮点数的正则表达式如下:{digit}+.{digit}+((E|e)(‘+’|’-’)?{digit}+)?
在小数点之前至少有一位数字,在小数点之后也至少有一位数字。在数字后可以附带这个数需要乘10的多少次幂,也可以不附带。
c语言中的运算符除了加减乘除、比较、赋值外,还有流输入输出。正则表达式如下:\+|-|\*|<=|<|==|=|>=|>|>>|<<。因为正则表达式本身有加号与乘号,所以在加号与乘号前追加反斜杠进行转义。
识别空格、tab、换行符、回车符(\r)的正则表达式为: \t\n\r,记为delim。为了识别多个空白,可用正则表达式{delim}+
识别字符串的正则表达式为:”[^”]*”,即在两个双引号内可以有任意个除双引号字符以外的字符。为了转义,在c语言程序中需写作:\"[^"]*\"
识别c语言程序开头包含的头文件时,需要先识别#号,再识别出除换行符以外的任何字符。正则表达式语句如下:"#".*
在lex程序中,在读取完成需要进行词法分析的源代码文件后,调用yylex()即可自动开始进行词法分析,词法分析得到的词法单元属性值暂存在全局变量yylval中,而识别得到的单词字符串存放在变量yytext中。
在运行过程中,每将输入的文件匹配到一个正则表达式,就自动执行其动作。在本实验中,被执行的动作为以二元组形式表示当前单词。即为:(单词种别,单词自身的值)。这一过程反复进行,并会在识别到非法字符时报错。直到读取到文件结束时,这一过程结束。

四、实验流程

在下载完成win_flex的压缩包后,对该文件夹解压可以看到win_flex.exe的文件。这一exe文件不能直接运行。需要首先配置环境变量,将这一文件所在的路径添加到系统变量的Path内。在cmd窗口,对Lex源程序的.l文件执行win_flex --nounistd lex.l,就能生成出lex.yy.c。添加参数–nounistd的目的是生成出能在windows环境下编译运行的lex.yy.c而不是只能在linux/unix环境下执行的lex.yy.c。
在编写完.l文件后,执行win_flex,生成lex.yy.c。在visual studio等编译器中可以编译运行这个文件,将待分析的另一个c语言源程序进行词法分析并输出到控制塔上。
因此,实验的整体操作流程如下

五、实验代码

5.1 代码说明

在%{ 与%}之间是插入c语言程序,include相关库并定义全局变量为计数器记录当前在分析第几个单词。

%{#include <stdio.h>#include <stdlib.h>int count = 0;
%}

正则表达式的声明部分,与第三章分析的各个单词类型对应的正则表达式是一致的。

digit        [0-9]
letter      [a-zA-Z]
reservedWord    [w][h][i][l][e]|[i][f]|[e][l][s][e]|[s][w][i][t][c][h]|[c][a][s][e]|[i][n][t]|[m][a][i][n]|[u][s][i][n][g]|[n][a][m][e][s][p][a][c][e]|[s][t][d]|[p][r][i][n][t][f]
id  ({letter}|_)({letter}|{digit}|_)*
num {digit}+
operator    \+|-|\*|<=|<|==|=|>=|>|>>|<<
delim       [ \t\n\r]
whitespace  {delim}+
semicolon [\;]
str \"[^"]*\"
other       .
%%

辅助函数部分,针对每个正则表达式都执行对应动作:计数器加一,分析当前单词的单词种别与单词自身的值。

%%
{reservedWord}  {count++;printf("%d\t(reserved word,\'%s\')\n",count,yytext);}
{id}    {count++;printf("%d\t(id,\'%s\')\n",count,yytext);}
{num}   {count++;printf("%d\t(num,\'%s\')\n",count,yytext);}
{operator}      {count++;printf("%d\t(op,\'%s\')\n",count,yytext);}
{whitespace}    { /* do    nothing*/ }
{str} {count++;printf("%d\t(string,\'%s\')\n",count,yytext);}
"(" {count++;printf("%d\t(left bracket,\'%s\')\n",count,yytext);}
")" {count++;printf("%d\t(right bracket,\'%s\')\n",count,yytext);}
"{" {count++;printf("%d\t(left bracket,\'%s\')\n",count,yytext);}
"}" {count++;printf("%d\t(right bracket,\'%s\')\n",count,yytext);}
":" {count++;printf("%d\t(colon,\'%s\')\n",count,yytext);}
";" {count++;printf("%d\t(semicolon,\'%s\')\n",count,yytext);}
"#".* {count++;printf("%d\t(head,\'%s\')\n",count,yytext);}
{other}     {printf("illegal character:\'%s\'\n",yytext);}
%%

main函数的作用就是读取文件到yyin,并调用yylex()自动地对yyin的文件进行词法分析。

int main(){yyin=fopen("F:/HOMEWORK/Compiler/Lab2/test.c","r");yylex();return 0;
}int yywrap(){return 1;}

5.2 完整代码

%{#include <stdio.h>#include <stdlib.h>int count = 0;%}
digit       [0-9]
letter      [a-zA-Z]
reservedWord    [w][h][i][l][e]|[i][f]|[e][l][s][e]|[s][w][i][t][c][h]|[c][a][s][e]|[i][n][t]|[m][a][i][n]|[u][s][i][n][g]|[n][a][m][e][s][p][a][c][e]|[s][t][d]|[p][r][i][n][t][f]
id  ({letter}|_)({letter}|{digit}|_)*
num {digit}+
operator    \+|-|\*|<=|<|==|=|>=|>|>>|<<
delim       [ \t\n\r]
whitespace  {delim}+
semicolon [\;]
str \"[^"]*\"
other       .
%%
{reservedWord}  {count++;printf("%d\t(reserved word,\'%s\')\n",count,yytext);}
{id}    {count++;printf("%d\t(id,\'%s\')\n",count,yytext);}
{num}   {count++;printf("%d\t(num,\'%s\')\n",count,yytext);}
{operator}      {count++;printf("%d\t(op,\'%s\')\n",count,yytext);}
{whitespace}    { /* do    nothing*/ }
{str} {count++;printf("%d\t(string,\'%s\')\n",count,yytext);}
"(" {count++;printf("%d\t(left bracket,\'%s\')\n",count,yytext);}
")" {count++;printf("%d\t(right bracket,\'%s\')\n",count,yytext);}
"{" {count++;printf("%d\t(left bracket,\'%s\')\n",count,yytext);}
"}" {count++;printf("%d\t(right bracket,\'%s\')\n",count,yytext);}
":" {count++;printf("%d\t(colon,\'%s\')\n",count,yytext);}
";" {count++;printf("%d\t(semicolon,\'%s\')\n",count,yytext);}
"#".* {count++;printf("%d\t(head,\'%s\')\n",count,yytext);}
{other}     {printf("illegal character:\'%s\'\n",yytext);}
%%
int main(){yyin=fopen("F:/HOMEWORK/Compiler/Lab2/test.c","r");yylex();return 0;
}int yywrap(){return 1;}

六、运行结果


编译运行.l文件,加入参数nounistd,生成了可在Windows 10 环境下可以运行的lex.yy.c,如图3所示。


如图4,编写用于测试词法分析器的真实c语言代码。

对lex.yy.c代码进行编译运行,并将结果输出在控制台上,如图5。该词法分析器能自动忽略空格、换行符、tab,按照顺序逐一将每个单词进行编号,并生成二元组(单词种别,单词自身的值)。
图5词法分析结果与图4的测试文件一一对应。
头文件首先被识别出来。识别语句using namespace std,并识别语句的分号。
识别int main,并识别紧随其后的左右小括号与大括号。
源代码“int a1=0;”被识别如下:保留字int,标识符a1,赋值号=,数字0。并识别分号。
源代码“if(a1==1);”被识别如下:保留字if、左括号、标识符a1、比较相等的符号==、数字1、右括号、分号。
源代码“printf(“hello world”)”被识别为:保留字printf、左括号、字符串”hello world”、右括号。需要说明的是,”hello world”字符串是一个单词,没有因为中间有空格而被识别为两个单词。
else、switch等单词均为保留字。识别标识符a1、括号的过程都是同理的。
源代码“case 1:printf(“hello”);”被识别为:保留字case、数字1、保留字printf、左括号、字符串”hello”、右括号、分号。源代码“case 2:printf(“world”);”同理。
最后识别两个右大括号。读取到文件结束符后,程序结束。

七、实验感悟

【编译原理】 实验一:词法分析器的自动实现(Lex词法分析)相关推荐

  1. html解析器编译原理,编译原理实验报告词法分析器(内含源代码).docx

    编译原理实验报告词法分析器(内含源代码) 编译原理实验(一) --词法分析器 实验描述 运行环境:vc++2008 对某特定语言A ,构造其词法规则. 该语言的单词符号包括: 1该程序能识别的单词符号 ...

  2. C++:编译原理实验之词法分析器

    一.实验目的 学会针对DFA转换图实现相应的高级语言源程序. 深刻领会状态转换图的含义,逐步理解有限自动机. 掌握手工生成词法分析器的方法,了解词法分析器的内部工作原理. 加强对C语言的掌握 二.实验 ...

  3. c语言词法分析器实验原理,词法分析器的设计与实现 编译原理实验报告.doc

    词法分析器的设计与实现 编译原理实验报告 中北大学软件学院 实 验 报 告 专 业 软件工程 课程名称 编译原理 学 号 姓 名 辅导教师 张静 成绩 实验日期2015.5.19实验时间14:00~1 ...

  4. 编译原理实验-LL1语法分析器(自动生成First集、Follow集求法)java实现

    编译原理实验-LL1语法分析器(自动生成First.Follow)java 博主在做实验时,参考众多他人代码,发现bug众多,在@moni_mm代码基础上,与伙伴把能看到的BUG都做出修正,同时增添了 ...

  5. 编译原理实验:词法分析

    编译原理实验:词法分析 1. 实验题目:词法分析 实验目的 实验内容 实验要求 输入输出 2. 设计思想 3.算法流程 4. 源程序 5. 调试数据 1. 实验题目:词法分析 实验目的 根据PL/0语 ...

  6. 贵州大学-编译原理实验2-句法分析器

    贵州大学-编译原理实验2-句法分析器 考虑下面的C语言子集的文法,其中<>括起来的为非终结符,粗体为终结符. ® <statement_list> <statement_ ...

  7. 编译原理实验c语言cfg文法,编译原理

    地址在符号表中引入指针previous,来连接上一个符号的首地址运行时存储空间组织活动记录用于管理函数变量的信息栈式存储过程进入和返回通过变更top和sp指针,实现活动记录的栈式处理静态链实现局部变量 ...

  8. 编译原理--实验2 语法分析

    文章目录 前言 1.1实验目的 1.2 实验任务 1.3 实验内容 1.3.1 实验要求 1.3.2 输入格式 1.3.3 输出格式 1.3.4 样例 1.4 程序 1.4.1 程序流程图 1.4.2 ...

  9. 编译原理实验二:Bison

    编译原理实验二:Bison 实验要求 1.了解Bision基础知识,如何将文法产生式转换为Bison语句 2.阅读/src/common/SyntaxTree.c,对应头文件 /include/Syn ...

最新文章

  1. 用C语言编程实现矩形波信号,信号与系统综合设计性实验
  2. 1.2 偏差/方差-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  3. python简单网络爬虫_【Python】简单的网络爬虫
  4. Linux网络编程组播测试代码
  5. all any 或 此运算符后面必须跟_any和all组合运算符用法区别
  6. MBSA有关安全漏洞的检查说明一
  7. 【零基础学Java】—类的定义(七)
  8. QYResearch回顾:2017年中国汽车语音识别系统产量为1413万
  9. Navicat无法连接SqlServer数据库
  10. Java基础教程之Java的变量
  11. prune研究记录(二)
  12. 2020年商用的5G,中兴通讯已经下了哪些先手棋?
  13. Linux下常用的压缩解压命令[收藏]
  14. python人脸识别代码_一行Python代码搞定人脸识别
  15. ansys命令流——点线面体基础操作(02)
  16. R语言-主成分分析和聚类分析实操(包含源码)
  17. java连接qq邮箱_Java使用qq邮箱发邮件实现
  18. 简单的下载excel模板
  19. 网络安全十大威胁的防范方法
  20. java基础(代码练习)

热门文章

  1. 转载——win7笔记本忘记密码怎么办
  2. 使用CSS3+JQuery打造自定义视频播放器
  3. Python: 1017 A除以B
  4. 《穷查理宝典》芒格思维笔记(一)
  5. 超级玛丽HTML5源代码学习------(四)
  6. javascript实现俄罗斯方块
  7. emlog怎么样判断文章名字是否重复,重复则提示
  8. Element UI 之table表格表头过长使用点点...显示,并添加鼠标移入悬浮显示
  9. 给学弟学妹们写了个 15W 字的图解操作系统!
  10. Guitar Pro8.0.1最新中文版本吉他谱下载及使用教程