├── .gitignore ├── README.md ├── imgs ├── for语句.png ├── if语句.png ├── repeat语句.png ├── while语句.png ├── 主函数流程图.png ├── 主程序.png ├── 主符号表结构.png ├── 函数调用.png ├── 函数过程定义.png ├── 分程序.png ├── 变量.png ├── 变量引用.png ├── 复合语句.png ├── 子符号表结构.png ├── 常量定义.png ├── 形式参数列表.png ├── 数据流图.png ├── 模块图.png ├── 模块图2.png ├── 类型.png ├── 表达式.png ├── 语句.png ├── 赋值语句.png ├── 过程调用语句.png └── 运行逻辑表.png ├── lex-yacc-src ├── PPT上的更正说明.txt ├── PascalProgram.pas ├── auto_compile.sh ├── auto_complie_and_run.bat ├── lex.l ├── main.cpp ├── main.h ├── pascal2c.exe ├── preProcessed.pas ├── unistd.h ├── yacc.output ├── yacc.tab.h ├── yacc.y └── 添加了错误个数控制的版本,与vs工程关联,所以无法单独正确运行 │ ├── lex.l │ ├── main.cpp │ ├── main.h │ └── yacc.y ├── src ├── ASTnodes.cpp ├── ASTnodes.h ├── CMakeLists.txt ├── FunctionReturnExistedCheck.cpp ├── PascalProgram.pas ├── codeGenerate.cpp ├── lex.yy.cpp ├── main.cpp ├── main.h ├── parseTree2AST.cpp ├── semanticAnalyse.cpp ├── symbolTable.cpp ├── symbolTable.h ├── yacc.tab.cpp └── yacc.tab.h ├── test-cases ├── lex错误测试样例.md ├── 代码生成测试样例.md ├── 综合测试用例.md ├── 语义分析测试样例.md └── 语法分析测试用例.md ├── 各模块测试文档 ├── 代码生成 - 测试文档.docx ├── 整体设计 - 测试文档.docx ├── 词法分析 - 测试文档.docx ├── 语义分析 - 测试文档.docx └── 语法分析 - 测试文档 - 不带调试输出.docx └── 各模块详细设计 ├── 代码生成 - 详细设计.docx ├── 整体设计 - 详细设计.docx ├── 词法分析 - 详细设计.docx ├── 语义分析 - 详细设计.docx └── 语法分析 - 详细设计.docx /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | src/cmake-build-debug/* 3 | .idea 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 项目说明 2 | - 此项目为本人大学期间的编译原理课程设计 3 | - 为PASCAL到C的编译器,本项目并不支持全部的PASCAL语法,只是其子集 4 | - 词法分析使用lex 5 | - 语法分析使用yacc 6 | - 整体工程使用C++,采用cmake构建 7 | 8 | ## 项目构建方式 9 | - 安装cmake 10 | - 安装MinGW,将mingw32-make.exe复制改名为make.exe 11 | - 在pascal2c-compiler/build目录下依次执行指令 12 | - cmake -G "MinGW Makefiles" ../src 13 | - make 14 | - make install 15 | - 在pascal2c-compiler/build/out/目录下,执行pascal2c.exe 16 | - 得到CProgram.c文件,该文件是将pascal源代码PascalProgram.pas编译为C代码的结果 17 | 18 | ## 目录结构 19 | - lex-yacc-src/ 20 | - 本项目的词法分析和语法分析使用lex和yacc 21 | - 该目录为lex和yacc的源代码目录 22 | - lex和yacc编译后得到c代码,加入src目录 23 | - src/ 24 | - pascal2c编译器的源代码 25 | - test-cases/ 26 | - 各种测试用例 27 | 28 | ## pascal2c.exe的使用 29 | | 参数接口 | 参数 | 参数功能 | 参数默认值 30 | | --- | --- | --- | --- 31 | | -inname | [file name] | 指定输入文件名 | PascalProgram.pas 32 | | -outname | [file name] | 指定输出文件名 | CProgram.c 33 | | -compiler | [compiler name] | 指定c编译器名,并将c程序编译成可执行文件 | gcc 34 | | -exename | [exe name] | 指定可执行文件名,自动编译 | CProcess.exe 35 | | -execute | 无 | 自动执行生成的可执行文件,如果未出现-e、-exename参数,则均按照默认方式进行操作 | 36 | | -errorbound | [n] | 指定错误上限,即编译器发现了指定个数的错误后,立即停止运行 | INF 37 | | -developer | 无 | 输出开发者信息 | 38 | | -version | 无 | 输出版本信息 | 39 | | -help | 无 | 输出所有命令行参数的帮助信息 | 40 | 41 | 注:中括号表示该参数可有可无 42 | ## 编译器功能模块图 43 | ![](imgs/模块图.png) 44 | 45 | ## 主函数流程图 46 | ![](imgs/主函数流程图.png) 47 | 48 | ## 需求分析 49 | ### 整体需求分析 50 | 一个完整的编译器分成分析阶段和综合阶段。分析阶段由词法分析、语法分析、语义分析组成;综合阶段由中间代码生成、代码优化、代码生成组成。我们需要实现的是PASCAL_S到C的编译器,源语言和目标语言均为高级语言,因此应省略综合阶段的中间代码生成和代码优化这两部分,也就是说,综合阶段直接将分析阶段得到的输出转化为目标代码。另外,符号表的管理和访问、错误处理将贯穿整个编译过程。 51 | 52 | 下面的数据流图说明了每一部分的输入输出,及其相互之间的逻辑关系。 53 | 54 | ![](imgs/数据流图.png) 55 | 56 | ### 词法分析的需求分析 57 | 编译的整个过程从词法分析开始。从左至右逐个字符地对源程序进行扫描,按照源语言的词法规则识别出一个个单词符号,把识别出来的标识符存入符号表中,并产生用于语法分析的记号序列。另外,词法分析程序还可以完成用户接口有关的一些任务,如识别源程序中的注释和跳过空格,把来自编译程序的错误信息和源程序联系起来。在遇到错误时,为了使词法分析程序能够继续运行下去,还要对出现的错误进行适当的恢复。 58 | 59 | 词法分析的输入是用源语言编写的程序,输出是详细词法错误信息及记号序列。记号指的是某一类单词的类别编码,如常数的记号num,而单词指的是某一类单词符号中的一个实例,如标识符position就是一个单词。我们计划利用LEX进行词法分析。 60 | 61 | LEX能够自动生成词法分析程序的前提就是我们能够提供所有单词的模式。一般来说,在输入符号串中有很多子串具有相同的记号输出,每个这样的子串都是一个单词,并且都可以用同一构成规则(即模式或者说正则表达式)描述。所以需要给出所有记号的正则表达式(描述记号的模式)的定义。为此,我们要根据提供的文法和语法图,以及相关文档,学习PASCAL_S,从中整理出各个不同种类的单词(包括常数、标识符、各种关键字等),然后再分析得到正则表达式。在分析过程中,可以利用正则文法、自动机等辅助分析。 62 | 63 | LEX通过正则表达式的匹配,执行相应的动作。而我们需要输出记号序列。词法分析程序在识别出一个记号后,要把与之有关的信息作为它的属性保留下来,记号影响语法分析的决策,属性影响记号的翻译。如果每一个关键字、运算符或标点符号作为单独的一类,则记号所代表的单词是唯一的,所以属性域可以是空的。若记号所代表的单词不唯一,则需要给出属性。 64 | 65 | LEX遵循最长匹配和优先匹配规则。值得注意的一些词法约定细节有:1)标识符长度受限;2)PASCAL不区分大小写,在分析中识别出一个单词,要马上将其所有字母转化为小写(字符常量、关键字除外);3)PASCAL语言程序的注释规则是注释用一对花括号括起来,编译程序要能处理注释,并将注释以某种形式保存下来,以便代码生成部分能够在恰当的部分用C语言的形式恢复注释。 66 | 67 | 词法分析阶段的错误主要就是读到非法字符(不属于该语言的字符集的字符),通常的做法是跳过非法字符,继续进行词法分析,同时需要输出详细的词法错误列表(错误发生的行数等),以便程序员修改词法错误。 68 | 69 | ### 语法分析的需求分析 70 | 语法分析是编译过程的核心部分,语法分析程序的输入是词法分析程序在扫描字符串源程序的过程中识别并生成的记号序列,语法分析程序分析验证这个记号序列是不是符合该语言语法规则的一个程序,若是,则输出其语法树,若不是,则表明输入的记号序列中存在语法错误,需要报告错误的性质和位置。 71 | 72 | 语法分析需要输出一棵抽象语法树。 73 | 74 | 我们将借助YACC工具,以LALR(1)的自底向上分析方法进行语法分析。为此,我们需要学习PASCAL_S语言,从中抽象出其语法结构,以文法表示。 75 | 76 | 我们需要一层一层(从简单到复杂)的分析PASCAL_S的各种语法单位,为详细设计中的文法设计奠定基础。 77 | 78 | PASCAL程序由三大部分组成:程序首部(head),说明部分(变量、常量、子过程、子函数的定义),语句部分(body,主程序,是一个复合语句块)。 79 | 80 | #### 常量 81 | const关键字用以说明接下来的定义语句都属于常量定义。常量定义需要指定初值,且不必指定类型。常量的初值可以由整数、浮点数、字符常量、别的常量标识符等指明,可以是一个可以由编译器计算出结果的常量表达式(这里我们将其简化,限定为只能是+、-等弹幕运算符加上一个常量标识符组成的最简单的常量表达式)。PASCAL-S的常量定义不包含类型,因此其类型需要编译器判断。 82 | 83 | #### 变量的定义 84 | var关键字用以说明接下来的定义语句都属于变量定义。变量定义必须指明类型,无需指定初值。变量也可以是一维或多维数组,数组的各维下标由表达式组成。 85 | 86 | #### 类型 87 | 可以是最简单的基本类型:integer、real、boolean、char,也可以是由这些基本类型组成的数组。 88 | 89 | #### 参数表 90 | 函数/过程的头部最重要的就是参数列表,参数列表由一系列的标识符、类型关键字组成的参数变量定义组成。PASCAL_S的参数有两种,引用和传值,语法上的区别在于是否包含var关键字。 91 | 92 | #### 表达式 93 | 表达式是由一系列的操作符和操作数组成的,其定义一般是递归的,也就是说,操作数不止是“数”,也可以是一个表达式。我们从操作符优先级的角度进行了分层,使得表达式的语法结构更加清晰。 94 | 95 | 首先引入最底层的因子概念,因子包括:(1)一个常量;(2)一个变量;(3)由单目运算符not、-与另一因子组成的新的因子(这些单目运算符的优先级通常是最高的);(4)括号括起来的表达式;(5)函数调用; 96 | 97 | 然后是项的概念,项可以是一个因子,也可以是由*、/、div、mod、and等优先级较高的双目运算符和两个因子组成的。 98 | 99 | 接下来是简单表达式的概念,简单表达式可以是一个项,也可以是由+、-、or等优先级较低的双目运算符和两个项组成。 100 | 101 | 最终是表达式的概念,表达式可以是一个简单表达式,可以是由>、=、<、<=、>=、<>等优先级最低的关系双目运算符和两个简单表达式组成。 102 | 103 | #### 语句 104 | 语句除了函数(通常表现为赋值语句)、过程调用(过程调用单独作为一条语句,产生某种副作用)外,主要以顺序结构、分支结构、循环结构分成三类。 105 | 106 | 顺序结构是由begin和end关键字及其包括的递归定义的复合语句块。 107 | 108 | 分支结构我们只支持if条件语句,其结构如下: 109 |
110 | IF <条件>
111 | THEN <语句1>
112 | ELSE <语句2>
113 | 
114 | 注:1、ELSE与最近的并且未被配对的ELSE配对;
115 | 2、 复合,如果THEN或ELSE带有多个语句,则要用BEGIN—END括起来;
116 | 
117 | 118 | 循环结构我们支持FOR语句、WHILE语句和REPEAT语句。 119 | 120 | FOR语句的结构如下: 121 |
122 | FOR<循环变量>:=<初值> TO<终值> DO<语句> 
123 | 
124 | 125 | WHILE语句与C语言中的WHILE语句基本一致,其结构如下: 126 |
127 | WHILE <条件> DO <语句>
128 | 
129 | 130 | REPEAT语句则类似于C语言中的DO-WHILE语句,即至少会执行一次循环体,但是在条件测试上有所区别,REPEAT-UNTIL语句在UNTIL指明的条件为真时退出循环。其结构如下: 131 |
132 | REPEAT
133 | <循环体>
134 | UNTIL
135 | <条件>分程序
136 | 
137 | #### 子函数/过程 138 | 函数和过程的头部中都包括名称和参数表,此外函数头还需指明返回值的类型,然后是子函数/过程的主体。子函数/过程中不能再嵌套函数/过程,另外,常量定义、变量定义、复合语句块等都与主程序类似。 139 | 140 | #### 分程序 141 | 分程序指的是PASCAL-S的主程序部分,首先要给出常量和变量的定义,然后是函数/过程的定义,最后是语句主体(begin和end包括的复合语句块) 142 | 143 | #### 程序 144 | 程序由程序名称标识符、参数列表和分程序组成。这里的参数列表给出的参数标识符,通常用于命令行参数的指定。与子函数/过程不同的是,这里不指出标识符的类型。因此,如果程序主体中用到了该参数,就必须在变量定义区中再定义一次,指明具体类型。 145 | 146 | 语法分析和语义分析都可以用YACC进行,其中语法分析的侧重点在于错误处理和提示,以便为后续语义分析提供正确的语法结构(语法树)。接下来我们从语法分析的错误处理角度进行需求分析。 147 | 148 | #### 错误处理 149 | 据统计,源程序中出现的错误多是语法错误,所以,编译时大多数错误的诊断和恢复工作集中在语法分析阶段。 150 | 151 | 语法分析程序进行错误处理的基本目标如下: 152 | - 能够清楚而准确地报告发现的错误,如错误的位置和性质。 153 | - 能够迅速地从错误中恢复过来,以便继续诊断后面可能存在的错误。 154 | - 错误处理功能不应该明显地影响编译程序对正确程序的处理效率。 155 | 156 | 要完成目标(1),需要我们主观积累经验,收集可能的错误,如常见的算法表达式的括号不匹配、缺少运算对象等,并对症下药。其次,准确地识别到错误发生的位置后,应无误地将位置(错误代码行数)和性质输出。在我们采用的LALR(1)分析中,分析程序总是根据当前的栈顶状态和当前输入符号去查分析表,若找不到合法的动作,则意味着发现了一个语法错误。 157 | 实现目标(2)和(3),需要采用合理的错误恢复策略。例如小范围的短语级恢复,对于算法表达式的括号不匹配,可选择向前指针跳过当前符号,继续分析。结合利弊,对不同的错误进行分别处理和恢复。 158 | 159 | #### 二义性消除 160 | 所有的二义性文法都不是LR文法。但PASCAL的某些结构用二义性文法描述比较直观且使用方便,例如if条件语句的直观描述产生式为`S->if E then S else S | if E then S | others`,根据PASCAL规定语法,需要在语法分析阶段增加“最近最后匹配原则”解决可能引发的冲突问题。 161 | 总之,在PASCAL语言中,有的文法表示可能是二义性的,但都说明了消除二义性的一些规则,以保证对每个句子的解释是唯一的,我们需要利用这些规则,确保语法分析不会受困于二义性的陷阱。 162 | 163 | ### 语义分析的需求分析 164 | 语义分析的输入是语法树,输出是注释分析树和语义错误信息(错误的性质和位置)和符号表,主要完成符号表的建立和操作、类型检查与转化、作用域识别等3个方面的内容。 165 | 166 | #### 符号表的定义 167 | 主符号表要求记录: 168 | - 种类标志 169 | - 标识符名字 170 | - 行号 171 | - 类型 172 | - 常量取值 173 | - 参数个数/数组维数 174 | - 数组各维上下界 175 | - 指向函数/过程子符号表的指针 176 | 177 | 子符号表的表结构是主符号表的子集。由于不支持函数和过程的嵌套定义,所以子符号表相比于主符号表,少了函数/过程相关的域。子符号表要求记录: 178 | - 种类标志 179 | - 标识符名字 180 | - 行号 181 | - 类型 182 | - 常量取值 183 | - 数组维数 184 | - 数组各维上下界 185 | 186 | 下面对符号表各域进行具体介绍。 187 | 188 | **种类标志**:记录着标识符的符号种类。 189 | - "value parameter"表示传值参数 190 | - "var parameter"表示传引用参数 191 | - "normal variant"表示普通变量 192 | - "constant"表示常量 193 | - "array"表示数组 194 | - "procedure"表示过程 195 | - "function"表示函数。 196 | 197 | **标识符名字**:作为语义分析部分识别标识符的主键,在进行添加、查找、修改等操作时发挥重要作用。 198 | 199 | **行号**:词法分析和语法分析时,在进行报错时可以很方便的获取出错的具体位置,但语义分析通常都是在更抽象的树结构上进行的,所以需要记录下每个符号的行号,以便报错包含位置信息。 200 | 201 | **类型**:对于变量和常量来说,该域记录着变量或常量类型; 对于数组来说,该域记录着数组元素的类型;对于函数来说,该域记录着函数返回值类型。取值为”integer”、”real”、”char”、”boolean”。 202 | 203 | **常量取值**:需要将常量的取值保存下来,以便后续计算常量表达式的值、进行常量定义时的常数传播、检查除0错误、检查数组下标越界。 204 | 205 | **参数个数/数组维数**:在参数个数/数组维度部分,对于数组类型的变量,我们将存储其维数;对于函数类型,我们将存储其参数个数。 206 | 207 | **数组各维上下界**:对于数组而言,在符号表中记录其各维上下界,便于判断其是否越界。 208 | 209 | **指向函数/过程子符号表的指针**:在该指针域中保存该符号表中指向函数/过程子符号表的指针,便于进行定位和重定位处理。 210 | 211 | #### 符号表的管理 212 | 定位操作:在每个程序块的入口处我们需要执行定位操作来建立一个符号表的子表,将该块的声明的所有标识符属性记录到该表中。 213 | 214 | 重定位操作:在每个程序块的出口处我们需要返回到主符号表,实现重定位操作,保证已经执行完的块中声明的局部变量不能再次被引用。 215 | 216 | #### 类型检查与转化 217 | 我们的语义分析需要支持四种基本类型:integer、real、boolean、char,以及这四种基本类型声明的数组。 218 | 219 | 类型转化:我们仅支持隐式类型转化,且其中也仅支持从integer类型到real类型的隐式类型转化。需要特别注意的是,传引用参数不支持隐式类型转化。 220 | 221 | 表达式类型检查:每个运算符对于操作数的类型都有不同的要求,需要具体分析不同运算符的具体要求,例如mod运算符要求两个操作数均为”integer”类型,relop运算符要求两个操作数类型一致,或者符合隐式类型转化的规定。 222 | 223 | 语句类型检查:语句并没有“integer”、“real”、“char”、“boolean”这些类型。以if语句为例,如果其条件表达式的类型为“bool”,那我们认为该语句的类型正确,赋值为”void”,否则我们认为该语句的类型错误,赋值为“error”;再比如赋值语句就要求左值和右值的类型一致。不同的语句有不同的要求,需要具体分析。 224 | 225 | #### 作用域识别 226 | 由于PASCAL-S不支持函数/过程的嵌套定义,所以作用域规则是十分简单的。 227 | 228 | 定义在PASCAL程序一开始的常量、变量就可以是视作是全局作用域,不仅可以被主程序体引用,也可以被子程序引用(如果子程序没有定义同名标识符)。 229 | 230 | 另外,每一个子函数/过程中定义的常量、变量的作用域就局限在当前函数/过程,属于局部作用域。 231 | 232 | 检测标识符未定义错误时,除了局部作用域(如果当前在局部作用域中),还需退回到全局作用域中。 233 | 234 | 检测标识符重定义错误时,只需要在局部作用域(如果当前在局部作用域中)中检查。 235 | 236 | #### 代码生成需求分析 237 | 代码生成输入一般是注释分析树和信息较为完备的符号表,输出是目标代码。目标代码要求能在gcc编译器下正确编译,生成的可执行文件能够正确执行,在合法的输入下,得到正确的输出结果。 238 | 239 | 由于源语言和目标语言都是高级语言,所以我们直接生成目标代码,而不生成中间代码,否则会更加麻烦。借助经过了语义分析的抽象语法树和符号表,我们可以很轻松的进行目标代码生成。 240 | 241 | 接下来,我们从源语言的需求和目标语言的特点出发,通过对比来讨论代码生成的需求细节。 242 | 243 | pascal主程序中的变量可以被所有的过程、函数体访问,具有全局作用域,因此对应于C语言中的全局变量。 244 | 245 | pascal主程序头中包含了一个无类型的标识符列表。经查阅资料,这个标识符列表类似于c语言中main函数的参数列表,例如在命令行调用时可以指定这些参数。我们注意到在pascal的语法中,程序头对于这些标识符的声明没有类型的指示,而c语言有。这预示着在pascal中,我们仍需要定义这些标识符为具体的变量,才能使用,否则就属于未定义就引用的错误。input和output是两个特例,这两个标识符被隐含声明为程序参数且被隐含定义为文件变量,与标准输入,标准输出相关联。需要特别注意的是,程序标识符只能被定义为字符串、文件等类型,如果定义为其它类型,应忽略对应的参数(以避免一些类型错误,PASCAL编译器是这么做的),而我们并不考虑这些类型,所以我们暂时保留这个标识符列表,但在测试用例中并不涉及。如果后续我们有时间增加字符串等类型的支持再进行考虑。在PASCAL中使用命令行参数的一个较为方便的做法是利用paramcount和paramstr这两个变量,这与c语言中main函数的参数int argc, char **argv类似。但由于仍涉及字符串操作,我们仍不考虑。 246 | 247 | 对于常量定义,pascal中的const关键字作用域较大,不局限于下一个分号,而C语言中,每一分号隔出的部分都要单独使用一个const关键字。且pascal中的常量在定义时不需要指明类型,但是C语言需要。所以在我们需要在词法分析阶段完成对常量类型的自动识别,在目标代码生成时,指明对应的类型。 248 | 249 | pascal在声明变量时,除了要说明类型,还要再前面加上var关键字,C语言中没有这样的关键字,只需要指明类型即可。var关键字的作用域与const关键字相同。 250 | 251 | C语言中数组各维下标默认从0开始,而pascal中的范围可以任意指定,因此需要对数组下标进行相应的变换(在目标代码中需要新增定义临时变量以指明偏移量)。 252 | 253 | PASCAL中函数返回值用 函数标识符:=表达式 表示,对应于C语言中的return语句。 254 | 255 | PASCAL中如果函数或者过程没有参数,则无需包含空内容的括号,C语言中则需要。 256 | 257 | PASCAL中多维数组的访问方法是在一个中括号内部,用逗号隔开各维索引,而C语言中则直接用中括号隔开各维索引。 258 | 259 | C语言中一些基本的符号与PASCAL有所区别,例如C语言中的不等于用!=,而PASCAL中用<>。 260 | 261 | PASCAL中的复合语句块用begin和end包括,而在C语言中用花括号包括。 262 | 263 | 代码生成的测试用例同整体测试,不再单独给出。 264 | 265 | ## 总体设计 266 | 语法分析调用词法分析得到记号序列,并分析生成抽象语法树。在抽象语法树上进行语义分析,建立和完善符号表,最后进行代码生成。 267 | 268 | 具体到开发细节,用LEX生成词法分析程序(C++),该词法分析程序由语法分析程序调用生成记号序列,用YACC生成语法分析程序(C++),该语法分析程序可以生成语法分析树,然后用C++编写程序将语法分析树转化为抽象语法树,作为语法分析的最终输出,然后用C++编写语义分析和代码生成程序,最后将各部分代码整合在一起,生成一个完整的编译器。 269 | ![](imgs/模块图2.png) 270 | 271 | ### 模块划分 272 | #### 预处理 273 | - 输入 274 | - PASCAL-S源程序文件 275 | - 输出 276 | - 经过预处理的PASCAL-S程序文件 277 | - 功能 278 | - PASCAL-S程序大小写不敏感,所以需要将所有字母转化为小写字母。 279 | #### 词法分析 280 | - 输入 281 | - 经过预处理的PASCAL-S程序文件 282 | - 输出 283 | - 记号序列 284 | - 功能 285 | - 编译的整个过程从词法分析开始。从左至右逐个字符地对源程序进行扫描,按照源语言的词法规则识别出一个个单词符号,产生用于语法分析的记号序列。识别源程序中的注释和跳过空格。在遇到错误时,为了使词法分析程序能够继续运行下去,还要对出现的词法错误进行报告,并进行适当的恢复。 286 | #### 语法分析 287 | - 输入 288 | - 记号序列 289 | - 输出 290 | - 抽象语法树 291 | - 功能 292 | - 语法分析程序的输入是词法分析程序在扫描字符串源程序的过程中识别并生成的记号序列,语法分析程序分析验证这个记号序列是不是符合该语言语法规则的一个程序,若是,则输出其语法分析树,并转化为抽象语法树,若不是,则表明输入的记号序列中存在语法错误,需要对语法错误进行适当的恢复,并报告错误的性质和位置。 293 | #### 语义分析 294 | - 输入 295 | - 抽象语法树 296 | - 输出 297 | - 抽象语法树、符号表 298 | - 功能 299 | - 遍历抽象语法树,完成符号表的建立和操作、类型检查与转化、作用域识别等3个方面的内容,需要报告语义错误的性质和错误。 300 | #### 代码生成 301 | - 输入 302 | - 抽象语法树、符号表 303 | - 输出 304 | - C语言代码 305 | - 功能 306 | - 遍历抽象语法树,并借助符号表的信息生成目标代码。 307 | 308 | ### 运行逻辑设计 309 | 编译器的运行设计主要针对错误的宏观处理,可以分为如下三种策略。 310 | ``` 311 | (1)一旦发现任何一个错误,编译器立即终止运行。 312 | (2)编译器尝试从各种错误中恢复过来,并完成整个编译过程。 313 | (3)根据编译过程的模块划分,将错误恢复局限在一个模块中。即在任何一个模块中发现错误时,编译器将尝试从错误中恢复过来,并完成当前模块的处理,然后终止运行。 314 | 315 | 采用策略(1)时,每运行一次编译器,编译程序只能报告一个错误,编译人员的工作效率将大打折扣。 316 | 采用策略(2)时,极有可能出现错上加错的情况,导致后续的报错无法和源程序对应,给编译人员带来不必要的麻烦。 317 | 采用策略(3)时,编译人员可以一次处理成批的错误,工作效率较高,且报错信息准确。 318 | ``` 319 | 因此,采用策略(3)并根据源程序的错误情况,可以将编译器的运行情况表示为下表: 320 | ![](imgs/运行逻辑表.png) 321 | 注:模块内部的接口设计、详细的错误处理方法,在详细设计中给出。 322 | ### 数据结构设计 323 | #### 记号 324 | 不同的记号有不同种类的属性,直观的想法是设计一个结构体,用不同类型的域去表示不同类型的属性,但是在词法和语法分析阶段,这些记号的属性的存储形式不会产生任何影响,因此记号的结构体中,直接用string类型去表示各种记号的属性,其具体类型的转换工作由后续模块进行。 325 | ```c++ 326 | 1. class node 327 | 2. { 328 | 3. string token; 329 | 4. string value; 330 | 5. }; 331 | ``` 332 | 其中,token表示的是记号或非终结符号的名称,value表示的是属性值。例如表达式的token域是”EXPRESSION”,value域为空;例如一个常数的123.456的token域是”NUMBER”, value域是”123.456”。 333 | 334 | #### 语法分析树 335 | 由于YACC的限制,我们将扩展记号的结构体,作为语法分析树的节点结构体。 336 | ```c++ 337 | 1. class node 338 | 2. { 339 | 3. string token; 340 | 4. string value; 341 | 5. vector children; 342 | 6. }; 343 | ``` 344 | 345 | #### 抽象语法树 346 | 由于篇幅限制,树结构中仅画出最重要的信息,具体内容参照节点类的定义代码。该部分文档也可能和代码有所出入,具体以代码为准。 347 | - 主程序(class _Program) 348 | ![](imgs/主程序.png) 349 | 主程序由程序名称标识符、参数列表、分程序构成,分别对应如上图所示的数据结构 350 | ```c++ 351 | 1. class _Program{ //主程序体语法树数据结构定义 352 | 2. pair programId; //PASCAL程序名称标识符及行号 353 | 3. vector< pair > paralist; //标识符名称及行号 354 | 4. _Subprogram* subProgram; //分程序 355 | 5. }; 356 | ``` 357 | 358 | - 分程序(class _Subprogram) 359 | ![](imgs/分程序.png) 360 | ```c++ 361 | 1. class _Subprogram{ //分程序定义语法树的数据结构定义 362 | 2. vector<_Constant*> constList; //常数定义列表 363 | 3. vector<_Variant*> variantList; //变量定义列表 364 | 4. vector<_FunctionDefinition*> subprogramDefinitionList; //子程序和子函数 365 | 5. _Compound* compound; //主程序体 366 | 6. }; 367 | ``` 368 | 369 | - 常量定义(class _Constant) 370 | ![](imgs/常量定义.png) 371 | 常量是不可再往下细化的语法单位,因此在语法树中附加行号信息,为错误处理机制提供方便(接下来所有原子级语法单位语法树都将附加行号变量)。常量也有可能由别的常量标识符提供取值,因此种类除了char、int、real之外,还设置了string,用于表明提供常量值的常量标识符的ID。常量标识符前面可能没有符号,也可能有加号,也可能有减号,其中加号和没有符号的等价,因此需要再加一个bool变量isMinusShow用于表示前面是否出现了减号。因此这里的value并不一定是常量的真实值,还需考虑isMinusShow的取值。 372 | ```c++ 373 | 1. list consts; //常量定义列表 374 | 2. class _Constant{ 375 | 3. pair constId; //常量标识符及行号 376 | 4. string type; //int,char,real,string(这个string指的是常量标识符的ID) 377 | 5. pair valueId; 378 | 6. char charValue; 379 | 7. int intValue; 380 | 8. float realValue; 381 | 9. string strOfVal; //所有常量取值的字符串表示 382 | 10. bool isMinusShow; //是否出现减号 383 | 11. }; 384 | ``` 385 | 386 | - 类型(class _Type) 387 | ![](imgs/类型.png) 388 | 如上图所示的语法树主要分析integer, real, boolean, char和array类型,类型标志flag用于指示该类型是否为array,是的话则为1,同时数组下界与上界被赋予有意义的数值;否则为0,且low和high变量的值无效。数组可以多维,vector的大小即维数,每一个pair为数组的上下界。 389 | ```c++ 390 | 1. class _Type{ 391 | 2. pair type; //基本类型及行号,int、char、real、boolean 392 | 3. int flag; //若是array则flag=1,否则flag=0 393 | 4. vector> ar; //数组各维上下界 394 | 5. }; 395 | ``` 396 | 397 | - 变量(class _Variant) 398 | ![](imgs/变量.png) 399 | ```c++ 400 | 1. listvars; //变量列表 401 | 2. class _Variant{ 402 | 3. pair variantId; //标识符及行号 403 | 4. _Type* type; //类型 404 | 5. }; 405 | ``` 406 | 407 | - 形式参数列表(class _FormalParameter) 408 | ![](imgs/形式参数列表.png) 409 | 参数分为引用和传值调用两种,根据是否包含var关键字来区分。 410 | ```c++ 411 | 1. list paralist; //参数列表 412 | 2. class _FormalParameter{ 413 | 3. pair paraId; //形式参数标识符和行号 414 | 4. string type; //形式参数类型,为基本类型 415 | 5. int flag; //flag=0代表传值调用,flag=1代表引用调用 416 | 6. }; 417 | ``` 418 | 419 | - 函数/过程定义(class _FunctionDefinition) 420 | ![](imgs/函数过程定义.png) 421 | 在这里我们把过程和函数统一成了一个结构体,可以通过返回值字符串是否为空来判断是函数还是过程。 422 | ```c++ 423 | 1. list functions//函数或过程体的列表 424 | 2. class _FunctionDefinition{//函数或过程体的语法树结构 425 | 3. pair functionId; //函数/过程标识符及行号 426 | 4. vector<_FormalParameter*> formalParaList; //形参列表 427 | 5. pair type; ///如果type.first是空串,则为过程,否则为函数,取值为"integer","real","boolean","char"四种 428 | 6. vector<_Constant*> constList; //常数定义列表 429 | 7. vector<_Variant*> variantList; //变量定义列表 430 | 8. _Compound* compound; //程序体 431 | 9. }; 432 | ``` 433 | 434 | - 函数调用(class _FunctionCall) 435 | ![](imgs/函数调用.png) 436 | 函数调用的参数列表是实际参数列表,与之前函数定义中的形式参数列表不同,这里的实际参数是一些表达式,因此加一个表达式结构体指针的线性表即可。 437 | ```c++ 438 | 1. class _FunctionCall{ 439 | 2. string functionid; //函数标识符及行号 440 | 3. vector<_Expression*> actualParalist; //实参 441 | 4. } 442 | ``` 443 | 444 | - 变量引用(class _VariantReference) 445 | ![](imgs/变量引用.png) 446 | ```c++ 447 | 1. class VariantReference{ 448 | 2. pair variantId;//变量标识符和行号 449 | 3. vector<_Expression*> expressionList;//各维的引用表达式 450 | 4. int flag;//0表示非数组,1表示数组 451 | 5. } 452 | ``` 453 | 454 | - 语句(class _Statement) 455 | ![](imgs/语句.png) 456 | 由于语句的种类很多,具有不同的语义和功能,不难想到利用C++继承、多态的性质进行数据结构的定义。 457 | 458 | 首先,定义语句的纯虚类:class Statement。随后下面对不同的子类进行展开设计。 459 | 460 | ```c++ 461 | 1. class _Statement{ 462 | 2. string type; 463 | 3. //"compound","repeat","while","for","if","assign","procedure" 464 | 4. string statementType; ////区别于type,取值为"void"或"error" 465 | 5. int lineNumber;//行号 466 | 6. } 467 | ``` 468 | 469 | - 赋值语句(class _AssignStatement) 470 | ![](imgs/赋值语句.png) 471 | ```c++ 472 | 5. class _AssignStatement:public _Statement{ 473 | 6. public: 474 | 7. _VariantReference* variantReference; //左值变量 475 | 8. _Expression* expression; //右值表达式 476 | 9. }; 477 | ``` 478 | 479 | - if语句(class _IfStatement) 480 | ![](imgs/if语句.png) 481 | 当els指针为NULL时,对应上图左边的结构;当els指针指向了一个语句结构时,对应上图右边的结构。 482 | ```c++ 483 | 10. class _IfStatetement:public _Statement{ 484 | 11. public: 485 | 12. _Expression* condition; //条件表达式 486 | 13. _Statement* then; //满足条件时执行的语句 487 | 14. _Statement* els; //不满足条件时执行的语句,如果为NULL则没有else部分 488 | 15. }; 489 | ``` 490 | 491 | - for语句(class _ForStatement) 492 | ![](imgs/for语句.png) 493 | ```c++ 494 | 1. class _Forstate:public _Statement{ 495 | 2. public: 496 | 3. pair id; //循环变量 497 | 4. _Expression* state; //起始值 498 | 5. _Expression* end; //终值 499 | 6. _Statement* _do; //循环体语句 500 | 7. }; 501 | ``` 502 | 503 | - while语句(class _WhileStatement) 504 | ![](imgs/while语句.png) 505 | ```c++ 506 | 1. class _WhileStatement:public _Statement{ 507 | 2. public: 508 | 3. Expression* condition; //条件表达式 509 | 4. Statement* _do; //循环体语句 510 | 5. }; 511 | ``` 512 | 513 | - repeat语句(class _Repeatstate) 514 | ![](imgs/repeat语句.png) 515 | ```c++ 516 | 1. class _WhileStatement:public _Statement{ 517 | 2. public: 518 | 3. Expression* condition; //条件表达式 519 | 4. Statement* _do; //循环体语句 520 | 5. }; 521 | ``` 522 | 523 | - 复合语句(class _Compound) 524 | ![](imgs/复合语句.png) 525 | ```c++ 526 | 1. class _Compound:public _Statement{ 527 | 2. public: 528 | 3. vectorstatements; //语句列表 529 | 4. }; 530 | ``` 531 | 532 | - 过程调用语句(class _Procudure_call) 533 | ![](imgs/过程调用语句.png) 534 | ```c++ 535 | 16. class _procedureCall:public _Statement{ 536 | 17. pair procedureId; //过程标识符及行号 537 | 18. vector<_Expression*> actualParaList; //实参 538 | 19. } 539 | ``` 540 | 541 | - 表达式(class _Expression) 542 | ![](imgs/表达式.png) 543 | ```c++ 544 | 1. class _Expression{ 545 | 2. string type;//表达式类型,"var"表示变量,"int"表示整数,"real"表示浮点数,"function"表示函数调用,"compound"表示复合表达式,compound有普通的二目运算符,还有minus、not、bracket等单目运算符 546 | 3. 547 | 4. variantRef* variantReference;//变量 548 | 5. 549 | 6. int intNum;//整数 550 | 7. 551 | 8. float realNum;//浮点数 552 | 9. 553 | 10. string strOfNum;//常数值的字符串表示 554 | 11. 555 | 12. char charVal; //常量字符 556 | 13. _FunctionCall *functionCall;//函数调用 557 | 14. 558 | 15. string operation;//复合表达式 559 | 16. string operationType;//操作符类型,"relop","mulop","addop","single" 560 | 17. _Expression *operand1,*operand2; 561 | 18. 562 | 19. int lineNumber;//行数 563 | 20. }expression; 564 | ``` 565 | 566 | #### 符号表 567 | - 主符号表结构 568 | ![](imgs/主符号表结构.png) 569 | - 子符号表结构 570 | ![](imgs/子符号表结构.png) 571 | - 伪代码 572 | ``` 573 | // 主符号表 574 | { 575 | 线性表(主符号表表项) 576 | } 577 | 578 | // 主符号表表项 579 | { 580 | 符号种类 //"normal variant"表示普通变量,"constant"表示常量,"array"表示数组 581 | //"procedure"表示过程,"function"表示函数标识符名称 582 | 标识符名称 583 | 行号 584 | 类型 //如果是变量/常量,则表示变量/常量类型; 585 | //如果是数组,则表示数组元素的类型; 586 | //如果是函数,则表示函数返回值类型,类型本身只能为基本类型 587 | 常量取值 588 | 数组维数/参数个数 //如果是数组,则表示数组维数,如果是函数/过程,则表示参数个数 589 | 数组各维上下界 590 | 指向过程/函数子符号表的指针 591 | } 592 | 593 | // 子符号表 594 | { 595 | 线性表(子符号表表项) 596 | } 597 | 598 | // 子符号表表项 599 | { 600 | 符号种类 //"value parameter"表示传值参数,"var parameter"表示传引用参数 601 | //"normal variant"表示普通变量,"constant"表示常量,"array"表示数组 602 | 标识符名称 603 | 行号 604 | 类型 //如果是变量/常量,则表示变量/常量类型; 605 | //如果是数组,则表示数组元素的类型; 606 | 常量取值 607 | 数组维数 //表示数组维数 608 | 数组各维上下界 609 | } 610 | 611 | ``` 612 | 613 | ### 模块之间的接口设计 614 | 模块之间的接口主要是一些函数和全局变量。 615 | #### 词法分析和语法分析之间的接口 616 | - yylval 结构体变量,用于保存记号的属性,在词法分析程序和语法分析程序之间共享记号信息 617 | - int yylex(); 调用词法分析器的接口,每调用一次,返回一个记号序列,其中记号本身为该函数的返回值,记号的属性保存在yylval结构体变量中;返回值为0表示词法分析程序停止运行 618 | 619 | #### 语法分析与语义分析之间的接口 620 | - class program *AST_Root 抽象语法树的根节点的指针 621 | 622 | #### 语义分析和代码生成之间的接口 623 | - class program *AST_Root 抽象语法树的根节点的指针 624 | - class Symbol_Table *S_Table 主符号表的指针 625 | 626 | #### 符号表操作接口 627 | - 添加传值参数 628 | - 函数接口:`void addPara(string id, int lineNumber, string type);` 629 | - 参数列表: 630 | - string id 传值参数标识符 631 | - int lineNumber 行号 632 | - string type 传值参数类型 633 | - 返回值:无 634 | - 添加引用参数 635 | - 函数接口:`void addVarPara(string id, int lineNumber, string type);` 636 | - 参数列表: 637 | - string id 引用参数标识符 638 | - int lineNumber 行号 639 | - string type 引用参数类型 640 | - 返回值:无 641 | - 添加普通变量 642 | - 函数接口:`void addVar(string id, int lineNumber, string type);` 643 | - 参数列表: 644 | - string id 普通变量标识符 645 | - int lineNumber 行号 646 | - string type 普通变量类型 647 | - 返回值:无 648 | - 添加常量 649 | - 函数接口:`void addConst(string id, int lineNumber, string type, bool isMinusShow, string value);` 650 | - 参数列表: 651 | - string id 常量标识符 652 | - int lineNumber 行号 653 | - string type 常量 654 | - bool isMinusShow 常量是否为负 655 | - string value 以字符串表示的常量取值 656 | - 返回值:无 657 | - 添加数组 658 | - 函数接口:`void addArray(string id, int lineNumber, string type, int amount, vector< pair > arrayRangeList);` 659 | - 参数列表: 660 | - string id 数组标识符 661 | - int lineNumber 行号 662 | - string type 数组元素类型 663 | - int amount 数组维数 664 | - vector< pair > arrayRangeList 数组各维上下界列表 665 | - 返回值:无 666 | - 添加过程 667 | - 函数接口:`void addProcedure(string id, int lineNumber, int amount, _SymbolTable *subSymbolTable=NULL);` 668 | - 参数列表: 669 | - string id 过程标识符 670 | - int lineNumber 行号 671 | - int amount 过程参数个数 672 | - _SymbolTable *subSymbolTable 指向子符号表的指针 673 | - 返回值:无 674 | - 添加函数 675 | - 函数接口:`void addFunction(string id, int lineNumber, string type, int amount, _SymbolTable *subSymbolTable=NULL);` 676 | - 参数列表: 677 | - string id 函数标识符 678 | - int lineNumber 行号 679 | - string type 函数返回值类型 680 | - int amount 函数参数个数 681 | - _SymbolTable *subSymbolTable 指向子符号表的指针 682 | - 返回值:无 683 | - 添加子符号表指针 684 | - 函数接口:`void addSubSymbolTable(string id, _SymbolTable *subSymbolTable);` 685 | - 参数列表: 686 | - string id 函数或过程标识符 687 | - _SymbolTable *subSymbolTable 指向子符号表的指针 688 | - 返回值:无 689 | - 以标识符查找记录 690 | - 函数接口:`_SymbolRecord* findSymbolRecord(_SymbolTable* currentSymbolTable, string id, int mode=0);` 691 | - 参数列表: 692 | - _SymbolTable* currentSymbolTable 指向所需要查找的符号表的指针 693 | - string id 标识符 694 | - int mode 如果当前符号表没有找到,是否需要到上一级符号表查找,mode=0表示需要,mode!=0表示不需要 695 | - 返回值:_SymbolRecord*,指向所找到的记录类型的指针,如果没有找到,则为NULL 696 | 697 | ## 详细设计 698 | 见docx 699 | 700 | ## 测试 701 | 见docx 702 | -------------------------------------------------------------------------------- /imgs/for语句.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/for语句.png -------------------------------------------------------------------------------- /imgs/if语句.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/if语句.png -------------------------------------------------------------------------------- /imgs/repeat语句.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/repeat语句.png -------------------------------------------------------------------------------- /imgs/while语句.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/while语句.png -------------------------------------------------------------------------------- /imgs/主函数流程图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/主函数流程图.png -------------------------------------------------------------------------------- /imgs/主程序.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/主程序.png -------------------------------------------------------------------------------- /imgs/主符号表结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/主符号表结构.png -------------------------------------------------------------------------------- /imgs/函数调用.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/函数调用.png -------------------------------------------------------------------------------- /imgs/函数过程定义.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/函数过程定义.png -------------------------------------------------------------------------------- /imgs/分程序.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/分程序.png -------------------------------------------------------------------------------- /imgs/变量.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/变量.png -------------------------------------------------------------------------------- /imgs/变量引用.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/变量引用.png -------------------------------------------------------------------------------- /imgs/复合语句.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/复合语句.png -------------------------------------------------------------------------------- /imgs/子符号表结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/子符号表结构.png -------------------------------------------------------------------------------- /imgs/常量定义.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/常量定义.png -------------------------------------------------------------------------------- /imgs/形式参数列表.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/形式参数列表.png -------------------------------------------------------------------------------- /imgs/数据流图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/数据流图.png -------------------------------------------------------------------------------- /imgs/模块图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/模块图.png -------------------------------------------------------------------------------- /imgs/模块图2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/模块图2.png -------------------------------------------------------------------------------- /imgs/类型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/类型.png -------------------------------------------------------------------------------- /imgs/表达式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/表达式.png -------------------------------------------------------------------------------- /imgs/语句.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/语句.png -------------------------------------------------------------------------------- /imgs/赋值语句.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/赋值语句.png -------------------------------------------------------------------------------- /imgs/过程调用语句.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/过程调用语句.png -------------------------------------------------------------------------------- /imgs/运行逻辑表.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/imgs/运行逻辑表.png -------------------------------------------------------------------------------- /lex-yacc-src/PPT上的更正说明.txt: -------------------------------------------------------------------------------- 1 | PPT上的语法图和文法产生式需要修改的地方 2 | 3 | 首先是语言语法图的问题(有些不算是问题吧,但是对应到语法分析,不可能知道这些信息,所以需要修改): 4 | P8 标识符这个语法图属于词法分析 5 | P10 常量中字符常量的识别由词法分析完成,这里直接写为“字符常量” 6 | 上面的“常量标识符”改为“标识符” 7 | 上面的“无符号数”改为“无符号整数”和“无符号浮点数” 8 | P11 常数和常整数属于词法分析。这里也需要改一下,词法分析的输出分为无符号整数(不带小数点部分的)和无符号浮点数(带小数点部分的) 9 | 这个更改会影响后面的,这个后面再说 10 | 11 | P13 “函数标识符”、“过程标识符”、“变量标识符”改为“标识符” 12 | 13 | P14 “变量标识符”改为“标识符” 14 | P15 “函数标识符”改为“标识符” 15 | 16 | 下面是文法产生式需要修改的地方: 17 | P17 前面提到,词法分析器对于常数的输出分为无符号常整数和无符号常浮点数 18 | 且词法分析器也可以识别字符常量,即'字符'。 19 | 所以const_value的产生式改为 20 | const_value -> +id | -id | id 21 | |+UINUM |-UINUM |UINUM 22 | |+UFNUM |-UFNUM |UFNUM 23 | |CHAR 24 | 其中UINUM表示无符号常整数,UFNUM表示无符号常浮点数,CHAR表示字符常量 25 | 26 | P18 simple_type直接改为终结符TYPE,integer、real、boolean、char作为这个终结符的不同属性 27 | 所以type产生式改为 28 | type->TYPE 29 | |array [ period ] of TYPE 30 | 31 | digits即UINUM,所以period的产生式改为 32 | period->period , UINUM .. UINUM 33 | |UINUM .. UINUM 34 | 35 | P20 为解决if-then-else的移进规约冲突需要在规则声明部分声明优先级 36 | %nonassoc LOWER_THAN_ELSE 37 | %nonassco ELSE 38 | (nonassco表示没有结合性,yacc规定写在下面的优先级较高) 39 | 并用诸如%prec LOWER_THAN_ELSE的形式加到对应的产生式后面 40 | 这样就可以解决移进规约冲突 41 | 42 | 43 | P21 state产生式增加 while和repeat until 44 | state->while expression do statement 45 | |repeat statement until expression 46 | 47 | 另外需要说明 48 | 常量定义中,赋值用的是=,所以=需要从relop中单独拿出来,涉及到relop的产生式,需要用=再写一个产生式出来 49 | 另外,减号还可能充当取相反数的单目运算符,所以-也要从addop中单独拿出来,涉及到addop的产生式,需要用-再写一个产生式出来 50 | 51 | 根据文法,整个程序中,如果有常量定义和变量定义,一定是常量定义在最前,变量定义随后,然后才是子过程、子函数、主程序体。 52 | 常量定义只能出现一个const,变量定义只能出现一个var 53 | 子过程和子函数的声明不分先后,也可以穿插着来 54 | 主程序体一定在最后 55 | 56 | -------------------------------------------------------------------------------- /lex-yacc-src/PascalProgram.pas: -------------------------------------------------------------------------------- 1 | program test(input,output; 2 | begin 3 | 4 | end. -------------------------------------------------------------------------------- /lex-yacc-src/auto_compile.sh: -------------------------------------------------------------------------------- 1 | flex lex.l 2 | mv lex.yy.c lex.yy.cpp 3 | bison -v -d --debug yacc.y 4 | mv yacc.tab.c yacc.tab.cpp 5 | g++ -o test yacc.tab.cpp lex.yy.cpp main.cpp -------------------------------------------------------------------------------- /lex-yacc-src/auto_complie_and_run.bat: -------------------------------------------------------------------------------- 1 | del lex.yy.c 2 | flex lex.l 3 | del lex.yy.cpp 4 | ren lex.yy.c lex.yy.cpp 5 | del yacc.tab.c 6 | bison -vd --debug yacc.y 7 | del yacc.tab.cpp 8 | ren yacc.tab.c yacc.tab.cpp 9 | g++ lex.yy.cpp yacc.tab.cpp main.cpp -o pascal2c.exe 10 | pascal2c.exe 11 | pause -------------------------------------------------------------------------------- /lex-yacc-src/lex.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "main.h" 3 | #include "yacc.tab.h" 4 | //处理位置信息 5 | int yycolumn = 1; 6 | extern YYLTYPE yylloc; 7 | #define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno - 1; \ 8 | yylloc.first_column = yycolumn; yylloc.last_column = yycolumn+yyleng-1; \ 9 | yycolumn += yyleng; 10 | 11 | extern string itos(int num); 12 | 13 | string charRec; //保存字符常量 14 | char lineBuffer[10005]; //保存当前行的所有内容 15 | vector lexicalErrorInformation; 16 | void addLexicalErrorInformation(char *word, string info, int l, int r); 17 | bool CheckAndAddLengthTooLargeErrorInformation(char *text, string type, int l, int r); 18 | 19 | //函数声明 20 | extern "C" 21 | { 22 | int yywrap(); 23 | int yylex(); 24 | } 25 | %} 26 | 27 | %option yylineno 28 | 29 | %x SCOM 30 | %X MCOM 31 | %x CH 32 | 33 | line \n.* 34 | letter [a-z] 35 | digit [0-9] 36 | blank_chars [ \f\r\t\v]+ 37 | identifier {letter}({letter}|{digit})* 38 | _integer {digit}+ 39 | floater {digit}+\.{digit}+ 40 | _type (integer|real|boolean|char) 41 | relop (>=|>|<=|<>|<) 42 | addop (\+|or) 43 | mulop (\*|\/|div|mod|and) 44 | delimiter (\(|\)|\[|\]|:|,|;|\.) 45 | 46 | %% 47 | {blank_chars} {} 48 | 49 | {line} { 50 | if(CheckAndAddLengthTooLargeErrorInformation(yytext, "line", 1, yyleng)) 51 | return 0; 52 | strcpy(lineBuffer,yytext+1); 53 | yycolumn=1; 54 | yyless(1); //yyleng是当前匹配的单词的长度,yyless(n)表示退回yyleng-n个字符,只保留n个字符 55 | } 56 | 57 | "program" { 58 | yylval=new Type; 59 | yylval->str=yytext; 60 | yylval->token="PROGRAM"; 61 | yylval->lineNumber = yylineno - 1; 62 | #ifdef LEXDEBUG 63 | cout << "keyword: " << yylval->str << endl; 64 | #endif 65 | return PROGRAM; 66 | } 67 | 68 | "const" { 69 | yylval=new Type; 70 | yylval->str=yytext; 71 | yylval->token="CONST"; 72 | yylval->lineNumber = yylineno - 1; 73 | #ifdef LEXDEBUG 74 | cout << "keyword: " << yylval->str << endl; 75 | #endif 76 | return CONST; 77 | } 78 | 79 | "var" { 80 | yylval=new Type; 81 | yylval->str=yytext; 82 | yylval->token="VAR"; 83 | yylval->lineNumber = yylineno - 1; 84 | #ifdef LEXDEBUG 85 | cout << "keyword: " << yylval->str << endl; 86 | #endif 87 | return VAR; 88 | } 89 | 90 | "array" { 91 | yylval=new Type; 92 | yylval->str=yytext; 93 | yylval->token="ARRAY"; 94 | yylval->lineNumber = yylineno - 1; 95 | #ifdef LEXDEBUG 96 | cout << "keyword: " << yylval->str << endl; 97 | #endif 98 | return ARRAY; 99 | } 100 | 101 | "of" { 102 | yylval=new Type; 103 | yylval->str=yytext; 104 | yylval->token="OF"; 105 | yylval->lineNumber = yylineno - 1; 106 | #ifdef LEXDEBUG 107 | cout << "keyword: " << yylval->str << endl; 108 | #endif 109 | return OF; 110 | } 111 | 112 | "procedure" { 113 | yylval=new Type; 114 | yylval->str=yytext; 115 | yylval->token="PROCEDURE"; 116 | yylval->lineNumber = yylineno - 1; 117 | #ifdef LEXDEBUG 118 | cout << "keyword: " << yylval->str << endl; 119 | #endif 120 | return PROCEDURE; 121 | } 122 | 123 | "function" { 124 | yylval=new Type; 125 | yylval->str=yytext; 126 | yylval->token="FUNCTION"; 127 | yylval->lineNumber = yylineno - 1; 128 | #ifdef LEXDEBUG 129 | cout << "keyword: " << yylval->str << endl; 130 | #endif 131 | return FUNCTION; 132 | } 133 | 134 | "begin" { 135 | yylval=new Type; 136 | yylval->str=yytext; 137 | yylval->token="BEGIN"; 138 | yylval->lineNumber = yylineno - 1; 139 | #ifdef LEXDEBUG 140 | cout << "keyword: " << yylval->str << endl; 141 | #endif 142 | return _BEGIN; 143 | } 144 | 145 | "end" { 146 | yylval=new Type; 147 | yylval->str=yytext; 148 | yylval->token="END"; 149 | yylval->lineNumber = yylineno - 1; 150 | #ifdef LEXDEBUG 151 | cout << "keyword: " << yylval->str << endl; 152 | #endif 153 | return END; 154 | } 155 | 156 | "if" { 157 | yylval=new Type; 158 | yylval->str=yytext; 159 | yylval->token="IF"; 160 | yylval->lineNumber = yylineno - 1; 161 | #ifdef LEXDEBUG 162 | cout << "keyword: " << yylval->str << endl; 163 | #endif 164 | return IF; 165 | } 166 | 167 | "then" { 168 | yylval=new Type; 169 | yylval->str=yytext; 170 | yylval->token="THEN"; 171 | yylval->lineNumber = yylineno - 1; 172 | #ifdef LEXDEBUG 173 | cout << "keyword: " << yylval->str << endl; 174 | #endif 175 | return THEN; 176 | } 177 | 178 | "for" { 179 | yylval=new Type; 180 | yylval->str=yytext; 181 | yylval->token="FOR"; 182 | yylval->lineNumber = yylineno - 1; 183 | #ifdef LEXDEBUG 184 | cout << "keyword: " << yylval->str << endl; 185 | #endif 186 | return FOR; 187 | } 188 | 189 | "to" { 190 | yylval=new Type; 191 | yylval->str=yytext; 192 | yylval->token="TO"; 193 | yylval->lineNumber = yylineno - 1; 194 | #ifdef LEXDEBUG 195 | cout << "keyword: " << yylval->str << endl; 196 | #endif 197 | return TO; 198 | } 199 | 200 | "do" { 201 | yylval=new Type; 202 | yylval->str=yytext; 203 | yylval->token="DO"; 204 | yylval->lineNumber = yylineno - 1; 205 | #ifdef LEXDEBUG 206 | cout << "keyword: " << yylval->str << endl; 207 | #endif 208 | return DO; 209 | } 210 | 211 | "else" { 212 | yylval=new Type; 213 | yylval->str=yytext; 214 | yylval->token="ELSE"; 215 | yylval->lineNumber = yylineno - 1; 216 | #ifdef LEXDEBUG 217 | cout << "keyword: " << yylval->str << endl; 218 | #endif 219 | return ELSE; 220 | } 221 | 222 | "repeat" { 223 | yylval=new Type; 224 | yylval->str=yytext; 225 | yylval->token="REPEAT"; 226 | yylval->lineNumber = yylineno - 1; 227 | #ifdef LEXDEBUG 228 | cout << "keyword: " << yylval->str << endl; 229 | #endif 230 | return REPEAT; 231 | } 232 | 233 | "until" { 234 | yylval=new Type; 235 | yylval->str=yytext; 236 | yylval->token="UNTIL"; 237 | yylval->lineNumber = yylineno - 1; 238 | #ifdef LEXDEBUG 239 | cout << "keyword: " << yylval->str << endl; 240 | #endif 241 | return UNTIL; 242 | } 243 | 244 | "while" { 245 | yylval=new Type; 246 | yylval->str=yytext; 247 | yylval->token="WHILE"; 248 | yylval->lineNumber = yylineno - 1; 249 | #ifdef LEXDEBUG 250 | cout << "keyword: " << yylval->str << endl; 251 | #endif 252 | return WHILE; 253 | } 254 | 255 | {_type} { 256 | yylval=new Type; 257 | yylval->str=yytext; 258 | yylval->token = "TYPE"; 259 | yylval->lineNumber = yylineno - 1; 260 | #ifdef LEXDEBUG 261 | cout << "type: " << yylval->str << endl; 262 | #endif 263 | return TYPE; 264 | } 265 | 266 | "not" { 267 | yylval=new Type; 268 | yylval->str=yytext; 269 | yylval->token="NOT"; 270 | yylval->lineNumber = yylineno - 1; 271 | #ifdef LEXDEBUG 272 | cout << "NOT: " << yylval->str << endl; 273 | #endif 274 | return NOT; 275 | } 276 | 277 | {relop} { 278 | yylval=new Type; 279 | yylval->str=yytext; 280 | yylval->token="RELOP"; 281 | yylval->lineNumber = yylineno - 1; 282 | #ifdef LEXDEBUG 283 | cout << "RELOP: " << yylval->str << endl; 284 | #endif 285 | return RELOP; 286 | } 287 | 288 | {addop} { 289 | yylval=new Type; 290 | yylval->str=yytext; 291 | yylval->token="ADDOP"; 292 | yylval->lineNumber = yylineno - 1; 293 | #ifdef LEXDEBUG 294 | cout << "ADDOP: " << yylval->str << endl; 295 | #endif 296 | return ADDOP; 297 | } 298 | 299 | {mulop} { 300 | yylval=new Type; 301 | yylval->str=yytext; 302 | yylval->token="MULOP"; 303 | yylval->lineNumber = yylineno - 1; 304 | #ifdef LEXDEBUG 305 | cout << "MULOP: " << yylval->str << endl; 306 | #endif 307 | return MULOP; 308 | } 309 | 310 | "-" { 311 | yylval=new Type; 312 | yylval->str=yytext; 313 | yylval->token = yytext; 314 | yylval->lineNumber = yylineno - 1; 315 | #ifdef LEXDEBUG 316 | cout << "UMINUS OR SUB: " << yylval->str << endl; 317 | #endif 318 | return yytext[0]; 319 | } 320 | 321 | "=" { 322 | yylval=new Type; 323 | yylval->str=yytext; 324 | yylval->token = yytext; 325 | yylval->lineNumber = yylineno - 1; 326 | #ifdef LEXDEBUG 327 | cout << "EQUAL: " << yylval->str << endl; 328 | #endif 329 | return yytext[0]; 330 | } 331 | 332 | {identifier} { 333 | if(CheckAndAddLengthTooLargeErrorInformation(yytext, "identifier", yycolumn-yyleng, yycolumn-1)){ 334 | yytext[100]=0; //截断处理 335 | //yycolumn=yycolumn-yyleng; 336 | //yylloc.first_column=yycolumn; 337 | //yylloc.last_column=yycolumn+100-1; 338 | //yycolumn+=100; 339 | yyleng=100; 340 | } 341 | yylval=new Type; 342 | yylval->str=yytext; 343 | yylval->token = "IDENTIFIER"; 344 | yylval->lineNumber = yylineno - 1; 345 | #ifdef LEXDEBUG 346 | cout << "identifier: " << yylval->str << endl; 347 | #endif 348 | return IDENTIFIER; 349 | } 350 | 351 | {floater} { 352 | yylval=new Type; 353 | yylval->str=yytext; 354 | yylval->token="UFNUM"; 355 | yylval->lineNumber = yylineno - 1; 356 | #ifdef LEXDEBUG 357 | cout << "floater:" << yylval->str << endl; 358 | #endif 359 | return UFNUM; 360 | } 361 | 362 | {_integer} { 363 | yylval=new Type; 364 | yylval->str=yytext; 365 | yylval->token="UINUM"; 366 | yylval->lineNumber = yylineno - 1; 367 | #ifdef LEXDEBUG 368 | cout << "integer:" << yylval->str << endl; 369 | #endif 370 | return UINUM; 371 | } 372 | 373 | ":=" { 374 | yylval=new Type; 375 | yylval->str=yytext; 376 | yylval->token="ASSIGNOP"; 377 | yylval->lineNumber = yylineno - 1; 378 | #ifdef LEXDEBUG 379 | cout << "ASSIGNOP: " << yylval->str << endl; 380 | #endif 381 | return ASSIGNOP; 382 | } 383 | 384 | "\.\." { 385 | yylval=new Type; 386 | yylval->str=yytext; 387 | yylval->token="RANGEDOT"; 388 | yylval->lineNumber = yylineno - 1; 389 | #ifdef LEXDEBUG 390 | cout << "RANGEDOT: " << yylval->str << endl; 391 | #endif 392 | return RANGEDOT; 393 | } 394 | 395 | {delimiter} { 396 | yylval=new Type; 397 | yylval->str = yytext; 398 | yylval->token = yytext; 399 | yylval->lineNumber = yylineno - 1; 400 | #ifdef LEXDEBUG 401 | cout << "delimiter: " << yylval->str << endl; 402 | #endif 403 | return yytext[0]; 404 | } 405 | 406 | "'" {//进入字符常量识别 407 | BEGIN CH; 408 | charRec=""; 409 | } 410 | 411 | "\/\/" {//进入单行注释 412 | BEGIN SCOM; 413 | } 414 | 415 | "\{" {//进入多行注释 416 | BEGIN MCOM; 417 | } 418 | 419 | . {//非法字符 错误3 420 | addLexicalErrorInformation(yytext, "Invalid character!", yycolumn-yyleng, yycolumn-1); 421 | //cout << "error: invalid char" << endl; 422 | } 423 | 424 | <> { //读取字符常量时遇到文件尾 错误4 425 | addLexicalErrorInformation(yytext, "Unexpected end of file when reading a char constant", yycolumn-yyleng, yycolumn-1); 426 | return 0; 427 | } 428 | 429 | ("'"|"\n") {//字符常量限定在一行中 430 | int len=charRec.length(); 431 | if(yytext[0]=='\'' && len==0){ 432 | addLexicalErrorInformation(yytext, "Char constant missing!", yycolumn-yyleng-1, yycolumn-1); //错误5 433 | //cout << "error: missing char" << endl; 434 | BEGIN INITIAL; 435 | yylval = new Type; 436 | yylval->str="\0"; 437 | yylval->token="CHAR"; 438 | yylval->lineNumber=yylineno - 1; 439 | #ifdef LEXDEBUG 440 | cout << "char: " << yylval->str << endl; 441 | #endif 442 | return CHAR; 443 | } 444 | else if(yytext[0]=='\'' && len==1){ 445 | yylval=new Type; 446 | yylval->str=charRec[0];//PASCAL似乎不支持转义字符 447 | yylval->token="CHAR"; 448 | yylval->lineNumber=yylineno - 1; 449 | #ifdef LEXDEBUG 450 | cout << "char: " << yylval->str << endl; 451 | #endif 452 | BEGIN INITIAL; 453 | return CHAR; 454 | } 455 | else if(yytext[0]=='\''){ 456 | addLexicalErrorInformation(yytext, "Too many characters in a char constant!", yycolumn-yyleng-len, yycolumn-yyleng-1); //错误6 457 | //cout << "error: too many char" << endl; 458 | yylval = new Type; 459 | yylval->str=charRec[0]; 460 | yylval->token="CHAR"; 461 | yylval->lineNumber=yylineno - 1; 462 | #ifdef LEXDEBUG 463 | cout << "char: " << yylval->str << endl; 464 | #endif 465 | BEGIN INITIAL; 466 | return CHAR; 467 | } 468 | else{ 469 | addLexicalErrorInformation(yytext, "Right quote missing!", yycolumn-yyleng-len+1, yycolumn-yyleng-len+1); //错误7 470 | yyless(0);//将换行符退回 471 | yylineno--;//行号减一 472 | //cout << "quote miss match" << endl; 473 | yylval = new Type; 474 | if(len==0) 475 | yylval->str="\0"; 476 | else 477 | yylval->str=charRec[0]; 478 | yylval->token="CHAR"; 479 | yylval->lineNumber=yylineno - 1; 480 | #ifdef LEXDEBUG 481 | cout << "char: " << yylval->str << endl; 482 | #endif 483 | BEGIN INITIAL; 484 | return CHAR; 485 | } 486 | } 487 | 488 | . { 489 | charRec+=yytext[0]; 490 | } 491 | 492 | <> { //单行注释遇到文件尾 493 | return 0; 494 | } 495 | 496 | "\n" { 497 | BEGIN INITIAL; 498 | yyless(0);//将换行符退回 499 | yylineno--;//行号减一 500 | } 501 | 502 | . {} 503 | 504 | <> { //多行注释遇到文件尾 错误8 505 | addLexicalErrorInformation(yytext, "Unexpected end of file when reading a multiple line comment, lacking of a right brace", yycolumn-yyleng, yycolumn-1); 506 | return 0; 507 | } 508 | 509 | {line} { 510 | if(CheckAndAddLengthTooLargeErrorInformation(yytext, "line", 1, yyleng)) //行长度超过限制 511 | return 0; 512 | yycolumn=1; 513 | strcpy(lineBuffer, yytext+1); 514 | yyless(1); 515 | } 516 | 517 | "\}" { 518 | BEGIN INITIAL; 519 | } 520 | 521 | . {} 522 | 523 | %% 524 | 525 | //这个函数是必须的,不用动 526 | int yywrap() 527 | { 528 | return 1; 529 | } 530 | 531 | void addLexicalErrorInformation(char *word, string info, int l, int r){ 532 | string errorInformation = "[" + info + "] " + itos(yylineno-1) + "." + itos(l) + "-" + itos(yylineno-1) + "." + itos(r) + "\n"; 533 | errorInformation += string(lineBuffer) + "\n"; 534 | for(int i=1;i<=l-1;i++) 535 | errorInformation+=" "; 536 | for(int i=l;i<=r;i++) 537 | errorInformation+="^"; 538 | //cout << errorInformation << endl; 539 | lexicalErrorInformation.push_back(errorInformation); 540 | } 541 | 542 | bool CheckAndAddLengthTooLargeErrorInformation(char *text, string type, int l, int r){ 543 | string errorInformation; 544 | int len=strlen(text); 545 | if(type=="line"){ 546 | if(len>10000){ //错误1 547 | errorInformation = "[Line length too large, exceed 10000] " + itos(yylineno-1) + "." + itos(l) + "-" + itos(yylineno-1) + "." +itos(r); 548 | errorInformation += "\nLex analyse abort!"; 549 | //cout << errorInformation << endl; 550 | lexicalErrorInformation.push_back(errorInformation); 551 | return true; 552 | } 553 | return false; 554 | } 555 | else if(type=="identifier"){ 556 | if(len>100){ //错误2 557 | string id = string(text); 558 | errorInformation = "[Identifier length too large, exceed 100] " + itos(yylineno-1) + "." + itos(l) + "-" + itos(yylineno-1) + "." + itos(r); 559 | //cout << errorInformation << endl; 560 | lexicalErrorInformation.push_back(errorInformation); 561 | return true; 562 | } 563 | return false; 564 | } 565 | else{ 566 | cout << "[CheckAndAddLengthTooLargeErrorInformation] type not found" << endl; 567 | return false; 568 | } 569 | } -------------------------------------------------------------------------------- /lex-yacc-src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include 3 | #include 4 | 5 | extern Type* ParseTreeHead; 6 | extern FILE* yyin; 7 | extern vector syntaxErrorInformation; 8 | 9 | extern "C"{ 10 | int yyparse(); 11 | } 12 | 13 | string process(string str); 14 | void dfs(Type* now); 15 | bool outputSyntaxErrorInformation(); 16 | 17 | int main() 18 | { 19 | 20 | #ifdef _WIN32 21 | string inName="PascalProgram.pas"; 22 | string outName="preProcessed.pas"; 23 | #elif __APPLE__ 24 | string inName="/Users/mac/yacc_and_lex_repository/lex_and_yacc/PascalProgram.pas"; 25 | string outName="/Users/mac/yacc_and_lex_repository/lex_and_yacc/preProcessed.pas"; 26 | #endif 27 | 28 | ifstream fin(inName.c_str()); 29 | ofstream fout(outName.c_str()); 30 | string str; 31 | while (getline(fin,str)) 32 | fout << endl << process(str); 33 | fin.close(); 34 | fout.close(); 35 | 36 | yydebug=1; 37 | 38 | #ifdef _WIN32 39 | const char* sFile = "preProcessed.pas"; 40 | #elif __APPLE__ 41 | const char *sFile = "/Users/mac/yacc_and_lex_repository/lex_and_yacc/preProcessed.pas"; 42 | #endif 43 | FILE* fp = fopen(sFile,"r"); 44 | if(fp==NULL){ 45 | printf("cannot open %s\n",sFile); 46 | return -1; 47 | } 48 | yyin=fp; 49 | 50 | printf("-----begin parsing %s\n",sFile); 51 | yyparse(); 52 | printf("-----end parsing\n"); 53 | if(ParseTreeHead!=NULL) 54 | //dfs(ParseTreeHead); 55 | 56 | fclose(fp); 57 | 58 | outputSyntaxErrorInformation(); 59 | 60 | return 0; 61 | } 62 | 63 | string process(string str) {//由于PASCAL大小写不敏感,所以需要将所有字母转化为小写 64 | for (int i = 0; i= 'A'&&str[i] <= 'Z') 66 | str[i] = str[i] + ('a' - 'A'); 67 | } 68 | return str; 69 | } 70 | 71 | void dfs(Type* now){ 72 | if(now->children.size()==0){ 73 | if(now->str=="") 74 | cout << now->token << "\t->\t" << "empty" << endl; 75 | return; 76 | } 77 | cout << now->token << "\t->"; 78 | for (int i = 0; i < now->children.size(); i++) { 79 | if (now->children[i]->children.size()==0 && now->children[i]->str != "") 80 | cout << "\t\"" << now->children[i]->str << "\""; 81 | else 82 | cout << "\t" << now->children[i]->token; 83 | } 84 | cout << endl; 85 | for(int i=0;ichildren.size();i++) 86 | dfs(now->children[i]); 87 | } 88 | 89 | string itos(int num){ 90 | stringstream sin; 91 | sin< 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | extern int yydebug; 15 | using namespace std; 16 | 17 | //重新定义属性类型(yylval实际上应由yacc定义)c 18 | class Type{ 19 | public: 20 | string str;//终结符号的具体属性 21 | string token;//终结符号或非终结符号本身的名称 22 | int lineNumber;//终结符号的行号,参照语法分析指导.docx 23 | vector children; //对应产生式下面的结点 24 | 25 | Type(){} 26 | Type(string typ, string name, int ln): str(typ), token(name), lineNumber(ln){} 27 | Type(string name, vector cdn): token(name), children(cdn){} 28 | }; 29 | #define YYSTYPE Type* 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /lex-yacc-src/pascal2c.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/lex-yacc-src/pascal2c.exe -------------------------------------------------------------------------------- /lex-yacc-src/preProcessed.pas: -------------------------------------------------------------------------------- 1 | 2 | program test(input,output; 3 | begin 4 | 5 | end. -------------------------------------------------------------------------------- /lex-yacc-src/unistd.h: -------------------------------------------------------------------------------- 1 | /** This file is part of the Mingw32 package. 2 | * unistd.h maps (roughly) to io.h 3 | */ 4 | #ifndef _UNISTD_H 5 | #define _UNISTD_H 6 | #include 7 | #include 8 | #endif /* _UNISTD_H */ -------------------------------------------------------------------------------- /lex-yacc-src/yacc.tab.h: -------------------------------------------------------------------------------- 1 | 2 | /* A Bison parser, made by GNU Bison 2.4.1. */ 3 | 4 | /* Skeleton interface for Bison's Yacc-like parsers in C 5 | 6 | Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 7 | Free Software Foundation, Inc. 8 | 9 | This program is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . */ 21 | 22 | /* As a special exception, you may create a larger work that contains 23 | part or all of the Bison parser skeleton and distribute that work 24 | under terms of your choice, so long as that work isn't itself a 25 | parser generator using the skeleton or a modified version thereof 26 | as a parser skeleton. Alternatively, if you modify or redistribute 27 | the parser skeleton itself, you may (at your option) remove this 28 | special exception, which will cause the skeleton and the resulting 29 | Bison output files to be licensed under the GNU General Public 30 | License without this special exception. 31 | 32 | This special exception was added by the Free Software Foundation in 33 | version 2.2 of Bison. */ 34 | 35 | 36 | /* Tokens. */ 37 | #ifndef YYTOKENTYPE 38 | # define YYTOKENTYPE 39 | /* Put the tokens into the symbol table, so that GDB and other debuggers 40 | know about them. */ 41 | enum yytokentype { 42 | PROGRAM = 258, 43 | CONST = 259, 44 | VAR = 260, 45 | ARRAY = 261, 46 | OF = 262, 47 | PROCEDURE = 263, 48 | FUNCTION = 264, 49 | _BEGIN = 265, 50 | END = 266, 51 | IF = 267, 52 | THEN = 268, 53 | FOR = 269, 54 | TO = 270, 55 | DO = 271, 56 | ELSE = 272, 57 | REPEAT = 273, 58 | UNTIL = 274, 59 | WHILE = 275, 60 | IDENTIFIER = 276, 61 | UINUM = 277, 62 | UFNUM = 278, 63 | CHAR = 279, 64 | TYPE = 280, 65 | ASSIGNOP = 281, 66 | RELOP = 282, 67 | ADDOP = 283, 68 | MULOP = 284, 69 | NOT = 285, 70 | RANGEDOT = 286, 71 | ADD = 287, 72 | MUL = 288, 73 | UMINUS = 289, 74 | LOWER_THAN_ELSE = 290, 75 | ONE = 291, 76 | TWO = 292, 77 | THREE = 293 78 | }; 79 | #endif 80 | 81 | 82 | 83 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 84 | typedef int YYSTYPE; 85 | # define YYSTYPE_IS_TRIVIAL 1 86 | # define yystype YYSTYPE /* obsolescent; will be withdrawn */ 87 | # define YYSTYPE_IS_DECLARED 1 88 | #endif 89 | 90 | extern YYSTYPE yylval; 91 | 92 | #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED 93 | typedef struct YYLTYPE 94 | { 95 | int first_line; 96 | int first_column; 97 | int last_line; 98 | int last_column; 99 | } YYLTYPE; 100 | # define yyltype YYLTYPE /* obsolescent; will be withdrawn */ 101 | # define YYLTYPE_IS_DECLARED 1 102 | # define YYLTYPE_IS_TRIVIAL 1 103 | #endif 104 | 105 | extern YYLTYPE yylloc; 106 | 107 | -------------------------------------------------------------------------------- /lex-yacc-src/yacc.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "main.h" 3 | #include "yacc.tab.h" 4 | extern "C" 5 | { 6 | void yyerror(const char *s); 7 | int yyparse(); 8 | extern int yylex(); 9 | } 10 | 11 | void yyerror(const char *s, YYLTYPE *loc); 12 | void yyerror(const char *s, int line, int col); 13 | void yyerror(const char *s, int startLine, int startCol, int endLine, int endCol); 14 | 15 | extern int yylineno; 16 | extern char* yytext; 17 | extern char lineBuffer[500]; 18 | extern int yyleng; 19 | extern int yycolumn; 20 | extern string itos(int num); 21 | 22 | bool haveSemanticError=false; 23 | int rec_line,rec_pos; 24 | char rec_buff[505]; 25 | 26 | Type* ParseTreeHead=NULL; 27 | 28 | vector syntaxErrorInformation; //存放语法错误信息 29 | 30 | %} 31 | 32 | %token PROGRAM 33 | %token CONST 34 | %token VAR 35 | %token ARRAY 36 | %token OF 37 | %token PROCEDURE 38 | %token FUNCTION 39 | %token _BEGIN 40 | %token END 41 | %token IF 42 | %token THEN 43 | %token FOR 44 | %token TO 45 | %token DO 46 | %token ELSE 47 | %token REPEAT 48 | %token UNTIL 49 | %token WHILE 50 | 51 | %token IDENTIFIER 52 | %token UINUM 53 | %token UFNUM 54 | %token CHAR 55 | %token TYPE 56 | %token ASSIGNOP 57 | %token RELOP 58 | %token ADDOP 59 | %token MULOP 60 | %token NOT 61 | %token RANGEDOT 62 | 63 | %start programstruct 64 | 65 | %left '+' '-' ADD 66 | %left '*' '/' MUL 67 | %right UMINUS 68 | %nonassoc LOWER_THAN_ELSE 69 | %nonassoc ELSE 70 | %nonassoc ONE 71 | %nonassoc TWO 72 | %nonassoc THREE 73 | 74 | %locations 75 | 76 | %% 77 | programstruct: program_head ';' program_body '.'{ //正常 78 | ParseTreeHead=$$=new Type; 79 | $$->token = "programstruct"; 80 | $$->children.push_back($1); $$->children.push_back($2); 81 | $$->children.push_back($3); $$->children.push_back($4); 82 | if(yylex()) //多余的内容 83 | yyerror("redundant content at the end!", @4.last_line, @4.last_column+1); 84 | YYACCEPT; 85 | }|program_head error program_body '.'{ //ERROR 缺少分号 checked 86 | ParseTreeHead=$$=new Type; 87 | $$->token = "programstruct"; 88 | yyerror("missing a semicolon here", @1.last_line, @1.last_column+1); 89 | }|program_head ';' program_body error{ //ERROR 缺少点号 checked 90 | ParseTreeHead=$$=new Type; 91 | $$->token = "programstruct"; 92 | yyerror("missing a dot here", @3.last_line, @3.last_column+1); 93 | }|error ';' program_body '.'{ //ERROR program_head识别失败 checked 94 | ParseTreeHead=$$=new Type; 95 | $$->token = "programstruct"; 96 | yyerror("fatal error in program head, maybe missing keyword \"program\"",@1.first_line, @1.first_column, @1.last_line, @1.last_column); 97 | }|program_head ';' error '.'{ //ERROR program_body识别失败 unchecked 98 | ParseTreeHead=$$=new Type; 99 | $$->token = "programstruct"; 100 | yyerror("fatal error in program body"); 101 | }|error program_head ';' program_body '.'{ //ERROR program_head前包含非法字符 checked 102 | ParseTreeHead=$$=new Type; 103 | $$->token = "programstruct"; 104 | yyerror("invalid symbol before program head", @$.first_line, @$.first_column, @2.first_line, @2.first_column-1); 105 | }|error program_head error program_body '.'{ //ERROR program_head前包含非法记号、缺失分号 checked 106 | ParseTreeHead=$$=new Type; 107 | $$->token = "programstruct"; 108 | yyerror("invalid token before program head, maybe missing keyword \"program\"", @$.first_line, @$.first_column, @2.first_line, @2.first_column-1); 109 | yyerror("missing a semicolon here", @2.last_line, @2.last_column+1); 110 | }|error program_head ';' program_body error{ //ERROR program_head前包含非法记号、缺失点号 checked 111 | ParseTreeHead=$$=new Type; 112 | $$->token = "programstruct"; 113 | yyerror("invalid token before program head, maybe missing keyword \"program\"", @$.first_line, @$.first_column, @2.first_line, @2.first_column-1); 114 | yyerror("missing a dot here", @4.last_line, @4.last_column+1); 115 | }|error program_head ';' error '.'{ //ERROR program_head前包含非法记号、program_body识别失败 unchecked 116 | ParseTreeHead=$$=new Type; 117 | $$->token = "programstruct"; 118 | yyerror("invalid token before program head, maybe missing keyword \"program\"", @$.first_line, @$.first_column, @2.first_line, @2.first_column-1); 119 | yyerror("fatal error in program body", @3.last_line, @3.last_column+1, @5.first_line, @5.first_column-1); 120 | }; 121 | 122 | program_head: PROGRAM IDENTIFIER '(' idlist ')'{ //正常 123 | $$=new Type; 124 | $$->token = "program_head"; 125 | $$->children.push_back($1); $$->children.push_back($2); 126 | $$->children.push_back($3); $$->children.push_back($4); $$->children.push_back($5); 127 | }|PROGRAM error '(' idlist ')'{ //ERROR 缺少主程序名 checked 128 | $$=new Type; 129 | $$->token = "program_head"; 130 | yyerror("missing program name here", @1.last_line, @1.last_column+1); 131 | }|PROGRAM IDENTIFIER error idlist ')'{ //ERROR 缺少左括号 checked 132 | $$=new Type; 133 | $$->token = "program_head"; 134 | yyerror("missing a left bracket here", @4.first_line, @4.first_column-1); 135 | }|PROGRAM IDENTIFIER '(' error ')'{ //ERROR idlist识别失败 checked 136 | $$=new Type; 137 | $$->token = "program_head"; 138 | yyerror("program identifier list missing or imcomplete", @4.first_line, @4.first_column, @4.last_line, @4.last_column); 139 | }|PROGRAM IDENTIFIER '(' idlist error{ //ERROR 缺少右括号 checked 140 | $$=new Type; 141 | $$->token = "program_head"; 142 | yyerror("missing a right bracket here", @4.last_line, @4.last_column+1); 143 | }|PROGRAM error{ //ERROR program head checked 144 | $$=new Type; 145 | $$->token = "program_head"; 146 | yyerror("program head imcomplete", @1.first_line, @1.first_column, @1.last_line, @1.last_column); 147 | }|PROGRAM IDENTIFIER error{ //ERROR idlist缺失 checked 148 | $$=new Type; 149 | $$->token = "program_head"; 150 | yyerror("program identifier list missing or imcomplete", @1.first_line, @1.first_column, @2.last_line, @2.last_column); 151 | }|PROGRAM IDENTIFIER '(' error{ //ERROR idlist缺失 checked 152 | $$=new Type; 153 | $$->token = "program_head"; 154 | yyerror("program identifier list missing or imcomplete", @1.first_line, @1.first_column, @2.last_line, @2.last_column); 155 | }; 156 | 157 | program_body: const_declarations var_declarations subprogram_declarations compound_statement{ //正常 158 | $$=new Type; 159 | $$->token = "program_body"; 160 | $$->children.push_back($1); $$->children.push_back($2); 161 | $$->children.push_back($3); $$->children.push_back($4); 162 | }; 163 | 164 | idlist: idlist ',' IDENTIFIER{ //正常 idlist的产生式不打算加入error 165 | $$=new Type; 166 | $$->token = "idlist"; 167 | $$->children.push_back($1); $$->children.push_back($2); $$->children.push_back($3); 168 | }|IDENTIFIER{ //正常 169 | $$=new Type; 170 | $$->token = "idlist"; 171 | $$->children.push_back($1); 172 | }; 173 | 174 | const_declarations: CONST const_declaration ';' { //正常 175 | $$=new Type; 176 | $$->token = "const_declarations"; 177 | $$->children.push_back($1); $$->children.push_back($2); $$->children.push_back($3); 178 | }|{ //正常 179 | $$=new Type; 180 | $$->token = "const_declarations"; 181 | }|CONST error ';' { //ERROR 常量定义出现错误 checked 182 | $$=new Type; 183 | $$->token = "const_declarations"; 184 | yyerror("fatal error in const declarations", @2.first_line, @2.first_column, @2.last_line, @2.last_column); 185 | }|CONST const_declaration error { //ERROR 缺少分号 checked 186 | $$=new Type; 187 | $$->token = "const_declarations"; 188 | yyerror("missing a semicolon here", @2.first_line, @2.first_column, @2.last_line, @2.last_column); 189 | }; 190 | 191 | const_declaration: const_declaration ';' IDENTIFIER '=' const_value{ //正常 192 | $$=new Type; 193 | $$->token = "const_declaration"; 194 | $$->children.push_back($1); $$->children.push_back($2); 195 | $$->children.push_back($3); $$->children.push_back($4); $$->children.push_back($5); 196 | }|const_declaration ';' IDENTIFIER '=' error{ //常数初始化右值缺失 checked 197 | $$=new Type; 198 | $$->token = "const_declaration"; 199 | yyerror("constant definition missing initial r-value", @4.first_line, @4.first_column, @4.last_line, @4.last_column); 200 | }|IDENTIFIER '=' const_value{ //正常 201 | $$=new Type; 202 | $$->token = "const_declaration"; 203 | $$->children.push_back($1); $$->children.push_back($2); $$->children.push_back($3); 204 | }|IDENTIFIER '=' error{ //常数初始化右值缺失 checked 205 | $$=new Type; 206 | $$->token = "const_declaration"; 207 | yyerror("constant definition missing initial r-value", @3.first_line, @3.first_column, @3.last_line, @3.last_column); 208 | }|const_declaration error IDENTIFIER '=' const_value{ //ERROR 缺少分号 checked 209 | $$=new Type; 210 | $$->token = "const_declaration"; 211 | yyerror("missing a semicolon here", @1.first_line, @1.first_column, @1.last_line, @1.last_column+1); 212 | }|const_declaration ';' IDENTIFIER error const_value{ //ERROR 缺少等号(常量的初始化用的是等号,而不是赋值号) checked 213 | $$=new Type; 214 | $$->token = "const_declaration"; 215 | yyerror("missing a equal sign here",@3.first_line, @3.first_column, @3.last_line, @3.last_column); 216 | }|IDENTIFIER error const_value{ //ERROR 缺少等号(常量的初始化用的是等号,而不是赋值号) checked 217 | $$=new Type; 218 | $$->token = "const_declaration"; 219 | yyerror("missing a equal sign here", @2.first_line, @2.first_column, @2.last_line, @2.last_column); 220 | }; 221 | 222 | const_value: '+' IDENTIFIER { //正常,该非终结符的产生式不打算加入error 223 | $$=new Type; 224 | $$->token = "const_value"; 225 | $$->children.push_back($1); $$->children.push_back($2); 226 | }|'-' IDENTIFIER { //正常 227 | $$=new Type; 228 | $$->token = "const_value"; 229 | $$->children.push_back($1); $$->children.push_back($2); 230 | }|IDENTIFIER { //正常 231 | $$=new Type; 232 | $$->token = "const_value"; 233 | $$->children.push_back($1); 234 | }|'+' UINUM { //正常 235 | $$=new Type; 236 | $$->token = "const_value"; 237 | $$->children.push_back($1); $$->children.push_back($2); 238 | }|'-' UINUM { //正常 239 | $$=new Type; 240 | $$->token = "const_value"; 241 | $$->children.push_back($1); $$->children.push_back($2); 242 | }|UINUM { //正常 243 | $$=new Type; 244 | $$->token = "const_value"; 245 | $$->children.push_back($1); 246 | }|'+' UFNUM { //正常 247 | $$=new Type; 248 | $$->token = "const_value"; 249 | $$->children.push_back($1); $$->children.push_back($2); 250 | }|'-' UFNUM { //正常 251 | $$=new Type; 252 | $$->token = "const_value"; 253 | $$->children.push_back($1); $$->children.push_back($2); 254 | }|UFNUM { //正常 255 | $$=new Type; 256 | $$->token = "const_value"; 257 | $$->children.push_back($1); 258 | }|CHAR{ //正常 259 | $$=new Type; 260 | $$->token = "const_value"; 261 | $$->children.push_back($1); 262 | }; 263 | 264 | var_declarations: VAR var_declaration ';'{ //正常 265 | $$=new Type; 266 | $$->token = "var_declarations"; 267 | $$->children.push_back($1); $$->children.push_back($2); $$->children.push_back($3); 268 | }|{ //正常 269 | $$=new Type; 270 | $$->token = "var_declarations"; 271 | }|VAR error ';'{ //ERROR 变量定义出现错误 checked 272 | $$=new Type; 273 | $$->token = "var_declarations"; 274 | yyerror("fatal error in variant declarations", @1.first_line, @1.first_column, @1.last_line, @1.last_column); 275 | }|VAR var_declaration error{ //ERROR 缺少分号 checked 276 | $$=new Type; 277 | $$->token = "var_declarations"; 278 | yyerror("missing a semicolon here", @2.last_line, @2.last_column+1); 279 | }; 280 | 281 | var_declaration: var_declaration ';' idlist ':' type { //正常 282 | $$=new Type; 283 | $$->token = "var_declaration"; 284 | $$->children.push_back($1);$$->children.push_back($2); 285 | $$->children.push_back($3); $$->children.push_back($4); $$->children.push_back($5); 286 | }|idlist ':' type { //正常 287 | $$=new Type; 288 | $$->token ="var_declaration"; 289 | $$->children.push_back($1);$$->children.push_back($2); $$->children.push_back($3); 290 | }|var_declaration error idlist ':' type { //ERROR 缺少分号 checked 291 | $$=new Type; 292 | $$->token = "var_declaration"; 293 | yyerror("missing a semicolon here", @1.last_line, @1.last_column+1); 294 | }|var_declaration ';' idlist error type { //ERROR 缺少冒号 checked 295 | $$=new Type; 296 | $$->token = "var_declaration"; 297 | yyerror("missing a colon here", @3.last_line, @3.last_column+1); 298 | }|var_declaration ';' idlist ':' error { //ERROR type识别失败 checked 299 | $$=new Type; 300 | $$->token = "var_declaration"; 301 | yyerror("missing a type here", @4.last_line, @4.last_column+1); 302 | }|idlist ':' error { //ERROR type识别失败 checked 303 | $$=new Type; 304 | $$->token ="var_declaration"; 305 | yyerror("missing a type here", @3.last_line, @3.last_column+1); 306 | }|idlist error type { //ERROR 缺少分号 checked 307 | $$=new Type; 308 | $$->token ="var_declaration"; 309 | yyerror("missing a colon here", @1.last_line, @1.last_column+1); 310 | }; 311 | 312 | type: TYPE{ //正常 313 | $$=new Type; 314 | $$->token = "type"; 315 | $$->children.push_back($1); 316 | }|ARRAY '[' period ']' OF TYPE{ //正常 317 | $$=new Type; 318 | $$->token = "type"; 319 | $$->children.push_back($1);$$->children.push_back($2); 320 | $$->children.push_back($3);$$->children.push_back($4); 321 | $$->children.push_back($5);$$->children.push_back($6); 322 | }|ARRAY error period ']' OF TYPE{ //ERROR 缺少左中括号 checked 323 | $$=new Type; 324 | $$->token = "type"; 325 | yyerror("missing a left square bracket here", @1.last_line, @1.last_column+1); 326 | }|ARRAY '[' period ']' error TYPE{ //ERROR 缺少OF关键字 checked 327 | $$=new Type; 328 | $$->token = "type"; 329 | yyerror("missing keyword \"OF\" here", @4.last_line, @4.last_column+1, @6.first_line, @6.first_column-1); 330 | }|ARRAY '[' period ']' OF error{ //ERROR 数组元素类型识别失败 checked 331 | $$=new Type; 332 | $$->token = "type"; 333 | yyerror("missing a base type keyword here", @5.last_line, @5.last_column+1); 334 | }|ARRAY error{ //ERROR 不完整的数组类型 checked 335 | $$=new Type; 336 | $$->token = "type"; 337 | yyerror("incomplete array type", &@$); 338 | }|ARRAY '[' error{ //ERROR 不完整的数组类型 checked 339 | $$=new Type; 340 | $$->token = "type"; 341 | yyerror("incomplete array type", &@$); 342 | }|ARRAY '[' period error{ //ERROR 不完整的数组类型 checked 343 | $$=new Type; 344 | $$->token = "type"; 345 | yyerror("incomplete array type", &@$); 346 | }; 347 | 348 | period: period ',' UINUM RANGEDOT UINUM{ //正常 349 | $$=new Type; 350 | $$->token="period"; 351 | $$->children.push_back($1);$$->children.push_back($2); 352 | $$->children.push_back($3);$$->children.push_back($4);$$->children.push_back($5); 353 | }|period error UINUM RANGEDOT UINUM{ //ERROR 缺少逗号 checked 354 | $$=new Type; 355 | $$->token="period"; 356 | yyerror("missing a comma here", @1.last_line, @1.last_column+1); 357 | }|period ',' UINUM error UINUM{ //ERROR 缺少双点号 checked 358 | $$=new Type; 359 | $$->token="period"; 360 | yyerror("missing range dot .. here", @3.last_line, @3.last_column+1); 361 | }|UINUM RANGEDOT UINUM{ //正常 362 | $$=new Type; 363 | $$->token="period"; 364 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 365 | }; 366 | 367 | subprogram_declarations: subprogram_declarations subprogram ';'{ //正常 368 | $$=new Type; 369 | $$->token="subprogram_declarations"; 370 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 371 | }|subprogram_declarations subprogram error{ //ERROR 缺少分号 checked 372 | $$=new Type; 373 | $$->token="subprogram_declarations"; 374 | yyerror("missing a semicolon here", @2.last_line, @2.last_column+1); 375 | }|{ //正常 376 | $$=new Type; 377 | $$->token ="subprogram_declarations"; 378 | }; 379 | 380 | subprogram: subprogram_head ';' subprogram_body{ //正常 381 | $$=new Type; 382 | $$->token="subprogram"; 383 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 384 | }|subprogram_head error subprogram_body{ //ERROR 缺少分号 checked 385 | $$=new Type; 386 | $$->token="subprogram"; 387 | yyerror("missing a semicolon here", @1.last_line, @1.last_column+1); 388 | }; 389 | 390 | subprogram_head: PROCEDURE IDENTIFIER formal_parameter{ //正常 391 | $$=new Type; 392 | $$->token="subprogram_head"; 393 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 394 | }|FUNCTION IDENTIFIER formal_parameter ':' TYPE{ //正常 395 | $$=new Type; 396 | $$->token="subprogram_head"; 397 | $$->children.push_back($1);$$->children.push_back($2); 398 | $$->children.push_back($3);$$->children.push_back($4);$$->children.push_back($5); 399 | }|FUNCTION error formal_parameter ':' TYPE{ //ERROR 函数名缺失 checked 400 | $$=new Type; 401 | $$->token="subprogram_head"; 402 | yyerror("missing function name", @1.last_line, @1.last_column+1); 403 | }|FUNCTION IDENTIFIER formal_parameter error TYPE{ //ERROR 缺少冒号 checked 404 | $$=new Type; 405 | $$->token="subprogram_head"; 406 | yyerror("missing a colon here", @3.last_line, @3.last_column); 407 | }|FUNCTION IDENTIFIER formal_parameter ':' error{ //ERROR 缺少基本类型关键字 checked 408 | $$=new Type; 409 | $$->token="subprogram_head"; 410 | yyerror("missing a base type keyword here", @4.last_line, @4.last_column+1); 411 | }|FUNCTION IDENTIFIER formal_parameter error{ //ERROR 缺少基本类型关键字 checked 412 | $$=new Type; 413 | $$->token="subprogram_head"; 414 | yyerror("missing a base type keyword here", @3.last_line, @3.last_column+1); 415 | }|FUNCTION error{ //ERROR 不完整的函数头 checked 416 | $$=new Type; 417 | $$->token="subprogram_head"; 418 | yyerror("incomplete function head", &@$); 419 | }|PROCEDURE error{ //ERROR 不完整的过程头 checked 420 | $$=new Type; 421 | $$->token="subprogram_head"; 422 | yyerror("incomplete procedure head", &@$); 423 | }; 424 | 425 | formal_parameter: '(' parameter_list ')'{ //正常 426 | $$=new Type; 427 | $$->token="formal_parameter"; 428 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 429 | }|{ //正常 430 | $$=new Type; 431 | $$->token="formal_parameter"; 432 | }|'(' error{ //ERROR 不完整的形参列表 433 | $$=new Type; 434 | $$->token="formal_parameter"; 435 | yyerror("incomplete formal parameter list", &@$); 436 | }|'(' parameter_list error{ //ERROR 右括号缺失 437 | $$=new Type; 438 | $$->token="formal_parameter"; 439 | yyerror("missing a right bracket here", @2.last_line, @2.last_column+1); 440 | }; 441 | 442 | parameter_list: parameter_list ';' parameter{ //正常 443 | $$=new Type; 444 | $$->token="parameter_list"; 445 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 446 | }|parameter_list error parameter{ //ERROR 缺少分号 checked 447 | $$=new Type; 448 | $$->token="parameter_list"; 449 | yyerror("missing a semicolon here", @1.last_line, @1.last_column+1); 450 | }|parameter{ //正常 451 | $$=new Type; 452 | $$->token="parameter_list"; 453 | $$->children.push_back($1); 454 | }; 455 | 456 | parameter: var_parameter { //正常,非终结符parameter的产生式不打算加入error 457 | $$=new Type; 458 | $$->token="parameter"; 459 | $$->children.push_back($1); 460 | }|value_parameter{ //正常 461 | $$=new Type; 462 | $$->token="parameter"; 463 | $$->children.push_back($1); 464 | }; 465 | 466 | var_parameter: VAR value_parameter{ //正常 467 | $$=new Type; 468 | $$->token="var_parameter"; 469 | $$->children.push_back($1);$$->children.push_back($2); 470 | }|VAR error{ //ERROR 不完整的引用参数列表 checked 471 | $$=new Type; 472 | $$->token="var_parameter"; 473 | yyerror("incomplete refereced parameter list", &@$); 474 | }; 475 | 476 | value_parameter: idlist ':' TYPE{ //正常 477 | $$=new Type; 478 | $$->token="value_parameter"; 479 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 480 | }|idlist error TYPE{ //ERROR 缺少分号 checked 481 | $$=new Type; 482 | $$->token="value_parameter"; 483 | yyerror("missing a colon here", @1.first_line, @1.last_column+1); 484 | }|idlist ':' error{ //ERROR 缺少基本类型关键字 checked 485 | $$=new Type; 486 | $$->token="value_parameter"; 487 | yyerror("missing a base type keyword here", @2.last_line, @2.last_column+1); 488 | }|idlist error{ //ERROR 缺少基本类型关键字 checked 489 | $$=new Type; 490 | $$->token="value_parameter"; 491 | yyerror("missing a base type keyword here", @1.last_line, @1.last_column+1); 492 | }; 493 | 494 | subprogram_body: const_declarations var_declarations compound_statement{ //正常 495 | $$=new Type; 496 | $$->token="subprogram_body"; 497 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 498 | }; 499 | 500 | compound_statement: _BEGIN statement_list END{ //正常 501 | $$=new Type; 502 | $$->token="compound_statement"; 503 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 504 | }|_BEGIN statement_list error{ //ERROR 缺少END关键字 checked 505 | $$=new Type; 506 | $$->token="compound_statement"; 507 | yyerror("missing keyword \"end\"", @2.last_line, @2.last_column+1); 508 | }; 509 | 510 | statement_list: statement_list ';' statement{ //正常 511 | $$=new Type; 512 | $$->token="statement_list"; 513 | $$->children.push_back($1);$$->children.push_back($2); $$->children.push_back($3); 514 | }|statement_list error statement{ //ERROR 缺失分号 这里引发了3个规约规约冲突 checked 515 | $$=new Type; 516 | $$->token="statement_list"; 517 | yyerror("missing a semicolon here", @1.last_line, @1.last_column+1); 518 | }|statement{ //正常 519 | $$=new Type; 520 | $$->token="statement_list"; 521 | $$->children.push_back($1); 522 | }; 523 | 524 | statement: variable ASSIGNOP expression{ //正常 525 | $$=new Type; 526 | $$->token="statement"; 527 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 528 | }|procedure_call{ //正常 529 | $$=new Type; 530 | $$->token="statement"; 531 | $$->children.push_back($1); 532 | }|compound_statement{ //正常 533 | $$=new Type; 534 | $$->token="statement"; 535 | $$->children.push_back($1); 536 | }|IF expression THEN statement else_part{ //正常 537 | $$=new Type; 538 | $$->token="statement"; 539 | $$->children.push_back($1);$$->children.push_back($2); 540 | $$->children.push_back($3);$$->children.push_back($4);$$->children.push_back($5); 541 | }|IF expression error statement else_part{ //ERROR 缺少then关键字 checked 542 | $$=new Type; 543 | $$->token="statement"; 544 | yyerror("missing keyword \"then\"", @2.last_line, @2.last_column+1); 545 | }|FOR IDENTIFIER ASSIGNOP expression TO expression DO statement{ //正常 546 | $$=new Type; 547 | $$->token="statement"; 548 | $$->children.push_back($1);$$->children.push_back($2); 549 | $$->children.push_back($3);$$->children.push_back($4); 550 | $$->children.push_back($5);$$->children.push_back($6); 551 | $$->children.push_back($7);$$->children.push_back($8); 552 | }|FOR IDENTIFIER error expression TO expression DO statement{ //ERROR 缺少赋值号 checked 553 | $$=new Type; 554 | $$->token="statement"; 555 | yyerror("missing assignop \":=\"", @2.last_line, @2.last_column+1); 556 | }|FOR IDENTIFIER ASSIGNOP expression error expression DO statement{ //ERROR 缺少关键字to checked 557 | $$=new Type; 558 | $$->token="statement"; 559 | yyerror("missing keywrod \"to\"", @4.last_line, @4.last_column+1); 560 | }|FOR IDENTIFIER ASSIGNOP expression TO expression error statement{ //ERROR 缺少关键字do checked 561 | $$=new Type; 562 | $$->token="statement"; 563 | yyerror("missing keywrod \"do\"", @6.last_line, @4.last_column+1); 564 | }|WHILE expression DO statement{ //正常 565 | $$=new Type; 566 | $$->token="statement"; 567 | $$->children.push_back($1);$$->children.push_back($2); 568 | $$->children.push_back($3);$$->children.push_back($4); 569 | }|WHILE expression error statement{ //ERROR 缺少关键字do checked 570 | $$=new Type; 571 | $$->token="statement"; 572 | yyerror("missing keywrod \"do\"", @2.last_line, @2.last_column+1); 573 | }|REPEAT statement UNTIL expression{ //正常 574 | $$=new Type; 575 | $$->token="statement"; 576 | $$->children.push_back($1);$$->children.push_back($2); 577 | $$->children.push_back($3);$$->children.push_back($4); 578 | }|REPEAT statement error expression{ //ERROR 缺少关键字until checked 579 | $$=new Type; 580 | $$->token="statement"; 581 | yyerror("missing keywrod \"until\"", @4.first_line, @4.first_column); 582 | }|{ //正常 583 | $$=new Type; 584 | $$->token="statement"; 585 | }; 586 | 587 | else_part: ELSE statement{ //正常 非终结符else_part的产生式不打算加error 588 | $$=new Type; 589 | $$->token="else_part"; 590 | $$->children.push_back($1);$$->children.push_back($2); 591 | }|%prec LOWER_THAN_ELSE{ //正常 592 | $$=new Type; 593 | $$->token="else_part"; 594 | }; 595 | 596 | variable: IDENTIFIER id_varpart{ //正常 597 | $$=new Type; 598 | $$->token="variable"; 599 | $$->children.push_back($1);$$->children.push_back($2); 600 | }; 601 | 602 | id_varpart: '[' expression_list ']'{ //正常 603 | $$=new Type; 604 | $$->token="id_varpart"; 605 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 606 | }|'[' error{ //ERROR 不完整的数组下标列表 checked 607 | $$=new Type; 608 | $$->token="id_varpart"; 609 | yyerror("incomplete expression list of array subindex", &@$); 610 | }|'[' expression_list error{ //ERROR 缺失右中括号 checked 611 | $$=new Type; 612 | $$->token="id_varpart"; 613 | yyerror("missing a right square bracket here", @2.last_line, @2.last_column+1); 614 | }|{ //正常 615 | $$=new Type; 616 | $$->token="id_varpart"; 617 | }; 618 | 619 | procedure_call: IDENTIFIER{ //正常 620 | $$=new Type; 621 | $$->token="procedure_call"; 622 | $$->children.push_back($1); 623 | }|IDENTIFIER '(' expression_list ')'{ //正常 624 | $$=new Type; 625 | $$->token="procedure_call"; 626 | $$->children.push_back($1);$$->children.push_back($2); 627 | $$->children.push_back($3);$$->children.push_back($4); 628 | }|IDENTIFIER '(' expression_list error{ //ERROR 缺少右括号 checked 629 | $$=new Type; 630 | $$->token="procedure_call"; 631 | yyerror("missing a right bracket here", @3.last_line, @3.last_column+1); 632 | }; 633 | 634 | expression_list: expression_list ',' expression{ //正常 635 | $$=new Type; 636 | $$->token="expression_list"; 637 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 638 | }|expression{ //正常 639 | $$=new Type; 640 | $$->token="expression_list"; 641 | $$->children.push_back($1); 642 | }|expression_list error expression{ //ERROR 缺少逗号 这里引发了一个移进规约冲突 checked 643 | $$=new Type; 644 | $$->token="expression_list"; 645 | yyerror("missing a comma here", @1.last_line, @1.last_column+1); 646 | }; 647 | 648 | expression: simple_expression RELOP simple_expression{ //正常 649 | $$=new Type; 650 | $$->token="expression"; 651 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 652 | }|simple_expression '=' simple_expression{ //正常 653 | $$=new Type; 654 | $$->token="expression"; 655 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 656 | }|simple_expression{ //正常 657 | $$=new Type; 658 | $$->token="expression"; 659 | $$->children.push_back($1); 660 | }; 661 | 662 | simple_expression: simple_expression ADDOP term{ //正常 663 | $$=new Type; 664 | $$->token="simple_expression"; 665 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 666 | }|simple_expression ADDOP error term %prec ADD{//error,缺少操作数 667 | $$=new Type; 668 | $$->token="simple_expression"; 669 | yyerror("missing operand",@2.last_line, @2.last_column+1); 670 | }|simple_expression '-' term{ //正常 671 | $$=new Type; 672 | $$->token="simple_expression"; 673 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 674 | }|simple_expression '-' error term %prec ADD{//error,缺少操作数 675 | $$=new Type; 676 | $$->token="simple_expression"; 677 | yyerror("missing operand",@2.last_line, @2.last_column+1); 678 | }|term{ //正常 679 | $$=new Type; 680 | $$->token="simple_expression"; 681 | $$->children.push_back($1); 682 | }; 683 | 684 | term: term MULOP factor{ //正常 685 | $$=new Type; 686 | $$->token="term"; 687 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 688 | }|term MULOP error factor %prec MUL{ //error,缺少操作数 689 | $$=new Type; 690 | $$->token="term"; 691 | yyerror("missing operand",@2.last_line, @2.last_column+1); 692 | }|factor{ //正常 693 | $$=new Type; 694 | $$->token="term"; 695 | $$->children.push_back($1); 696 | }; 697 | 698 | factor: UINUM{ //正常 699 | $$=new Type; 700 | $$->token="factor"; 701 | $$->children.push_back($1); 702 | }|UFNUM{ //正常 703 | $$=new Type; 704 | $$->token="factor"; 705 | $$->children.push_back($1); 706 | }|variable{ //正常 707 | $$=new Type; 708 | $$->token="factor"; 709 | $$->children.push_back($1); 710 | }|IDENTIFIER '(' expression_list ')'{ //正常 711 | $$=new Type; 712 | $$->token="factor"; 713 | $$->children.push_back($1);$$->children.push_back($2); 714 | $$->children.push_back($3);$$->children.push_back($4); 715 | }|IDENTIFIER '(' expression_list error{ //ERROR 缺少右括号 这里引发了一个移进规约冲突 716 | $$=new Type; 717 | $$->token="factor"; 718 | yyerror("missing a right bracket here", @3.last_line, @3.last_column+1); 719 | }|IDENTIFIER '(' error{ //ERROR 函数调用的表达式列表缺失 720 | $$=new Type; 721 | $$->token="factor"; 722 | yyerror("missing actual parameter list of function call", @2.last_line, @2.last_column+1); 723 | }|'(' expression ')'{ //正常 724 | $$=new Type; 725 | $$->token="factor"; 726 | $$->children.push_back($1);$$->children.push_back($2);$$->children.push_back($3); 727 | }|'(' expression error{ //ERROR 缺少右括号 728 | $$=new Type; 729 | $$->token="factor"; 730 | yyerror("missing a right bracket here", @2.last_line, @2.last_column+1); 731 | }|NOT factor{ //正常 732 | $$=new Type; 733 | $$->token="factor"; 734 | $$->children.push_back($1);$$->children.push_back($2); 735 | }|'-' factor{ //正常 736 | $$=new Type; 737 | $$->token="factor"; 738 | $$->children.push_back($1);$$->children.push_back($2); 739 | }|CHAR{ //正常 740 | $$=new Type; 741 | $$->token="factor"; 742 | $$->children.push_back($1); 743 | }; 744 | 745 | %% 746 | 747 | 748 | void yyerror(const char *s){ 749 | haveSemanticError = true;//错误标志,含有语法错误 750 | string errorInformation;//定义错误信息 751 | errorInformation += string(s);//添加错误信息 752 | errorInformation += ", location: " + itos(yylineno-1) + "." + itos(yycolumn-yyleng);//添加错误位置 753 | syntaxErrorInformation.push_back(errorInformation);//存放错误信息 754 | } 755 | 756 | void yyerror(const char *s, YYLTYPE *loc){//处理单个字符的错误 757 | haveSemanticError = true; 758 | string errorInformation; 759 | errorInformation = "syntax error, " + string(s) + ", location: " + itos(loc->first_line) + "." + itos(loc->first_column) + "-" + itos(loc->last_line) + "." + itos(loc->last_column); 760 | syntaxErrorInformation.push_back(errorInformation); 761 | } 762 | 763 | void yyerror(const char *s, int line, int col){//处理一行以内的错误 764 | haveSemanticError = true; 765 | string errorInformation; 766 | errorInformation = "syntax error, " + string(s) + ", location: " + itos(line) + "." + itos(col); 767 | syntaxErrorInformation.push_back(errorInformation); 768 | } 769 | 770 | void yyerror(const char *s, int startLine, int startCol, int endLine, int endCol){//处理涉及多行的错误 771 | haveSemanticError = true; 772 | string errorInformation; 773 | errorInformation = "syntax error, " + string(s) + ", location: " + itos(startLine) + "." + itos(startCol) + "-" + itos(endLine) + "." + itos(endCol); 774 | syntaxErrorInformation.push_back(errorInformation); 775 | } 776 | -------------------------------------------------------------------------------- /lex-yacc-src/添加了错误个数控制的版本,与vs工程关联,所以无法单独正确运行/lex.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "main.h" 3 | #include "yacc.tab.h" 4 | //处理位置信息 5 | int yycolumn = 1; 6 | extern YYLTYPE yylloc; 7 | #define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno - 1; \ 8 | yylloc.first_column = yycolumn; yylloc.last_column = yycolumn+yyleng-1; \ 9 | yycolumn += yyleng; 10 | 11 | extern string itos(int num); 12 | 13 | string charRec; //保存字符常量 14 | char lineBuffer[10005]; //保存当前行的所有内容 15 | vector lexicalErrorInformation; 16 | void addLexicalErrorInformation(char *word, string info, int l, int r); 17 | bool CheckAndAddLengthTooLargeErrorInformation(char *text, string type, int l, int r); 18 | 19 | //函数声明 20 | extern "C" 21 | { 22 | int yywrap(); 23 | int yylex(); 24 | } 25 | %} 26 | 27 | %option yylineno 28 | 29 | %x SCOM 30 | %X MCOM 31 | %x CH 32 | 33 | line \n.* 34 | letter [a-z] 35 | digit [0-9] 36 | blank_chars [ \f\r\t\v]+ 37 | identifier {letter}({letter}|{digit})* 38 | _integer {digit}+ 39 | floater {digit}+\.{digit}+ 40 | _type (integer|real|boolean|char) 41 | relop (>=|>|<=|<>|<) 42 | addop (\+|or) 43 | mulop (\*|\/|div|mod|and) 44 | delimiter (\(|\)|\[|\]|:|,|;|\.) 45 | 46 | %% 47 | {blank_chars} {} 48 | 49 | {line} { 50 | if(CheckAndAddLengthTooLargeErrorInformation(yytext, "line", 1, yyleng)) 51 | return 0; 52 | strcpy(lineBuffer,yytext+1); 53 | yycolumn=1; 54 | yyless(1); //yyleng是当前匹配的单词的长度,yyless(n)表示退回yyleng-n个字符,只保留n个字符 55 | } 56 | 57 | "program" { 58 | yylval=new Type; 59 | yylval->str=yytext; 60 | yylval->token="PROGRAM"; 61 | yylval->lineNumber = yylineno - 1; 62 | #ifdef LEXDEBUG 63 | cout << "keyword: " << yylval->str << endl; 64 | #endif 65 | return PROGRAM; 66 | } 67 | 68 | "const" { 69 | yylval=new Type; 70 | yylval->str=yytext; 71 | yylval->token="CONST"; 72 | yylval->lineNumber = yylineno - 1; 73 | #ifdef LEXDEBUG 74 | cout << "keyword: " << yylval->str << endl; 75 | #endif 76 | return CONST; 77 | } 78 | 79 | "var" { 80 | yylval=new Type; 81 | yylval->str=yytext; 82 | yylval->token="VAR"; 83 | yylval->lineNumber = yylineno - 1; 84 | #ifdef LEXDEBUG 85 | cout << "keyword: " << yylval->str << endl; 86 | #endif 87 | return VAR; 88 | } 89 | 90 | "array" { 91 | yylval=new Type; 92 | yylval->str=yytext; 93 | yylval->token="ARRAY"; 94 | yylval->lineNumber = yylineno - 1; 95 | #ifdef LEXDEBUG 96 | cout << "keyword: " << yylval->str << endl; 97 | #endif 98 | return ARRAY; 99 | } 100 | 101 | "of" { 102 | yylval=new Type; 103 | yylval->str=yytext; 104 | yylval->token="OF"; 105 | yylval->lineNumber = yylineno - 1; 106 | #ifdef LEXDEBUG 107 | cout << "keyword: " << yylval->str << endl; 108 | #endif 109 | return OF; 110 | } 111 | 112 | "procedure" { 113 | yylval=new Type; 114 | yylval->str=yytext; 115 | yylval->token="PROCEDURE"; 116 | yylval->lineNumber = yylineno - 1; 117 | #ifdef LEXDEBUG 118 | cout << "keyword: " << yylval->str << endl; 119 | #endif 120 | return PROCEDURE; 121 | } 122 | 123 | "function" { 124 | yylval=new Type; 125 | yylval->str=yytext; 126 | yylval->token="FUNCTION"; 127 | yylval->lineNumber = yylineno - 1; 128 | #ifdef LEXDEBUG 129 | cout << "keyword: " << yylval->str << endl; 130 | #endif 131 | return FUNCTION; 132 | } 133 | 134 | "begin" { 135 | yylval=new Type; 136 | yylval->str=yytext; 137 | yylval->token="BEGIN"; 138 | yylval->lineNumber = yylineno - 1; 139 | #ifdef LEXDEBUG 140 | cout << "keyword: " << yylval->str << endl; 141 | #endif 142 | return _BEGIN; 143 | } 144 | 145 | "end" { 146 | yylval=new Type; 147 | yylval->str=yytext; 148 | yylval->token="END"; 149 | yylval->lineNumber = yylineno - 1; 150 | #ifdef LEXDEBUG 151 | cout << "keyword: " << yylval->str << endl; 152 | #endif 153 | return END; 154 | } 155 | 156 | "if" { 157 | yylval=new Type; 158 | yylval->str=yytext; 159 | yylval->token="IF"; 160 | yylval->lineNumber = yylineno - 1; 161 | #ifdef LEXDEBUG 162 | cout << "keyword: " << yylval->str << endl; 163 | #endif 164 | return IF; 165 | } 166 | 167 | "then" { 168 | yylval=new Type; 169 | yylval->str=yytext; 170 | yylval->token="THEN"; 171 | yylval->lineNumber = yylineno - 1; 172 | #ifdef LEXDEBUG 173 | cout << "keyword: " << yylval->str << endl; 174 | #endif 175 | return THEN; 176 | } 177 | 178 | "for" { 179 | yylval=new Type; 180 | yylval->str=yytext; 181 | yylval->token="FOR"; 182 | yylval->lineNumber = yylineno - 1; 183 | #ifdef LEXDEBUG 184 | cout << "keyword: " << yylval->str << endl; 185 | #endif 186 | return FOR; 187 | } 188 | 189 | "to" { 190 | yylval=new Type; 191 | yylval->str=yytext; 192 | yylval->token="TO"; 193 | yylval->lineNumber = yylineno - 1; 194 | #ifdef LEXDEBUG 195 | cout << "keyword: " << yylval->str << endl; 196 | #endif 197 | return TO; 198 | } 199 | 200 | "do" { 201 | yylval=new Type; 202 | yylval->str=yytext; 203 | yylval->token="DO"; 204 | yylval->lineNumber = yylineno - 1; 205 | #ifdef LEXDEBUG 206 | cout << "keyword: " << yylval->str << endl; 207 | #endif 208 | return DO; 209 | } 210 | 211 | "else" { 212 | yylval=new Type; 213 | yylval->str=yytext; 214 | yylval->token="ELSE"; 215 | yylval->lineNumber = yylineno - 1; 216 | #ifdef LEXDEBUG 217 | cout << "keyword: " << yylval->str << endl; 218 | #endif 219 | return ELSE; 220 | } 221 | 222 | "repeat" { 223 | yylval=new Type; 224 | yylval->str=yytext; 225 | yylval->token="REPEAT"; 226 | yylval->lineNumber = yylineno - 1; 227 | #ifdef LEXDEBUG 228 | cout << "keyword: " << yylval->str << endl; 229 | #endif 230 | return REPEAT; 231 | } 232 | 233 | "until" { 234 | yylval=new Type; 235 | yylval->str=yytext; 236 | yylval->token="UNTIL"; 237 | yylval->lineNumber = yylineno - 1; 238 | #ifdef LEXDEBUG 239 | cout << "keyword: " << yylval->str << endl; 240 | #endif 241 | return UNTIL; 242 | } 243 | 244 | "while" { 245 | yylval=new Type; 246 | yylval->str=yytext; 247 | yylval->token="WHILE"; 248 | yylval->lineNumber = yylineno - 1; 249 | #ifdef LEXDEBUG 250 | cout << "keyword: " << yylval->str << endl; 251 | #endif 252 | return WHILE; 253 | } 254 | 255 | {_type} { 256 | yylval=new Type; 257 | yylval->str=yytext; 258 | yylval->token = "TYPE"; 259 | yylval->lineNumber = yylineno - 1; 260 | #ifdef LEXDEBUG 261 | cout << "type: " << yylval->str << endl; 262 | #endif 263 | return TYPE; 264 | } 265 | 266 | "not" { 267 | yylval=new Type; 268 | yylval->str=yytext; 269 | yylval->token="NOT"; 270 | yylval->lineNumber = yylineno - 1; 271 | #ifdef LEXDEBUG 272 | cout << "NOT: " << yylval->str << endl; 273 | #endif 274 | return NOT; 275 | } 276 | 277 | {relop} { 278 | yylval=new Type; 279 | yylval->str=yytext; 280 | yylval->token="RELOP"; 281 | yylval->lineNumber = yylineno - 1; 282 | #ifdef LEXDEBUG 283 | cout << "RELOP: " << yylval->str << endl; 284 | #endif 285 | return RELOP; 286 | } 287 | 288 | {addop} { 289 | yylval=new Type; 290 | yylval->str=yytext; 291 | yylval->token="ADDOP"; 292 | yylval->lineNumber = yylineno - 1; 293 | #ifdef LEXDEBUG 294 | cout << "ADDOP: " << yylval->str << endl; 295 | #endif 296 | return ADDOP; 297 | } 298 | 299 | {mulop} { 300 | yylval=new Type; 301 | yylval->str=yytext; 302 | yylval->token="MULOP"; 303 | yylval->lineNumber = yylineno - 1; 304 | #ifdef LEXDEBUG 305 | cout << "MULOP: " << yylval->str << endl; 306 | #endif 307 | return MULOP; 308 | } 309 | 310 | "-" { 311 | yylval=new Type; 312 | yylval->str=yytext; 313 | yylval->token = yytext; 314 | yylval->lineNumber = yylineno - 1; 315 | #ifdef LEXDEBUG 316 | cout << "UMINUS OR SUB: " << yylval->str << endl; 317 | #endif 318 | return yytext[0]; 319 | } 320 | 321 | "=" { 322 | yylval=new Type; 323 | yylval->str=yytext; 324 | yylval->token = yytext; 325 | yylval->lineNumber = yylineno - 1; 326 | #ifdef LEXDEBUG 327 | cout << "EQUAL: " << yylval->str << endl; 328 | #endif 329 | return yytext[0]; 330 | } 331 | 332 | {identifier} { 333 | if(CheckAndAddLengthTooLargeErrorInformation(yytext, "identifier", yycolumn-yyleng, yycolumn-1)){ 334 | yytext[100]=0; //截断处理 335 | //yycolumn=yycolumn-yyleng; 336 | //yylloc.first_column=yycolumn; 337 | //yylloc.last_column=yycolumn+100-1; 338 | //yycolumn+=100; 339 | yyleng=100; 340 | } 341 | yylval=new Type; 342 | yylval->str=yytext; 343 | yylval->token = "IDENTIFIER"; 344 | yylval->lineNumber = yylineno - 1; 345 | #ifdef LEXDEBUG 346 | cout << "identifier: " << yylval->str << endl; 347 | #endif 348 | return IDENTIFIER; 349 | } 350 | 351 | {floater} { 352 | yylval=new Type; 353 | yylval->str=yytext; 354 | yylval->token="UFNUM"; 355 | yylval->lineNumber = yylineno - 1; 356 | #ifdef LEXDEBUG 357 | cout << "floater:" << yylval->str << endl; 358 | #endif 359 | return UFNUM; 360 | } 361 | 362 | {_integer} { 363 | yylval=new Type; 364 | yylval->str=yytext; 365 | yylval->token="UINUM"; 366 | yylval->lineNumber = yylineno - 1; 367 | #ifdef LEXDEBUG 368 | cout << "integer:" << yylval->str << endl; 369 | #endif 370 | return UINUM; 371 | } 372 | 373 | ":=" { 374 | yylval=new Type; 375 | yylval->str=yytext; 376 | yylval->token="ASSIGNOP"; 377 | yylval->lineNumber = yylineno - 1; 378 | #ifdef LEXDEBUG 379 | cout << "ASSIGNOP: " << yylval->str << endl; 380 | #endif 381 | return ASSIGNOP; 382 | } 383 | 384 | "\.\." { 385 | yylval=new Type; 386 | yylval->str=yytext; 387 | yylval->token="RANGEDOT"; 388 | yylval->lineNumber = yylineno - 1; 389 | #ifdef LEXDEBUG 390 | cout << "RANGEDOT: " << yylval->str << endl; 391 | #endif 392 | return RANGEDOT; 393 | } 394 | 395 | {delimiter} { 396 | yylval=new Type; 397 | yylval->str = yytext; 398 | yylval->token = yytext; 399 | yylval->lineNumber = yylineno - 1; 400 | #ifdef LEXDEBUG 401 | cout << "delimiter: " << yylval->str << endl; 402 | #endif 403 | return yytext[0]; 404 | } 405 | 406 | "'" {//进入字符常量识别 407 | BEGIN CH; 408 | charRec=""; 409 | } 410 | 411 | "\/\/" {//进入单行注释 412 | BEGIN SCOM; 413 | } 414 | 415 | "\{" {//进入多行注释 416 | BEGIN MCOM; 417 | } 418 | 419 | . {//非法字符 错误3 420 | addLexicalErrorInformation(yytext, "Invalid character!", yycolumn-yyleng, yycolumn-1); 421 | //cout << "error: invalid char" << endl; 422 | } 423 | 424 | <> { //读取字符常量时遇到文件尾 错误4 425 | addLexicalErrorInformation(yytext, "Unexpected end of file when reading a char constant", yycolumn-yyleng, yycolumn-1); 426 | return 0; 427 | } 428 | 429 | ("'"|"\n") {//字符常量限定在一行中 430 | int len=charRec.length(); 431 | if(yytext[0]=='\'' && len==0){ 432 | addLexicalErrorInformation(yytext, "Char constant missing!", yycolumn-yyleng-1, yycolumn-1); //错误5 433 | //cout << "error: missing char" << endl; 434 | BEGIN INITIAL; 435 | yylval = new Type; 436 | yylval->str="\0"; 437 | yylval->token="CHAR"; 438 | yylval->lineNumber=yylineno - 1; 439 | #ifdef LEXDEBUG 440 | cout << "char: " << yylval->str << endl; 441 | #endif 442 | return CHAR; 443 | } 444 | else if(yytext[0]=='\'' && len==1){ 445 | yylval=new Type; 446 | yylval->str=charRec[0];//PASCAL似乎不支持转义字符 447 | yylval->token="CHAR"; 448 | yylval->lineNumber=yylineno - 1; 449 | #ifdef LEXDEBUG 450 | cout << "char: " << yylval->str << endl; 451 | #endif 452 | BEGIN INITIAL; 453 | return CHAR; 454 | } 455 | else if(yytext[0]=='\''){ 456 | addLexicalErrorInformation(yytext, "Too many characters in a char constant!", yycolumn-yyleng-len, yycolumn-yyleng-1); //错误6 457 | //cout << "error: too many char" << endl; 458 | yylval = new Type; 459 | yylval->str=charRec[0]; 460 | yylval->token="CHAR"; 461 | yylval->lineNumber=yylineno - 1; 462 | #ifdef LEXDEBUG 463 | cout << "char: " << yylval->str << endl; 464 | #endif 465 | BEGIN INITIAL; 466 | return CHAR; 467 | } 468 | else{ 469 | addLexicalErrorInformation(yytext, "Right quote missing!", yycolumn-yyleng-len+1, yycolumn-yyleng-len+1); //错误7 470 | yyless(0);//将换行符退回 471 | yylineno--;//行号减一 472 | //cout << "quote miss match" << endl; 473 | yylval = new Type; 474 | if(len==0) 475 | yylval->str="\0"; 476 | else 477 | yylval->str=charRec[0]; 478 | yylval->token="CHAR"; 479 | yylval->lineNumber=yylineno - 1; 480 | #ifdef LEXDEBUG 481 | cout << "char: " << yylval->str << endl; 482 | #endif 483 | BEGIN INITIAL; 484 | return CHAR; 485 | } 486 | } 487 | 488 | . { 489 | charRec+=yytext[0]; 490 | } 491 | 492 | <> { //单行注释遇到文件尾 493 | return 0; 494 | } 495 | 496 | "\n" { 497 | BEGIN INITIAL; 498 | yyless(0);//将换行符退回 499 | yylineno--;//行号减一 500 | } 501 | 502 | . {} 503 | 504 | <> { //多行注释遇到文件尾 错误8 505 | addLexicalErrorInformation(yytext, "Unexpected end of file when reading a multiple line comment, lacking of a right brace", yycolumn-yyleng, yycolumn-1); 506 | return 0; 507 | } 508 | 509 | {line} { 510 | if(CheckAndAddLengthTooLargeErrorInformation(yytext, "line", 1, yyleng)) //行长度超过限制 511 | return 0; 512 | yycolumn=1; 513 | strcpy(lineBuffer, yytext+1); 514 | yyless(1); 515 | } 516 | 517 | "\}" { 518 | BEGIN INITIAL; 519 | } 520 | 521 | . {} 522 | 523 | %% 524 | 525 | //这个函数是必须的,不用动 526 | int yywrap() 527 | { 528 | return 1; 529 | } 530 | 531 | void addLexicalErrorInformation(char *word, string info, int l, int r){ 532 | string errorInformation = "[" + info + "] " + itos(yylineno-1) + "." + itos(l) + "-" + itos(yylineno-1) + "." + itos(r) + "\n"; 533 | errorInformation += string(lineBuffer) + "\n"; 534 | for(int i=1;i<=l-1;i++) 535 | errorInformation+=" "; 536 | for(int i=l;i<=r;i++) 537 | errorInformation+="^"; 538 | //cout << errorInformation << endl; 539 | lexicalErrorInformation.push_back(errorInformation); 540 | CHECK_ERROR_BOUND 541 | } 542 | 543 | bool CheckAndAddLengthTooLargeErrorInformation(char *text, string type, int l, int r){ 544 | string errorInformation; 545 | int len=strlen(text); 546 | if(type=="line"){ 547 | if(len>10000){ //错误1 548 | errorInformation = "[Line length too large, exceed 10000] " + itos(yylineno-1) + "." + itos(l) + "-" + itos(yylineno-1) + "." +itos(r); 549 | errorInformation += "\nLex analyse abort!"; 550 | //cout << errorInformation << endl; 551 | lexicalErrorInformation.push_back(errorInformation); 552 | return true; 553 | CHECK_ERROR_BOUND 554 | } 555 | return false; 556 | } 557 | else if(type=="identifier"){ 558 | if(len>100){ //错误2 559 | string id = string(text); 560 | errorInformation = "[Identifier length too large, exceed 100] " + itos(yylineno-1) + "." + itos(l) + "-" + itos(yylineno-1) + "." + itos(r); 561 | //cout << errorInformation << endl; 562 | lexicalErrorInformation.push_back(errorInformation); 563 | return true; 564 | CHECK_ERROR_BOUND 565 | } 566 | return false; 567 | } 568 | else{ 569 | cout << "[CheckAndAddLengthTooLargeErrorInformation] type not found" << endl; 570 | return false; 571 | } 572 | } -------------------------------------------------------------------------------- /lex-yacc-src/添加了错误个数控制的版本,与vs工程关联,所以无法单独正确运行/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include 3 | #include 4 | 5 | extern Type* ParseTreeHead; 6 | extern FILE* yyin; 7 | extern vector syntaxErrorInformation; 8 | 9 | extern "C"{ 10 | int yyparse(); 11 | } 12 | 13 | string process(string str); 14 | void dfs(Type* now); 15 | bool outputSyntaxErrorInformation(); 16 | 17 | int main() 18 | { 19 | 20 | #ifdef _WIN32 21 | string inName="PascalProgram.pas"; 22 | string outName="preProcessed.pas"; 23 | #elif __APPLE__ 24 | string inName="/Users/mac/yacc_and_lex_repository/lex_and_yacc/PascalProgram.pas"; 25 | string outName="/Users/mac/yacc_and_lex_repository/lex_and_yacc/preProcessed.pas"; 26 | #endif 27 | 28 | ifstream fin(inName.c_str()); 29 | ofstream fout(outName.c_str()); 30 | string str; 31 | while (getline(fin,str)) 32 | fout << endl << process(str); 33 | fin.close(); 34 | fout.close(); 35 | 36 | yydebug=1; 37 | 38 | #ifdef _WIN32 39 | const char* sFile = "preProcessed.pas"; 40 | #elif __APPLE__ 41 | const char *sFile = "/Users/mac/yacc_and_lex_repository/lex_and_yacc/preProcessed.pas"; 42 | #endif 43 | FILE* fp = fopen(sFile,"r"); 44 | if(fp==NULL){ 45 | printf("cannot open %s\n",sFile); 46 | return -1; 47 | } 48 | yyin=fp; 49 | 50 | printf("-----begin parsing %s\n",sFile); 51 | yyparse(); 52 | printf("-----end parsing\n"); 53 | if(ParseTreeHead!=NULL) 54 | //dfs(ParseTreeHead); 55 | 56 | fclose(fp); 57 | 58 | outputSyntaxErrorInformation(); 59 | 60 | return 0; 61 | } 62 | 63 | string process(string str) {//由于PASCAL大小写不敏感,所以需要将所有字母转化为小写 64 | for (int i = 0; i= 'A'&&str[i] <= 'Z') 66 | str[i] = str[i] + ('a' - 'A'); 67 | } 68 | return str; 69 | } 70 | 71 | void dfs(Type* now){ 72 | if(now->children.size()==0){ 73 | if(now->str=="") 74 | cout << now->token << "\t->\t" << "empty" << endl; 75 | return; 76 | } 77 | cout << now->token << "\t->"; 78 | for (int i = 0; i < now->children.size(); i++) { 79 | if (now->children[i]->children.size()==0 && now->children[i]->str != "") 80 | cout << "\t\"" << now->children[i]->str << "\""; 81 | else 82 | cout << "\t" << now->children[i]->token; 83 | } 84 | cout << endl; 85 | for(int i=0;ichildren.size();i++) 86 | dfs(now->children[i]); 87 | } 88 | 89 | string itos(int num){ 90 | stringstream sin; 91 | sin<=errorBound){\ 12 | cout << "There have been more than " << errorBound << " errors, compiler abort." << endl;\ 13 | outputErrors();\ 14 | exit(0);\ 15 | } 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | extern int yydebug; 25 | using namespace std; 26 | 27 | //重新定义属性类型(yylval实际上应由yacc定义)c 28 | class Type{ 29 | public: 30 | string str;//终结符号的具体属性 31 | string token;//终结符号或非终结符号本身的名称 32 | int lineNumber;//终结符号的行号,参照语法分析指导.docx 33 | vector children; //对应产生式下面的结点 34 | 35 | Type(){} 36 | Type(string typ, string name, int ln): str(typ), token(name), lineNumber(ln){} 37 | Type(string name, vector cdn): token(name), children(cdn){} 38 | }; 39 | #define YYSTYPE Type* 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/ASTnodes.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/src/ASTnodes.cpp -------------------------------------------------------------------------------- /src/ASTnodes.h: -------------------------------------------------------------------------------- 1 | /* 2 | 抽象语法树各节点类的定义 3 | */ 4 | 5 | #ifndef ASTNODES_H 6 | #define ASTNODES_H 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | class _Expression; 13 | class _FunctionCall; 14 | class _VariantReference; 15 | class _Statement; 16 | class _Compound; 17 | class _RepeatStatement; 18 | class _WhileStatement; 19 | class _ForStatement; 20 | class _IfStatement; 21 | class _AssignStatement; 22 | class _ProcedureCall; 23 | class _Type; 24 | class _FormalParameter; 25 | class _FunctionDefinition; 26 | class _Variant; 27 | class _Constant; 28 | class _SubProgram; 29 | class _Program; 30 | 31 | class _Expression 32 | { 33 | public: 34 | string type;//表达式类型,"var"表示变量,"integer"表示整数,"real"表示浮点数,"char"表示常量字符 35 | //"function"表示函数调用,"compound"表示复合表达式, 36 | //compound有普通的二目运算符,还有"minus"、"not"、"bracket"等单目运算符 37 | 38 | _VariantReference* variantReference;//变量或常量或数组 39 | 40 | int intNum;//整数 41 | 42 | float realNum;//浮点数 43 | 44 | string strOfNum;//整数和浮点数的string表示(考虑从PASCAL-S源程序将字符串转为浮点数,再将浮点数转为字符串会带来精度问题,所以需要存下初始字符串值) 45 | 46 | char charVal;//常量字符 47 | 48 | _FunctionCall *functionCall;//函数调用 49 | 50 | string operation;//具体操作符 51 | string operationType;//操作符类型,"relop","mulop","addop","single" 52 | _Expression *operand1,*operand2; 53 | 54 | int lineNumber;//行号, 用表达式中最先出现的操作数的行号表示 55 | public: 56 | _Expression(); 57 | ~_Expression(); 58 | //语义分析相关 59 | public: 60 | int totalIntValue; 61 | bool totalIntValueValid; 62 | string expressionType;//区别于type,这个值表示表达式的具体类型,即"integer"、"real"、"char"、"boolean"、"error",其中error表示表达式中包含类型不一致的操作数 63 | }; 64 | 65 | class _FunctionCall 66 | { 67 | public: 68 | pair functionId;//函数标识符 69 | vector<_Expression*> actualParaList;//实际参数列表,由表达式组成 70 | public: 71 | _FunctionCall(); 72 | ~_FunctionCall(); 73 | public: 74 | string returnType;//"integer"、"real"、"char"、"boolean"、"error",其中error表示函数标识符不存在 75 | }; 76 | 77 | class _VariantReference 78 | { 79 | public: 80 | pair variantId;//变量或常量标识符和行号 81 | int flag;//0表示非数组,1表示数组 82 | vector<_Expression*> expressionList;//各维引用表达式列表 83 | public: 84 | _VariantReference(); 85 | ~_VariantReference(); 86 | public: 87 | int locFlag;//-1表示左值,1表示右值,0表示什么都不是 左值特判 88 | string kind;//"array","var","constant","function call","function return reference" 89 | string variantType;//"integer"、"real"、"char"、"boolean"、"error",其中"error"表示数组某一维下标表达式的类型不为"integer"或标识符不存在 90 | }; 91 | 92 | class _Statement 93 | { 94 | public: 95 | string type;//"compound","repeat","while","for","if","assign","procedure" 96 | string statementType;//区别于type,取值为"void"或"error" 97 | int lineNumber;//行号 98 | bool isReturnStatement;//是否是返回值语句 99 | public: 100 | _Statement(){} 101 | ~_Statement(){} 102 | }; 103 | 104 | class _Compound:public _Statement 105 | { 106 | public: 107 | vector<_Statement*> statementList;//语句列表 108 | //行号由begin的位置决定 109 | public: 110 | _Compound(); 111 | ~_Compound(); 112 | }; 113 | 114 | class _RepeatStatement:public _Statement 115 | { 116 | public: 117 | _Expression *condition;//条件表达式 118 | _Statement *_do;//循环体语句 119 | //行号由repeat的位置决定 120 | public: 121 | _RepeatStatement(); 122 | ~_RepeatStatement(); 123 | }; 124 | 125 | class _WhileStatement:public _Statement 126 | { 127 | public: 128 | _Expression *condition;//条件表达式 129 | _Statement *_do;//循环体语句 130 | //行号由while的位置决定 131 | public: 132 | _WhileStatement(); 133 | ~_WhileStatement(); 134 | }; 135 | 136 | class _ForStatement:public _Statement 137 | { 138 | public: 139 | pair id;//循环变量 140 | _Expression *start;//起始值 141 | _Expression *end;//终止值 142 | _Statement *_do;//循环体语句 143 | //行号由for的位置决定 144 | public: 145 | _ForStatement(); 146 | ~_ForStatement(); 147 | }; 148 | 149 | class _IfStatement:public _Statement 150 | { 151 | public: 152 | _Expression *condition;//条件表达式 153 | _Statement *then;//满足条件时执行的语句 154 | _Statement *els;//不满足条件时执行的语句,如果为NULL,则没有else部分 155 | //行号由if的位置决定 156 | public: 157 | _IfStatement(); 158 | ~_IfStatement(); 159 | }; 160 | 161 | class _AssignStatement:public _Statement 162 | { 163 | public: 164 | _VariantReference* variantReference;//左值变量 165 | _Expression* expression;//右值表达式 166 | //行号由赋值符号的位置决定 167 | public: 168 | _AssignStatement(); 169 | ~_AssignStatement(); 170 | }; 171 | 172 | class _ProcedureCall:public _Statement 173 | { 174 | public: 175 | pair procedureId;//过程标识符 176 | vector<_Expression*> actualParaList;//实际参数列表,由表达式组成 177 | //行号由procedure名的位置决定 178 | public: 179 | _ProcedureCall(); 180 | ~_ProcedureCall(); 181 | }; 182 | 183 | class _Type//类型 184 | { 185 | public: 186 | pair type;//基本类型及行号 "integer"、"char"、"real"、"boolean" 187 | int flag;//0表示非数组,1表示数组 188 | vector< pair > arrayRangeList;//flag=1时,表示数组各维上下界 189 | public: 190 | _Type(); 191 | _Type(pair _type,int _flag,vector< pair > _arrayRangeList); 192 | ~_Type(){} 193 | }; 194 | 195 | class _FormalParameter//形式参数 196 | { 197 | public: 198 | pair paraId;//形式参数标识符和行号 199 | string type;//形式参数类型,形式参数一定是基本类型,所以改为string 200 | int flag;//flag=0表示传值调用,flag=1表示引用调用 201 | public: 202 | _FormalParameter(); 203 | _FormalParameter(pair _paraId,string _type,int _flag); 204 | ~_FormalParameter(){} 205 | }; 206 | 207 | class _FunctionDefinition 208 | {//函数/过程定义 209 | public: 210 | pair functionID;//函数/过程标识符及行号 211 | vector<_FormalParameter*> formalParaList;//形式参数列表 212 | pair type;//如果type.first是空串,则为过程,否则为函数,取值为"integer","real","boolean","char"四种 213 | vector<_Constant*> constList;//常数定义列表 214 | vector<_Variant*> variantList;//变量定义列表 215 | _Compound* compound; 216 | public: 217 | _FunctionDefinition(); 218 | ~_FunctionDefinition(); 219 | }; 220 | 221 | class _Variant//变量定义 222 | { 223 | public: 224 | pair variantId;//变量标识符ID及行号 225 | _Type *type;//变量类型 226 | public: 227 | _Variant(); 228 | _Variant(pair _variantId,_Type *_type); 229 | ~_Variant(); 230 | }; 231 | 232 | class _Constant//常量定义 233 | {//常量定义的时候,右值可以是已经定义好的常量标识符 234 | //在代码生成的时候,可以根据常量的范围对类型进行进一步的细化 235 | public: 236 | pair constId; 237 | string type;//常数类型,分为"id","integer","real","char" 238 | 239 | pair valueId; 240 | char charValue; 241 | int intValue; 242 | float realValue; 243 | 244 | string strOfVal;//所有常量取值的字符串表示 245 | bool isMinusShow; 246 | public: 247 | _Constant(){} 248 | ~_Constant(){} 249 | }; 250 | 251 | class _SubProgram//分程序 252 | { 253 | public: 254 | vector<_Constant*> constList;//常数定义列表 255 | vector<_Variant*> variantList;//变量定义列表 256 | vector<_FunctionDefinition*> subprogramDefinitionList;//子程序和子函数定义列表 257 | _Compound *compound;//主程序体 258 | public: 259 | _SubProgram(); 260 | ~_SubProgram(); 261 | }; 262 | 263 | class _Program//程序 264 | { 265 | public: 266 | pair programId;//PASCAL程序名称标识符及行号 267 | vector< pair > paraList;//PASCAL程序参数列表及行号 268 | _SubProgram* subProgram;//分程序 269 | public: 270 | _Program(); 271 | ~_Program(); 272 | }; 273 | 274 | #endif // !ASTNODES_H 275 | 276 | 277 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | project(pascal2c) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | include_directories(./) 7 | aux_source_directory(. DIR_SRCS) 8 | add_executable(pascal2c ${DIR_SRCS}) 9 | 10 | 11 | set(CMAKE_INSTALL_PREFIX ./out) 12 | install(TARGETS pascal2c 13 | RUNTIME DESTINATION bin) 14 | install(FILES PascalProgram.pas DESTINATION bin) 15 | -------------------------------------------------------------------------------- /src/FunctionReturnExistedCheck.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/src/FunctionReturnExistedCheck.cpp -------------------------------------------------------------------------------- /src/PascalProgram.pas: -------------------------------------------------------------------------------- 1 | program quicksort(input,output); 2 | var 3 | n,i:integer; 4 | a:array[0..100000] of integer; 5 | 6 | procedure kp(l,r:integer); 7 | var 8 | i,j,mid:integer; 9 | begin 10 | if l>=r then exit; 11 | i:=l;j:=r;mid:=a[(l+r) div 2]; 12 | repeat 13 | begin 14 | while a[i]mid do j:=j-1; 16 | if i<=j then 17 | begin 18 | a[0]:=a[i];a[i]:=a[j];a[j]:=a[0]; 19 | i:=i+1;j:=j-1; 20 | end 21 | end 22 | until i>j; 23 | kp(l,j); 24 | kp(i,r) 25 | end; 26 | 27 | begin 28 | read(n); 29 | for i:=1 to n do 30 | read(a[i]); 31 | kp(1,n); 32 | for i:=1 to n do 33 | write(a[i],' '); 34 | end. -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/src/main.cpp -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | /* 2 | 主头文件 3 | */ 4 | #ifndef MAIN_H 5 | #define MAIN_H 6 | #define YYERROR_VERBOSE 7 | #define YYDEBUG 1 8 | //#define LEXDEBUG 词法分析DEBUG开关 9 | extern void outputErrors(); 10 | extern int errorCount; 11 | extern int errorBound; 12 | 13 | #define CHECK_ERROR_BOUND errorCount++;\ 14 | if(errorCount>=errorBound){\ 15 | cout << "There have been more than " << errorBound << " errors, compiler abort." << endl;\ 16 | outputErrors();\ 17 | exit(0);\ 18 | } 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | using namespace std; 28 | 29 | //重新定义属性类型(yylval实际上应由yacc定义)c 30 | class Type{ 31 | public: 32 | string str;//终结符号的具体属性 33 | string token;//终结符号或非终结符号本身的名称 34 | int lineNumber;//终结符号的行号,参照语法分析指导.docx 35 | vector children; //对应产生式下面的结点 36 | 37 | Type(){} 38 | Type(string typ, string name, int ln): str(typ), token(name), lineNumber(ln){} 39 | Type(string name, vector cdn): token(name), children(cdn){} 40 | }; 41 | #define YYSTYPE Type* 42 | 43 | #endif //!MAIN_H -------------------------------------------------------------------------------- /src/parseTree2AST.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 普通语法分析树到抽象语法树的转换 3 | */ 4 | #include "main.h" 5 | #include "ASTnodes.h" 6 | #include 7 | 8 | int str2int(string str); 9 | float str2float(string str); 10 | void getIdList(Type *now, vector< pair >& res,bool reverseFlag); 11 | void getArrayRangeList(Type *now, vector< pair >& _arrayRangeList); 12 | _Type* getType(Type *now); 13 | void getVariant(Type *now, vector<_Variant*>& _variantList); 14 | void getVariantList(Type *now, vector<_Variant*>& _variantList); 15 | void setConst(Type *now, _Constant* &_constant); 16 | void getConst(Type *now, vector<_Constant*>& _constantList); 17 | void getConstList(Type *now, vector<_Constant*>& _constantList); 18 | void getValueParameter(Type *now, vector<_FormalParameter*>& _formalParaList, int flag = 0); 19 | void getParameter(Type *now, vector<_FormalParameter*>& _formalParaList); 20 | void getFormalParameter(Type *now, vector<_FormalParameter*>& _formalParaList); 21 | void getFormalParaList(Type *now, vector<_FormalParameter*>& _formalParaList); 22 | void getSubprogramHead(Type *now, pair& functionID, vector<_FormalParameter*>& _formalParaList, pair &_type); 23 | _Expression* getFactor(Type *now); 24 | _Expression* getTerm(Type *now); 25 | _Expression* getSimpleExpression(Type *now); 26 | _Expression* getExpression(Type *now); 27 | void getExpressionList(Type *now, vector<_Expression*>& _expressionList); 28 | void getVariantReferenceList(Type *now, vector<_Expression*>& _expressionList); 29 | _VariantReference* getVariantReference(Type *now); 30 | _Statement* getElseStatement(Type *now); 31 | _Statement* getProcedureCall(Type *now); 32 | _Statement* getStatement(Type *now); 33 | void getStatementList(Type *now, vector<_Statement*>& _statementList); 34 | _Compound* getCompoundStatement(Type *now); 35 | void getSubprogramBody(Type *now, vector<_Constant*>& _constList, vector<_Variant*>& _variantList, _Compound* &_compound); 36 | _FunctionDefinition* getSubprogramDefinition(Type *now); 37 | void getSubprogramDefinitionList(Type *now, vector<_FunctionDefinition*>& _subprogramDefinitionList); 38 | _SubProgram* getProgramBody(Type *now); 39 | void getProgramHead(Type *now, pair& _programId, vector< pair >& _paraList); 40 | _Program* getProgram(Type *now); 41 | 42 | int str2int(string str){ 43 | int res=0; 44 | int len=int(str.length()); 45 | for(int i=0;i >& res,bool reverseFlag){ 69 | if(now->token!="idlist"){ 70 | cout << "getIdList error" << endl; 71 | return; 72 | } 73 | if(now->children[0]->str==""){ 74 | res.push_back(make_pair(now->children[2]->str,now->children[2]->lineNumber)); 75 | getIdList(now->children[0],res,reverseFlag); 76 | } 77 | else{ 78 | res.push_back(make_pair(now->children[0]->str,now->children[0]->lineNumber)); 79 | if(reverseFlag) 80 | reverse(res.begin(),res.end()); 81 | } 82 | } 83 | 84 | void getArrayRangeList(Type *now,vector< pair >& _arrayRangeList){ 85 | if(now->token!="period"){ 86 | cout << "getArrayRangeList error" << endl; 87 | return; 88 | } 89 | int loc=int(now->children.size()-3); 90 | _arrayRangeList.push_back(make_pair(str2int(now->children[loc]->str),str2int(now->children[loc+2]->str))); 91 | if(loc==2) 92 | getArrayRangeList(now->children[0],_arrayRangeList); 93 | else 94 | reverse(_arrayRangeList.begin(),_arrayRangeList.end()); 95 | } 96 | 97 | _Type* getType(Type *now){ 98 | if(now->token!="type"){ 99 | cout << "getType error" << endl; 100 | return NULL; 101 | } 102 | _Type* _type = new _Type; 103 | int loc=int(now->children.size()-1); 104 | _type->type=make_pair(now->children[loc]->str,now->children[loc]->lineNumber); 105 | if(loc==5){ 106 | _type->flag=1; 107 | getArrayRangeList(now->children[2],_type->arrayRangeList); 108 | } 109 | else 110 | _type->flag=0; 111 | return _type; 112 | } 113 | 114 | void getVariant(Type *now,vector<_Variant*>& _variantList){ 115 | if(now->token!="var_declaration"){ 116 | cout << "getVariant error" << endl; 117 | return; 118 | } 119 | vector< pair > _idList; 120 | int loc=int(now->children.size()-3); 121 | getIdList(now->children[loc],_idList,false); 122 | _Type *_type=getType(now->children[loc+2]); 123 | for(int i=0;i<_idList.size();i++) 124 | _variantList.push_back(new _Variant(_idList[i],_type)); 125 | if(loc==2) 126 | getVariant(now->children[0],_variantList); 127 | else 128 | reverse(_variantList.begin(),_variantList.end()); 129 | } 130 | 131 | void getVariantList(Type *now,vector<_Variant*>& _variantList){ 132 | if(now->token!="var_declarations"){ 133 | cout << "getVariantList error" << endl; 134 | return; 135 | } 136 | if(now->children.size()) 137 | getVariant(now->children[1],_variantList); 138 | } 139 | 140 | void setConst(Type *now,_Constant* &_constant){//pascal在定义常量时,并没有指定常量的类型,所以需要自行判断 141 | if(now->token!="const_value"){ 142 | cout << "setConst error" << endl; 143 | return; 144 | } 145 | int loc=1; 146 | if(now->children.size()==1) 147 | loc=0; 148 | if(now->children[loc]->token=="IDENTIFIER"){//如果右值是标识符 149 | _constant->type="id"; 150 | _constant->valueId = make_pair(now->children[loc]->str,now->children[loc]->lineNumber); 151 | _constant->strOfVal = now->children[loc]->str; 152 | _constant->isMinusShow = (loc == 1 && now->children[0]->token == "-"); 153 | } 154 | else if(now->children[loc]->token=="UINUM"){ 155 | _constant->type="integer"; 156 | _constant->intValue=str2int(now->children[loc]->str); 157 | _constant->strOfVal = now->children[loc]->str; 158 | _constant->isMinusShow = (loc == 1 && now->children[0]->token == "-"); 159 | } 160 | else if(now->children[loc]->token=="UFNUM"){ 161 | _constant->type="real"; 162 | _constant->realValue=str2float(now->children[loc]->str); 163 | _constant->strOfVal = now->children[loc]->str; 164 | _constant->isMinusShow = (loc == 1 && now->children[0]->token == "-"); 165 | } 166 | else if(now->children[loc]->token=="CHAR"){ 167 | _constant->type="char"; 168 | _constant->charValue=now->children[loc]->str[0]; 169 | _constant->strOfVal = now->children[loc]->str; 170 | } 171 | else{ 172 | cout << "setConst error" << endl; 173 | } 174 | } 175 | 176 | void getConst(Type *now,vector<_Constant*>& _constantList){ 177 | if(now->token!="const_declaration"){ 178 | cout << "getConst error" << endl; 179 | return; 180 | } 181 | int loc=int(now->children.size()-3); 182 | _Constant* _constant=new _Constant; 183 | _constant->constId=make_pair(now->children[loc]->str,now->children[loc]->lineNumber); 184 | setConst(now->children[loc+2],_constant); 185 | _constantList.push_back(_constant); 186 | if(loc==2) 187 | getConst(now->children[0],_constantList); 188 | else 189 | reverse(_constantList.begin(),_constantList.end()); 190 | } 191 | 192 | void getConstList(Type *now,vector<_Constant*>& _constantList){ 193 | if(now->token!="const_declarations"){ 194 | cout << "getConstList error" << endl; 195 | return; 196 | } 197 | if(now->children.size()) 198 | getConst(now->children[1],_constantList); 199 | } 200 | 201 | void getValueParameter(Type *now,vector<_FormalParameter*>& _formalParaList,int flag){ 202 | if(now->token!="value_parameter"){ 203 | cout << "getValueParameter error" << endl; 204 | return; 205 | } 206 | vector< pair > _idList; 207 | getIdList(now->children[0],_idList,false); 208 | string _type=now->children[2]->str; 209 | for(int i=0;i<_idList.size();i++) 210 | _formalParaList.push_back(new _FormalParameter(_idList[i],_type,flag)); 211 | } 212 | 213 | void getParameter(Type *now,vector<_FormalParameter*>& _formalParaList){ 214 | if(now->token!="parameter"){ 215 | cout << "getParameter error" << endl; 216 | return; 217 | } 218 | if(now->children[0]->token=="var_parameter") 219 | getValueParameter(now->children[0]->children[1],_formalParaList,1); 220 | else if(now->children[0]->token=="value_parameter") 221 | getValueParameter(now->children[0],_formalParaList,0); 222 | else 223 | cout << "getParameter error" << endl; 224 | } 225 | 226 | void getFormalParameter(Type *now,vector<_FormalParameter*>& _formalParaList){ 227 | if(now->token!="parameter_list"){ 228 | cout << "getFormalParameter error" << endl; 229 | return; 230 | } 231 | int loc=int(now->children.size()-1); 232 | getParameter(now->children[loc],_formalParaList); 233 | if(loc==2) 234 | getFormalParameter(now->children[0],_formalParaList); 235 | else 236 | reverse(_formalParaList.begin(),_formalParaList.end()); 237 | } 238 | 239 | void getFormalParaList(Type *now,vector<_FormalParameter*>& _formalParaList){ 240 | if(now->token!="formal_parameter"){ 241 | cout << "getFormalParaList error" << endl; 242 | return; 243 | } 244 | if(now->children.size()) 245 | getFormalParameter(now->children[1],_formalParaList); 246 | } 247 | 248 | void getSubprogramHead(Type *now,pair& functionID,vector<_FormalParameter*>& _formalParaList,pair &_type){ 249 | if(now->token!="subprogram_head"){ 250 | cout << "getSubprogramHead error" << endl; 251 | return; 252 | } 253 | functionID=make_pair(now->children[1]->str,now->children[1]->lineNumber); 254 | getFormalParaList(now->children[2],_formalParaList); 255 | _type=make_pair("",-1); 256 | if (now->children.size() == 5) 257 | _type = make_pair(now->children[4]->str, now->children[4]->lineNumber); 258 | } 259 | 260 | //"var"表示变量,"integer"表示整数,"real"表示浮点数,"char"表示字符常量 261 | //"function"表示函数调用,"compound"表示复合表达式 262 | //compound有普通的二目运算符,还有minus、not、bracket等单目运算符 263 | _Expression* getFactor(Type *now){ 264 | if(now->token!="factor"){ 265 | cout << "getFactor error" << endl; 266 | return NULL; 267 | } 268 | _Expression* _expression = new _Expression; 269 | _expression->operand1=_expression->operand2=NULL; 270 | if(now->children[0]->token=="UINUM"){ 271 | _expression->type="integer"; 272 | _expression->strOfNum = now->children[0]->str; 273 | _expression->intNum=str2int(now->children[0]->str); 274 | _expression->lineNumber=now->children[0]->lineNumber; 275 | } 276 | else if(now->children[0]->token=="UFNUM"){ 277 | _expression->type="real"; 278 | _expression->strOfNum = now->children[0]->str; 279 | _expression->realNum=str2float(now->children[0]->str); 280 | _expression->lineNumber=now->children[0]->lineNumber; 281 | } 282 | else if(now->children[0]->token=="variable"){ 283 | _expression->type="var"; 284 | _expression->variantReference=getVariantReference(now->children[0]); 285 | _expression->lineNumber = _expression->variantReference->variantId.second; 286 | } 287 | else if(now->children[0]->token=="IDENTIFIER"){ 288 | _expression->type="function"; 289 | _expression->functionCall = new _FunctionCall; 290 | _expression->functionCall->functionId=make_pair(now->children[0]->str,now->children[0]->lineNumber); 291 | getExpressionList(now->children[2],_expression->functionCall->actualParaList); 292 | _expression->lineNumber = _expression->functionCall->functionId.second; 293 | } 294 | else if(now->children[0]->token=="("){ 295 | _expression->type="compound"; 296 | _expression->operationType = "single"; 297 | _expression->operation="bracket"; 298 | _expression->operand1=getExpression(now->children[1]); 299 | _expression->lineNumber = _expression->operand1->lineNumber; 300 | } 301 | else if(now->children[0]->token=="NOT"){ 302 | _expression->type="compound"; 303 | _expression->operationType = "single"; 304 | _expression->operation="not"; 305 | _expression->operand1=getFactor(now->children[1]); 306 | _expression->lineNumber = _expression->operand1->lineNumber; 307 | } 308 | else if(now->children[0]->token=="-"){ 309 | _expression->type="compound"; 310 | _expression->operationType = "single"; 311 | _expression->operation="minus"; 312 | _expression->operand1=getFactor(now->children[1]); 313 | _expression->lineNumber = _expression->operand1->lineNumber; 314 | } 315 | else if (now->children[0]->token == "CHAR") { 316 | _expression->type = "char"; 317 | _expression->charVal = now->children[0]->str[0]; 318 | _expression->lineNumber = now->children[0]->lineNumber; 319 | } 320 | else{ 321 | cout << "getFactor error" << endl; 322 | return NULL; 323 | } 324 | return _expression; 325 | } 326 | 327 | _Expression* getTerm(Type *now){ 328 | if(now->token!="term"){ 329 | cout << "term" << endl; 330 | return NULL; 331 | } 332 | _Expression* _expression=NULL; 333 | if(now->children.size()==3){ 334 | _expression = new _Expression; 335 | _expression->type="compound"; 336 | _expression->operation=now->children[1]->str; 337 | _expression->operationType="mulop"; 338 | _expression->operand1=getTerm(now->children[0]); 339 | _expression->operand2=getFactor(now->children[2]); 340 | _expression->lineNumber = _expression->operand1->lineNumber; 341 | } 342 | else 343 | _expression=getFactor(now->children[0]); 344 | return _expression; 345 | } 346 | 347 | _Expression* getSimpleExpression(Type *now){ 348 | if(now->token!="simple_expression"){ 349 | cout << "getSimpleExpression error" << endl; 350 | return NULL; 351 | } 352 | _Expression* _expression=NULL; 353 | if(now->children.size()==3){ 354 | _expression = new _Expression; 355 | _expression->type="compound"; 356 | _expression->operation=now->children[1]->str; 357 | _expression->operationType="addop"; 358 | _expression->operand1=getSimpleExpression(now->children[0]); 359 | _expression->operand2=getTerm(now->children[2]); 360 | _expression->lineNumber = _expression->operand1->lineNumber; 361 | } 362 | else 363 | _expression=getTerm(now->children[0]); 364 | return _expression; 365 | } 366 | 367 | _Expression* getExpression(Type *now){ 368 | if(now->token!="expression"){ 369 | cout << "getExpression error" << endl; 370 | return NULL; 371 | } 372 | _Expression* _expression=NULL; 373 | if(now->children.size()==3){ 374 | _expression = new _Expression; 375 | _expression->type="compound"; 376 | _expression->operation=now->children[1]->str; 377 | _expression->operationType="relop"; 378 | _expression->operand1=getSimpleExpression(now->children[0]); 379 | _expression->operand2=getSimpleExpression(now->children[2]); 380 | _expression->lineNumber = _expression->operand1->lineNumber; 381 | } 382 | else 383 | _expression=getSimpleExpression(now->children[0]); 384 | return _expression; 385 | } 386 | 387 | void getExpressionList(Type *now,vector<_Expression*>& _expressionList){ 388 | if(now->token!="expression_list"){ 389 | cout << "getExpressionList error" << endl; 390 | return; 391 | } 392 | int loc=int(now->children.size()-1); 393 | _expressionList.push_back(getExpression(now->children[loc])); 394 | if(loc==2) 395 | getExpressionList(now->children[0],_expressionList); 396 | else 397 | reverse(_expressionList.begin(),_expressionList.end()); 398 | } 399 | 400 | void getVariantReferenceList(Type *now,vector<_Expression*>& _expressionList){ 401 | if(now->token!="id_varpart"){ 402 | cout << "getVariantReferenceList error" << endl; 403 | return; 404 | } 405 | if(now->children.size()) 406 | getExpressionList(now->children[1],_expressionList); 407 | } 408 | 409 | _VariantReference* getVariantReference(Type *now){ 410 | if(now->token!="variable"){ 411 | cout << "getVariantReference error" << endl; 412 | return NULL; 413 | } 414 | _VariantReference* _variantReference = new _VariantReference; 415 | _variantReference->variantId=make_pair(now->children[0]->str,now->children[0]->lineNumber); 416 | getVariantReferenceList(now->children[1],_variantReference->expressionList); 417 | if (_variantReference->expressionList.size()) 418 | _variantReference->flag = 1; 419 | else 420 | _variantReference->flag = 0; 421 | return _variantReference; 422 | } 423 | 424 | _Statement* getElseStatement(Type *now){ 425 | if(now->token!="else_part"){ 426 | cout << "getElseStatement error" << endl; 427 | return NULL; 428 | } 429 | if(now->children.size()==0) 430 | return NULL; 431 | return getStatement(now->children[1]); 432 | } 433 | 434 | _Statement* getProcedureCall(Type *now) { 435 | if (now->token != "procedure_call") { 436 | cout << "getProcedureCall error" << endl; 437 | return NULL; 438 | } 439 | _ProcedureCall *_procedureCall = new _ProcedureCall; 440 | _procedureCall->lineNumber = now->children[0]->lineNumber; 441 | _procedureCall->type = "procedure"; 442 | _procedureCall->procedureId = make_pair(now->children[0]->str, now->children[0]->lineNumber); 443 | if (now->children.size() == 4) 444 | getExpressionList(now->children[2], _procedureCall->actualParaList); 445 | return _procedureCall; 446 | } 447 | 448 | _Statement* getStatement(Type *now){ 449 | if(now->token!="statement"){ 450 | cout << "getStatement error" << endl; 451 | return NULL; 452 | } 453 | if (now->children.size() == 0) 454 | return NULL; 455 | if(now->children[0]->token=="variable"){ 456 | _AssignStatement *_assignStatement = new _AssignStatement; 457 | _assignStatement->lineNumber = now->children[1]->lineNumber; 458 | _assignStatement->type="assign"; 459 | _assignStatement->variantReference=getVariantReference(now->children[0]); 460 | _assignStatement->expression=getExpression(now->children[2]); 461 | return _assignStatement; 462 | } 463 | else if(now->children[0]->token=="procedure_call") 464 | return getProcedureCall(now->children[0]); 465 | else if(now->children[0]->token=="compound_statement") 466 | return getCompoundStatement(now->children[0]); 467 | else if(now->children[0]->token=="IF"){ 468 | _IfStatement* _ifStatement = new _IfStatement; 469 | _ifStatement->lineNumber = now->children[0]->lineNumber; 470 | _ifStatement->type="if"; 471 | _ifStatement->condition=getExpression(now->children[1]); 472 | _ifStatement->then=getStatement(now->children[3]); 473 | _ifStatement->els=getElseStatement(now->children[4]); 474 | return _ifStatement; 475 | } 476 | else if(now->children[0]->token=="FOR"){ 477 | _ForStatement* _forStatement = new _ForStatement; 478 | _forStatement->lineNumber = now->children[0]->lineNumber; 479 | _forStatement->type="for"; 480 | _forStatement->id=make_pair(now->children[1]->str,now->children[1]->lineNumber); 481 | _forStatement->start=getExpression(now->children[3]); 482 | _forStatement->end=getExpression(now->children[5]); 483 | _forStatement->_do=getStatement(now->children[7]); 484 | return _forStatement; 485 | } 486 | else if(now->children[0]->token=="WHILE"){ 487 | _WhileStatement* _whileStatement = new _WhileStatement; 488 | _whileStatement->lineNumber = now->children[0]->lineNumber; 489 | _whileStatement->type="while"; 490 | _whileStatement->condition=getExpression(now->children[1]); 491 | _whileStatement->_do=getStatement(now->children[3]); 492 | return _whileStatement; 493 | } 494 | else if(now->children[0]->token=="REPEAT"){ 495 | _RepeatStatement* _repeatStatement = new _RepeatStatement; 496 | _repeatStatement->lineNumber = now->children[0]->lineNumber; 497 | _repeatStatement->type="repeat"; 498 | _repeatStatement->condition=getExpression(now->children[3]); 499 | _repeatStatement->_do=getStatement(now->children[1]); 500 | return _repeatStatement; 501 | } 502 | else{ 503 | cout << "[getStatement] statement token error" << endl; 504 | return NULL; 505 | } 506 | } 507 | 508 | void getStatementList(Type *now,vector<_Statement*>& _statementList){ 509 | if(now->token!="statement_list"){ 510 | cout << "getStatementList error" << endl; 511 | return; 512 | } 513 | int loc=int(now->children.size()-1); 514 | _Statement* statement = getStatement(now->children[loc]); 515 | if(statement != NULL) 516 | _statementList.push_back(statement); 517 | if(loc==2) 518 | getStatementList(now->children[0],_statementList); 519 | else 520 | reverse(_statementList.begin(),_statementList.end()); 521 | } 522 | 523 | _Compound* getCompoundStatement(Type *now){ 524 | if(now->token!="compound_statement"){ 525 | cout << "getCompoundStatement error" << endl; 526 | return NULL; 527 | } 528 | _Compound *_compound = new _Compound; 529 | _compound->lineNumber = now->children[0]->lineNumber; 530 | _compound->type = "compound"; 531 | getStatementList(now->children[1],_compound->statementList); 532 | return _compound; 533 | } 534 | 535 | void getSubprogramBody(Type *now,vector<_Constant*>& _constList,vector<_Variant*>& _variantList,_Compound* &_compound){ 536 | if(now->token!="subprogram_body"){ 537 | cout << "getSubprogramBody error" <children[0],_constList); 541 | getVariantList(now->children[1],_variantList); 542 | _compound = getCompoundStatement(now->children[2]); 543 | } 544 | 545 | _FunctionDefinition* getSubprogramDefinition(Type *now){ 546 | if(now->token!="subprogram"){ 547 | cout << "getSubprogramDefinition error" << endl; 548 | return NULL; 549 | } 550 | _FunctionDefinition *_functionDefinition=new _FunctionDefinition; 551 | getSubprogramHead(now->children[0],_functionDefinition->functionID,_functionDefinition->formalParaList,_functionDefinition->type); 552 | getSubprogramBody(now->children[2],_functionDefinition->constList,_functionDefinition->variantList,_functionDefinition->compound); 553 | return _functionDefinition; 554 | } 555 | 556 | void getSubprogramDefinitionList(Type *now,vector<_FunctionDefinition*>& _subprogramDefinitionList){ 557 | if(now->token!="subprogram_declarations"){ 558 | cout << "getSubprogramDefinitionList error" << endl; 559 | return; 560 | } 561 | if (now->children.size()) { 562 | _subprogramDefinitionList.push_back(getSubprogramDefinition(now->children[1])); 563 | getSubprogramDefinitionList(now->children[0], _subprogramDefinitionList); 564 | } 565 | else 566 | reverse(_subprogramDefinitionList.begin(),_subprogramDefinitionList.end()); 567 | } 568 | 569 | _SubProgram* getProgramBody(Type *now){ 570 | if(now->token!="program_body"){ 571 | cout << "getProgramBody error" << endl; 572 | return NULL; 573 | } 574 | _SubProgram *_subProgram=new _SubProgram; 575 | getConstList(now->children[0],_subProgram->constList); 576 | getVariantList(now->children[1],_subProgram->variantList); 577 | getSubprogramDefinitionList(now->children[2],_subProgram->subprogramDefinitionList); 578 | _subProgram->compound = getCompoundStatement(now->children[3]); 579 | return _subProgram; 580 | } 581 | 582 | void getProgramHead(Type *now,pair& _programId,vector< pair >& _paraList){ 583 | if(now->token!="program_head"){ 584 | cout << "getProgramHead error" << endl; 585 | return; 586 | } 587 | _programId=make_pair(now->children[1]->str,now->children[1]->lineNumber); 588 | getIdList(now->children[3],_paraList,true); 589 | } 590 | 591 | _Program* getProgram(Type *now){ 592 | if(now->token!="programstruct"){ 593 | cout << "getProgram error" << endl; 594 | return NULL; 595 | } 596 | _Program* ASTRoot=new _Program; 597 | getProgramHead(now->children[0],ASTRoot->programId,ASTRoot->paraList); 598 | ASTRoot->subProgram=getProgramBody(now->children[2]); 599 | return ASTRoot; 600 | } -------------------------------------------------------------------------------- /src/semanticAnalyse.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/src/semanticAnalyse.cpp -------------------------------------------------------------------------------- /src/symbolTable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 符号表实现代码 3 | */ 4 | #include "symbolTable.h" 5 | #include 6 | using namespace std; 7 | 8 | _SymbolTable *mainSymbolTable;//主符号表 9 | _SymbolTable *currentSymbolTable;//当前符号表 10 | 11 | _SymbolRecord* findSymbolRecord(_SymbolTable* currentSymbolTable, string id, int mode = 0); 12 | 13 | void _SymbolTable::addPara(string id, int lineNumber, string type) { 14 | if (this->idToLoc.count(id)) { 15 | for (int i = 0; i < idCount[id]; i++) 16 | id = "_" + id; 17 | } 18 | _SymbolRecord* tmpRecord = new _SymbolRecord; 19 | tmpRecord->setPara(id, lineNumber, type); 20 | this->recordList.push_back(tmpRecord); 21 | this->idToLoc[id] = int(recordList.size() - 1); 22 | if (this->idCount.count(id)) 23 | this->idCount[id]++; 24 | else 25 | this->idCount[id] = 1; 26 | } 27 | 28 | void _SymbolTable::addVarPara(string id, int lineNumber, string type) { 29 | if (this->idToLoc.count(id)) { 30 | for (int i = 0; i < idCount[id]; i++) 31 | id = "_" + id; 32 | } 33 | _SymbolRecord* tmpRecord = new _SymbolRecord; 34 | tmpRecord->setVarPara(id, lineNumber, type); 35 | this->recordList.push_back(tmpRecord); 36 | this->idToLoc[id] = int(recordList.size() - 1); 37 | if (this->idCount.count(id)) 38 | this->idCount[id]++; 39 | else 40 | this->idCount[id] = 1; 41 | } 42 | 43 | void _SymbolTable::addVar(string id, int lineNumber, string type) { 44 | _SymbolRecord* tmpRecord = new _SymbolRecord; 45 | tmpRecord->setVar(id, lineNumber, type); 46 | this->recordList.push_back(tmpRecord); 47 | this->idToLoc[id] = int(recordList.size() - 1); 48 | } 49 | 50 | void _SymbolTable::addConst(string id, int lineNumber, string type, bool isMinusShow, string value) { 51 | _SymbolRecord* tmpRecord = new _SymbolRecord; 52 | tmpRecord->setConst(id, lineNumber, type, isMinusShow, value); 53 | this->recordList.push_back(tmpRecord); 54 | this->idToLoc[id] = int(recordList.size() - 1); 55 | } 56 | 57 | void _SymbolTable::addArray(string id, int lineNumber, string type, int amount, vector< pair > arrayRangeList) { 58 | _SymbolRecord* tmpRecord = new _SymbolRecord; 59 | tmpRecord->setArray(id, lineNumber, type, amount, arrayRangeList); 60 | this->recordList.push_back(tmpRecord); 61 | this->idToLoc[id] = int(recordList.size() - 1); 62 | } 63 | 64 | void _SymbolTable::addProcedure(string id, int lineNumber, int amount, _SymbolTable *subSymbolTable) { 65 | _SymbolRecord* tmpRecord = new _SymbolRecord; 66 | tmpRecord->setProcedure(id, lineNumber, amount, subSymbolTable); 67 | this->recordList.push_back(tmpRecord); 68 | this->idToLoc[id] = int(recordList.size() - 1); 69 | } 70 | 71 | void _SymbolTable::addFunction(string id, int lineNumber, string type, int amount, _SymbolTable *subSymbolTable) { 72 | _SymbolRecord* tmpRecord = new _SymbolRecord; 73 | tmpRecord->setFunction(id, lineNumber, type, amount, subSymbolTable); 74 | this->recordList.push_back(tmpRecord); 75 | this->idToLoc[id] = int(recordList.size() - 1); 76 | } 77 | 78 | void _SymbolTable::addSubSymbolTable(string id, _SymbolTable* symbolTable) { 79 | if (idToLoc.count(id)) { 80 | int loc = idToLoc[id]; 81 | recordList[loc]->subSymbolTable = symbolTable; 82 | } 83 | else 84 | cout << "[_SymbolTable::addSubSymbolTable] ERROR: subprogram id not found" << endl; 85 | } 86 | 87 | void _SymbolTable::addProgramName(string id, int lineNumber, string subprogramType, int amount, string returnType) { 88 | if (recordList.size() != 0) { 89 | cout << "[_SymbolTable::addProgramName] recordList.size() is not equal to 0" << endl; 90 | return; 91 | } 92 | if (this->idToLoc.count(id)) { 93 | for (int i = 0; i < idCount[id]; i++) 94 | id = "_" + id; 95 | } 96 | _SymbolRecord* tmpRecord = new _SymbolRecord; 97 | tmpRecord->setProgramName(id, lineNumber, subprogramType, amount, returnType); 98 | this->recordList.push_back(tmpRecord); 99 | this->idToLoc[id] = int(recordList.size() - 1); 100 | if (this->idCount.count(id)) 101 | this->idCount[id]++; 102 | else 103 | this->idCount[id] = 1; 104 | } 105 | 106 | void _SymbolTable::addVoidPara(string id, int lineNumber) { 107 | if (this->idToLoc.count(id)) { 108 | for (int i = 0; i < idCount[id]; i++) 109 | id = "_" + id; 110 | } 111 | _SymbolRecord* tmpRecord = new _SymbolRecord; 112 | tmpRecord->setVoidPara(id, lineNumber); 113 | this->recordList.push_back(tmpRecord); 114 | this->idToLoc[id] = int(recordList.size() - 1); 115 | if (this->idCount.count(id)) 116 | this->idCount[id]++; 117 | else 118 | this->idCount[id] = 1; 119 | } 120 | 121 | _SymbolTable::_SymbolTable(string type) { 122 | recordList.clear(); 123 | idToLoc.clear(); 124 | this->tableType=type; 125 | } 126 | 127 | void _SymbolRecord::setPara(string id, int lineNumber, string type) { 128 | flag = "value parameter"; 129 | this->id = id; 130 | this->lineNumber = lineNumber; 131 | this->type = type; 132 | } 133 | 134 | void _SymbolRecord::setVarPara(string id,int lineNumber, string type) { 135 | flag = "var parameter"; 136 | this->id = id; 137 | this->lineNumber = lineNumber; 138 | this->type = type; 139 | } 140 | 141 | void _SymbolRecord::setVar(string id, int lineNumber, string type) { 142 | flag = "normal variant"; 143 | this->id = id; 144 | this->lineNumber = lineNumber; 145 | this->type = type; 146 | } 147 | 148 | void _SymbolRecord::setConst(string id, int lineNumber, string type, bool isMinusShow, string value) { 149 | flag = "constant"; 150 | this->id = id; 151 | this->lineNumber = lineNumber; 152 | this->type = type; 153 | this->isMinusShow = isMinusShow; 154 | if (type == "char") 155 | this->value += "'"; 156 | this->value += value; 157 | if (type == "char") 158 | this->value += "'"; 159 | } 160 | 161 | void _SymbolRecord::setArray(string id, int lineNumber, string type, int amount, vector< pair > arrayRangeList) { 162 | flag = "array"; 163 | this->id = id; 164 | this->lineNumber = lineNumber; 165 | this->type = type; 166 | this->amount = amount; 167 | this->arrayRangeList = arrayRangeList; 168 | } 169 | 170 | void _SymbolRecord::setProcedure(string id, int lineNumber, int amount, _SymbolTable *subSymbolTable) { 171 | flag = "procedure"; 172 | this->id = id; 173 | this->lineNumber = lineNumber; 174 | this->amount = amount; 175 | this->subSymbolTable = subSymbolTable; 176 | } 177 | 178 | void _SymbolRecord::setFunction(string id, int lineNumber, string type, int amount, _SymbolTable *subSymbolTable) { 179 | flag = "function"; 180 | this->id = id; 181 | this->lineNumber = lineNumber; 182 | this->type = type; 183 | this->amount = amount; 184 | this->subSymbolTable = subSymbolTable; 185 | } 186 | 187 | //这是一条特殊的记录,表示当前符号表对应的程序名、行号、"procedure"还是"function"、参数个数 188 | //如果是"function",则returnType为其返回值类型 189 | //如果是"procedure",则returnType为"" 190 | void _SymbolRecord::setProgramName(string id, int lineNumber, string subprogramType, int amount, string returnType) { 191 | flag = "(sub)program name"; 192 | this->id = id; 193 | this->lineNumber = lineNumber; 194 | this->subprogramType = subprogramType; 195 | this->amount = amount; 196 | this->type = returnType; 197 | } 198 | 199 | void _SymbolRecord::setVoidPara(string id, int lineNumber) { 200 | flag = "parameter of program"; 201 | this->id = id; 202 | this->lineNumber = lineNumber; 203 | } 204 | 205 | string _SymbolRecord::findXthFormalParaType(int X) { 206 | if ((flag == "function" || flag == "procedure") && X >= 1 && X < amount + 1) 207 | return subSymbolTable->recordList[X]->type; 208 | else { 209 | cout << "[_SymbolRecord::findXthFormalParaType] record is not a function or procedure, or formal parameter index out of range" << endl; 210 | return ""; 211 | } 212 | } 213 | 214 | bool _SymbolRecord::isXthFormalParaRefered(int X) { 215 | if ((flag == "function" || flag == "procedure") && X >= 1 && X < amount + 1) 216 | return subSymbolTable->recordList[X]->flag=="var parameter"; 217 | else { 218 | cout << "[_SymbolRecord::isXthFormalParaRefered] record is not a function or procedure, or formal parameter index out of range" << endl; 219 | return ""; 220 | } 221 | } 222 | 223 | bool _SymbolRecord::checkArrayXthIndexRange(int X, int index) { 224 | if ((flag == "array") && X >= 0 && X < amount) 225 | return index >= arrayRangeList[X].first&&index <= arrayRangeList[X].second; 226 | else { 227 | cout << "[_SymbolRecord::checkArrayXthIndexRange] record is not a array, or index out of range" << endl; 228 | return false; 229 | } 230 | } 231 | 232 | //找出标识符在符号表中的位置 233 | _SymbolRecord* findSymbolRecord(_SymbolTable* currentSymbolTable, string id, int mode) { 234 | if (currentSymbolTable->idToLoc.count(id)) { 235 | int loc = currentSymbolTable->idToLoc[id]; 236 | return currentSymbolTable->recordList[loc]; 237 | } 238 | if (mode != 0) 239 | return NULL; 240 | if (currentSymbolTable->tableType == "sub" && mainSymbolTable->idToLoc.count(id)) { 241 | int loc = mainSymbolTable->idToLoc[id]; 242 | return mainSymbolTable->recordList[loc]; 243 | } 244 | return NULL; 245 | } 246 | 247 | //检查id是否是引用参数 248 | bool checkIsReferedPara(_SymbolTable* currentSymbolTable, string id) { 249 | if (currentSymbolTable->tableType == "main") 250 | return false; 251 | if (currentSymbolTable->idToLoc.count(id)) { 252 | int loc = currentSymbolTable->idToLoc[id]; 253 | _SymbolRecord *record = currentSymbolTable->recordList[loc]; 254 | return record->flag == "var parameter"; 255 | } 256 | else //子符号表没找到,那么就是在主符号表中,主符号表中没有传值参数这一类 257 | return false; 258 | } -------------------------------------------------------------------------------- /src/symbolTable.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/src/symbolTable.h -------------------------------------------------------------------------------- /src/yacc.tab.h: -------------------------------------------------------------------------------- 1 | 2 | /* A Bison parser, made by GNU Bison 2.4.1. */ 3 | 4 | /* Skeleton interface for Bison's Yacc-like parsers in C 5 | 6 | Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 7 | Free Software Foundation, Inc. 8 | 9 | This program is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . */ 21 | 22 | /* As a special exception, you may create a larger work that contains 23 | part or all of the Bison parser skeleton and distribute that work 24 | under terms of your choice, so long as that work isn't itself a 25 | parser generator using the skeleton or a modified version thereof 26 | as a parser skeleton. Alternatively, if you modify or redistribute 27 | the parser skeleton itself, you may (at your option) remove this 28 | special exception, which will cause the skeleton and the resulting 29 | Bison output files to be licensed under the GNU General Public 30 | License without this special exception. 31 | 32 | This special exception was added by the Free Software Foundation in 33 | version 2.2 of Bison. */ 34 | 35 | 36 | /* Tokens. */ 37 | #ifndef YYTOKENTYPE 38 | # define YYTOKENTYPE 39 | /* Put the tokens into the symbol table, so that GDB and other debuggers 40 | know about them. */ 41 | enum yytokentype { 42 | PROGRAM = 258, 43 | CONST = 259, 44 | VAR = 260, 45 | ARRAY = 261, 46 | OF = 262, 47 | PROCEDURE = 263, 48 | FUNCTION = 264, 49 | _BEGIN = 265, 50 | END = 266, 51 | IF = 267, 52 | THEN = 268, 53 | FOR = 269, 54 | TO = 270, 55 | DO = 271, 56 | ELSE = 272, 57 | REPEAT = 273, 58 | UNTIL = 274, 59 | WHILE = 275, 60 | IDENTIFIER = 276, 61 | UINUM = 277, 62 | UFNUM = 278, 63 | CHAR = 279, 64 | TYPE = 280, 65 | ASSIGNOP = 281, 66 | RELOP = 282, 67 | ADDOP = 283, 68 | MULOP = 284, 69 | NOT = 285, 70 | RANGEDOT = 286, 71 | ADD = 287, 72 | MUL = 288, 73 | UMINUS = 289, 74 | LOWER_THAN_ELSE = 290, 75 | ONE = 291, 76 | TWO = 292, 77 | THREE = 293 78 | }; 79 | #endif 80 | 81 | 82 | 83 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 84 | typedef int YYSTYPE; 85 | # define YYSTYPE_IS_TRIVIAL 1 86 | # define yystype YYSTYPE /* obsolescent; will be withdrawn */ 87 | # define YYSTYPE_IS_DECLARED 1 88 | #endif 89 | 90 | extern YYSTYPE yylval; 91 | 92 | #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED 93 | typedef struct YYLTYPE 94 | { 95 | int first_line; 96 | int first_column; 97 | int last_line; 98 | int last_column; 99 | } YYLTYPE; 100 | # define yyltype YYLTYPE /* obsolescent; will be withdrawn */ 101 | # define YYLTYPE_IS_DECLARED 1 102 | # define YYLTYPE_IS_TRIVIAL 1 103 | #endif 104 | 105 | extern YYLTYPE yylloc; 106 | 107 | -------------------------------------------------------------------------------- /test-cases/lex错误测试样例.md: -------------------------------------------------------------------------------- 1 | lex的错误类型本身就很少 2 | 1. 行长度超过限制,本编译器设置为10000 词法分析器abort 3 | 2. 标识符长度超过限制,本编译器设置为100 截断处理 4 | 3. 非法字符 跳过 5 | 4. 读取字符常量时遇到文件尾 6 | 5. 读取的字符常量为空 提交"\0" 7 | 6. 读取的字符常量不止一个字符 提交第一个字符 8 | 7. 读取字符常量时,先遇到了换行符而不是右单引号,也就是右单引号缺失的情况 9 | 8. 读取多行注释时遇到文件尾,也就是右花括号缺失的情况 10 | 11 | ### 行长度超过限制 12 |
 13 | program test(input,output);
 14 | var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:integer;
 15 | begin
 16 | 
 17 | end.
 18 | 
19 | 20 | ### 标识符长度超过限制 21 |
 22 | program test(input,output);
 23 | var asadhsadsadsadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:integer;
 24 | begin
 25 | 
 26 | end.
 27 | 
28 | 29 | ### 非法字符 30 |
 31 | program test(input,output);
 32 | var a:integer;
 33 | begin?
 34 |     $$
 35 | end.##
 36 | 
37 | 38 | ### 读取字符常量时遇到文件尾 39 |
 40 | program test(input,output);
 41 | const a='
 42 | 
43 | 44 | ### 读取的字符常量为空 45 |
 46 | program test(input,output);
 47 | const a=''
 48 | begin
 49 |     
 50 | end.
 51 | 
52 | 53 | ### 读取的字符常量不止一个字符 54 |
 55 | program test(input,output);
 56 | const a='abc';
 57 | begin
 58 |     writeln(a);
 59 | end.
 60 | 
61 | 62 | ### 读取字符常量时,先遇到了换行符而不是右单引号 63 |
 64 | program test(input,output);
 65 | const a='a
 66 |       b='
 67 |       c='cba
 68 | begin
 69 | 
 70 | end.
 71 | 
72 | 73 | ### 读取多行注释时遇到文件尾 74 |
 75 | program test(input,output);
 76 | {
 77 | begin
 78 | 
 79 | end.
 80 | 
81 | 82 | ## 错误组合测试 83 | ### 标识符长度超过限制、非法字符 84 |
 85 | program test(input,output);
 86 | var asadhsadsadsadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:integer;
 87 | #
 88 | begin
 89 | 
 90 | end.
 91 | 
92 | 93 | ### 读取的字符常量为空,读取字符常量时遇到文件尾 94 |
 95 | program test(input,output);
 96 | const a=''
 97 |       b='abc
 98 | 
99 | 100 | ### 读取的字符常量不止一个字符、读取字符常量时,先遇到了换行符而不是右单引号、读取多行注释时遇到文件尾 101 |
102 | program test(input,output);
103 | const a='abc'
104 |       b='bac
105 | begin
106 | {123
107 | end.
108 | 
109 | 110 | ## 综合测试 111 |
112 | program quicksort(input,output);
113 | var
114 | n,i:integer;
115 | a:array[0..100000] of integer;
116 | b:char;
117 | 
118 | procedure kp(l,r:integer);
119 | var
120 | i,j,mid:integer;
121 | begin
122 |     b:='a';
123 |     if l>=r then exit;
124 |     i:=l;j:=r;mid:=a[(l+r) div 2];
125 |     repeat
126 | 	begin
127 |          while a[i]mid do dec(j);
129 |          if i<=j then
130 |          begin
131 |              a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
132 |              inc(i);dec(j);
133 |          end
134 | 	end
135 |     until i>j;
136 |     kp l,j);
137 |     kp(i,r)
138 | end;
139 | 
140 | begin
141 |     readln(n);
142 |     for i:=1 to n do
143 |     read(a[i]);
144 |     kp(1,n);
145 |     for i:=1 to n do
146 |     write(a[i]);
147 | end.
148 | 
149 | 
-------------------------------------------------------------------------------- /test-cases/代码生成测试样例.md: -------------------------------------------------------------------------------- 1 | ## 单语法成分测试 2 | ### write/writeln语句 3 | #### 关注点 4 | 1. 编译成功,运行成功 5 | 2. writeln不带参数地调用,转化为printf("\n"); 6 | 3. 输出bool类型时,会转化为用大括号括起来的if判断语句 7 | 4. 不同格式的表达式正确对应到不同的格式控制符 8 | 9 | #### PASCAL源程序 10 |
 11 | program test(input,output);
 12 | const a=1; //整型常量
 13 |       b=3.0; //浮点型常量
 14 |       c='c'; //字符型常量
 15 |       blank=' '; //空格
 16 | var   d:integer; //整型变量
 17 |       e:real; //浮点型变量
 18 |       f:char; //字符型变量
 19 |       g:boolean; //布尔型变量
 20 | begin
 21 |     d:=6;
 22 |     e:=6.0;
 23 |     f:='f';
 24 |     g:=2>1;//不支持true常量,所以这么写
 25 |     writeln(a,blank,b,blank,c,blank,1,blank,1.0,blank,'y');
 26 |     write(a,blank,b,blank,c,blank,1,blank,1.0,blank,'y');
 27 |     writeln;
 28 |     writeln(g);
 29 |     writeln(a+b,blank,a*b,blank,g,blank,a>b,blank,c,blank,d,blank,e,blank,d<>e);
 30 | end.
 31 | 
32 | 33 | #### C程序用例 34 | 无 35 | 36 | ### read语句 37 | #### 关注点 38 | 1. 编译成功,运行成功 39 | 2. 生成的C代码中,不同格式的表达式正确对应到不同的格式控制符 40 | 3. 生成的C代码中,读取到普通变量时,正确添加了取地址符 41 | 4. 生成的C代码中,读取到引用(指针)参数时,不需要添加取地址符,因为指针本身就已经代表地址了 42 | 5. 运行后,正确读取所有值,并原样输出所有值 43 | #### PASCAL源程序 44 |
 45 | program test(input,output);
 46 | var   a,i:integer; //整型变量
 47 |       b:real; //浮点型变量
 48 |       c:char; //字符型变量
 49 |       d:array[1..6] of integer; //数组
 50 | procedure pro(var a:integer);
 51 | begin
 52 |     read(a);
 53 | end;
 54 | begin
 55 |     read(c,a); //读取字符和整数
 56 |     for i:=1 to 6 do
 57 |         pro(d[i]); //循环加调用程序读取6个整数
 58 |     read(b); //读取浮点数
 59 | 
 60 |     writeln(c,' ',a); //输出字符和整数
 61 |     for i:=1 to 6 do //输出6个整数,空格分隔
 62 |         write(d[i],' '); 
 63 |     writeln; //输出换行
 64 |     writeln(b); //输出浮点数
 65 | end.
 66 | 
67 | 68 | #### C程序 69 |
 70 | c 100
 71 | 1 2 3 4 5 6
 72 | 2.333
 73 | 
74 | 75 | ### 头文件 76 | #### 关注点 77 | #### PASCAL-S源程序 78 |
 79 | program test(input,output);
 80 | var a,b:integer;
 81 | begin
 82 |     a:=3*b;
 83 | end.
 84 | 
85 | 86 |
 87 | program test(input,output);
 88 | var a,b:integer;
 89 | begin
 90 |     read(b);
 91 |     a:=3*b;
 92 |     writeln(a);
 93 | end.
 94 | 
95 | 96 | #### C程序用例 97 | 第二个程序的测试用例 98 |
 99 | 100
100 | 
101 | 102 | ### 运算符和表达式 103 | #### 关注点 104 | 1. 生成的C代码中,各种运算符均转化正确 105 | 2. 生成的C代码中,对于a:=--b这种连着的单目运算符,添加了括号,更加易读 106 | 3. 生成的C代码中,对于不同类型的表达式,输出格式控制符正确 107 | 4. bool类型表达式的输出转化为了if-else语句 108 | 5. 输出结果符合预设值 109 | 110 | #### PASCAL-S源程序 111 |
112 | program test(input,output);
113 | const a=3;
114 |       b=1.0;
115 |       c='c';
116 | var d,e,f:integer;
117 |     g,h,i:real;
118 |     j,k,l:char;
119 |     m,n,o:boolean;
120 | function fun(a:integer):integer;
121 | begin
122 |     exit(a+1);
123 | end;
124 | begin
125 |     d:=5; e:=10;
126 |     g:=0.25; h:=0.5;
127 |     j:='a'; k:='b';
128 | 
129 |     f:= d mod (e div fun(d)); //涉及mod、div和函数调用的复杂表达式
130 |     writeln(f); //类型为integer
131 | 
132 |     g:= --d + e / d * ( - b); //涉及加减乘除、取相反数、加括号的复杂表达式
133 |     writeln(g); //类型为real
134 | 
135 |     o:= ( ( f mod e ) <> d ) or ( a > b); //涉及<>、or的复杂表达式
136 |     writeln(o); //类型为boolean
137 | 
138 |     m:= not not ( ( d + e ) = f ); //涉及取非、=的复杂表达式
139 |     writeln(m); //类型为boolean
140 | 
141 |     n:= ( g * e < f ) and ( (f mod e) >= d ); //涉及and、<、>=、mode的复杂表达式
142 |     writeln(n); //类型为boolean
143 | 
144 |     writeln( j <= c); //比较char的大小关系
145 | 
146 |     writeln( m > n); //比较boolean的大小关系
147 | end.
148 | 
149 | 150 | ### 引用参数与指针 151 | #### 关注点 152 | 1. PASCAL-S源程序中普通变量作为引用形参对应的实参调用时,在生成的C代码中加上&取地址符 153 | 2. PASCAL-S源程序中引用参数作为引用形参对应的实参调用时,在生成的C代码中无需前置任何符号,因为引用参数对应到C代码中已经是指针了,所以调用时,传本身就已经是地址了。 154 | 3. PASCAL-S源程序中,用到引用参数的地方(除了2中的情况),在生成的C代码中,都需加上前置的"*",表示解引用 155 | #### PASCAL-S源程序 156 |
157 | program test(input, output);
158 | var ans:integer;
159 | {
160 |     求斐波那契数列值的过程,利用引用参数保存结果;
161 |     n表示求第n项斐波那契数列值;
162 |     fib(0)=1, fib(1)=1, ……, fib(n)=fib(n-1)+fib(n-2);
163 | }
164 | procedure fib(n:integer;var res:integer);
165 | var tmp1,tmp2:integer;
166 | begin
167 |     if n=0 then
168 |         res:=1
169 |     else
170 |         if n=1 then
171 |             res:=1
172 |         else
173 |         begin
174 |             fib(n-1,tmp1);
175 |             fib(n-2,tmp2);
176 |             res:=tmp1+tmp2;
177 |         end;
178 | end;
179 | {
180 |     自己编写的输出函数,可以实现输出n次out值;
181 |     递归调用自身,n每次减1;
182 |     out值采用的是引用参数;
183 | }
184 | procedure mywrite(n:integer; var out:integer);
185 | begin
186 |     if n=0 then
187 |         exit
188 |     else
189 |     begin
190 |         writeln(out);
191 |         mywrite(n-1, out);
192 |     end;
193 | end;
194 | 
195 | begin
196 |     fib(10, ans); //ans=fib(10)
197 |     mywrite(3, ans); //输出ans 3次
198 | end.
199 | 
200 | 201 | #### C程序用例 202 | 无 203 | 204 | ### 常量和变量定义 205 | #### 关注点 206 | 1. 生成的C代码中,各种类型的常量定义均正确的加上了类型关键字,类型关键字的转化正确; 207 | 2. 生成的C代码中,各种类型的变量定义正确; 208 | 3. 生成的C代码中,各种类型的数组定义正确,各维大小正确; 209 | 210 | #### PASCAL-S源程序 211 |
212 | program test(input, output);
213 | const a=1; //整型常量定义
214 |       b=2.0; //浮点型常量定义
215 |       c='c'; //字符型常量定义
216 | var   d,dd,ddd:integer; //整型变量定义
217 |       e,ee,eee:real; //浮点型变量定义
218 |       f,ff,fff:char; //字符型变量定义
219 |       g,gg,ggg:boolean; //boolean型变量定义
220 |       h,hh,hhh:array[1..3] of integer; //整型数组定义
221 |       i,ii,iii:array[1..3, 4..9] of real; //浮点型数组定义
222 |       j,jj,jjj:array[1..3, 4..9, 10..18] of char; //字符型数组定义
223 |       k,kk,kkk:array[1..3, 4..9, 10..18, 19..30] of boolean; //布尔型数组定义
224 | procedure pro;
225 | const a=1; //整型常量定义
226 |       b=2.0; //浮点型常量定义
227 |       c='c'; //字符型常量定义
228 | var   d,dd,ddd:integer; //整型变量定义
229 |       e,ee,eee:real; //浮点型变量定义
230 |       f,ff,fff:char; //字符型变量定义
231 |       g,gg,ggg:boolean; //boolean型变量定义
232 |       h,hh,hhh:array[1..3] of integer; //整型数组定义
233 |       i,ii,iii:array[1..3, 4..9] of real; //浮点型数组定义
234 |       j,jj,jjj:array[1..3, 4..9, 10..18] of char; //字符型数组定义
235 |       k,kk,kkk:array[1..3, 4..9, 10..18, 19..30] of boolean; //布尔型数组定义
236 | begin
237 |       
238 | end;
239 | begin
240 |     
241 | end.
242 | 
243 | #### C程序用例 244 | 无 245 | 246 | ### 程序声明 247 | #### 关注点 248 | 1. 生成的C代码中,子程序声明正确; 249 | 2. 生成的C代码中,子程序定义的子程序头正确; 250 | 3. 生成的C代码中,子程序声明和子程序头的参数的声明顺序与PASCAL-S源程序一致 251 | 4. 生成的C代码中,子程序声明和子程序头的参数中,PASCAL-S源程序的引用参数成功的转化为了指针 252 | #### PASCAL-S源程序 253 |
254 | program test(input,output);
255 | procedure pro(var a,b,c:integer; d:real; e,f:char; var g,h,i:boolean);
256 | begin
257 | 
258 | end;
259 | function fun(a:integer; var b,c,d:real; var e,f,g:boolean; h,i:char):real;
260 | begin
261 |     fun:=1;
262 | end;
263 | begin
264 |     
265 | end.
266 | 
267 | 268 | #### C程序用例 269 | 无 270 | 271 | ### 数组定义与数组元素引用 272 | #### 关注点 273 | 1. 生成的C代码中,数组定义的各维大小正确 274 | 2. 生成的C代码中,两个三重循环中,对数组元素的引用,下标表达式添加了正确的偏移量 275 | #### PASCAL-S源程序 276 |
277 | program test(input,output);
278 | var i,j,k:integer;
279 |     a:array[0..1, 2..3, 4..5] of integer; //数组定义
280 | begin
281 |     for i:=0 to 1 do
282 |         for j:=2 to 3 do
283 |             for k:=4 to 5 do
284 |                 read(a[i,j,k]); //三重循环,读入每一个数组元素,共8个
285 |     for i:=0 to 1 do
286 |         for j:=2 to 3 do
287 |             for k:=4 to 5 do
288 |                 writeln(a[i,j,k]) //三重循环,输出每一个数组元素,换行符分隔
289 | end.
290 | 
291 | #### C程序用例 292 |
293 | 1 2 3 4 5 6 7 8
294 | 
295 | 296 | ### 返回语句 297 | #### 关注点 298 | 1. 赋值形式的返回值语句正确的转化为了C程序中的return语句; 299 | 2. exit带参数的返回值语句正确的转化为了C程序中的return语句; 300 | 3. exit不带参数的返回语句正确的转化为了C程序中的return语句; 301 | 4. 输出结果符合预设值 302 | #### PASCAL-S源程序 303 |
304 | program test(input,output);
305 | var b,c,d:integer;
306 | procedure pro;
307 | begin
308 |     exit;
309 | end;
310 | function fun(a:integer):char;
311 | begin
312 |     if a<60 then
313 |         exit('l')
314 |     else
315 |         if a=60 then
316 |             fun:='m'
317 |         else
318 |             exit('h');
319 | end;
320 | function fun2(a:integer; var b,c,d:integer):integer;
321 | begin
322 |     if a=0 then
323 |         fun2:=b+c+d
324 |     else
325 |         if a=1 then
326 |             fun2:=b*c*d
327 |         else
328 |             exit(-b-c-d);
329 | end;
330 | begin
331 |     read(b,c,d);
332 |     writeln(fun(b), ' ', fun(c), ' ', fun(d));
333 |     writeln(fun2(0, b, c, d), ' ', fun2(1, b, c, d), ' ', fun2(2, b, c, d));
334 | end.
335 | 
336 | #### C程序用例 337 |
338 | 59 60 61
339 | 
340 | 341 | ### 程序的无参调用 342 | #### 关注点 343 | 1. 过程的无参调用正确的转化为了C代码,添加了一对括号 344 | 2. 函数的无参调用正确的转化为了C代码,添加了一对括号 345 | #### PASCAL-S源程序 346 |
347 | program test(input,output);
348 | var a:integer;
349 | procedure pro;
350 | begin
351 |     writeln(a);
352 | end;
353 | function fun:integer;
354 | begin
355 |     fun:=100;
356 | end;
357 | begin
358 |     writeln(fun);
359 |     a:=fun mod 3;
360 |     pro;
361 | end.
362 | 
363 | 364 | #### C程序用例 365 | 无 366 | 367 | ### 各种语句混合与缩进 368 | #### 关注点 369 | 1. if语句转化正确 370 | 2. while语句转化正确 371 | 3. for语句转化正确 372 | 4. repeat语句转化正确,特别是条件表达式,需要取非 373 | 5. compound语句转化正确 374 | 6. 语句的缩进美观,且符合设计 375 | 7. 输入的10个数正确的被排序,按照从小到大的顺序输出 376 | #### PASCAL-S源程序 377 |
378 | program test(input, output);
379 | var i:integer;
380 |     a:array[1..10] of integer;
381 | procedure swap(var a,b:integer); //交换两个数的值
382 | var tmp:integer;
383 | begin
384 |     tmp:=a;
385 |     a:=b;
386 |     b:=tmp;
387 | end;
388 | procedure bubbleSort; //冒泡排序
389 | var i,j:integer;
390 | begin
391 |     for i:= 1 to 10 do //for语句
392 |     begin //compound语句
393 |         j:=i+1;
394 |         while j <= 10 do //while语句
395 |         begin //compound语句
396 |             if a[i]>a[j] then //if语句
397 |                 swap(a[i],a[j]);
398 |             j:=j+1;
399 |         end
400 |     end;
401 | end;
402 | begin
403 |     i:=1;
404 |     repeat //repeat语句
405 |     begin //compound语句
406 |         read(a[i]);
407 |         i:=i+1
408 |     end
409 |     until i=11;
410 |     bubbleSort;
411 |     for i:= 1 to 10 do //for语句
412 |         write(a[i],' ');
413 |     writeln;
414 | end.
415 | 
416 | #### C程序用例 417 |
418 | 8 3 5 4 0 6 9 7 1 2
419 | 
420 | 421 | ## 综合测试 422 | ### 快速排序 423 | #### PASCAL-S源程序 424 |
425 | program quicksort(input,output);
426 | var
427 | n,i:integer;
428 | a:array[0..100000] of integer;
429 | 
430 | procedure kp(l,r:integer);
431 | var
432 | i,j,mid:integer;
433 | begin
434 |     if l>=r then exit;
435 |     i:=l;j:=r;mid:=a[(l+r) div 2];
436 |     repeat
437 | 	begin
438 |          while a[i]mid do j:=j-1;
440 |          if i<=j then
441 |          begin
442 |              a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
443 |              i:=i+1;j:=j-1;
444 |          end
445 | 	end
446 |     until i>j;
447 |     kp(l,j);
448 |     kp(i,r)
449 | end;
450 | 
451 | begin
452 |     read(n);
453 |     for i:=1 to n do
454 |     read(a[i]);
455 |     kp(1,n);
456 |     for i:=1 to n do
457 |     write(a[i],' ');
458 | end.
459 | 
460 | 461 | #### C程序用例 462 |
463 | 10
464 | 5 9 2 1 0 8 3 4 6 7
465 | 
466 | 467 | ### 最大公因数 468 | #### PASCAL源程序 469 |
470 | program example(input,output);
471 | var n,i,x,y:integer;
472 | function gcd(a,b:integer):integer;
473 | begin
474 | 	if b=0 then gcd:=a
475 | 	else gcd:=gcd(b,a mod b);
476 | end;
477 | begin
478 |     read(n);
479 |     for i:= 1 to n do
480 |     begin
481 |         read(x,y);
482 |         writeln(gcd(x,y))
483 |     end;
484 | end.
485 | 
486 | 487 | #### C程序用例 488 |
489 | 5
490 | 100 36
491 | 3 0
492 | 50 30
493 | 12 28
494 | 327 198321
495 | 
496 | 497 | -------------------------------------------------------------------------------- /test-cases/综合测试用例.md: -------------------------------------------------------------------------------- 1 | ### hello world 2 |
  3 | program test(input,output);
  4 | begin
  5 |     writeln('h','e','l','l','o',' ','w','o','r','l','d','!');
  6 | end.
  7 | 
8 | 9 | ### 快速排序 10 |
 11 | program quicksort(input,output);
 12 | var
 13 | n,i:integer;
 14 | a:array[0..100000] of integer;
 15 | 
 16 | procedure kp(l,r:integer);
 17 | var
 18 | i,j,mid:integer;
 19 | begin
 20 |     if l>=r then exit;
 21 |     i:=l;j:=r;mid:=a[(l+r) div 2];
 22 |     repeat
 23 | 	begin
 24 |          while a[i]mid do j:=j-1;
 26 |          if i<=j then
 27 |          begin
 28 |              a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
 29 |              i:=i+1;j:=j-1;
 30 |          end
 31 | 	end
 32 |     until i>j;
 33 |     kp(l,j);
 34 |     kp(i,r)
 35 | end;
 36 | 
 37 | begin
 38 |     read(n);
 39 |     for i:=1 to n do
 40 |     read(a[i]);
 41 |     kp(1,n);
 42 |     for i:=1 to n do
 43 |     write(a[i],' ');
 44 | end.
 45 | 
46 | 47 | ### 冒泡排序 48 |
 49 | program test(input, output);
 50 | var i:integer;
 51 |     a:array[1..10] of integer;
 52 | procedure swap(var a,b:integer);
 53 | var tmp:integer;
 54 | begin
 55 |     tmp:=a;
 56 |     a:=b;
 57 |     b:=tmp;
 58 | end;
 59 | procedure bubbleSort;
 60 | var i,j:integer;
 61 | begin
 62 |     for i:= 1 to 10 do
 63 |     begin
 64 |         j:=i+1;
 65 |         while j <= 10 do
 66 |         begin
 67 |             if a[i]>a[j] then
 68 |                 swap(a[i],a[j]);
 69 |             j:=j+1;
 70 |         end
 71 |     end;
 72 | end;
 73 | begin
 74 |     i:=1;
 75 |     repeat
 76 |     begin
 77 |         read(a[i]);
 78 |         i:=i+1
 79 |     end
 80 |     until i=11;
 81 |     bubbleSort;
 82 |     for i:= 1 to 10 do
 83 |         write(a[i],' ');
 84 |     writeln;
 85 | end.
 86 | 
87 | 88 | ### 最大公因数 89 |
 90 | program example(input,output);
 91 | var n,i,x,y:integer;
 92 | function gcd(a,b:integer):integer;
 93 | begin
 94 | 	if b=0 then gcd:=a
 95 | 	else gcd:=gcd(b,a mod b);
 96 | end;
 97 | begin
 98 |     read(n);
 99 |     for i:= 1 to n do
100 |     begin
101 |         read(x,y);
102 |         writeln(gcd(x,y))
103 |     end;
104 | end.
105 | 
106 | 107 | ### 词法+语法错误 108 |
109 | program test(input,output;
110 | #
111 | #
112 | #
113 | #
114 | #
115 | #
116 | #
117 | #
118 | #
119 | #
120 | begin
121 | 
122 | end.
123 | 
124 | 125 | ### 很多语义错误 126 |
127 | program read(write,output);//主程序名和库程序同名
128 | const m=10;
129 |       exit=m;//exit是库函数
130 | var a,x,y:integer;
131 |     b:real;
132 |     c:char;
133 |     d:boolean;
134 |     e:array[1..5] of integer;
135 | function fun1:integer;//报函数没有返回语句的警告
136 | begin
137 |     v:=a;//v未定义
138 | end;
139 | 
140 | function fun2:integer;
141 | begin
142 |     fun2:=1;
143 |     fun2:=e[6];//数组下标越界
144 |     fun2;//函数不能作为一条单独的语句
145 |     a:=fun2[1];//错把函数名当做数组
146 | end;
147 | 
148 | procedure pro1(a:integer;b:real);
149 | var c:real;  
150 |     d:integer;
151 | begin 
152 |     c:=a+b;//integer可以隐式转换为real
153 |     d:=a+b;//real不能隐式转换为integer
154 | end;
155 | 
156 | procedure pro2(var a:real;b:integer);
157 | begin 
158 |     exit(a+b);//过程没有返回值
159 | end;
160 | 
161 | begin
162 |     a:=1;
163 |     m:=a;//常量赋值语句右值不为常量
164 |     b:=2;
165 |     c:=3;//赋值语句左右类型不匹配
166 |     d:=a>b;//d为false
167 |     if a then b:=b+1;//if条件表达式不为boolean
168 |     repeat a:=a+c until not d;//a:=a+c语句左右类型不匹配
169 |     for b:=10 to 1 do e(a,a);//循环变量不可以是real;错把数组名当做函数
170 |     while a<10 do a:=a+1;
171 |     x:=pro1(x,y);//pro1为过程,没有返回值
172 |     x:=1;
173 |     y:=2;
174 |     pro1(x,y);//传值参数支持integer到real的隐式转换
175 |     pro2(x,y);//pro2的第一个参数为传引用,integer无法隐式转换为real
176 |     pro1(x+y);//pro1有两个参数
177 |     pro1(x+y,x+y);//传值参数支持复合表达式
178 |     pro2(x+y);//pro2有两个参数
179 |     pro2(x+y,x+y);//pro2第一个参数为引用参数,只能是变量或者数组元素,不能是复杂表达式
180 | end.
181 | 
-------------------------------------------------------------------------------- /test-cases/语法分析测试用例.md: -------------------------------------------------------------------------------- 1 | ### programstruct 2 | programstruct ---> program_head ';' program_body '.' 3 | 4 | #### 分析成功后有多余的内容 5 | programstruct ---> program_head ';' program_body '.' 6 |
   7 | program test(input,output);
   8 | var b:real;
   9 |     c:array[1..5,6..10] of integer;
  10 | function fun(d,e:integer):integer;
  11 | begin
  12 |     fun:=d+e;
  13 | end;
  14 | begin
  15 |     c[3,8]:=fun(3,8);
  16 | end.
  17 | b:=c[1,6];
  18 | 
19 | 20 | #### 主程序头尾部缺少分号 21 | programstruct ---> program_head error program_body '.' 22 |
  23 | program test(input,output)
  24 | begin
  25 | 
  26 | end.
  27 | 
28 | 29 | #### 结尾缺少点号(end后) 30 | programstruct ---> program_head ';' program_body error 31 |
  32 | program test(input,output);
  33 | begin
  34 | 
  35 | end
  36 | 
37 | 38 | #### 主程序头识别失败 39 | programstruct ---> error ';' program_body '.' 40 |
  41 | ;
  42 | begin
  43 | 
  44 | end.
  45 | 
46 | 47 |
  48 | (input,output);
  49 | begin
  50 | 
  51 | end.
  52 | 
53 | 54 | #### program_body识别失败 unchecked 55 | programstruct ---> program_head ';' error '.' 56 |
  57 | program test(input,output);
  58 | 
  59 | .
  60 | 
61 | 62 | #### program_head前包含非法字符 63 | programstruct ---> error program_head ';' program_body '.' 64 |
  65 | 1 program test(input,output);
  66 | begin
  67 | 
  68 | end.
  69 | 
70 | 71 | #### program_head前包含非法记号、缺失分号 72 | programstruct ---> error program_head error program_body '.' 73 |
  74 | 1 program test(input,output)
  75 | begin
  76 | 
  77 | end.
  78 | 
79 | 80 | #### program_head前包含非法记号、缺失点号 81 | programstruct ---> error program_head ';' program_body error 82 |
  83 | 1 program test(input,output);
  84 | begin
  85 | 
  86 | end
  87 | 
88 | 89 | #### program_head前包含非法记号、program_body识别失败 unchecked 90 | programstruct ---> error program_head ';' error '.' 91 |
  92 | 1 program test(input,output);
  93 | 
  94 | .
  95 | 
96 | 97 | ### program_head 98 | program_head ---> PROGRAM IDENTIFIER '(' idlist ')' 99 | 100 | #### 缺少左括号 101 | program_head ---> PROGRAM IDENTIFIER error idlist ')' 102 |
 103 | program test input,ouput);
 104 | begin
 105 | 
 106 | end.
 107 | 
108 | 109 | #### 缺少右括号 110 | program_head ---> PROGRAM IDENTIFIER '(' idlist error 111 |
 112 | program test (input,output;
 113 | begin
 114 | 
 115 | end.
 116 | 
117 | 118 |
 119 | program test();
 120 | begin
 121 | 
 122 | end.
 123 | 
124 | 125 | #### 缺少主程序名 126 | program_head ---> PROGRAM error '(' idlist ')' 127 |
 128 | program (input,output);
 129 | begin
 130 | 
 131 | end.
 132 | 
133 | 134 | #### 主程序头不完整 135 | program_head ---> PROGRAM error 136 |
 137 | program
 138 | begin
 139 | 
 140 | end.
 141 | 
142 | 143 |
 144 | program test
 145 | begin
 146 | 
 147 | end.
 148 | 
149 | 150 | #### 主程序参数列表缺失 151 | program_head ---> PROGRAM IDENTIFIER '(' error ')' 152 |
 153 | program test (1,2);
 154 | begin
 155 | 
 156 | end.
 157 | 
 158 | 
159 | program_head ---> PROGRAM IDENTIFIER error 160 |
 161 | program test
 162 | begin
 163 | 
 164 | end.
 165 | 
 166 | 
167 | program_head ---> PROGRAM IDENTIFIER '(' error 168 |
 169 | program test(
 170 | begin
 171 | 
 172 | end.
 173 | 
174 | 175 | 176 | ### const_declarations 177 | const_declarations ---> CONST const_declaration ';' | empty 178 | 179 | #### 常量定义出现错误 180 | const_declarations ---> CONST error 181 |
 182 | program test(input,output);
 183 | const 1
 184 | begin
 185 | 
 186 | end.
 187 | 
 188 | 
189 | const_declarations ---> CONST error ';' 190 |
 191 | program test(input,output);
 192 | const 1;
 193 | begin
 194 | 
 195 | end.
 196 | 
197 | 198 | #### 缺少分号 199 | const_declarations ---> CONST const_declaration error 200 |
 201 | program test(input,output);
 202 | const a=3;b=5
 203 | begin
 204 | 
 205 | end.
 206 | 
207 | 208 | ### const_declaration 209 | const_declaration ---> const_declaration ';' IDENTIFIER '=' const_value | IDENTIFIER '=' const_value 210 | 211 | #### 常数初始化右值缺失 212 | const_declaration ---> const_declaration ';' IDENTIFIER '=' error 213 |
 214 | program test(input,output);
 215 | const a=1;b=;
 216 | begin
 217 | 
 218 | end.
 219 | 
220 | 221 | const_declaration ---> IDENTIFIER '=' error 222 |
 223 | program test(input,output);
 224 | const a=;
 225 | begin
 226 | 
 227 | end.
 228 | 
229 | 230 | 231 | #### 缺少分号 232 | const_declaration ---> const_declaration error IDENTIFIER '=' const_value 233 |
 234 | program test(input,output);
 235 | const a=1 b=a;
 236 | begin
 237 | 
 238 | end.
 239 | 
240 | 241 | #### 缺少等号 242 | const_declaration ---> const_declaration ';' IDENTIFIER error const_value 243 |
 244 | program test(input,output);
 245 | const a=1;b 2;
 246 | begin
 247 | 
 248 | end.
 249 | 
250 | 251 | const_declaration ---> IDENTIFIER error const_value 252 |
 253 | program test(input,output);
 254 | const a 1;
 255 | begin
 256 | 
 257 | end.
 258 | 
259 | 260 | 261 | ### var_declarations 262 | var_declarations ---> VAR var_declaration ';' | empty 263 | #### 变量定义出现错误 264 | var_declarations ---> VAR error ';' 265 |
 266 | program test(input,output);
 267 | var ;
 268 | begin
 269 | 
 270 | end.
 271 | 
272 | 273 |
 274 | program test(input,output);
 275 | var x;
 276 | begin
 277 | 
 278 | end.
 279 | 
280 | 281 | #### 缺少分号 282 | var_declarations ---> VAR var_declaration error 283 |
 284 | program test(input,output);
 285 | var x:integer; y:real
 286 | begin
 287 | 
 288 | end.
 289 | 
290 | 291 | ### var_declaration 292 | var_declaration ---> var_declaration ';' idlist ':' type | idlist ':' type 293 | #### 缺少分号 294 | var_declaration ---> var_declaration error idlist ':' type 295 |
 296 | program test(input,output);
 297 | var x:integer y:real;
 298 | begin
 299 | 
 300 | end.
 301 | 
302 | 303 | #### 缺少冒号 304 | var_declaration ---> idlist error type 305 |
 306 | program test(input,output);
 307 | var b real;
 308 | procedure pro;
 309 | begin
 310 | end;
 311 | begin
 312 | 
 313 | end.
 314 | 
315 | 316 | var_declaration ---> var_declaration ';' idlist error type 317 |
 318 | program test(input,output);
 319 | var x:integer;y real;
 320 | begin
 321 | 
 322 | end.
 323 | 
324 | 325 | #### type识别失败 326 | var_declaration ---> var_declaration ';' idlist ':' error 327 |
 328 | program test(input,output);
 329 | var x:integer;y:;
 330 | begin
 331 | 
 332 | end.
 333 | 
334 | 335 |
 336 | program test(input,output);
 337 | var x:integer;y:abc;
 338 | begin
 339 | 
 340 | end.
 341 | 
342 | 343 | var_declaration ---> idlist ':' error 344 |
 345 | program test(input,output);
 346 | var x:;
 347 | begin
 348 | 
 349 | end.
 350 | 
351 | 352 |
 353 | program test(input,output);
 354 | var x:123;
 355 | begin
 356 | 
 357 | end.
 358 | 
359 | 360 | ### type 361 | //删除了缺少右中括号的产生式、数组维数识别失败 362 | type ---> TYPE | ARRAY '[' period ']' OF TYPE 363 | 364 | #### 缺少左中括号 365 | type ---> ARRAY error period ']' OF TYPE 366 |
 367 | program test(input,output);
 368 | var a: array 1..3] of integer;
 369 | begin
 370 | 
 371 | end.
 372 | 
373 | 374 | #### 缺少OF关键字 375 | type ---> ARRAY '[' period ']' error TYPE 376 |
 377 | program test(input,output);
 378 | var a: array[1..3] integer;
 379 | begin
 380 | 
 381 | end.
 382 | 
383 | 384 | #### 数组元素类型识别失败 385 | type ---> ARRAY '[' period ']' OF error 386 |
 387 | program test(input,output);
 388 | var a: array[1..2] of ;
 389 | begin
 390 | 
 391 | end.
 392 | 
393 | 394 |
 395 | program test(input,output);
 396 | var a: array[1..2] of 123;
 397 | begin
 398 | 
 399 | end.
 400 | 
401 | 402 | #### 不完整的数组类型 403 | type ---> ARRAY error 404 |
 405 | program test(input,output);
 406 | var a: array;
 407 | begin
 408 | 
 409 | end.
 410 | 
411 | 412 |
 413 | program test(input,output);
 414 | var a: array 123;
 415 | begin
 416 | 
 417 | end.
 418 | 
419 | 420 | type ---> ARRAY '[' error 421 |
 422 | program test(input,output);
 423 | var a: array [a;
 424 | begin
 425 | 
 426 | end.
 427 | 
428 | 429 | type ---> ARRAY '[' period error 430 |
 431 | program test(input,output);
 432 | var a: array [1..3,4..6,7..9;
 433 | begin
 434 | 
 435 | end.
 436 | 
437 | 438 | ### period 439 | period ---> period ',' UINUM RANGEDOT UINUM | UINUM RANGEDOT UINUM 440 | 441 | #### 缺少逗号 442 | period ---> period error UINUM RANGEDOT UINUM 443 |
 444 | program test(input,output);
 445 | var a: array [1..3 4..6 7..9];
 446 | begin
 447 | 
 448 | end.
 449 | 
450 | 451 | #### 缺少双点号 452 | period ---> period ',' UINUM error UINUM 453 |
 454 | program test(input,output);
 455 | var a: array [1..3,4 6,7 9];
 456 | begin
 457 | 
 458 | end.
 459 | 
460 | 461 | 462 | ### subprogram_declarations 463 | subprogram_declarations ---> subprogram_declarations subprogram ';' | empty 464 | 465 | #### 缺少分号 466 | subprogram_declarations ---> subprogram_declarations subprogram error 467 |
 468 | program test(input,output);
 469 | var b:real;
 470 | procedure pro;
 471 | begin
 472 | end
 473 | begin
 474 | 
 475 | end.
 476 | 
477 | 478 | ### subprogram 479 | subprogram ---> subprogram_head ';' subprogram_body 480 | 481 | #### 缺少分号 482 | subprogram ---> subprogram_head error subprogram_body 483 |
 484 | program test(input,output);
 485 | var b:real;
 486 | procedure pro
 487 | begin
 488 | end;
 489 | begin
 490 | 
 491 | end.
 492 | 
493 | 494 | ### subprogram_head 495 | subprogram_head ---> PROCEDURE IDENTIFIER formal_parameter | FUNCTION IDENTIFIER formal_parameter ':' TYPE 496 | 497 | #### 函数名缺失 498 | subprogram_head ---> FUNCTION error formal_parameter ':' TYPE 499 |
 500 | program test(input,output);
 501 | var b:real;
 502 | function :integer;
 503 | begin
 504 | end;
 505 | begin
 506 | 
 507 | end.
 508 | 
509 | 510 |
 511 | program test(input,output);
 512 | var b:real;
 513 | function (a:integer):integer;
 514 | begin
 515 | end;
 516 | begin
 517 | 
 518 | end.
 519 | 
520 | 521 | #### 缺少冒号 522 | subprogram_head ---> FUNCTION IDENTIFIER formal_parameter error TYPE 523 |
 524 | program test(input,output);
 525 | var b:real;
 526 | function fun(a:integer)integer;
 527 | begin
 528 | end;
 529 | begin
 530 | 
 531 | end.
 532 | 
533 | 534 | #### 缺少基本类型关键字 535 | subprogram_head ---> FUNCTION IDENTIFIER formal_parameter ':' error 536 |
 537 | program test(input,output);
 538 | var b:real;
 539 | function fun;
 540 | begin
 541 | end;
 542 | begin
 543 | 
 544 | end.
 545 | 
546 | 547 | subprogram_head ---> FUNCTION IDENTIFIER formal_parameter error 548 |
 549 | program test(input,output);
 550 | var b:real;
 551 | function fun(a:integer);
 552 | begin
 553 | end;
 554 | begin
 555 | 
 556 | end.
 557 | 
558 | 559 | #### 不完整的函数头 560 | subprogram_head ---> FUNCTION error 561 |
 562 | program test(input,output);
 563 | var b:real;
 564 | function;
 565 | begin
 566 | end;
 567 | begin
 568 | 
 569 | end.
 570 | 
571 | 572 | subprogram_head ---> FUNCTION IDENTIFIER error 573 |
 574 | program test(input,output);
 575 | var b:real;
 576 | function fun;
 577 | begin
 578 | end;
 579 | begin
 580 | 
 581 | end.
 582 | 
583 | 584 | #### 不完整的过程头 585 | subprogram_head ---> PROCEDURE error 586 |
 587 | program test(input,output);
 588 | var b:real;
 589 | procedure;
 590 | begin
 591 | end;
 592 | begin
 593 | 
 594 | end.
 595 | 
596 | 597 |
 598 | program test(input,output);
 599 | var b:real;
 600 | procedure (a:integer);
 601 | begin
 602 | end;
 603 | begin
 604 | 
 605 | end.
 606 | 
607 | 608 | ### formal_parameter 609 | formal_parameter ---> '(' parameter_list ')' | empty 610 | 611 | #### 不完整的形参列表 612 | formal_parameter ---> '(' error 613 |
 614 | program test(input,output);
 615 | var b:real;
 616 | procedure pro();
 617 | begin
 618 | end;
 619 | begin
 620 | 
 621 | end.
 622 | 
623 | 624 |
 625 | program test(input,output);
 626 | var b:real;
 627 | procedure pro(123);
 628 | begin
 629 | end;
 630 | begin
 631 | 
 632 | end.
 633 | 
634 | 635 |
 636 | program test(input,output);
 637 | var b:real;
 638 | procedure pro(;
 639 | begin
 640 | end;
 641 | begin
 642 | 
 643 | end.
 644 | 
645 | 646 | #### 右括号缺失 647 | formal_parameter ---> '(' parameter_list error 648 |
 649 | program test(input,output);
 650 | var b:real;
 651 | procedure pro(a:integer;
 652 | begin
 653 | end;
 654 | begin
 655 | 
 656 | end.
 657 | 
658 | 659 | ### parameter_list 660 | parameter_list ---> parameter_list ';' parameter | parameter 661 | 662 | #### 缺少分号 663 | parameter_list ---> parameter_list error parameter 664 |
 665 | program test(input,output);
 666 | var b:real;
 667 | procedure pro(var a:integer b:real);
 668 | begin
 669 | end;
 670 | begin
 671 | 
 672 | end.
 673 | 
674 | 675 | ### var_parameter 676 | var_parameter ---> VAR value_parameter 677 | 678 | #### 不完整的引用参数列表 679 | var_parameter ---> VAR error 680 |
 681 | program test(input,output);
 682 | var b:real;
 683 | procedure pro(var );
 684 | begin
 685 | end;
 686 | begin
 687 | 
 688 | end.
 689 | 
690 | 691 |
 692 | program test(input,output);
 693 | var b:real;
 694 | procedure pro(var 123);
 695 | begin
 696 | end;
 697 | begin
 698 | 
 699 | end.
 700 | 
701 | 702 | ### value_parameter 703 | value_parameter ---> idlist ':' TYPE 704 | 705 | #### 缺少分号 706 | value_parameter ---> idlist ':' error 707 |
 708 | program test(input,output);
 709 | var b:real;
 710 | procedure pro(a integer);
 711 | begin
 712 | end;
 713 | begin
 714 | 
 715 | end.
 716 | 
717 | 718 | #### 缺少基本类型关键字 719 | value_parameter ---> idlist ':' error 720 |
 721 | program test(input,output);
 722 | var b:real;
 723 | procedure pro(a:);
 724 | begin
 725 | end;
 726 | begin
 727 | 
 728 | end.
 729 | 
730 | 731 | value_parameter ---> idlist error 732 |
 733 | program test(input,output);
 734 | var b:real;
 735 | procedure pro(var a);
 736 | begin
 737 | end;
 738 | begin
 739 | 
 740 | end.
 741 | 
742 | 743 | ### compound_statement 744 | compound_statement ---> _BEGIN statement_list END 745 | 746 | #### 缺少end关键字 747 | compound_statement ---> _BEGIN statement_list error 748 |
 749 | program test(input,output);
 750 | var b:real;
 751 | begin
 752 | 
 753 | .
 754 | 
755 | 756 | ### statement_list 757 | statement_list ---> statement_list ';' statement | statement 758 | 759 | #### 缺少分号 760 | statement_list ---> statement_list error statement 761 |
 762 | program test(input,output);
 763 | var b:real;
 764 | procedure pro;
 765 | var a:integer;
 766 | begin
 767 |     b:=b;
 768 |     b:=b
 769 |     b:=b
 770 | end;
 771 | begin
 772 | 
 773 | end.
 774 | 
775 | 776 | ### statement 777 | statement ---> variable ASSIGNOP expression | procedure_call | 778 | compound_statement | IF expression THEN statement else_part | 779 | FOR IDENTIFIER ASSIGNOP expression TO expression DO statement | 780 | WHILE expression DO statement | REPEAT statement UNTIL expression | empty 781 | 782 | #### IF语句缺少then关键字 783 | statement ---> IF expression error statement else_part 784 |
 785 | program test(input,output);
 786 | var b:real;
 787 | procedure pro;
 788 | var a:integer;
 789 | begin
 790 |     if a>b
 791 |         b:=1;
 792 | end;
 793 | begin
 794 | 
 795 | end.
 796 | 
797 | 798 | #### FOR语句缺少赋值号 799 | statement ---> FOR IDENTIFIER error expression TO expression DO statement 800 |
 801 | program test(input,output);
 802 | var b:real;
 803 | procedure pro;
 804 | var a:integer;
 805 | begin
 806 |     for a 1 to 2 do
 807 |         b:=1;
 808 | end;
 809 | begin
 810 | 
 811 | end.
 812 | 
813 | 814 | #### FOR语句缺少关键字to 815 | statement ---> FOR IDENTIFIER ASSIGNOP expression error expression DO statement 816 |
 817 | program test(input,output);
 818 | var b:real;
 819 | procedure pro;
 820 | var a:integer;
 821 | begin
 822 |     for a:=1  2 do
 823 |         b:=1;
 824 | end;
 825 | begin
 826 | 
 827 | end.
 828 | 
829 | 830 | #### FOR语句缺少关键字do 831 | statement ---> FOR IDENTIFIER ASSIGNOP expression TO expression error statement 832 |
 833 | program test(input,output);
 834 | var b:real;
 835 | procedure pro;
 836 | var a:integer;
 837 | begin
 838 |     for a:=1 to 2
 839 |         b:=1;
 840 | end;
 841 | begin
 842 | 
 843 | end.
 844 | 
845 | 846 | #### WHILE语句缺少关键字do 847 | statement ---> WHILE expression error statement 848 |
 849 | program test(input,output);
 850 | var b:real;
 851 | procedure pro;
 852 | var a:integer;
 853 | begin
 854 |     while a=1
 855 |         b:=1;
 856 | end;
 857 | begin
 858 | 
 859 | end.
 860 | 
861 | 862 | #### REPEAT语句缺少关键字until 863 | statement ---> REPEAT statement error expression 864 |
 865 | program test(input,output);
 866 | var b:real;
 867 | procedure pro;
 868 | var a:integer;
 869 | begin
 870 |     repeat
 871 |         b:=1
 872 |     a=1;
 873 | end;
 874 | begin
 875 | 
 876 | end.
 877 | 
878 | 879 | ### id_varpart 880 | id_varpart ---> '[' expression_list ']' | empty 881 | 882 | #### 缺少右中括号 883 | id_varpart ---> '[' expression_list error 884 |
 885 | program test(input,output);
 886 | var b:real;
 887 |     c:array[1..5,6..10] of integer;
 888 | procedure pro;
 889 | var a:integer;
 890 | begin
 891 |     repeat
 892 |         c[1,6:=100
 893 |     until a=1;
 894 | end;
 895 | begin
 896 | 
 897 | end.
 898 | 
899 | 900 | #### 不完整的数组下标列表 901 | id_varpart ---> '[' error 902 |
 903 | program test(input,output);
 904 | var b:real;
 905 |     c:array[1..5,6..10] of integer;
 906 | procedure pro;
 907 | var a:integer;
 908 | begin
 909 |     repeat
 910 |         c[:=100
 911 |     until a=1;
 912 | end;
 913 | begin
 914 | 
 915 | end.
 916 | 
917 | 918 |
 919 | program test(input,output);
 920 | var b:real;
 921 |     c:array[1..5,6..10] of integer;
 922 | procedure pro;
 923 | var a:integer;
 924 | begin
 925 |     repeat
 926 |         c[]:=100
 927 |     until a=1;
 928 | end;
 929 | begin
 930 | 
 931 | end.
 932 | 
933 | 934 | ### procedure_call 935 | procedure_call ---> IDENTIFIER | IDENTIFIER '(' expression_list ')' 936 | 937 | #### 缺少右括号 938 | procedure_call ---> IDENTIFIER '(' expression_list error 939 |
 940 | program test(input,output);
 941 | var b:real;
 942 |     c:array[1..5,6..10] of integer;
 943 | procedure pro;
 944 | var a:integer;
 945 | begin
 946 |     pro(a;
 947 | end;
 948 | begin
 949 | 
 950 | end.
 951 | 
952 | 953 | ### expression_list 954 | expression_list ---> expression_list ',' expression | expression 955 | 956 | #### 缺少逗号 957 | expression_list ---> expression_list error expression 958 |
 959 | program test(input,output);
 960 | var b:real;
 961 |     c:array[1..5,6..10] of integer;
 962 | procedure pro;
 963 | var a:integer;
 964 | begin
 965 |     c[a+b a*b]:=1;
 966 | end;
 967 | begin
 968 | 
 969 | end.
 970 | 
971 | 972 | ### factor 973 | factor ---> UINUM | UFNUM | variable | IDENTIFIER '(' expression_list ')' | '(' expression ')' | NOT factor | '-' factor | CHAR 974 | 975 | #### 缺少右括号 976 | factor ---> IDENTIFIER '(' expression_list error 977 |
 978 | program test(input,output);
 979 | var b:real;
 980 |     c:array[1..5,6..10] of integer;
 981 | function fun(d,e:integer):integer;
 982 | begin
 983 |     fun:=d+e;
 984 | end;
 985 | begin
 986 |     c[3,8]:=fun(b;
 987 | end.
 988 | 
989 | 990 | factor ---> '(' expression error 991 |
 992 | program test(input,output);
 993 | var b:real;
 994 |     c:array[1..5,6..10] of integer;
 995 | function fun(d,e:integer):integer;
 996 | begin
 997 |     fun:=d+e;
 998 | end;
 999 | begin
1000 |     c[3,8]:=(b+c;
1001 | end.
1002 | 
1003 | 1004 | #### 函数调用表达式列表缺失 1005 | factor ---> IDENTIFIER '(' error 1006 |
1007 | program test(input,output);
1008 | var b:real;
1009 |     c:array[1..5,6..10] of integer;
1010 | function fun(d,e:integer):integer;
1011 | begin
1012 |     fun:=d+e;
1013 | end;
1014 | begin
1015 |     c[3,8]:=fun(;
1016 | end.
1017 | 
1018 | 1019 | ### 整体黑盒测试 1020 | quick_sort 1021 |
1022 | 
1023 | program quicksort(input,output);
1024 | var
1025 | n,i:integer;
1026 | a:array[0..100000] of integer;
1027 | b:char;
1028 | 
1029 | procedure kp(l,r:integer);
1030 | var
1031 | i,j,mid:integer;
1032 | begin
1033 | b:='a';
1034 | if l>=r then exit;
1035 | i:=l;j:=r;mid:=a[(l+r) div 2];
1036 | repeat
1037 | begin
1038 | while a[i]mid do dec(j);
1040 | if i<=j then
1041 | begin
1042 | a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
1043 | inc(i);dec(j);
1044 | end
1045 | end
1046 | until i>j;
1047 | kp(l,j);
1048 | kp(i,r)
1049 | end;
1050 | 
1051 | begin
1052 | readln(n);
1053 | for i:=1 to n do
1054 | read(a[i]);
1055 | kp(1,n);
1056 | for i:=1 to n do
1057 | write(a[i]);
1058 | end.
1059 | 
1060 | -------------------------------------------------------------------------------- /各模块测试文档/代码生成 - 测试文档.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块测试文档/代码生成 - 测试文档.docx -------------------------------------------------------------------------------- /各模块测试文档/整体设计 - 测试文档.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块测试文档/整体设计 - 测试文档.docx -------------------------------------------------------------------------------- /各模块测试文档/词法分析 - 测试文档.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块测试文档/词法分析 - 测试文档.docx -------------------------------------------------------------------------------- /各模块测试文档/语义分析 - 测试文档.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块测试文档/语义分析 - 测试文档.docx -------------------------------------------------------------------------------- /各模块测试文档/语法分析 - 测试文档 - 不带调试输出.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块测试文档/语法分析 - 测试文档 - 不带调试输出.docx -------------------------------------------------------------------------------- /各模块详细设计/代码生成 - 详细设计.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块详细设计/代码生成 - 详细设计.docx -------------------------------------------------------------------------------- /各模块详细设计/整体设计 - 详细设计.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块详细设计/整体设计 - 详细设计.docx -------------------------------------------------------------------------------- /各模块详细设计/词法分析 - 详细设计.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块详细设计/词法分析 - 详细设计.docx -------------------------------------------------------------------------------- /各模块详细设计/语义分析 - 详细设计.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块详细设计/语义分析 - 详细设计.docx -------------------------------------------------------------------------------- /各模块详细设计/语法分析 - 详细设计.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yorange0/pascal2c-compiler/8687b1bf36819a74f57e4764d7f7c78dadfafafc/各模块详细设计/语法分析 - 详细设计.docx --------------------------------------------------------------------------------