基于GUI的交互式编译系统之中间代码生成器的设计与实现毕业论文.docx

上传人:哈尼dd 文档编号:3323081 上传时间:2019-08-12 格式:DOCX 页数:60 大小:1.09MB
返回 下载 相关 举报
基于GUI的交互式编译系统之中间代码生成器的设计与实现毕业论文.docx_第1页
第1页 / 共60页
基于GUI的交互式编译系统之中间代码生成器的设计与实现毕业论文.docx_第2页
第2页 / 共60页
基于GUI的交互式编译系统之中间代码生成器的设计与实现毕业论文.docx_第3页
第3页 / 共60页
基于GUI的交互式编译系统之中间代码生成器的设计与实现毕业论文.docx_第4页
第4页 / 共60页
基于GUI的交互式编译系统之中间代码生成器的设计与实现毕业论文.docx_第5页
第5页 / 共60页
点击查看更多>>
资源描述

《基于GUI的交互式编译系统之中间代码生成器的设计与实现毕业论文.docx》由会员分享,可在线阅读,更多相关《基于GUI的交互式编译系统之中间代码生成器的设计与实现毕业论文.docx(60页珍藏版)》请在三一文库上搜索。

1、基于GUI的交互式编译系统之中间代码生成器的设计与实现基于GUI的交互式编译系统之中间代码生成器的设计与实现摘要本设计实现了一个编译器前端,它将一个用C语言的子语言编写的源程序翻译成中间代码。词法分析器、语法分析器、中间代码生成器均是采用C+语言手动书写完成,未采用自动生成器,GUI采用Win32 API实现以保证轻快的运行速度及良好的系统性能,编辑控件采用Scintilla。词法分析器采用确定有限自动机实现,语法分析器是一个递归下降分析器,中间代码生成器输出的中间代码以四元式形式表示。本设计实现的编译器前端,运行在Windows平台下,Windows系统版本为Windows XP、Windo

2、ws 7或更高版本。本设计提供了一个可工作的界面友好的编译器前端,可以用来理解编译原理及解释怎样用一种语言如C+实现编译器前端,以供学习和教学所用。关键词:编译器前端;GUI;C+Design & Implementation of Intermediate Code Generator of Interactive Compilation System Based GUIAbstractThis final project implements a compiler front-end, it translates source programs written in a subset of

3、 the C language into intermediate code. The lexer、parser and intermediate code generator are all hand-written in C+, no auto lexer or parser are used, GUI is implemented in Win32 API for fast running speed and high performance, and edit control uses Scintilla. The lexer is implemented in Determinist

4、ic finite automata, the parser is a recursive-descent parser, the intermediate codes are represented in quadruple。The compiler front-end runs on the Windows platform, Windows system version is Windows XP, Windows 7 or later. This project provide a working and user interface friendly compiler front-e

5、nd, which can be used to demonstrate compiler principle and how compilers can be implemented in a language such as C+, for learning and teaching.Keywords: compiler front-end; GUI; C+目录1 绪论32 基本原理32.1 词法分析32.1.1 词法分析结果32.1.2 确定有限自动机32.2 语法分析32.2.1 递归下降分析法32.2.2 运算符的优先级32.3 中间代码生成32.3.1 四元式32.3.2 四元式的

6、常见结构32.4 符号表32.4.1 作用域32.4.2 局部变量名的存储布局33 设计与实现33.1 C子语言33.1.1数据类型33.1.2 字面值33.1.3 表达式33.1.4 语句33.1.5 函数33.2 符号表33.3 词法分析器33.4 语法分析器33.5 中间代码生成器33.6 GUI34 测试3总结3参考文献3致谢3附录 源程序44附件1:开题报告(文献综述)附件2:译文及原文影印件1 绪论很少有人去自己编写或修改编译器,那么为什么要去实现编译器前端呢?很重要的一点就是,理解计算机程序怎样被编译以及执行,可以帮助任何程序员理解他们写的代码是怎样驱动计算机的,从而帮助他们写出

7、更快、更高效的程序。编译原理经过多年发展已日趋成熟,然而现代很多跟编译原理相关的教材,内容陈旧落后,比如以Fortran或Pascal等过时语言为例进行分析讲解,或者全书充满晦涩难懂的定理公式,不能以直观的方式进行阐述,致使学生望而生畏。本设计用C+语言实现了一个编译器前端,它将一个用C子语言编写的源程序翻译成中间代码,拥有友好直观的交互式图形界面,有助于对编译原理的理解,可用于学习及教学。在一段程序可以执行之前,首先需要把它翻译成一种其能够被计算机接受的形式,完成这项翻译工作的程序称为编译器(compiler)1。简单而言,编译器是一个程序,它将使用源语言编写的程序转换成另一种目标语言。在转

8、换阶段很重要的一部分是报告用户当前源程序的错误。为了将源程序从一种语言翻译成另一种语言,编译器必须首先把程序的各种成分拆开,并搞清其结构和含义,然后再把这些成分组合成有意义的计算机能识别的语言。编译器的前端进行词法分析、语法分析和语义分析,并且产生中间代码,即进行分析。编译器的后端对中间代码进行优化并将中间代码翻译成机器语言,即进行组合。词法分析的任务是:对源程序进行从左到右逐个字符地扫描,产生一个个独立的单词符号(token)。词法分析是编译的基础。语法分析的任务是:在词法分析识别出一系列单词符号的基础上,分析并判定源程序的结构是否符合语法规则。语法分析可以粗略地分为两类,一类是自顶向下,一

9、类是自底向上2。对于本设计,采用的是自顶向下进行分析。语法分析得到语法树,尽管可以直接将语法树转换成目标机器代码,但这样做不利于可移植性和模块化设计。假设需要这样一个编译器:它可以编译N种不同的源语言,然后为M台不同的目标机生成代码。理论上,这是N*M个编译器,如图1.1(a),但实现这么多的编译器是需要花费大量的人力物力。中间代码(intermediate code, IC)是一种抽象机器语言,它可以表示目标机的操作而不需太多涉及与机器相关的细节,而且,它也独立于源语言的细节3。一个可移植的编译器如图1.1(b)所示,它先将源语言转换成中间代码,然后再将中间代码转化成目标机器语言,这样便只需

10、要实现N个前端和M个后端。这种实现要更容易合理些。即使在只需实现一个前端和一个后端的情况下,好的中间代码也利于将系统模块化,使得编译器前端不会因机器相关的细节而复杂化,编译器后端不会因源语言的特殊信息而干扰。编译器可以使用的中间代码有多种形式,对于本设计,采用简单的四元式。IC (a) (b)图1.1 面向5种语言并支持4种目标机的编译器:(a)没有IC,(b)有IC编译器的每个阶段都可能遇到错误,如果编译器在遇到第一个错误时就停止运行,对于修正程序肯定起不到多大帮助作用。词法分析阶段可以检测出来自输入的字符串不能形成语言的任何单词符号(token)。语法分析阶段可以检测出违反语言语法的单词符

11、号串。本设计可以报告出错误是什么及错误在源程序的行号和列号。2 基本原理一个编译器是一个计算机程序,它可以把用某种高级语言写的源代码转换成另一种形式,典型的形式是机器码。机器码是计算机可以执行的一系列指令4。int max(int a, int b)if(a b)return a;return b;一个编译器由有两部分组成,如图2.1所示。(1)源代码分析器:它将输入的源代码看作是一个字符串,然后将其翻译成有意义的符号(变量,值,操作符等)。(2)目标代码生成器:它将源代码分析器的结果转换成可执行代码。t1 = -ct2 = b * t1t3 = t1 + t2t4 = t3目标代码源代码目标

12、代码生成器源代码分析器图2.1 编译器结构源代码分析器不依赖于机器,然而目标代码生成器需要针对不同的机器类型生成不同的代码,因此是依赖于机器的。源代码分析器经常被称作编译器的前端,目标代码生成器被称作后端。本设计要实现的正是编译器的前端。编译器的前端又分为三个阶段,如图2.2所示。t1 = -ct2 = b * t1t3 = t1 + t2t4 = t3前端源代码中间代码生成器语法分析器词法分析器图2.2 编译器前端2.1 词法分析词法分析器以字符流作为输入,删除单词之间的空白符和注释(程序中每一部分都有可能出现空白和注释)并生成一系列的名字、关键字和标点符号。如果让语法分析器来处理它们就会使

13、得语法分析过于复杂,结构也不清晰,这便是将词法分析成为一个独立阶段,从语法分析中分离出去的主要原因5。在词法分析器中,词法单元(token)通常包含以下几种类型: 标识符 保留字(如:“if”,“while”等) 数值常量(如:整数,实数等) 字符串常量 简单符号(运算符如:“+”,“-”等,分隔符如:“;”,“,”等) 多重符号(运算符如“+=”,“+”等)这些词法单元将用于下一阶段语法分析。2.1.1 词法分析结果对于下面一段程序:int match(char* str)/ find a zeroif(!strncmp(str, “0”, 1)return 0;词法分析器将产生如下toke

14、ns:INTID(match)LPARENCHARSTARID(str) RPARENLBRACEIFLPARENBANGID(strncmp) LPAREN ID(str) COMMA STRING(0) COMMANUM(1)RPAREN RPAREN RETURN REAL(0)SEMIRBRACEOF2.1.2 确定有限自动机确定有限自动机可用来实现词法分析器。有限自动机包括一个有限状态集合和一些从一个状态通往另一状态的边,每条边上标有一个符号;其中一个状态是初态,某些状态是终态6。图2.3给出了几个有限自动机的例子。if312IFa-z0-910-92120-9IDNUM图2.3 词

15、法单词的有限自动机在确定有限自动机中,不会有从同一状态发出的两条边标记有相同的符号,确定有限自动机以如下方式接受或拒绝一个字符串:从初始状态出发,对于输入串中的每个字符,自动机都将沿着一条确定的边到达另一状态,这条边必须是标有输入字符的边,对n个字符的字符串进行了n次状态转换后,如果自动机到达了一个终态,自动机将接受该字符串,若到达的不是终态,或者找不到与输入字符相匹配的边,那么自动机将拒绝接受该字符串7。2.2 语法分析语法分析是分析如何根据一个文法生成一个终结符号串的过程。一种语言的识别器是一个程序,它把输入看作一个字符串x,如果x是该语言的一个句子,则回答是,否则回答否。大多数分析方法都

16、可以归为以下两类:自顶向下方法和自底向上方法。在自顶向下语法分析器中,构造过程从根结点开始,逐步向叶子节点方向进行,直至推出句子。自顶向下方法可以较容易地手工构造出高效的语法分析器。在自底向上语法分析器中,逐步对输入串进行归约,直至文法的开始符号,即从叶子节点开始,逐步向上归约,直至语法树的根节点。LL(1)文法表示对输入串从左到右扫描,进行最左推导,分析时每步向前查看一个字符。LL(1)分析法需要消除左递归和克服回溯。LR分析法表示对输入串从左到右扫描,构造最右推导的逆过程。LR分析法若采取手工构造,工作量非常大。本设计语法分析采用递归下降分析法。2.2.1 递归下降分析法递归下降分析方法是

17、一种不带回溯的自顶向下语法分析方法,它使用一组递归过程来处理输入。为文法的每个非终结符都创建一个相应的过程。递归下降分析法的一种简单形式是预测分析法。在预测分析法中,各个非终结符号对应的过程中的控制流可以由向前看符号无二义性地确定,在分析输入串时出现的过程调用序列隐式地定义了该输入串的一棵语法树8。假设用预测分析法分析以下文法(黑体字符序列被视为一个单元,也就是单个终结符号):stmtexpr;|if(expr) stmt|for(optExpr; optExpr; optExpr) stmt|otheroptExpr|expr则预测分析器如下所示:void stmt() switch(cur

18、Token) case expr:accept(expr); accept(;);break;case if:accept(if); accept(); accept(expr); accept(); stmt();break;case for:accept(for); accept();optExpr(); accept(;); optExpr(); accept(;) optExpr();accept(); stmt(); break;case other:accept(other); break;default:report(“syntax error”);void optExpr()

19、if(curToken = expr)accept(expr);void accept(terminal t) if(curToken = t)curToken = nextTerminal;elsereport(“syntax error”);该预测分析器中包含了两个过程stmt()和optExpr(),分别对应于文法中非终结符号stmt和optExpr。该分析器中还包括一个额外的过程accept。这个额外的过程用来简化stmt和optExpr()的代码。过程accept(t)将它的参数t和向前看符号比较,如果匹配就前进到下一个输入终结符号。因此,accept改变了全局变量curToken的

20、值,该变量存储了当前正被扫描的输入终结符号。在分析过程的开始,首先调用文法的开始非终结符号stmt对应的过程,根据相应的语法规则,调用相应的处理过程。例如在处理“for(expr; expr; expr) other”输入时,curToken被初始化为第一个终结符号for。每个非终结符都产生一个对相应过程的调用:accept(for); accept();optExpr(); accept(;); optExpr(); accept(;); optExpr();accept(); stmt();2.2.2 运算符的优先级考虑表达式5 + 2 * 3。该表达式可有两种不同的翻译,即(5 +)*

21、3或5 + (2 * 3)。因此当多种运算符出现时,需要给出一些规则来确定运算符之间的相对优先关系。先考虑“+ - * /”这四个常用运算符之间的优先级关系:左结合:+ -左结合:* /创建两个非终结符expr和term,expr对应于“左结合:+-”,term对应于“左结合:*/”,并使用另一个非终结符号factor来表示表达式中的基本单元。当前,表达式中基本单元是数字位和带括号的表达式。factor digit | (expr)现在考虑具有最高优先级的二目运算符*和/。由于这些运算符是左结合的,因此其产生式和左结合列表的产生式类似:term term * factor|term / fac

22、tor|factor类似的,expr生成由加减运算符分隔的term列表:expr expr + term | expr term|term因此最终得到的文法是:expr expr + term | expr term | termterm term * factor | term / factor | factorfactor digit | (expr)2.3 中间代码生成目标代码1目标代码分析器1中间代码目标代码分析器2目标代码2图2.4 中间代码经常会有这种情况,编译器需要为几个目标机器生成机器码或汇编程序。中间代码是跟目标机器无关的,所以相同的中间代码可以在目标语言之间共享(如图2.4

23、)。那么为一台新的机器开发编译器时就可以减少工作量。另外,很容易对中间代码进行优化,优化也是与机器无关的9。中间代码生成阶段将语法树翻译成中间语言表示形式。中间代码是机器无关的,但是它们接近机器指令。源程序通过中间代码生成器翻译成等价的中间语言。中间代码可以是不同的语言,它由编译器的设计者决定。语法树可以作为中间语言,后缀表达式可以作为中间语言,三地址代码(四元式)也可以作为中间语言。在后缀表达式中,任何语句表示都可以不使用括号,如:a * (9 + d) = a9d+*后缀表达式计算可以通过栈来实现。然而使用后缀表达式有很多不利的地方,如后缀表达式生成的汇编代码包含冗余的操作;这些操作只能在

24、汇编代码中进行优化,而不是在中间代码中;优化需要针对特定的目标机器。因此需要一种接近汇编语言的中间代码,它支持机器无关级的优化。所以本设计采用四元式。2.3.1 四元式在四元式中,所有的操作都可以归约为一元或二元操作。这种中间代码可以看成是一系列的执行步骤,每步的执行结果存储在临时变量中10。四元式由如下成分组成: 操作符 操作数,即两个操作数 结果,存储运算结果(operator, arg1, arg2, result)一个简单的表达式可以用一个四元式表示:b + c = (+, b, c, tmp1)稍微复杂的表达式可以由一个四元式集合表示,临时变量存储中间结果。a * (5 + d)=

25、(+, 5, d ,tmp1)(*, a, tmp1, tmp2)2.3.2 四元式的常见结构 算术运算和布尔表达式a + b = (+, a, b, tmp1)a * (b + c) = (+, b, c, tmp1), (*, a, tmp1, tmp2)按照运算顺序,先计算括号中的表达式“b + c”,运算结果保存在临时变量tmp1中,然后计算a * tmp1。a ( (-, a, _, tmp)下划线表示空。 赋值a = a + b = (+, a, b, tmp), (=, tmp, _, a)本设计的赋值运算只支持简单赋值,不支持连续赋值,如a = b = 0。 声明int a,

26、b= 无int a=5 = (=, 5, _, a)声明时可以进行初始化。 数组引用a = xi = (=, xi, _, a)xi = a = (=, a, _, xi) 无条件跳转(jmp, jump_address, _, _)jump_address表示跳转目标地址,在本设计中是一个目标标号。 条件跳转(, i, 5, tmp1)/ 条件(jtrue, jump_address, tmp1, _)/ 表示如果tmp1为真则跳转。注:是条件调转还是无条件调转,由arg2决定。 for循环for(i = 0; i (=, 0, _, i)/ 初始化(label_0:, _, _, _)(,

27、 i, 3, temp_0)/ 条件(jtrue, label_1, temp_0, _)(jmp, label_3, _, _)(label_1:, _, _, _)body of loop.(label_2:, _, _, _)(+, i, 1, i)/ 迭代(jmp, label_0, _, _)(label_3:, _, _, _)每个for语句会产生四个标号,一个表示类似“i = 0”的初始化,一个表示类似“i ”的条件判断,一个表示body,一个表示类似“i+”的表达式。 if-else语句if(a (, a, b, temp_0)(jtrue, label_1, temp_0,

28、_)(jmp, label_0, _, _)(label_1:, _, _, _)(=, a, _, c)(jmp, label_2, _, _)(label_0:, _, _, _)(=, b, _, c)(label_2:, _,_, _)一个if-else语句会产生3个标号,一个表示条件为真时的执行语句,一个表示条件为假的执行语句,一个表示跳出if-else语句。 while语句while(a (label_0:, _, _, _)(, a, b, temp_0)(jtrue, label_1, temp_0, _)(jmp, label_2, _, _)(label_1:, _, _,

29、 _)(+, a, 1, temp_1)(=, temp_1, _, a)(jmp, label_0, _, _)(label_2:, _, _, _)每个while语句产生3个标号,一个表示类似“a = 0”的初始化,一个表示类似“a (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:, _, _

30、, _)(=, 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()int a = 1, b = 1, c;c = add(a, b);=(add:, _, _, _)(enter, 16, _, _)(+, a, b, temp_0)(return, temp_0, _, _)(retu

31、rn, _, _, _)(main:, _, _, _)(enter, 16, _, _)(=, 1, _, a)(=, 1, _, b)(param, b, _, _)(param, a, _, _)(call, add, _, temp_1)(incStackPtr, 8, _, _)(=, temp_1, _, c)(return, _, _, _)每个函数调用会针对主调函数和被调函数产生相应的标号。以上只是列举了一些简单情况下的示例,对于复杂的源程序,翻译成的四元式集是以上常见四元式结构组合的结果。2.4 符号表符号表是一种供编译器用于保存有关源程序构造的各种信息的数据结构,这些信息在

32、编译器的分析阶段被逐步收集并放入符号表11。编译器用符号表跟踪作用域及名字绑定的相关信息。在源程序中每次遇到名字都会去搜索符号表。如果新的名字出现或关于一个已存在名字新的信息出新,要对符号表进行更新。符号表条目可在词法分析阶段、语法分析阶段和语义分析阶段创建(如图2.5)。在本设计中,由语法分析器来创建这些条目。因为相对于词法分析器而言,语法分析器知道一个程序的语法结构,它可以更好地区分一个词法单元的实际意义,因此常更适合创建符号表条目。前端词法分析器中间代码生成器语法分析器符号表图2.5 符号表符号表通常用哈希表实现。KEY:词素(lexeme),VALUE:符号(symbol)。2.4.1

33、 作用域在静态类型编程语言中,变量在使用之前必须声明,声明提供了变量的类型。如: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。为防止引用变量产生冲突,须为每个作用域设置一个符号表。2.4.2 局部变量名的存储布局从变量类型可以知道该变量在运

34、行时刻需要的内存数量。在编译时刻,可以使用这些数量为每个名字分配一个相对地址。名字的类型和相对地址信息保存在相应的符号表条目中12。数据对象的存储布局受目标机器的寻址约束的影响。比如,将整数相加的指令往往希望整数能够对齐(aligned),也就是说,希望它们被放在内存中特定的位置上,比如地址能够被4整除的位置上。类型的宽度(width)是指该类型的一个对象所需的存储单元的数量。一般情况下,字符类型(char)占用一个字节,整型(int)占用4个字节。可以使用一个变量,比如offset,来跟踪下一个可用的相对地址。在考虑第一个声明之前,offset被设置为0。每处理一个变量x时,x被加入符号表,

35、它的相对地址被设置为offset的当前值,随后,x类型的宽度被加到offset上。3 设计与实现3.1 C子语言本设计将一个用C子语言编写的源程序翻译成中间代码,该子语言描述如下:3.1.1数据类型该子语言支持两种数据类型: int:32位有符号整型。 char: 8位无符号整型。只支持静态数组。如果传递一个数组给函数,数组将会以指针形式传递,所以对于数组的任何更改,将会影响调用函数传递的数组。另外,如果超过了数组的长度,调用函数的栈结构将会被破坏。每个作用域中的局部变量应该在该作用域块的开始即任何其他语句之前进行声明,就像以前的C98标准那样。3.1.2 字面值 整型,如:2343, -12

36、3 字符串, 如:“Hi, my name is XiKangjien” 字符, 如:a, n3.1.3 表达式表达式中只支持以下运算符:+,-,后缀+和-,*,/,%,=,=,|, &布尔表达式中不支持短路代码。在短路代码中,布尔运算符&、|和!被翻译成跳转指令。运算符本身不出现在代码中,布尔表达式的值是通过代码序列中的位置来表示的。3.1.4 语句 if-else语句 switch语句 while语句 do-while语句 for语句 break和continue语句3.1.5 函数有几个内建的函数用来基本的输入输出,它们是:- printStr(char str); printStr(s

37、tring);在标准输出中打印一个以null结尾的字符串。- printChar(char c);- printInt(int n);- readStr(char buffer, int bufferSize);- readInt(int n)这些函数会调用标准C输入输出函数,如printf和scanf,另外,这些函数名被视为关键字,所以它们是该语言语法的一部分。可以自定义函数。但是,需要知道这里不支持函数的前向声明:int f(int x);所以应该注意定义函数的顺序,当定义了很多相互调用的函数,会使程序变得复杂。另外,本子语言尽可能合理地去实现作用域,局部变量的作用域和生存周期就像C语言那

38、样,但是没有全局作用域,也就是说不能定义全局变量。可是,在函数内部,可以自由嵌套作用域。比如:void foo()int x, y;/ 嵌套块,产生一个新的内部作用域。int x; / 嵌套作用域中的定义的x,它会将外部作用域中x覆盖。if (true)int x; / if块中定义的变量x, 它会将外部作用域中x覆盖。在这个子语言中有很多的限制,比如没有类型检测,只有少量的语义分析等等。所以在此不是创建一种新的语言,而是以此子语言为例编写一个编译器前端。3.2 符号表一个符号表必须允许添加新项,查找已存在项,支持在编译期间动态增长符号表。符号表可以实现为线性表和哈希表,线性表虽然容易实现,但

39、表很大时性能会很差,所以本设计采用哈希表。本设计的符号表由类SymbolTable实现,其内部存储结构由哈希表实现(这里使用标准容器unordered_map),KEY代表词素(lexeme),VALUE代表与该词素对应的符号(Symbol)。符号由类Symbol实现。由于作用域可以嵌套,同时又要为每个作用域创建一个符号表,所以在类SymbolTable中,容器inner_scopes_存储嵌套的内部作用域,容器中的每个元素为指向内部作用域符号表的指针。指针outer_scope_指向外部作用域符号表。在创建一个符号表时,要为其传递外部作用域符号表参数,若当前创建的符号表为根符号表,则默认为其

40、传递参数NULL。在符号表中插入新项有两种方式。一是插入Symbol,二是插入词素和词法单元标记。通过词素获取相应的符号,由重载运算符实现。class SymbolTablepublic:SymbolTable(SymbolTable* prev = NULL) : outer_scope_(prev) SymbolTable();bool Insert(Symbol* symbol);bool Insert(const std:string& lexeme, TokenTag tag);bool IsInCurrentScope(const std:string& lexeme) const

41、;/ 重载了运算符,可以直接通过symboltablekey来获取value。Symbol* operator (const std:string& key);std:vector inner_scopes_;/ 内部作用域指针。SymbolTable* outer() return outer_scope_; private:SymbolTable* outer_scope_;/ 指向外部作用域/ 用哈希map存储符号表。std:unordered_map table_;类Symbol表示符号表的符号,它也是类VariableSymbol和类FunctionSymbol的基类。一个符号由词素和相应的词法单元标记组成,一个用于关键字if的符号对象可以通过以下语句创建:Symbol symbol_if(“if”, IF);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/环境 > 装饰装潢


经营许可证编号:宁ICP备18001539号-1