1、 中国矿业大学计算机学院2012 级本科生实验报告课程名称 系统软件开发实践 报告时间 2015/5/1 学生姓名 徐竹 学 号 08123325 专 业 计算机科学与技术 任课教师 刘 晋 -任课教师评语任课教师评语(对实验课程基础理论的掌握;对实验课程知识应用能力的评价;对课程报告相关实验、作品、软件等成果的评价;实验课学习态度和上课纪律;实验课程成果和报告工作量;总体评价和成绩;存在问题等):成 绩: 任课教师签字:年 月 日系统软件开发实践 实验报告 第 1 页-实验一(第一周) 词法分析器(flex 实验)一、实验目的1、通过对 flex 基本知识的阅读,了解其工作原理和过程以及其匹
2、配模式和规则,掌握简单的 lex 语法和规则;2、在上述基础上能够自主编写出简单且可以运行的词法分析器,实现简单的词法分析功能;3、通过实验,设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。二、实验说明本次编制调试的词法分析器基本可以实现如下简单功能:1、可以匹配识别关键字:else if switch for int float return void while(所有的关键字都是保留字,并且必须是小写) ;2、可以匹配识别专用符号: + - * / = = != = ; , ( ) /* */3、标识
3、符(ID) 和数字(NU )通过下列正则表达式定义:ID = letter letter*NUM = digit digit*letter = a|z|A|Zdigit = 0|94、可以匹配识别空格(空格由空白、换行符和制表符组成,空格通常被忽略, ,除了它必须分开 ID、NUM 关键字) ;5、可以识别简单的注释(/* 注释内容*/) ;三、实验原理与分析词法分析的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。词法分析阶段是编译过程的第一个阶段,是编译的基础。这个阶段的任务是从左到右一个字符一个字符地读入
4、源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。词法分析是编译程序的第一个阶段且是必要阶段;词法分析的核心任务是扫描、识别单词且对识别出的单词给出定性、定长的处理;实现词法分析程序的常用途径:自动生成,手工生成。而本次实验用的是自动生成工具 flex,相对于手动生成可以极大地减少工系统软件开发实践 实验报告 第 2 页-作量。单词的描述也就是模式(Lexical Pattern),模式一般用正规表达式进行精确描述。FLEX 通过读取一个有规定格式的文本文件,输出一个如下所示的 C 语言源程序。| 输入文件*.l |-|flex 工具 |-|输出文件 lex
5、.yy.c |FLEX 的输入文件为 LEX 源文件,它内含正规表达式和对相应模式处理的 C 语言代码。FLEX 通过对.l 源文件的扫描自动生成相应的词法分析函数 int yylex(),并将之输出到lex.yy.c 的文件中。该文件即为 LEX 的输出文件或输出的词法分析器。 LEX 的源文件由三个部份组成,每个部分之间用顶行的“%”分割,其格式如下:定义部份%规则部份 %用户附加 C 语言部份其中,定义部分由 C 语言代码、模式的宏定义、条件模式的开始条件说明三部份组成。C 代码部份由顶行的%和%引入,LEX 扫描源文件时将%和%之间的部分原封不动的拷贝到输出文件 lex.yy.c 中。
6、而模式宏定义则是一个正则表达式的定义。正则表达式的匹配如下:第二部分规则部份是 LEX 源文件的核心部份,它包括一组模式和在生成分析器识别相应模式后对相应模式进行处理的 C 语言动作(Action)。LEX 对第三部分不作任何处理,仅仅将之直接拷贝到输出文件 lex.yy.c 的尾部。在些部份,可定义对模式进行处理的 C 语言函数、主函数和 yylex 要调用的函数 yywrap()等。如果用户在其它 C 模块中提供这些函数,用户代码部份可以省略。yylex()函数被调用之后,它首先检查全局文件指针变量 yyin 是否有定义,如有,则将之设置为将要扫描的文件指针。如无,则设置为标准输入文件 s
7、tdin。同理,如全局系统软件开发实践 实验报告 第 3 页-文件指针变量 yyout 无定义,则将之设置为标准输出文件 stdout。若有多个模式与被扫描文件中的字符串相匹配,则 yylex()执行能匹配最长字符串的模式,称为“最长匹配原则” ;若还有多个模式匹配长度相同的字符串, 则 yylex()选择在 LEX 源文件中排列最前面的模式进行匹配,称为“最先匹配原则” 。yylex()常通过超前搜索一个字符来实现这样的原则,如果使 用超前搜索匹配了某一模式,则 yylex()在进行下一次分析前,将回退一个字符。另外,LEX 提供控制模式在一定状态下使用的功能,称为条件模式。LEX 首先在定
8、义部份通过%start 来定义条件句。在规则部份可通过宏 BEGIN 条件名 来激活条件。BEGIN INITIAL 或 BEGIN 0 将休眠所有的条件模式,使分析器回到开始状态。四、实验步骤和过程分析1、lex 源代码编写通过前期对 flex 的了解自主编写了 以下简单的的词法分析器,该词法分析器能够实现基本的词法分析功能如行数、关键字个数、单词个数以及简单注释等的判别。由于功能简单,所以本次代码完全是自己一一在记事本里面编写而成;digit 0-9NUM digitdigit* /*此正则表达式用于对数字进行匹配*/letter A-Za-zID letterletter* /*此正则表
9、达式是用于对标示符进行模式匹配*/“else“ num_id+;“while“ +num_id; /*这是实现代对关键字进行匹配*/“+“|“-“|“*“|“/“|“=“|“|“=“|“=“|“!=“|“;“|“,“|“(“|“)“|“|“|“|“|“/*“|“*“fuhao+; /*这些代码可以用于匹配其它符号*/ tn+ nword+; /*识别单词个数*/n hangshu+; /*对行数进行识别并统计 */*下面再编写一个 comment 函数用于判断注释 */comment()char c,c1;loop:while(c=input()!=*if(c1=input()!=/goto
10、loop;if(c!=0)putchar(n);int yywrap()return 1;系统软件开发实践 实验报告 第 4 页-最后将这些代码按照 flex 语法进行整合得到完整 flex 源码。2、通过命令行调试运行得到 lex.yy.exe 文件;3、编写测试文件(命名为 123.cpp)并与 lex.yy.exe 放于同一文件夹内;123.cpp:#include using namespace std;int mainint a=33,b=1123;c=12;c=a+b;cout 0);struct Page *p = base;for (; p != base + n; p +)
11、/检查此页是否是保留页assert(PageReserved(p);/设置标志位p-flags = 0;SetPageProperty(p);/将引用计数清零p-property = 0;set_page_ref(p, 0);/使用头插法将空闲页插入到链表(使用头插法是因为地址是从低地址向高地址增长)list_add_before(nr_free += n;/本行用于计算空闲页的总数base-property = n;(2)default_alloc_pages ()函数这个函数是用来分配空闲页链表的。大致可以分为七个步骤:第一步:寻找足够大的空闲块第二步:如果找到了,重新设置标志位,从空闲链
12、表中删除此页第三步:判断空闲块大小是否合适第四步:如果不合适,分割页块第五步:如果合适则不进行操作第六步:计算剩余空闲页个数第七步:返回分配的页块地址static struct Page *default_alloc_pages(size_t n) assert(n 0);if (n nr_free) return NULL;list_entry_t *le, *len;le = /在空闲页链表中寻找合适大小的页块while(le=list_next(le) != /找到合适页块if(p-property = n)系统软件开发实践 实验报告 第 22 页-int i;for(i=0;iprop
13、ertyn) /如果找到的页块大小合适则分割大页块(le2page(le,page_link)-property = p-property - n; /如果大小合适则不需要操作了ClearPageProperty(p);SetPageReserved(p);nr_free -= n;return p;return NULL;(3)default_free_pages()函数这个函数的作用是释放已经使用完的页,把他们合并到 freelist 中。这个函数的基本完成思想和思路为:1、首先在 freelist 中查找合适的位置以供插入;2、然后改变被释放页的标志位,以及头部的计数器;3、尝试在 fr
14、eelist 中向高地址或低地址合并;static voiddefault_free_pages(struct Page *base, size_t n) assert(n 0); /本行用来检测标志位是否有错误assert(PageReserved(base);list_entry_t *le = struct Page * p;/查找插入位置while(le=list_next(le) != if(pbase)break;/向插入位置插入多个页并设置标志位for(p=base;ppage_link);base-flags = 0;set_page_ref(base, 0);ClearPag
15、eProperty(base);系统软件开发实践 实验报告 第 23 页-SetPageProperty(base);base-property = n;/记录页块信息到头部p = le2page(le,page_link) ;/向高地址合并if( base+n = p )base-property += p-property;p-property = 0;le = list_prev(;/向低地址合并p = le2page(le, page_link);if(le!=base-property = 0;break;le = list_prev(le);p = le2page(le,page_
16、link);nr_free += n;return ;2、实现寻找虚拟地址对应的页表项通过设置页表和对应的页表项,可建立虚拟内存地址和物理内存地址的对应关系。其中的 get_pte 函数是设置页表项环节中的一个重要步骤。此函数找到一个虚地址对应的二级页表项的内核虚地址,如果此二级页表项不存在,则分配一个包含此项的二级页表。尝试获取页表的地址,如果获取不到就新建一个页表:pde_t *pdep = /本行用于尝试获取页表/用 if 语句判断是否获取页表成功if (!(*pdep if (!create | (page = alloc_page() = NULL) return NULL;set_
17、page_ref(page, 1); /获取页的线性地址uintptr_t pa = page2pa(page);memset(KADDR(pa), 0, PGSIZE); /设置权限*pdep = pa | PTE_U | PTE_W | PTE_P;return 系统软件开发实践 实验报告 第 24 页-3、释放某虚地址所在的页并取消对应二级页表项的映射当释放一个包含某虚地址的物理内存页时,需要让对应此物理内存页的管理数据结构 Page 做相关的清除处理,使得此物理内存页成为空闲;另外还需把表示虚地址与物理地址对应关系的二级页表项清除。本练习的基本思路为判断此页被引用的次数,如果仅仅被引用
18、一次,则这个页也可以被释放。否则,只能释放页表入口。具体代码实现过程如下:if (*ptep if (page_ref_dec(page) = 0) /此 if 语句用来判断页表是否被多次引用free_page(page); /如果仅仅引用一次则释放此页,如果被多次引用则不能释放*ptep = 0;tlb_invalidate(pgdir, la); 系统软件开发实践课程小结部分首先要说的是,相对于其它实验课报告书写来讲,本次实验 24 页的实验报告的书写委实是不容易,因为大部分内容需要自己重新编辑、整理和分析,不过,这次报告书写的确是对之前六周实验课的又一次深入的回顾与学习啊,之前好多不懂的
19、问题,通过本次报告书写过程中查找资料和询问他人大部分都明白和解决了。这些也算是本次报告书写的感触以及感悟吧。通过六个周的实验课的学习,我也渐渐明白系统软件开发实践这门课程对我们领悟经典编译器以及系统软件(操作系统等)的设计理念、深入理解系统软件的功能特性和编译器的设计和实现过程的确有很大帮助。如果我们今后能够基于这些功能特性是很容易编写出高质量程序的。但学习这些内容和知识却也不是一件容易的事情。通过六周的学习和实验,我所学的也仅仅是这门课的皮毛而已。由于我们对着门课程并不是太熟悉,好多东西积累更是不足,这也导致了我们在实系统软件开发实践 实验报告 第 25 页-验课程中注定是要遇到好多问题,但
20、我觉得系统软件开发实践实验课是一门极具实践性质的课程,所以实践的过程也即是不断学习的过程。在实验的设计过程中,我们不断地运用到了之前在课堂上所学到的编译原理知识以及操作系统和汇编语言等方面的知识,这极大地锻炼了自己的实践能力。另外在这次设计的过程中,我懂得了在设计遇到困难的时候怎样去解决这个困难,向比我们知识丰富的人虚心请教和自己查找网上的资料是我解决问题的主要方法,这样也同时扩宽了我的知识面,打破了课堂的局限。也正式通过这门实践课,我初步接触并理解了一个编译器的基本设计和实现过程。当然,这也是基于之前学过编译原理的一点点基础之上的。也是为了完成课程中的相关实验,搭建相关实验环境,我逐步接触到了 linux 系统,并通过自己查资料找和学习一步步完成了 ubuntu 系统的安装和实验环境的搭建和配置过程,让自己的电脑也名副其实的拥有了双系统。特别是对 linux 系统的接触和学习对我今后工作和学习中所遇到的服务器的相关操作一定会有很大的帮助。最后我还想说的是,通过课堂和实验我们能够学到的知识毕竟有限,更多的相关知识的学习还要靠我们今后自觉地去涉足、去学习、去探索。