版权所有南京大学计算机科学与技术系许畅等2022春季版 2.词法分析与语法分析 本章实验为实验一,任务是编写一个程序对使用C一语言书写的源代码进行词法分析和语 法分析(C-一语言的文法参见附录A),并打印分析结果。实验要求使用词法分析工具GNU Flex和语法分析工具GNU Bison,并使用C语言来完成。在两个强大工具的帮助下,编写一个 能进行词法分析和语法分析的程序是一件相当轻松愉快的事情。 需要注意的是,由于在后面的实验中还会用到本次实验已经写好的代码,因此保持一个良 好的代码风格、系统地设计代码结构和各模块之间的接口对于整个实验来讲相当重要。 2.1实验内容 2.1.1实验要求 你的程序要能够查出C-一源代码中可能包含的下述几类错误: 1)词法错误(错误类型A):即出现C-一词法中未定义的字符以及任何不符合C一词法单 元定义的字符; 2)语法错误(错误类型B)。 除此之外,你的程序可以选择完成以下部分或全部的要求: 1)要求11:识别八进制数和十六进制数。若输入文件中包含符合词法定义的八进制数 (如0123)和十六进制数(如0x3F),你的程序需要得出相应的词法单元;若输入文件中包 含不符合词法定义的八进制数(如09)和十六进制数(如0x1G),你的程序需要给出输入文 件有词法错误(即错误类型A)的提示信息。八进制数和十六进制数的定义参见附录A。 2)要求1.2:识别指数形式的浮点数。若输入文件中包含符合词法定义的指数形式的浮点 数(如1.05e-4),你的程序需要得出相应的词法单元;若输入文件中包含不符合词法定义的 指数形式的浮点数(如1.05e),你的程序需要给出输入文件有词法错误(即错误类型A)的提 示信息。指数形式的浮点数的定义参见附录A。 3)要求1.3:识别“"和“件.*"形式的注释。若输入文件中包含符合定义的“1和“*..*" 形式的注释,你的程序需要能够滤除这样的注释;若输入文件中包含不符合定义的注释(如 “*"注释中缺少“”),你的程序需要给出由不符合定义的注释所引发的错误的提示信 息。注释的定义参见附录A。 你的程序在输出错误提示信息时,需要输出具体的错误类型、出错的位置(源程序行号) 以及相关的说明文字。 10
版权所有 南京大学计算机科学与技术系 许畅等 2022春季版 10 2. 词法分析与语法分析 本章实验为实验一,任务是编写一个程序对使用C−−语言书写的源代码进行词法分析和语 法分析(C−−语言的文法参见附录A),并打印分析结果。实验要求使用词法分析工具GNU Flex和语法分析工具GNU Bison,并使用C语言来完成。在两个强大工具的帮助下,编写一个 能进行词法分析和语法分析的程序是一件相当轻松愉快的事情。 需要注意的是,由于在后面的实验中还会用到本次实验已经写好的代码,因此保持一个良 好的代码风格、系统地设计代码结构和各模块之间的接口对于整个实验来讲相当重要。 2.1 实验内容 2.1.1 实验要求 你的程序要能够查出C−−源代码中可能包含的下述几类错误: 1) 词法错误(错误类型A):即出现C−−词法中未定义的字符以及任何不符合C−−词法单 元定义的字符; 2) 语法错误(错误类型B)。 除此之外,你的程序可以选择完成以下部分或全部的要求: 1) 要求1.1:识别八进制数和十六进制数。若输入文件中包含符合词法定义的八进制数 (如0123)和十六进制数(如0x3F),你的程序需要得出相应的词法单元;若输入文件中包 含不符合词法定义的八进制数(如09)和十六进制数(如0x1G),你的程序需要给出输入文 件有词法错误(即错误类型A)的提示信息。八进制数和十六进制数的定义参见附录A。 2) 要求1.2:识别指数形式的浮点数。若输入文件中包含符合词法定义的指数形式的浮点 数(如1.05e-4),你的程序需要得出相应的词法单元;若输入文件中包含不符合词法定义的 指数形式的浮点数(如1.05e),你的程序需要给出输入文件有词法错误(即错误类型A)的提 示信息。指数形式的浮点数的定义参见附录A。 3) 要求1.3:识别“//”和“/*…*/”形式的注释。若输入文件中包含符合定义的“//”和“/*…*/” 形式的注释,你的程序需要能够滤除这样的注释;若输入文件中包含不符合定义的注释(如 “/*…*/”注释中缺少“/*”),你的程序需要给出由不符合定义的注释所引发的错误的提示信 息。注释的定义参见附录A。 你的程序在输出错误提示信息时,需要输出具体的错误类型、出错的位置(源程序行号) 以及相关的说明文字
版权所有南京大学计算机科学与技术系许畅等2022春季版 2.1.2输入格式 你的程序的输入是一个包含C-一源代码的文本文件,程序需要能够接收一个输入文件名作 为参数。例如,假设你的程序名为cc、输入文件名为test1、程序和输入文件都位于当前目录 下,那么在Linux命令行下运行./cc test1即可获得以testl作为输入文件的输出结果。 2.13输出格式 实验一要求通过标准输出打印程序的运行结果。对于那些包含词法或者语法错误的输入文 件,只要输出相关的词法或语法有误的信息即可。在这种情况下,注意不要输出任何与语法树 有关的内容。要求输出的信息包括错误类型、出错的行号以及说明文字,其格式为: Error type[错误类型]at Line[行号]:[说明文字]. 说明文字的内容设有具体要求,但是错误类型和出错的行号一定要正确,因为这是判断输 出的错误提示信息是否正确的唯一标准。请严格遵守实验要求中给定的错误分类(即词法错误 为错误类型A,语法错误为错误类型B),否则将影响你的实验评分。注意,输入文件中可能 会包含一个或者多个错误(但输入文件的同一行中保证不出现多个错误),你的程序需要将这 些错误全部报告出来,每一条错误提示信息在输出中单独占一行。 对于那些没有任何词法或语法错误的输入文件,你的程序需要将构造好的语法树按照先序 遍历的方式打印每一个结点的信息,这些信息包括: 1)如果当前结点是一个语法单元并且该语法单元没有产生ε(即空串),则打印该语法单 元的名称以及它在输入文件中的行号(行号被括号所包围,并且与语法单元名之间有一个空 格)。所谓某个语法单元在输入文件中的行号是指该语法单元产生出的所有词素中的第一个在 输入文件中出现的行号。 2)如果当前结点是一个语法单元并且该语法单元产生了ε,则无需打印该语法单元的信 息。 3)如果当前结点是一个词法单元,则只要打印该词法单元的名称,而无需打印该词法单 元的行号。 )如果当前结点是词法单元ID,则要求额外打印该标识符所对应的词素; b)如果当前结点是词法单元TYPE,则要求额外打印说明以该类型为nt还是float; c)如果当前结点是词法单元NT或者FLOAT,则要求以十进制的形式额外打印该数 字所对应的数值; d)词法单元所额外打印的信息与词法单元名之间以一个冒号和一个空格隔开。 11
版权所有 南京大学计算机科学与技术系 许畅等 2022春季版 11 2.1.2 输入格式 你的程序的输入是一个包含C−−源代码的文本文件,程序需要能够接收一个输入文件名作 为参数。例如,假设你的程序名为cc、输入文件名为test1、程序和输入文件都位于当前目录 下,那么在Linux命令行下运行./cc test1即可获得以test1作为输入文件的输出结果。 2.1.3 输出格式 实验一要求通过标准输出打印程序的运行结果。对于那些包含词法或者语法错误的输入文 件,只要输出相关的词法或语法有误的信息即可。在这种情况下,注意不要输出任何与语法树 有关的内容。要求输出的信息包括错误类型、出错的行号以及说明文字,其格式为: Error type [错误类型] at Line [行号]: [说明文字]. 说明文字的内容没有具体要求,但是错误类型和出错的行号一定要正确,因为这是判断输 出的错误提示信息是否正确的唯一标准。请严格遵守实验要求中给定的错误分类(即词法错误 为错误类型A,语法错误为错误类型B),否则将影响你的实验评分。注意,输入文件中可能 会包含一个或者多个错误(但输入文件的同一行中保证不出现多个错误),你的程序需要将这 些错误全部报告出来,每一条错误提示信息在输出中单独占一行。 对于那些没有任何词法或语法错误的输入文件,你的程序需要将构造好的语法树按照先序 遍历的方式打印每一个结点的信息,这些信息包括: 1) 如果当前结点是一个语法单元并且该语法单元没有产生(即空串),则打印该语法单 元的名称以及它在输入文件中的行号(行号被括号所包围,并且与语法单元名之间有一个空 格)。所谓某个语法单元在输入文件中的行号是指该语法单元产生出的所有词素中的第一个在 输入文件中出现的行号。 2) 如果当前结点是一个语法单元并且该语法单元产生了,则无需打印该语法单元的信 息。 3) 如果当前结点是一个词法单元,则只要打印该词法单元的名称,而无需打印该词法单 元的行号。 a) 如果当前结点是词法单元ID,则要求额外打印该标识符所对应的词素; b) 如果当前结点是词法单元TYPE,则要求额外打印说明以该类型为int还是float; c) 如果当前结点是词法单元INT或者FLOAT,则要求以十进制的形式额外打印该数 字所对应的数值; d) 词法单元所额外打印的信息与词法单元名之间以一个冒号和一个空格隔开
版权所有南京大学计算机科学与技术系许畅等2022春季版 每一条词法或语法单元的信息单独占一行,而每个子结点的信息相对于其父结点的信息来 说,在行首都要求缩进2个空格。具体输出格式可参见后续的样例。 2.1.4测试环境 你的程序将在如下环境中被编译并运行: 1)GNU Linux Release:Ubuntu 12.04,kernel version 3.2.0-29; 2)GCC version 4.6.3; 3)GNU Flex version 2.5.35; 4)GNU Bison version 2.5 一般而言,只要避免使用过于冷门的特性,使用其它版本的Liux或者GCC等,也基本上 不会出现兼容性方面的问题。注意,实验一的检查过程中不会去安装或尝试引用各类方便编程 的函数库(如gb等),因此请不要在你的程序中使用它们。 2.1.5提交要求 实验一要求提交如下内容: 1)Flex、Bison以及C语言的可被正确编译运行的源程序。 2)一份PDF格式的实验报告,内容包括: )你的程序实现了哪些功能?简要说明如何实现这些功能。清晰的说明有助于助教 对你的程序所实现的功能进行合理的测试。 b)你的程序应该如何被编译?可以使用脚本、makefile或逐条输入命令进行编译,请 详细说明应该如何编译你的程序。无法顺利编译将导致助教无法对你的程序所实 现的功能进行任何测试,从而丢失相应的分数。 ©)实验报告的长度不得超过三页!所以实验报告中需要重点描述的是你的程序中的 亮点,是你认为最个性化、最具独创性的内容,而相对简单的、任何人都可以做 的内容则可不提或简单地提一下,尤其要避免大段地向报告里贴代码。实验报告 中所出现的最小字号不得小于五号字(或英文11号字)。 2.1.6样例(必做内容) 实验一的样例包括必做内容样例与选做要求样例两部分,分别对应于实验要求中的必做内 容和选做要求。请仔细阅读样例,以加深对实验要求以及输出格式要求的理解。这节列举必做 内容样例。 12
版权所有 南京大学计算机科学与技术系 许畅等 2022春季版 12 每一条词法或语法单元的信息单独占一行,而每个子结点的信息相对于其父结点的信息来 说,在行首都要求缩进2个空格。具体输出格式可参见后续的样例。 2.1.4 测试环境 你的程序将在如下环境中被编译并运行: 1) GNU Linux Release: Ubuntu 12.04, kernel version 3.2.0-29; 2) GCC version 4.6.3; 3) GNU Flex version 2.5.35; 4) GNU Bison version 2.5。 一般而言,只要避免使用过于冷门的特性,使用其它版本的Linux或者GCC等,也基本上 不会出现兼容性方面的问题。注意,实验一的检查过程中不会去安装或尝试引用各类方便编程 的函数库(如glib等),因此请不要在你的程序中使用它们。 2.1.5 提交要求 实验一要求提交如下内容: 1) Flex、Bison以及C语言的可被正确编译运行的源程序。 2) 一份PDF格式的实验报告,内容包括: a) 你的程序实现了哪些功能?简要说明如何实现这些功能。清晰的说明有助于助教 对你的程序所实现的功能进行合理的测试。 b) 你的程序应该如何被编译?可以使用脚本、makefile或逐条输入命令进行编译,请 详细说明应该如何编译你的程序。无法顺利编译将导致助教无法对你的程序所实 现的功能进行任何测试,从而丢失相应的分数。 c) 实验报告的长度不得超过三页!所以实验报告中需要重点描述的是你的程序中的 亮点,是你认为最个性化、最具独创性的内容,而相对简单的、任何人都可以做 的内容则可不提或简单地提一下,尤其要避免大段地向报告里贴代码。实验报告 中所出现的最小字号不得小于五号字(或英文11号字)。 2.1.6 样例(必做内容) 实验一的样例包括必做内容样例与选做要求样例两部分,分别对应于实验要求中的必做内 容和选做要求。请仔细阅读样例,以加深对实验要求以及输出格式要求的理解。这节列举必做 内容样例
版权所有南京大学计算机科学与技术系许畅等2022春季版 样例1: 输入(行号是为标识需要,并非样例输入的一部分,后同): 1 int main() 2{ 3 int i 1; 4 int j=~i; 51 输出: 这个程序存在词法错误。第4行中的字符“”没有在我们的C一词法中被定义过,因此你 的程序可以输出如下的错误提示信息: Error type A at Line 4:Mysterious character "" 样例2: 输入: 1 int main() 2 3 f1oata[10][2]; 4 int i; 5 a[5,3]=1.5; 6 if(a[1][2]=0)i-1e1sei=0; 7} 输出: 这个程序存在两处语法错误。其一,虽然我们的程序中允许出现方括号与逗号等字符,但 二维数组正确的访问方式应该是a5][3]而非a[5,3]。其二,第6行的f-else语句在else之前少了 一个分号。因此你的程序可以输出如下的两行错误提示信息: Error type B at Line 5:Missing "]" Error type B at Line 6:Missing ";" 样例3: 输入: 1 int inc() 2{ 3 int i; 4 1-i+1: 51 输出: 这个程序非常简单,也没有任何词法或语法错误,因此你的程序需要输出如下的语法树结 点信息(行号是为标识需要,并非程序输出的一部分,后同): 1 Program (1) 2 ExtDefList (1) 3 ExtDef (1) 4 Specifier (1) TYPE:int 13
版权所有 南京大学计算机科学与技术系 许畅等 2022春季版 13 样例1: 输入(行号是为标识需要,并非样例输入的一部分,后同): 1 int main() 2 { 3 int i = 1; 4 int j = ~i; 5 } 输出: 这个程序存在词法错误。第4行中的字符“~”没有在我们的C−−词法中被定义过,因此你 的程序可以输出如下的错误提示信息: Error type A at Line 4: Mysterious character "~". 样例2: 输入: 1 int main() 2 { 3 float a[10][2]; 4 int i; 5 a[5,3] = 1.5; 6 if (a[1][2] == 0) i = 1 else i = 0; 7 } 输出: 这个程序存在两处语法错误。其一,虽然我们的程序中允许出现方括号与逗号等字符,但 二维数组正确的访问方式应该是a[5][3]而非a[5,3]。其二,第6行的if-else语句在else之前少了 一个分号。因此你的程序可以输出如下的两行错误提示信息: Error type B at Line 5: Missing "]". Error type B at Line 6: Missing ";". 样例3: 输入: 1 int inc() 2 { 3 int i; 4 i = i + 1; 5 } 输出: 这个程序非常简单,也没有任何词法或语法错误,因此你的程序需要输出如下的语法树结 点信息(行号是为标识需要,并非程序输出的一部分,后同): 1 Program (1) 2 ExtDefList (1) 3 ExtDef (1) 4 Specifier (1) 5 TYPE: int
版权所有南京大学计算机科学与技术系许畅等2022春季版 6 FunDec(1)) 7 ID:inc 8 LP RP 10 CompSt (2) LC 12 DefList(3)】 1 Def (3) 14 Specifier(3)】 5 TYPE:int 16 DecList (3) Dec (3) 18 VarDec (3) 1 ID:i 20 SEMI 1 StmtList (4) Stmt (4) 23 Exp (4) 24 Exp(4)】 25 ID:i 26 ASSIGNOP 27 Exp (4) 28 Exp (4) 29 ID:i 0 PLUS 3 Exp (4) 2 INT:1 33 SEMI 34 RC 样例4: 输入: 1 struct Complex 2 { 3 float real,image; 4 }; 5 int main() 6 > struct Complex xi y.image =3.5; 9} 输出: 这个程序虽然包含了语义错误(即使用了未定义的变量y),但不存在任何词法或语法错 误,因此你的程序不能报错而是要输出相应的语法树结点信息。至于把该语义错误检查出来的 任务,我们则放到实验二中去做。本样例输入所对应的正确输出应为: 1 Program (1) 2 ExtDefList (1) 3 ExtDef (1) 4 Specifier (1) 5 StructSpecifier (1) STRUCT 7 OptTag (1) 8 ID:Comple× 9 LC 10 DefList (3) 11 Def (3) Specifier (3) a TYPE:float DecList (3) 14
版权所有 南京大学计算机科学与技术系 许畅等 2022春季版 14 6 FunDec (1) 7 ID: inc 8 LP 9 RP 10 CompSt (2) 11 LC 12 DefList (3) 13 Def (3) 14 Specifier (3) 15 TYPE: int 16 DecList (3) 17 Dec (3) 18 VarDec (3) 19 ID: i 20 SEMI 21 StmtList (4) 22 Stmt (4) 23 Exp (4) 24 Exp (4) 25 ID: i 26 ASSIGNOP 27 Exp (4) 28 Exp (4) 29 ID: i 30 PLUS 31 Exp (4) 32 INT: 1 33 SEMI 34 RC 样例4: 输入: 1 struct Complex 2 { 3 float real, image; 4 }; 5 int main() 6 { 7 struct Complex x; 8 y.image = 3.5; 9 } 输出: 这个程序虽然包含了语义错误(即使用了未定义的变量y),但不存在任何词法或语法错 误,因此你的程序不能报错而是要输出相应的语法树结点信息。至于把该语义错误检查出来的 任务,我们则放到实验二中去做。本样例输入所对应的正确输出应为: 1 Program (1) 2 ExtDefList (1) 3 ExtDef (1) 4 Specifier (1) 5 StructSpecifier (1) 6 STRUCT 7 OptTag (1) 8 ID: Complex 9 LC 10 DefList (3) 11 Def (3) 12 Specifier (3) 13 TYPE: float 14 DecList (3)