基于gui的交互式编译系统之中间代码生成器的设计与实现毕业论文(编辑修改稿)内容摘要:

(label_2:, _, _, _) (+, i, 1, i) // 迭代 (jmp, label_0, _, _) (label_3:, _, _, _) 每个 for 语句会产生四个标号,一个表示类似“ i = 0”的初始化,一个表示类似“ i 3”的条件判断,一个表示 body,一个表示类似“ i++”的表达式。  ifelse 语句 if(a b) 基于 GUI 的交互式编译系统之中间代码生成器的设计与实现 12 c = a。 else c = b。 = (, a, b, temp_0) (jtrue, label_1, temp_0, _) (jmp, label_0, _, _) (label_1:, _, _, _) (=, a, _, c) (jmp, label_2, _, _) (label_0:, _, _, _) (=, b, _, c) (label_2:, _, _, _) 一个 ifelse 语句会产生 3 个标号,一个表示条件为真时的执行语句,一个表示条件为假的执行语句,一个表示跳出 ifelse 语句。  while 语句 while(a b) a = a + 1。 = (label_0:, _, _, _) (, a, b, temp_0) (jtrue, label_1, temp_0, _) (jmp, label_2, _, _) (label_1:, _, _, _) (+, a, 1, temp_1) (=, temp_1, _, a) (jmp, label_0, _, _) (label_2:, _, _, _) 每个 while 语句产生 3 个标号,一个表示类似“ a = 0”的初始化,一个表示类似“ a b”的条件判断,一个表示 body。 基于 GUI 的交互式编译系统之中间代码生成器的设计与实现 13  switch 语句 switch(i) { case 1: a = a + 1。 break。 default: a = a + 2。 } = (jmp, label_0, _, _) (label_3:, _, _, _) (+, a, 1, temp_0) (=, temp_0, _, a) (jmp, label_2, _, _) (label_1:, _, _, _) (+, a, 2, temp_1) (=, temp_1, _, a) (jmp, label_2, _, _) (label_0:, _, _, _) (==, i, 1, temp_2) (jtrue, label_3, temp_2, _) (jmp, label_1, _, _) (label_2:, _, _, _) 每个 switch 语句会 针对相应的 case 和 default 产生标号,同时,还会产生跳出 switch的标号。  函数调用 int add(int a, int b) { return a + b。 } void main() 基于 GUI 的交互式编译系统之中间代码生成器的设计与实现 14 { int a = 1, b = 1, c。 c = add(a, b)。 } = (add:, _, _, _) (enter, 16, _, _) (+, a, b, temp_0) (return, temp_0, _, _) (return, _, _, _) (main:, _, _, _) (enter, 16, _, _) (=, 1, _, a) (=, 1, _, b) (param, b, _, _) (param, a, _, _) (call, add, _, temp_1) (incStackPtr, 8, _, _) (=, temp_1, _, c) (return, _, _, _) 每个函数调用会针对主调函数和被调函数产生相应的标号。 以上只是列举了一些简单情况下的示例,对于复杂的源程序,翻译成的四元式集是以上常见四元式结构组合的结果。 符号表 符号表是一种供编译器用于保存有关源程序构造的各种信息的数据结构,这些信息在编译器的分析阶段被逐步收集并放入符号表 [11]。 编译器用符号表跟踪作用域及名字绑定的相关信息。 在源程序 中每次遇到名字都会去搜索符号表。 如果新的名字出现或关于一个已存在名字新的信息出新,要对符号表进行更新。 符号表条目可在词法分析阶段、语法分析阶段和语义分析阶段创建(如图 )。 在基于 GUI 的交互式编译系统之中间代码生成器的设计与实现 15 本设计中,由语法分析器来创建这些条目。 因为相对于词法分析器而言,语法分析器知道一个程序的语法结构,它可以更好地区分一个词法单元的实际意义,因此常更适合创建符号表条目。 图 符号表 符号表通常用哈希表实现。 KEY:词素( lexeme), VALUE:符号( symbol)。 作用域 在静态类型编程语言中,变量在使用之前必须声明,声明提供了变量的类型。 如:int a。 char c。 通常,声明只在它的作用域内有效。  函数作用域:每个变量在函数内部定义。  块作用域:变量只在代码块内有效。 float foo(int a, float b) { int c。 // c 为局部作用域中变量。 { int b = 100。 // 块作用域中定义的 b 将参数 b 覆盖。 c = a + b。 // 将参数 a 的值与新定义的 b 值之和赋值给 c。 } return float(c) / b // 此处的 b 为参数 b。 } 为防止引用变量产生冲突,须为每个作用域设置一个符号表。 前端 词法分析器 语法分析器 中间代码生成器 符号表 基于 GUI 的交互式编译系统之中间代码生成器的设计与实现 16 局部变量名的存储布局 从变量类型可以知道该变量在运行时刻需要的内存数量。 在编译时刻,可以使用这些数量为每个名字分配一个相对地址。 名字的类型和相对地址信息保存在相应的符号表条目中 [12]。 数据对象的存储布局受目标机器的寻址约束的影响。 比如,将整数相加的指令往往希望整数能够对齐( aligned),也就是说,希望它们被放在内存中特定的位置上,比如地址能够被 4 整除的位置上。 类型的宽度( width)是指该类型的一个对象所需的存储单元的数量。 一般情况下,字符类型( char)占用一个字节,整型( int)占用 4 个字节。 可以使用一个变量,比如 offset,来跟踪下一个可用的相对地址。 在考虑第一个声明之前, offset 被设置为 0。 每处理一个变量 x 时, x 被加入符号表,它的相对地址被设置为 offset 的当前值,随后, x 类型的宽度被加到 offset 上。 基于 GUI 的交互式编译系统之中间代码生成器的设计与实现 17 3 设计与实现 C 子语言 本设计将一个用 C 子语言编写的源程序翻译成中间代码,该C子语言描述如下: 数据类型 该 子语言支持两种数据类型:  int: 32 位有符号整型。  char: 8 位无符号整型。 只支持静态数组。 如果 传递一个数组给函数,数组将会以指针形式传递,所以对于数组的任何更改,将会影响调用函数传 递的数组。 另外,如果超过了数组的长度,调用函数的栈结构将会被破坏。 每个作用域中的局部变量应该在该作用域块的开始即任何其他语句之前进行声明,就像以前的 C98 标准那样。 字面值  整型,如: 2343, 123  字符串, 如:“ Hi, my name is XiKangjie\n”  字符, 如: ’a’, ‘\n’ 表达式 表达式中只支持以下运算符: +, ,后缀 ++和 , *, /, %, , =, , =, ==, ||, amp。 amp。 布尔表达式中不支持短路代码。 在短路代码中,布尔运算符 amp。 amp。 、 ||和。 被翻译成跳转指令。 运算符本身不出现在代码中,布尔表达式的值是通过代码序列中的位置来表示的。 基于 GUI 的交互式编译系统之中间代码生成器的设计与实现 18 语句  ifelse 语句  switch 语句  while 语句  dowhile 语句  for 语句  break 和 continue 语句 函数 有几个内建的函数用来基本的输入输出,它们是: printStr(char str[])。 printStr(string)。 在标准输出中打印一个以 null 结尾的字符串。 printChar(char c)。 printInt(int n)。 readStr(char buffer[], int bufferSize)。 readInt(int n) 这些函数会调用标准 C 输入输出函数,如 printf 和 scanf,另外,这些函数名被视为关键字,所以它们是该语言语法的一部 分。 可以自定义函数。 但是,需要知道这里不支持函数的前向声明 : int f(int x)。 所以应该注意定义函数的顺序,当 定义了很多相互调用的函数 ,会使程序变得复杂。 另外,本子语言 尽可能合理地去实现作用域,局部变量的作用域和生存周期就像 C语言那样,但是没有全局作用域 ,也就是说不能定义全局变量。 可是,在函数内部, 可以自由嵌套作用域。 比如: void foo() { int x, y。 // 嵌套块,产生一个新的内部作用域。 { 基于 GUI 的交互式编译系统之中间代码生成器的设计与实现 19 int x。 // 嵌套作用域中的定义的 x,它会将外部作用域中 x 覆盖。 if (true) { int x。 // if 块中定义的变量 x, 它会将外部作用域中 x 覆盖。 } } } 在这个子语言中有很 多的限制,比如没有类型检测,只有少量的语义分析等等。 所以在此 不是创建一种新的语言,而是以此子语言为例编写一个编译器前端。 符号表 一个符号表必须允许添加新项,查找已存在项,支持在编译期间动态增长符号表。 符号表可以实现为线性表和哈希表,线性表虽然容易实现,但表很大时性能会很差,所以本设计采用哈希表。 本设计的符号表由类 SymbolTable 实现,其内部存储结构由哈希表实现(这里使用标准容器 unordered_map), KEY 代表词素( lexeme), VALUE 代表与该词素对应的符号( Symbol)。 符号由类 Symbol 实现。 由于作用域可以嵌套,同时又要为每个作用域创建一个符号表,所以在类SymbolTable 中,容器 inner_scopes_存储嵌套的内部作用域,容器中的每个元素为指向内部作用域符号表的指针。 指针 outer_scope_指向外部作用域符号表。 在创建一个符号表时,要为其传递外部作用域符号表参数,若当前创建的符号表为根符号表,则默认为其传递参数 NULL。 在符号表中插入新项有两种方式。 一是插入 Symbol,二是插入词素和词法单元标记。 通过词素获取相应的符号,由重载运算符 []实现。 class SymbolTable { public: SymbolTable(SymbolTable* prev = NULL。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。