实现一个C++实现的拓展C0文法MIPS交叉编译器
本文禁止任何爬虫爬取!来源:http://www.cnblogs.com/sciencefans/
学期终于结束了~这学期学习了编译原理,同时做了北航最高难度的编译课程设计——设计实现一个拓展C0文法的编译器。
那么接下来贴一下编译器设计的设计和实现细节吧。
本文将介绍一个小型编译系统的实现,通过作者在两个月的课程设计中总结出来的一些经验接地气地讲一讲如何一步一步构建一个编译器,详尽的说明其中的很多困难,以及作者是如何一步一步解决他们的。让拥有很少编程经验的同学也能够有所收获。
本系统实现了一个以扩充C0文法为输入语言的采用C++语言和面向过程的思路设计的编译器,采用递归子程序的方法来设计分析过程。可以生成符合MIPS指令集规范的汇编代码,用MARS汇编可生成32位应用程序。
本系统考虑到不同MIPS模拟器的功能和使用方法的差异,以及用户手工键入汇编,多有不便,本系统采用了在windows,Linux和mac系统下均可是用的Mars simulator作为模拟工具。
课程设计一发下来,只有一个PPT,一个文档样例,一个需求说明和三种难度的文法。没有任何的指导手册和讲解,完全要靠自己啦~
毕竟初生牛犊不怕虎,习惯性地选择了高难度。点开之后发现居然有四十多条文法,很多还是复合文法。感觉有些复杂,再加上这种比较大的工程如果一开始没有设计好到最后会非常痛苦,所以即使有一些设计的想法在证明完备之前也一时不敢下手。
后来去图书馆查阅了一些相关的书籍,发现不论是C,Pascal还是Fortran,都是遵循词法分析->一种语法语义分析的方法->转换为中间代码->生成机器指令并链接这样的步骤来的,感觉如果自己这样也应该不会有什么大错,于是就从词法分析开始写起。
刚开始写lax的时候感觉不就是一个状态比较多的自动机么,于是就很快设计了一个NFA,结果发现光有NFA是远远不行滴,因为存在很多的不确定分支。于是重新翻课本,按照课本上的方法确定花最小化成DFA然后代码实现之后写完了。比如举一个简单的例子,首先我们看下面的NFA,它是从一组词法分析所用的正则表达式转换而来的。这个NFA合并了IF、ID、NUM、error这四个单词的NFA。因此,它的四个接受状态分别代表遇到了四种不同的单词。
设计好之后因为它包含很多的不确定分支和ε,所以需要做一次NFA->DFA的确定化。按照课本上的方法,用ε-闭包的方法就求得了一个DFA,用上图的例子,我们可以得到如下DFA,可以证明这个DFA和上图中的NFA是等价的。
之后,可以采用直接状态机的编码方式来编写,也可以采用逐步判断分支的方式来编写,我采用的是后者,在程序中可以清晰的看见。
在编写的过程中也没有遇到太多困难,我觉得其中值得一提的就是预读行缓冲这个部分了。记得在做这个实验之前就已经阅读了pl0编译器的源码,它也采用了行缓冲技术。当时在阅读源码的时候还感觉很奇怪,从小文件里读字符何必要采用这种十来个byte的buffer缓冲技术呢,当我自己实现的时候我才意识到它的重要性。在出错处理的时候,需要用到它来记录定位出错的位置,此外,在阅读需要回溯的个别文法的时候比如定义变量和定义函数具有相同的前三个词型,这时当判断出了是哪一类的时候需要回溯处理(虽然改写了文法消除了回溯但是回溯会使得程序更加好写,且并不会增加太多效率负担),行缓冲技术在这里就派上用场了,他可以直接读取前几个字符,而不需要再对文件指针进行处理。
词法分析第二个值得一提的就是对于常数的处理了。有些同学采用读取有符号常数的方法,比如“-123”会被当做一个词语读入。但是我觉得这样会导致在语法分析中的极大不便。比如在处理“—123”,“+-123”等这种语句的时候会非常麻烦。于是我将常熟前面的符号都提出来,分别当成两个单词读入,这在后面的语法分析的过程中证明了这是一个非常好的设计选择。
词法分析之后就该写语法分语义分析了。因为是自己开发能,本着能用即可的原则,我才用了最好用程序实现的递归子程序的方法。也称为递归下降法,这是一种适合手写语法编译器的方法,且非常简单。递归下降法对语言所用的文法有一些限制,但递归下降是现阶段主流的语法分析方法,因为它可以由开发人员高度控制,在提供错误信息方面也很有优势。就连微软C#官方的编译器也是手写而成的递归下降语法分析器。使用递归下降法编写语法分析器无需任何类库,编写简单的分析器时甚至连前面学习的词法分析库都无需使用。
我思考了一下语法分析的过程,联想起课堂上老师讲的LL分析法,LR分析法等,感觉每种文法都要有自己的条件,那么我所选到的文法是否符合这个条件呢?这是我当时遇到的难题。尽管当时老师说使用这个方法是问题不大的,顶多需要改一点点文法,但是仍然想自己证明一下放置到最后出现文法不匹配的问题。因为是上下文无关的文法,首先必须要通过超前查看进行分支预测。支持递归下降的文法,必须能通过从左往右超前查看k个字符决定采用哪一个产生式。书上称这种文法为LL(k)文法。这里的超前阅读正是使用了之前我所说的行缓冲技术才能达到这一点,否则直接面向文件操作,一旦涉及到回溯会非常痛苦。这个名字中第一个L表示从左往右扫描字符串,其实就是在行缓冲中进行扫描,这一点可以从我的编译程序中的nnum变量从0开始递增的特性看出来;而第二个L表示最左推导,对于每一个产生式都要从左往右开始分析即可。但是仅仅满足这个是不一定能够使用递归下降分析的。比如如下这个文法:
F → ( E )
E → F * F
E → F / F
当编写非终结符E的解析方法时,需要在两个E产生式中进行分支预测。然而两个E产生式都以F开头,而且F本身又可能是任意长的表达式,无论超前查看多少字符,都无法判定到底应该用乘号的产生式还是除号的产生式。遇到这种情况,我们可以用提取左公因式的方法,将它转化为LL(k)的文法。
我所抽到的文法中不包含左递归问题,但是包含回溯问题,通过稍微改写文法和一些程序上的技巧就轻松解决了,这并不是什么问题。
因为我采用的是一遍扫描的方式,所以在语法分析的时候会同时进行超前一个单词的词法分析以及和语法分析相同位置的语义分析。
语言语义,就是这段代码实际的含义。编程语言的代码必须有绝对明确的含义,这样人们才能让程序做自己想做的事情,在语义不通的情况下需要及时报错。比如最简单的一行代码:a = 1; 它的语义是“将32位整型常量存储到变量a中”。首先我们对“1”有明确的定义,它是32位有符号整型字面量,这里“32位有符号整型”就是表达式“1”的类型。其次,这句话成为合法的编程语言,32位整型常量必须能够隐式转换为a的类型。假设a就是int型变量,那么这条语句就直接将1存储到a所在内存里。如果a是浮点数类型的,那么这句话就隐含着将整型常量1转换为浮点类型的步骤。在语义分析中,类型检查是贯穿始终的一个步骤。类型检查要做到判定每一个表达式的声明类型,判定每一个字段、形式参数、变量声明的类型,判断每一次赋值、传参数时,是否存在合法的隐式类型转换,判断一元和二元运算符左右两侧的类型是否合法(比如+不就不能在bool和int之间进行,但是我得到的问法只包含CHAR和INT这两个类型,所以暂时不用考虑这个问题)。
在语义分析中,符号表和四元式也相继建立起来。
符号表设计是一个很头疼的事情,因为又涉及到一时设计终身受用或者一时马虎终身麻烦的那个关键的“一时”这个阶段。最开始我的设计里只有变量名,类型,值和地址这几个项目。到后来发现在处理函数参数的时候如果不能知道函数定义的参数是多少个,是很难判断函数参数是否正确的,以及在数组定义和使用的过程中很难知道这个变量名是不是数组名,如果是数组名的话那么这个数组应该有多大,引用的时候是否越界等。这时候这些信息从哪来呢?只能从符号表来了。于是又硬生生的给符号表加上了“isVector”、“para”这样的字段,分别表示是否是数组以及数组元素数量、函数参数数量这样的信息。每次定义函数和数组的时候填入这两个字段,之后只需要查询就完美解决了上述问题。
出错处理部分:这个部分是我觉得最繁杂的一个部分了。因为在不同的地方出错,跳读的区间是不同的。所以需要慢慢磨。但是由于技术性较低,所以花了一些时间就搞定了,复杂但不难。
四元式的设计:原以为四元式的设计会比较难,因为对这方面并没有太多了解,但是直到写的时候才发现并不是很难。四元式设计我总结出来需要注意两点:1.一定要设计成上下文无关的四元式,否则转汇编的时候会非常的麻烦;2.数组操作一定要小心。为了给数组赋值我专门创造了一个运算符”[]=, var1, var2, var3”, 它代表VAR1[VAR2] = VAR3。此外还设计了一个“GETA, VAR1, VAR2, VAR3”来表示var3 = VAR1[VAR2],这样就完美的解决了数组操作的问题。
再往后就是转成汇编了。这一块儿存在一些难点。
首先我就在运行栈的设计上卡壳了。因为我并不想把全局变量存在data段上,虽然C采用了这种设计但是我仍然觉得不够“美”。于是我就把全局变量塞到运行栈的栈底区域。但是这就带来一个问题——如何给这些常量变量定位?这个问题也同样存在于之后的函数中的变量常量定位。在临时符号表中不能存出绝对地址,因为我们无法预测在运行的时候运行栈内是怎样的。其实一开始我确实写的是绝对地址…后来我发现这个问题的时候只好全部重新来过,建立用了一个临时符号表来存储变量的相对地址。这样一来变得简单多了——每个函数内的变量常量个数在编译的时候就已经确定好了。于是完全可以用相对于函数起始位置的地址来表示变量的地址。当要对变量进行读写操作的时候只需要将它的相对地址addr进行如下操作就是它的绝对地址:addr($fp)。
但是第一个问题依旧存在——在任何时候都能访问的全局变量该怎么算地址呢?在这里我做了一个小trick,把整个栈底的基地址写在了$t9中,由于T9这个寄存器在我的设计中是不会用到的,所以这样$t9就相当于一个全局FP一样,其中的全局变量和常量都用相对于$t9的相对偏移作为地址存储,这样就完美的解决了变量常量的存储问题。
最后就是优化部分了。我才用了DAG消除公共子表达式,窥孔优化,消除死代码,以及引用计数和FIFO的寄存器分配策略。这些写起来都还挺快的。唯一需要说的就是消除共公共子表达式了。课本用了一个启发式算法求解,但是经过我的大量测试发现很多情况是不适用的。比如当整个图中没有父节点的点有很多的时候,通常采用最左或者随机选点的方式。但是这样冥想是不正确的,因为当一个点所代表的变量是父节点之一,而这个变量在改变之前又被别的节点调用做子节点,这时就会出现使用修改后的数据这一现象的产生。举一个最简单的例子:C=A, A=B, B=C,在到处过程中C有可能写入了A的新数据,而不是A0。为此我自己写了一个可证正确性的算法:
- 通过扫描基本块,由上向下找出有相同的op(对应DAG图中的父节点),var1(对应DAG图中的左子节点),var2(对应DAG图中的右子节点)且var3为临时变量的四元式对(A, B);
- 从B向下继续扫描四元式,寻找所有与B具有相同var3的四元式C1,C2,…;
- 将Ci的var3置为A.var3;
- 删除B,将B之后的四元式前移。
正确性证明:
对于任意在语法分析过程中定义的临时变量$_ti(详见syn.cpp),均有如下定理:$_ti仅会出现在之后四元式的var1和var2位置,永不会被修改
因此我们无需担心DAG图中会出现临时变量重定义的情况。
因此,一旦出现任意两个临时变量有相同的子表达式,完全可以用其中一个代替全部。因此以上算法正确。
至此,整个编译器就已经实现了。
接下来说说具体实现:
1.我所收到的文发如下:
C0文法-数组-无实型-高级
1.<加法运算符> ::= +|- 定义加减法运算符 例子:3+4 a+b 3+a 2.<乘法运算符> ::= *|/ 定义乘除法运算符 例子:1/2 a/2 a/b 3.<关系运算符> ::= <|<=|>|>=|!=|== 定义关系运算符 例子:1<2 a>=3 b!=8 4.<字母> ::= _|a|...|z|A|...|Z 定义字母可以为大小写字母或者下划线 例子:_ a B 5.<数字> ::= 0|<非零数字> 定义数字为0~9的单位数字字符 例子: 0 1 8 6.<非零数字> ::= 1|...|9 定义非零数字为1~9的单位数字字符 例子: 1 8 7.<字符> ::= '<加法运算符>'|'<乘法运算符>'|'<字母>'|'<数字>' 定义字符为以单引号开始和结束,其间有且仅有一个字符。 例子: '+' '/' 'a' '8' 8.<字符串> ::= "{十进制编码为32,33,35-126的ASCII字符}" 定义字符串可以为0个,1个,或多个十进制编码为32,33,35-126的ASCII字符 需要注意的是不包括双引号,但是包括空格 字符串的第一个和最后一个字符为双引号 例子:"hello, world~" 9.<程序> ::= [<常量说明>][<变量说明>]{<有返回值函数定义>|<无返回值函数定义>}<主函数> 定义程序。 限定程序的子成分顺序,必须为常量说明在前,然后是变量说明,以上两者均可没有。 然后是有返回或者无返回的函数定义若干(可以是0个),然后才是主函数 例子: const int a = 3; int b = 4; void f(int a); int f2(); void main(){...} 10.<常量说明> ::= const<常量定义>;{ const<常量定义>;} 定义常量说明可以是一个或者多个const<常量定义>;这样的格式 例子: const int a = 2; const char c = 'b'; 11.<常量定义> ::= int<标识符>=<整数>{,<标识符>=<整数>} | char<标识符>=<字符>{,<标识符>=<字符>} 定义常量定义可以是整型常量或者字符型常量 整型常量的定义格式是int后跟一个或多个<标识符>=<整数>的形式,之间用逗号隔开 字符型常量同理 例子: int a = 2; char b = 'b'; 12.<无符号整数> ::= <非零数字>{<数字>} 定义无符号整数的开头必为非零数字,其后可跟若干个数字 该限定表明以0开头的数字串不属于无符号整数 0就不是无符号整数 例子: 1 99 13.<整数> ::= [+|-]<无符号整数>|0 定义整数是以可省略的正负号开头,后跟无符号整数或者0的字符串 例子: 0 1 3 14.<标识符> ::= <字母>{<字母>|<数字>} 定义标志符是必须由字母为开头,后跟0到多个字母或者数字的字符串 15.<声明头部> ::= int<标识符> | char<标识符> 定义声明头部 16.<变量说明> ::= <变量定义>;{<变量定义>;} 定义变量说明为一个或多个变量定义和分号组成的字符串 17.<变量定义> ::= <类型标识符>(<标识符>|<标识符>‘[’<无符号整数>‘]’){,(<标识符>|<标识符>‘[’<无符号整数>‘]’ )} 定义变量定义,变量可以为一个标志符或者由标志符为起始的数组形式。 例子: int a2bc_d int word[10] 但是不能如下定义: int 34dfn int word[-1] 18.<类型标识符> ::= int | char 定义类型标识符为整数和字符这两种 19.<有返回值函数定义> ::= <声明头部>‘(’<参数>‘)’ ‘{’<复合语句>‘}’ 定义有返回值函数。必须包含头声明头部,参数和复合语句以及必要的括号 例子: int f(char a){ ... ... } char f(char a){ ... ... } 20.<无返回值函数定义> ::= void<标识符>‘(’<参数>‘)’ ‘{’<复合语句>‘}’ 没啥好说的。 例子: void f(char a){ ... ... } 21.<复合语句> ::= [<常量说明>][<变量说明>]<语句列> 定义复合语句是现场两再变量再语句的顺序。 例子: const int a = 2; char b = '4'; ... 22.<参数> ::= <参数表> 。。。 23.<参数表> ::= <类型标识符><标识符>{,<类型标识符><标识符>}| <空> 参数表由若干个类型标识符和标志符的集合组成,其间用逗号隔开。可以为空。 类型标识符和标志符的顺序不能反。 需要注意的事不能有数组形式 例如: int a, char b, int c, 24.<主函数> ::= void main ‘(’ ‘)’ ‘{’<复合语句>‘}’ 例子: void main() { ... } 25.<表达式> ::= [+|-]<项>{<加法运算符><项>} 表达式是由可省略的+-开头的若干个由加法运算符连接的项的字符串 例如: 3*4+2/6-4*a 26.<项> ::= <因子>{<乘法运算符><因子>} 项是由乘法运算符连接的一个或多个因子 例如: 4*b*a 13*6*num[15] 27.<因子> ::= <标识符>|<标识符>‘[’<表达式>‘]’|<整数>|<字符>|<有返回值函数调用语句>|‘(’<表达式>‘)’ 因子是由标志符或标志符后跟方括号括起来的表达式或整数或者字符或者有返回值得函数调用语句或以圆括号括起来的表达式 例如: num[15] num[a] a 4 (3*13+5*a-2/f) 28.<语句> ::= <条件语句>|<循环语句>|‘{’<语句列>‘}’|<有返回值函数调用语句>; |<无返回值函数调用语句>;|<赋值语句>;|<读语句>;|<写语句>;|<空>;|<返回语句>; 29.<赋值语句> ::= <标识符>=<表达式>|<标识符>‘[’<表达式>‘]’=<表达式> 例如: a[3] = 4 b = 5 30.<条件语句> ::= if ‘(’<条件>‘)’<语句>[else<语句>] 例如: if(a > b){ a = 1; b = 2; } 31.<条件> ::= <表达式><关系运算符><表达式>|<表达式> 表达式为0条件为假,否则为真,值得注意的是一个条件中只有一个关系运算符,不支持嵌套 例如: 1&2 a&b a 0 1 32.<循环语句> ::= while ‘(’<条件>‘)’<语句>| for‘(’<标识符>=<表达式>;<条件>;<标识符>=<标识符>(+|-)<步长>‘)’<语句> 循环语句具有如下形式: while(...){ ... } for(...;...;...){ ... } 其中大括号有时可省略 for的括号中各类型元素不能省略也不能乱位。 33.<步长> ::= <非零数字>{<数字>} 步长为以非零数字开始数字串 形式和无符号整数类似 34.<有返回值函数调用语句> ::= <标识符>‘(’<值参数表>‘)’ 例如: f(2, 3) 35.<无返回值函数调用语句> ::= <标识符>‘(’<值参数表>‘)’ 同上 36.<值参数表> ::= <表达式>{,<表达式>}|<空> 值参数表是若干个(包括0)表达式的集合 37.<语句列> ::= {<语句>} 语句列是若干(包括0)个连续语句的集合 38.<读语句> ::= scanf ‘(’<标识符>{,<标识符>}‘)’ 定义读语句是以scanf起始,后接圆括号阔起来的一个或多个以逗号隔开的标识符。 例子: scanf(a, b) 39.<写语句> ::= printf ‘(’<字符串>,<表达式>‘)’| printf ‘(’<字符串>‘)’| printf ‘(’<表达式>‘)’ 定义写语句是以printf为起始的,后接圆括号括起来的字符串或表达式或者两者都有,若两者都存在,则字符串在先,以逗号隔开。 例子: printf("%d", a) printf(a) printf("Hello, compilier!\n") 40.<返回语句> ::= return[‘(’<表达式>‘)’] 返回语句是以return开始,后接可有可无的以圆括号包围的表达式 例子: return 0
2.目标代码说明
目标代码选择为32位MIPS指令集,输出的MIPS汇编程序的后缀名为.s,可以直接在MARS, PCSpim等虚拟机上运行。目标代码生成程序的输入为中间代码生成的DAG图,才用DAG图节点生成的顺序将各个节点依次翻译为MIPS汇编代码。
指令 |
示例 |
语义 |
系统调用 |
syscall |
|
取立即数 |
Li $s1, 100 |
$s1 = 100 |
加 |
Add $s1,$s2,$s3 |
$s3=$s1+$s2 |
立即数加 |
Addi $s1,$s2,100 |
$s3=$s1+100 |
立即数减 |
Subi $s1,$s2,100 |
$s3=$s1-100 |
减 |
sub $s1,$s2,$s3 |
$s3=$s1-$s2 |
乘 |
mult $s2,$s3 |
Hi,Lo=$s2*$s3 |
除 |
div $s2,$s3 |
Lo=$s2/$s3 Hi=$s2 Mod $s3 |
取字 |
Lw $s1,100($s2) |
$s1=memory[$s2+100] |
存字 |
sw $s1,100($s2) |
memory[$s2+100]=$s1 |
Beq |
beq $s1,$s2,100 |
If($s1==$s2) goto PC+4+400 |
Bne |
beq $s1,$s2,100 |
If($s1!=$s2) goto PC+4+400 |
Slt |
slt $s1,$s2, $s3 |
If($s2<$s3) $s1=1; Else $s1=0; |
j |
J 2000 |
Goto 8000 |
jr |
Ja $ra |
Goto $ra |
jal |
Jal 2500 |
$ra=PC+4; Goto 10000; |
3. 优化方案*
1.消除局部公共子表达式
2.常数合并(窥孔优化)
3.消除死代码
4.删除冗余跳转代码
5.通过引用计数和FIFO策略的寄存器分配方案
二.详细设计
1.程序结构
如下图所示
共有七个文件(绿色块表示)。
其中六个功能块分别进行词法分析,语法分析和语义分析,生成中间代码,生成汇编指令,出错处理和优化。
上图中省略的函数和方法包括:
Lax.cpp:
Syn.cpp:
Midcode:
2.类/方法/函数功能
函数功能见上图。
所有函数:
函数名 |
作用和功能 |
词法分析: |
|
void getch(); |
获取一个字符 |
int getsym(); |
获取一个词语 |
语法分析: |
|
void program(); |
程序递归子程序 |
void defhead(); |
定义头部递归子程序 |
void varstate(); |
变量声明递归子程序 |
void vardef(); |
变量定义递归子程序 |
void constdef(int tclass); |
常量定义递归子程序 |
void conststate(); |
常量声明递归子程序 |
void sentencelist(); |
语句列递归子程序 |
void complexsentence(); |
复杂语句递归子程序 |
void sentence(); |
语句递归子程序 |
void condition(); |
条件递归子程序 |
void loopsentence(); |
循环语句递归子程序 |
void valueofpara(); |
值参数表递归子程序 |
void scanfsentence(); |
读语句递归子程序 |
void printfsentence(); |
写语句递归子程序 |
void parametertable(); |
参数表递归子程序 |
void returnsentence(); |
返回语句递归子程序 |
void expression(); |
表达式递归子程序 |
void item(); |
项递归子程序 |
void factor(); |
因子递归子程序 |
中间代码: |
|
void insmidcode(char* op, char* t1, char* t2, char* t3); |
插入中间代码 |
void insmidcode(char* op, int t1, int t2, char* t3); |
|
void insmidcode(char* op, char t1, int t2, char* t3); |
|
char* nextlab(); |
返回下一个label名 |
char* nextvar(); |
返回下一个临时变量名 |
汇编相关: |
|
void midcode2asm(); |
中间代码转汇编 |
int findvartable(char *name); |
在变量表中查找 |
void midcode2asm(); |
中间代码转汇编 |
void insertaddress(int kind, int addr = -1, int nmi = -1); |
向变量表中插入一个变量和地址 |
void pushstack(char* item = "0", int lenth = 1); |
压栈lenth*4个字节 |
void funcasm(); |
开始函数定义 |
int varaddr(char *name); |
求变量的相对fp的地址 |
void dataseg(); |
数据段 |
void jmpasm(); |
跳转 |
void printint(); |
写一个整数语句 |
void callasm(); |
调用函数 |
void setlabasm(); |
放置标签 |
void addasm(); |
四则运算 |
void subasm(); |
|
void mulasm(); |
|
void divasm(); |
|
void greasm(); |
比较运算 |
void geqasm(); |
|
void lssasm(); |
|
void leqasm(); |
|
void eqlasm(); |
|
void neqasm(); |
|
void assasm(); |
变量赋值语句 |
void aassasm(); |
包含数组元素的操作 |
void assaasm(); |
|
void scfasm(); |
读语句 |
void prtasm(); |
写语句 |
void fupaasm(); |
填入参数语句 |
void retasm(); |
函数返回 |
void paraasm(); |
参数声明处理 |
void jneasm(); |
否定则跳转 |
void intcharasm(); |
变量定义语句 |
void constdefasm(); |
常亮定义语句 |
void intcharaasm(); |
变量定义语句 |
3.调用依赖关系
如图所示。
4.符号表管理方案
1 typedef struct{ 2 3 char name[ MAXIDENLEN ]; //identifier name 4 5 int kind; //identifier kind (define as follow) 6 7 int value; //1对于函数来说,表示返回值为Int 0返回值为void 8 9 int address; //address 10 11 int paranum; // 12 13 }symb; 14 15 #define CONST 0 //常亮 16 17 #define VARIABLE 1 //变量 18 19 #define FUNCTION 2 //函数 20 21 #define PARA 3 //参数 22 23 typedef struct { 24 25 symb element[ MAXSYMTABLENUM ]; 26 27 int index; 28 29 int ftotal; //分程序总数 30 31 int findextable[ MAXSYMTABLENUM ];//分程序索引数组 32 33 }symtable; 34 35 extern symtable maintable;
符号管理结构由一张符号表,分程序总数,分程序索引数组和符号表栈顶指针构成。
其中符号表含有名称,类型,值,地址和参数个数这几个属性。
其代表的含义如下所示:
表项 |
含义 |
名称 |
符号的名称,如name, functiona, para1 |
类型 |
CONST 0 //常亮 VARIABLE 1 //变量 FUNCTION 2 //函数 PARA 3 //参数 |
值 |
存储常量的值 |
地址 |
存储这个变量在符号表里的地址 |
参数个数 |
表示函数的参数个数 表示数组的元素数量 |
5.存储分配方案
1.存储方式:采用引用计数算法进行寄存器分配
2.运行栈结构:
如下图所示:
6. 解释执行程序*
本编译器不采用解释执行方式。
7. 四元式设计*
四元式种类 |
代表的含义 |
= , 2 , , temp |
temp = 2; |
[]= , a , i , t |
a[i] = t; |
int , , , a |
int a; |
const,int,5 , a |
const int a = 5; |
char, , 30, a |
char a[30]; |
fupa, , , a |
a is a function parameter |
call, f , , a |
a = f() |
call, f , , |
f() |
<=.., a , b , |
a <= b |
jne , , , lable |
if not satisfy(==false) then jump |
jmp , , , label |
jump to label |
lab:, , , labx |
set label |
geta, a , n , b |
b = a[n] |
ret , , , (a) |
return a / return |
prt , a , b , symb |
print("a", b) |
scf , , , a |
scanf(a) |
func,int, , f |
start of function int f() |
para,int, , a |
f(int a, ...) |
end , , , f |
end of function f |
8. 优化方案*
0.划分基本快:
很明显,在本设计中,有关影响数据的操作只有以+, -, *, /, []=为operation的语句。所以我们只需要不断读取以这些符号为开头的连续四元式规约为同一基本块即可。
1.窥孔优化:
通过窥孔优化合并常数。
不断读取四元式,一旦发现有常数运算的立即变为赋值操作。
2.消除公共子表达式(书上算法有误,自创算法):
课本上DAG图算法的漏洞:由于课本上的通过构造DAG图消除公共子表达式的启发式算法存在明显问题,当有多个变量没有父节点时,启发式算法中进入队列的顺序将会直接影响结果。一旦进入队列顺序不正确,将会导致导出的代码使用了错误的节点变量。
因此,我在这里提出一个新的可证明正确性的算法:
新算法:
1. 通过扫描基本块,由上向下找出有相同的op(对应DAG图中的父节点),var1(对应DAG图中的左子节点),var2(对应DAG图中的右子节点)且var3为临时变量的四元式对(A, B);
2. 从B向下继续扫描四元式,寻找所有与B具有相同var3的四元式C1,C2,…;
3. 将Ci的var3置为A.var3;
4. 删除B,将B之后的四元式前移。
正确性证明:
对于任意在语法分析过程中定义的临时变量$_ti(详见syn.cpp),均有如下定理:
$_ti仅会出现在之后四元式的var1和var2位置,永不会被修改
因此我们无需担心DAG图中会出现临时变量重定义的情况。
因此,一旦出现任意两个临时变量有相同的子表达式,完全可以用其中一个代替全部。因此以上算法正确。
3.删除冗余代码标签:
很多情况下,程序或出现如下的句型:
If(xxxxx){
……
}
……
即不存在else。
此外,还有很多情况会导致在转化成四元式的时候两个甚至多个label连在一起,这样就导致了代码冗余。
算法:
扫描整个四元式,一旦遇到lab:,删除其后的所有相邻lab代码,并更改所有var3为被删除的lab的四元式中跳转指令的var3为最先发现的lab,反复执行直到读完整个四元式。
4.通过引用计数和FIFO策略的寄存器分配方案:
本程序使用s0到s7存储局部变量。
建立一个寄存器表,如下所示:
寄存器 |
变量编号 |
$s0 |
1 |
$s1 |
8 |
$s2 |
7 |
$s3 |
… |
$s4 |
… |
$s5 |
… |
$s6 |
… |
$s7 |
… |
实际运行时的情况举例:
其中symbnum指的是变量在变量表中的编号,cnt为计数的积分,越高使用频率就越大。
通过引用计数算法,扫描整个函数,查找每个变量使用的频度值,从大到小排序,分配寄存器。
9. 出错处理
0.接口:void error(int _errsig, int signal)
1.出错类型和相关信息:
出错名称 |
出错代码 |
出错原因 |
NOSUCHFILE |
999 |
源文件缺少 |
FILEINCOMPLETE |
0 |
文件不完整 |
DOUBLEQUOTESLACK |
1 |
缺少“"” |
UNACCEPTATLECHAR |
2 |
不可接受的字符 |
SINGLEQUOTESLACK |
3 |
缺少“'” |
OUTOFTABLE |
4 |
符号表爆了 |
SYMBOLCONFLICT |
5 |
变量名冲突 |
CSTDEFINEFAIL |
6 |
常量声明失败 |
VARNOTINIT |
7 |
变量未初始化 |
UNKNOWRIGHTSYM |
8 |
等号右边字符非法 |
SEMICOLONLACK |
9 |
丢失“;” |
KEYWORDERROR |
10 |
关键字错误 |
IDENTIFIERLACK |
11 |
丢失标志符 |
RIGHTBRACKLACK |
12 |
丢失“]” |
FUNCTIONNOTFOUND |
13 |
调用函数未定义 |
FORMALPARANUMUNMATCH |
14 |
形参个数不匹配 |
VARNOTDEFINE |
15 |
未定义变量 |
LEFTPARENTLACK |
16 |
丢失“(” |
RIGHTPARENTLACK |
17 |
丢失“)” |
IMMLACK |
18 |
丢失立即数 |
RIGHTBRACELACK |
19 |
丢失“}” |
FUNCTIONRETURNNULL |
20 |
函数无返回值却被用于参数 |
EXPRESSIONERROR |
21 |
表达式缺失或错误 |
UNACCEPTABLESENTENCE |
22 |
句子不合法 |
ASSIGNCONST |
23 |
给常数赋值 |
LEFTBRACELACK |
24 |
缺少“{” |
NONERETURN |
25 |
缺少返回值 |
PLUSMINULACK |
26 |
缺少‘+’或‘-’ |
MAINLACK |
27 |
缺少main函数 |
MOREWORD |
28 |
main函数后面有多余字符 |
CONSTNOTINIT |
29 |
常量没有初始化 |
2.出错处理方式种类:
处理方式名称 |
代码 |
处理方式 |
QUIT |
1 |
直接退出程序 |
DONOTHING |
2 |
不做任何处理 |
ICV |
3 |
跳到下一个类型声明符号int/char/void |
CICVIFIRSP |
4 |
跳到下一个以下集合的元素 { CONSTTK INTTK CHARTK VOIDTK IFTK WHILETK FORTK IDEN RETURNTK SCANFTK PRINTFTK} |
CS |
5 |
跳到下一个逗号或者分号 |
CLR |
6 |
跳到下一个逗号或者括号 |
IWFRSPIFCV |
7 |
跳到下一个语句列的FIRST集合元素之一 |
IWFLIRSPE |
8 |
跳到下一个以下集合的元素: {IFTK WHILETK FORTK LBRACK IDEN RETURNTK SCANFTK PRINTFTK ELSETK RBRACE} |
IWFXXXANE |
9 |
跳到下一个以下集合的元素: { IFTK WHILETK FORTK LBRACK IDEN RETURNTK SCANFTK PRINTFTK SEMICN ELSETK RPARENT COMMA PLUS MINU MULT DIV LSS LEQ GRE GEQ NEQ EQL} |
3.出错处理方式:
1.递归子程序发现错误立即调用error()并传递出错信号;
2.error函数通过接收到的出错信号打印出出错信息和位置信息;
3.通过出错类型型号和位置判断应该如何进行跳读,基本上是遇到错误则跳到同层符号的FIRST集合元素。具体情况具体分析,详见err.cpp。
4.继续执行编译,直到文件结束。
三.操作说明
1.运行环境
代码可在windows,Linux和mac下编译正常执行;
需要Mars进行模拟;
在三种平台下均可使用Mars进行模拟执行生成的汇编代码。
2.操作步骤
1.使用VS201*编译本程序后会出现如下exC0compiler.exe的程序。此即为编译器的主程序。
2.运行编译器程序。
3.将需要编译的文件拖入程序框内,如果路径存在空格,需要加上引号。之后按回车。如图所示:
4.如果编译成功,会出现如下提示,并跳转到第六步:
5.如果编译失败,会出现如下提示:
6.编译成功后,将会生成如下几个文件:
7.可以通过optMidCode.txt和midcode.txt进行比对来看优化效果
8.接下来打开MARS模拟器,导入asmrst.asm,如图:
9.编译执行即可,如图:
10.需要注意的是,任何输入都必须用换行符隔开,这是Mars定义的模拟特性。
下图就是一个正确的输入:
而下图用空格隔开将会导致程序出错:
最后贴一下工程代码,需要注意的是这个代码是历史版本存在一些漏洞:
1 // 2 // glob.h 3 // exc0compiler 4 // 5 // Created by sciencefans on 14/11/19. 6 // Copyright (c) 2014年 sciencefans. All rights reserved. 7 // 8 9 #ifndef exc0compiler_glob_h 10 #define exc0compiler_glob_h 11 #include <string> 12 #include <iostream> 13 #include <fstream> 14 #include <algorithm> 15 #include <vector> 16 #include <map> 17 #include <ctype.h> 18 19 using namespace std; 20 21 ///======================================lax 22 23 extern const int kwdnum; 24 extern char *word[]; 25 26 extern char *wsym[]; 27 28 #define BEGINTK 1 29 #define CALLTK 2 30 #define CASETK 3 31 #define CHARTK 4 32 #define CONSTTK 5 33 #define DEFAULTTK 6 34 #define DOTK 7 35 #define ELSETK 8 36 #define ENDTK 9 37 #define FLOATTK 10 38 #define FORTK 11 39 #define IFTK 12 40 #define INTTK 13 41 #define MAINTK 14 42 #define ODDTK 15 43 #define PRINTFTK 16 44 #define PROCETK 17 45 #define READTK 18 46 #define RETURNTK 19 47 #define RPTTK 20 48 #define SCANFTK 21 49 #define SWITCHTK 22 50 #define THENTK 23 51 #define UTLTK 24 52 #define VARTK 25 53 #define VOIDTK 26 54 #define WHILETK 27 55 #define WRITETK 28 56 #define IDEN 29 57 #define INTCON 30 58 #define CHARCON 31 59 #define STRCON 32 60 #define PLUS 33 61 #define MINU 34 62 #define MULT 35 63 #define PERIOD 36 64 #define DIV 37 65 #define COLON 38 66 #define LSS 39 67 #define QMARK 40 68 #define LEQ 41 69 #define DQMARK 42 70 #define GRE 43 71 #define LPARENT 44 72 #define GEQ 45 73 #define RPARENT 46 74 #define EQL 47 75 #define LBRACK 48 76 #define NEQ 49 77 #define RBRACK 50 78 #define ASSIGN 51 79 #define LBRACE 52 80 #define SEMICN 53 81 #define RBRACE 54 82 #define COMMA 55 83 84 #define CINTCON 56 85 #define CCHARCON 57 86 87 extern ofstream laxrst, midcoderst, asmrst, symtablehis; 88 extern int ch;//the 89 90 extern int line[ 500 ], backupline[ 500 ]; 91 extern int lnum , cnum , llen, prllen; 92 extern FILE* src; 93 94 //define id, num and sym 95 extern string id, prid; 96 extern int num; 97 extern string sym; 98 extern double dnum; 99 extern int symid; 100 101 //declare functioint getsym(); 102 void getch(); 103 int getsym(); 104 bool stringcmp(char* a, char* b); 105 106 107 ///======================================syn 108 void program(); 109 void defhead(); 110 void varstate(); 111 void vardef(); 112 void constdef(int tclass); 113 void conststate(); 114 void sentencelist(); 115 void complexsentence(); 116 void sentence(); 117 void condition(); 118 void loopsentence(); 119 void valueofpara(); 120 void scanfsentence(); 121 void printfsentence(); 122 void parametertable(); 123 void returnsentence(); 124 void expression(); 125 void item(); 126 void factor(); 127 void lower(char* s); 128 //the word tobe dealwith 129 extern int wd; 130 131 #define MAXIDENLEN 30 132 #define MAXSYMTABLENUM 200 133 134 //define symbol table 135 typedef struct{ 136 char name[ MAXIDENLEN ]; //identifier name 137 int kind; //identifier kind (define as follow) 138 int value; //1对于函数来说,表示返回值为Int 0返回值为void 139 int address; //address 140 int paranum; // 141 }symb; 142 #define CONST 0 //常亮 143 #define VARIABLE 1 //变量 144 #define FUNCTION 2 //函数 145 #define PARA 3 //参数 146 /**************************** 147 * symbol table 148 * name kind value address paranum 149 * 150 * 151 * 152 * 153 * 154 ***************************/ 155 typedef struct { 156 symb element[ MAXSYMTABLENUM ]; 157 int index; 158 int ftotal; //分程序总数 159 int findextable[ MAXSYMTABLENUM ];//分程序索引数组 160 }symtable; 161 extern symtable maintable; 162 extern int value; //保存常量的值;对于子程序,0表示void,1表示int 163 extern int address; //变量的地址;函数返回值的地址 164 extern int paranum; //全局变量,用来处理函数定义,因为函数的参数个数只能在参数表子程序执行结束之后才知道,所以只能在后面才插入符号表信息 165 extern int kind; //正在处理的标志符的类型 166 extern char name[ MAXIDENLEN ]; //标志符的名字,包括常量变量和函数 167 extern int hsymid; //上一个单词类型 168 extern char nowitem[ 200 ]; 169 extern int returnnum; //记录是否有返回值 170 extern char procname[ 100 ]; 171 extern int mf; //主函数个数 172 173 174 ///=====================================四元式 175 void insmidcode(char* op, char* t1, char* t2, char* t3); 176 void insmidcode(char* op, int t1, int t2, char* t3); 177 void insmidcode(char* op, char t1, int t2, char* t3); 178 char* nextlab(); 179 char* nextvar(); 180 #define MAXMIDCODE 1000 181 /**************************** 182 * op: symbol of operator 183 * var1: op1 184 * var2: op2 185 * var3: distination var 186 * e.g. 187 * = , 2 , , temp ==> temp = 2; 188 * []= , a , i , t ==> a[i] = t; 189 * int , , , a ==> int a; 190 * const,int,5 , a ==> const int a = 5; 191 * char, , 30, a ==> char a[30]; 192 * fupa, , , a ==> a is a function parameter 193 * call, f , , a ==> a = f() 194 * call, f , , ==> f() 195 * <=.., a , b , ==> a <= b 196 * jne , , , lable ==> if not satisfy(==false) then jump 197 * jmp , , , label ==> jump to label 198 * lab:, , , labx ==> set label 199 * geta, a , n , b ==> b = a[n] 200 * ret , , , (a) ==> return a / return 201 * prt , a , b , symb ==> print("a", b) 202 * scf , , , a ==> scanf(a) 203 * func,int, , f ==> start of function int f() 204 * para,int, , a ==> f(int a, ...) 205 * end , , , f ==> end of function f 206 ****************************/ 207 typedef struct{ 208 char op[ 10 ]; 209 char var1[ 200 ]; 210 char var2[ 30 ]; 211 char var3[ 30 ]; 212 }fourvarcode; 213 extern fourvarcode midcode[ MAXMIDCODE ]; 214 extern int midcodeiter; 215 extern int labelcnt; 216 extern int varcnt; 217 218 ///=====================================优化 219 extern FILE* optcodefile; 220 void printOptimize(); 221 int isconst(char name[]); 222 void delsetlab(); 223 void delpublic(); 224 void combine(); 225 void scan(); 226 227 228 ///=====================================汇编 229 extern int mi; 230 extern int sp; 231 extern int x; 232 void midcode2asm(); 233 int findvartable(char *name); 234 void midcode2asm(); 235 void insertaddress(int kind, int addr = -1, int nmi = -1); 236 void pushstack(char* item = "0", int lenth = 1); 237 void funcasm(); 238 int varaddr(char *name); 239 void dataseg(); 240 void jmpasm(); 241 void printint(); 242 void callasm(); 243 void setlabasm(); 244 void addasm(); 245 void subasm(); 246 void mulasm(); 247 void divasm(); 248 void greasm(); 249 void geqasm(); 250 void lssasm(); 251 void leqasm(); 252 void eqlasm(); 253 void neqasm(); 254 void assasm(); 255 void aassasm(); 256 void assaasm(); 257 void scfasm(); 258 void prtasm(); 259 void fupaasm(); 260 void retasm(); 261 void paraasm(); 262 void jneasm(); 263 void intcharasm(); 264 void constdefasm(); 265 void intcharaasm(); 266 void savesreg(); 267 void loadsreg(); 268 void cnt(char * name); 269 void cntopt(); 270 #endif
1 // 2 // err.h 3 // exc0compiler 4 // 5 // Created by sciencefans on 14/11/15. 6 // Copyright (c) 2014年 sciencefans. All rights reserved. 7 // 8 9 #ifndef exc0compiler_err_h 10 #define exc0compiler_err_h 11 12 #define NOSUCHFILE 999 13 #define FILEINCOMPLETE 0 14 #define DOUBLEQUOTESLACK 1 15 #define UNACCEPTATLECHAR 2 16 #define SINGLEQUOTESLACK 3 17 #define OUTOFTABLE 4 18 #define SYMBOLCONFLICT 5 19 #define CSTDEFINEFAIL 6 //常亮声明失败 20 #define VARNOTINIT 7 //变量未初始化 21 #define UNKNOWRIGHTSYM 8 //等号右边字符非法 22 #define SEMICOLONLACK 9 //丢失“;” 23 #define KEYWORDERROR 10 //关键字错误 24 #define IDENTIFIERLACK 11 //丢失标志符 25 #define RIGHTBRACKLACK 12 //丢失“]” 26 #define FUNCTIONNOTFOUND 13 //调用函数未定义 27 #define FORMALPARANUMUNMATCH 14 //形参个数不匹配 28 #define VARNOTDEFINE 15 //未定义变量 29 #define LEFTPARENTLACK 16 //丢失“(” 30 #define RIGHTPARENTLACK 17 //丢失“)” 31 #define IMMLACK 18 //丢失立即数 32 #define RIGHTBRACELACK 19 //丢失“}” 33 #define FUNCTIONRETURNNULL 20 //函数无返回值却被用于参数 34 #define EXPRESSIONERROR 21 //表达式缺失或错误 35 #define UNACCEPTABLESENTENCE 22 //句子不合法 36 #define ASSIGNCONST 23 //给常数赋值 37 #define LEFTBRACELACK 24 //缺少“{” 38 #define NONERETURN 25 //缺少返回值 39 #define PLUSMINULACK 26 //缺少‘+’或‘-’ 40 #define MAINLACK 27 //缺少main函数 41 #define MOREWORD 28 //main函数后面有多余字符 42 #define CONSTNOTINIT 29 //常量没有初始化 43 44 extern void error(int _errsig, int signal = 0); 45 extern int errnum; 46 #endif
1 // 2 // main.cpp 3 // exc0compiler 4 // 5 // Created by sciencefans on 14/11/14. 6 // Copyright (c) 2014年 sciencefans. All rights reserved. 7 // 8 9 #include "glob.h" 10 #include "err.h" 11 12 using namespace std; 13 14 int prllen; 15 const int kwdnum = 28; 16 char *word[] = { 17 "begin", "$call", "case", "char", "const",//0~4 18 "default", "do", "else", "$end", "float", //5~9 19 "for", "if", "int", "main", "$odd",//10~14 20 "printf", "$procedure", "$read", "return", "$repeat", //15~19 21 "scanf", "switch", "$then", "until", "$var",//20~24 22 "void", "while", "$write"//25~27 23 }; 24 char *wsym[] = { 25 "BEGINTK", "CALLTK", "CASETK", "CHARTK", "CONSTTK", 26 "DEFAULTTK", "DOTK", "ELSETK", "ENDTK", "FLOATTK", 27 "FORTK", "IFTK", "INTTK", "MAINTK", "ODDTK", 28 "PRINTFTK", "PROCETK", "READTK", "RETURNTK", "RPTTK", 29 "SCANFTK", "SWITCHTK", "THENTK", "UTLTK", "VARTK", 30 "VOIDTK", "WHILETK", "WRITETK" 31 }; 32 33 int ch = ' ';//the 34 35 int line[ 500 ], backupline[ 500 ]; 36 int lnum = 0, cnum = 0, llen = 0; 37 FILE* src = NULL; 38 39 //define id, num and sym 40 string id = ""; 41 int num; 42 string sym; 43 double dnum; 44 int symid; 45 string prid; 46 47 48 int getsym(){ 49 prid = id; 50 id = ""; 51 while ( isspace(ch) && ch != EOF ) { 52 getch(); 53 } 54 if ( ch == EOF ){ 55 symid = -1; 56 return -1; 57 } 58 //when the ch is alpha 59 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 60 //!!! this version donnot has lenth limit 61 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 62 if ( isalpha(ch) || ch == '_' ){ 63 string tempstr; 64 while ( isalpha(ch) || isdigit(ch) || ch == '_' ) { 65 ch = tolower(ch); 66 tempstr += ch; 67 getch(); 68 } 69 id = tempstr; 70 //seatch reserved word table 71 int iter = 0; 72 for ( iter = 0; iter < kwdnum; iter++ ) { 73 if ( stringcmp(word[ iter ], (char*)tempstr.c_str()) ) { 74 sym = wsym[ iter ]; 75 symid = iter + 1; 76 break; 77 } 78 } 79 if ( iter == kwdnum ) { 80 sym = "IDEN"; 81 symid = IDEN; 82 } 83 } 84 else if ( isdigit(ch) ){ 85 86 sym = "INTCON"; 87 symid = INTCON; 88 num = 0; 89 while ( isdigit(ch) ){ 90 id += ch; 91 num = num * 10 + (int)( ch - '0' ); 92 getch(); 93 } 94 if ( ch == '.' ) { 95 id += ch; 96 sym = "FLOATCON"; 97 symid = -1; 98 double t = 0.1; 99 dnum = num; 100 getch(); 101 while ( isdigit(ch) ){ 102 id += ch; 103 dnum = dnum + (int)( ch - '0' ) * t; 104 t /= 10; 105 getch(); 106 } 107 } 108 } 109 else if ( ch == '=' ){ 110 id += ch; 111 sym = "ASSIGN"; 112 symid = ASSIGN; 113 getch(); 114 if ( ch == '=' ) { 115 id += ch; 116 sym = "EQL"; 117 symid = EQL; 118 getch(); 119 } 120 } 121 else if ( ch == '<' ){ 122 id += ch; 123 getch(); 124 if ( ch == '=' ) { 125 id += ch; 126 sym = "LEQ"; 127 symid = LEQ; 128 getch(); 129 } 130 else{ 131 sym = "LSS"; 132 symid = LSS; 133 } 134 } 135 else if ( ch == '>' ){ 136 id += ch; 137 getch(); 138 if ( ch == '=' ) { 139 id += ch; 140 sym = "GEQ"; 141 symid = GEQ; 142 getch(); 143 } 144 else{ 145 sym = "GRE"; 146 symid = GRE; 147 } 148 } 149 else if ( ch == '!' ){ 150 id += ch; 151 getch(); 152 if ( ch == '=' ) { 153 id += ch; 154 sym = "NEQ"; 155 symid = NEQ; 156 getch(); 157 } 158 } 159 else if ( ch == '\"' ){ 160 string tempstr; 161 getch(); 162 while ( ch == 32 || ch == 33 || (ch <= 126 && ch >= 35) ) { 163 tempstr += ch; 164 getch(); 165 } 166 if ( ch == '\"' ) { 167 getch(); 168 sym = "STRCON"; 169 symid = STRCON; 170 id = tempstr; 171 } 172 else{ 173 error(DOUBLEQUOTESLACK); 174 return -1; 175 } 176 } 177 else if ( ch == '\'' ){ 178 getch(); 179 if ( ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '_' || isalnum(ch) ) { 180 id += ch; 181 getch(); 182 } 183 else{ 184 error(UNACCEPTATLECHAR); 185 return -1; 186 } 187 if ( ch == '\'' ){ 188 sym = "CHARCON"; 189 symid = CHARCON; 190 getch(); 191 } 192 else{ 193 error(SINGLEQUOTESLACK); 194 return -1; 195 } 196 } 197 else { 198 if ( ch == '+' ){ 199 sym = "PLUS"; 200 symid = PLUS; 201 } 202 else if ( ch == '-' ){ 203 sym = "MINU"; 204 symid = MINU; 205 } 206 else if ( ch == '*' ){ 207 sym = "MULT"; 208 symid = MULT; 209 } 210 else if ( ch == '/' ){ 211 sym = "DIV"; 212 symid = DIV; 213 } 214 else if ( ch == ',' ){ 215 sym = "COMMA"; 216 symid = COMMA; 217 } 218 else if ( ch == ':' ){ 219 sym = "COLON"; 220 symid = COLON; 221 } 222 else if ( ch == ';' ){ 223 sym = "SEMICN"; 224 symid = SEMICN; 225 } 226 else if ( ch == '{' ){ 227 sym = "LBRACE"; 228 symid = LBRACE; 229 } 230 else if ( ch == '[' ){ 231 sym = "LBRACK"; 232 symid = LBRACK; 233 } 234 else if ( ch == '(' ){ 235 sym = "LPARENT"; 236 symid = LPARENT; 237 } 238 else if ( ch == '}' ){ 239 sym = "RBRACE"; 240 symid = RBRACE; 241 } 242 else if ( ch == ']' ){ 243 sym = "RBRACK"; 244 symid = RBRACK; 245 } 246 else if ( ch == ')' ){ 247 sym = "RPARENT"; 248 symid = RPARENT; 249 } 250 id += ch; 251 getch(); 252 } 253 if ( !strcmp(sym.c_str(), "INTCON") ) { 254 laxrst << sym << ' ' << num << endl; 255 } 256 else if ( !strcmp(sym.c_str(), "FLOATCON") ){ 257 laxrst << sym << ' ' << dnum << endl; 258 } 259 else{ 260 laxrst << sym << ' ' << id << endl; 261 } 262 263 return 0; 264 } 265 266 ///read one character in source file and store in 'ch' 267 void getch(){ 268 int i = 0; 269 prllen = llen; 270 if ( cnum == llen && ~line[ llen ] ) { 271 272 ch = fgetc(src); 273 while ( ch == ' ' || ch == '\n' || ch == '\t' ){ 274 if (ch == '\n') { 275 lnum++; 276 } 277 backupline[ i++ ] = ch; //保存源文件的行,用于发生错误时输出 278 ch = fgetc(src); 279 } 280 //保存过滤掉空白字符后的一行字符 281 for ( llen = 0; ch != '\n' && ch != EOF; llen++ ) { 282 line[ llen ] = ch; 283 backupline[ i++ ] = ch; //保存源文件的行,用于发生错误时输出 284 ch = fgetc(src); 285 } 286 if ( ch == EOF ) 287 line[ llen ] = EOF; 288 else 289 line[ llen ] = '\n'; 290 backupline[ i ] = '\0'; 291 292 cnum = 0; 293 ch = '\n'; 294 lnum++; 295 /*midcoderst << "##LINE " << lnum << ": "; 296 for ( int t = 0; t < llen; t++ ){ 297 midcoderst << (char)line[ t ]; 298 } 299 midcoderst << endl;*/ 300 } 301 else{ 302 ch = line[ cnum++ ]; 303 } 304 } 305 306 307 //return: 308 // true: a > b 309 // false: a < b 310 bool stringcmp(char *a, char *b){ 311 int i = 0; 312 while ( true ){ 313 if (( a[ i ] == 0) && (b[ i ] == 0 )) { 314 return true; 315 } 316 else if ( a[ i ] != b[ i ] ){ 317 return false; 318 } 319 else{ 320 i++; 321 } 322 323 } 324 }
1 // 2 // syn.cpp 3 // exc0compiler 4 // 5 // Created by sciencefans on 14/11/18. 6 // Copyright (c) 2014年 sciencefans. All rights reserved. 7 // 8 9 10 11 #include "glob.h" 12 #include "err.h" 13 14 15 16 int wd = -1; 17 symtable maintable; 18 int value; //保存常量的值;对于子程序,0表示void,1表示int 19 int address; //变量的地址;函数返回值的地址 20 int paranum; //全局变量,用来处理函数定义,因为函数的参数个数只能在参数表子程序执行结束之后才知道,所以只能在后面才插入符号表信息 21 int kind; //正在处理的标志符的类型 22 char name[ MAXIDENLEN ]; //标志符的名字,包括常量变量和函数 23 int hsymid; //上一个单词类型 24 char nowitem[ 200 ]; 25 int returnnum = 0; //记录是否有返回值 26 char procname[ 100 ]; 27 int hiscnt = 1; 28 int sislob = 1; 29 int factclass = 0; 30 #define INT 1 31 #define CHAR 2 32 #define subfuncindex(n) maintable.findextable[(n)] 33 34 //fill in symbol table 35 //name: symbol name 36 //kind: the kind of name(see syn.h) 37 //value: the value of const 38 //address: the address of the var 39 //para: the formal parameter of function 40 int arrnum(char *name){ 41 int n; 42 int m = maintable.findextable[ 1 ]; 43 n = maintable.findextable[ maintable.ftotal ]; 44 //查找符号表中是否有 45 while ( n < maintable.index ) { 46 if ( strcmp(maintable.element[ n ].name, name) == 0 ) 47 return maintable.element[ n ].paranum; 48 n++; 49 } 50 51 //如果分程序符号表中无定义,查找最外层符号表 52 if ( n == maintable.index ) { 53 n = 0; 54 while ( n < m ) { 55 if ( strcmp(maintable.element[ n ].name, name) == 0 ) 56 return maintable.element[ n ].paranum; 57 n++; 58 } 59 //符号表中没有定义 60 if ( n == m ) { 61 printf("\"%s\" ", name); 62 //error(VARNOTDEFINE); 63 return -1; 64 } 65 } 66 } 67 68 void pushtable(char* name, int kind, int value, int address, int paranum, int isVec = 0){ 69 70 //whether table is full 71 if ( maintable.index >= MAXSYMTABLENUM ){ 72 error(OUTOFTABLE); 73 exit(0); 74 } 75 76 //whether conflict 77 //function 78 if ( kind == FUNCTION ) { 79 int iter = 1; 80 for ( iter = 1; iter <= maintable.ftotal; iter++ ) { 81 if ( !strcmp(maintable.element[ maintable.findextable[ iter ] ].name, name) ) { 82 error(SYMBOLCONFLICT); 83 return; 84 } 85 } 86 maintable.findextable[ ++maintable.ftotal ] = maintable.index; 87 } 88 else{ 89 //others 90 int iter = maintable.findextable[ maintable.ftotal ]; 91 for ( ; iter < maintable.index; iter++ ) { 92 if ( !strcmp(maintable.element[ iter ].name, name) ) { 93 error(SYMBOLCONFLICT); 94 return; 95 } 96 } 97 //if not para and non-glob-var, compare with global var. 98 if ( kind != PARA && sislob) { 99 iter = 0; 100 while ( iter < maintable.findextable[ 1 ] ) { 101 if ( !strcmp(maintable.element[ iter ].name, name) ) { 102 error(SYMBOLCONFLICT); 103 return; 104 } 105 iter++; 106 } 107 } 108 } 109 110 strcpy(maintable.element[ maintable.index ].name, name); 111 maintable.element[ maintable.index ].kind = kind; 112 maintable.element[ maintable.index ].value = value; 113 maintable.element[ maintable.index ].address = maintable.index; 114 maintable.element[ maintable.index ].paranum = isVec ? isVec : paranum; 115 if (maintable.index <= hiscnt) { 116 symtablehis << "----------------------------------------------------------------" << endl; 117 } 118 hiscnt = maintable.index; 119 symtablehis << maintable.index << "\t" << name << "\t" << kind << "\t" << value << "\t" << address << "\t" << paranum << "\t" << isVec << endl; 120 maintable.index++; 121 } 122 123 void insertproc(int paranum) 124 { 125 int x = maintable.findextable[ maintable.ftotal ]; //array[i],指向的是当前正在被分析的函数在符号表中的索引 126 maintable.element[ x ].paranum = paranum;//插入函数参数个数信息 127 return; 128 } 129 130 //look up symbol table 131 //flag=1时,说明要在分程序索引里查找,flag=0时,在当前所在分程序符号表中查找 132 //flag2=1时,只在当前函数作用域里找 133 int searchst(char* name, int flag, int flag2 = 0){ 134 int n; 135 int m = maintable.findextable[ 1 ]; 136 if ( flag == 1 ) { 137 n = 1; 138 while ( n <= maintable.ftotal ) { 139 if ( strcmp(maintable.element[ maintable.findextable[ n ] ].name, name) == 0 ) 140 break; 141 n++; 142 } 143 144 //如果函数标志符没有定义 145 if ( n > maintable.ftotal ) { 146 printf("\"%s\" ", name); 147 //error(FUNCTIONNOTFOUND); 148 return -1 * FUNCTIONNOTFOUND; 149 } 150 151 //如果函数的实参个数与形参个数不匹配 152 if ( maintable.element[ maintable.findextable[ n ] ].paranum != paranum ) { 153 printf("\"%s\" ", name); 154 //error(FORMALPARANUMUNMATCH); 155 return -1 * FORMALPARANUMUNMATCH; 156 } 157 158 //如果函数标识符无内容 159 if ( maintable.element[ maintable.findextable[ n ] ].value == 0 ) 160 return -1 * FUNCTIONRETURNNULL; 161 162 return maintable.element[ maintable.findextable[ n ] ].address; 163 } 164 else{ 165 n = maintable.findextable[ maintable.ftotal ]; 166 //查找符号表中是否有 167 while ( n < maintable.index ) { 168 if ( strcmp(maintable.element[ n ].name, name) == 0 ) 169 break; 170 n++; 171 } 172 173 //如果分程序符号表中无定义,查找最外层符号表 174 if ( n == maintable.index ) { 175 n = 0; 176 while ( n < m ) { 177 if ( strcmp(maintable.element[ n ].name, name) == 0 ) 178 break; 179 n++; 180 } 181 //符号表中没有定义 182 if ( n == m ) { 183 printf("\"%s\" ", name); 184 //error(VARNOTDEFINE); 185 return -1; 186 } 187 } 188 if ( maintable.element[ n ].kind == INTTK || maintable.element[ n ].kind == CHARTK ) 189 return maintable.element[ n ].address; 190 if ( maintable.element[ n ].kind == CINTCON || maintable.element[ n ].kind == CCHARCON ) 191 return -2; //const 返回负两倍地址 192 if ( maintable.element[ n ].kind == PARA ) 193 return maintable.element[ n ].address; //参数标志 194 return -1; 195 } 196 } 197 198 199 200 //clear symbol table 201 void flushst(){ 202 int x = maintable.index - 1; 203 int y; 204 while ( ( maintable.element[ x ].kind == INTTK || maintable.element[ x ].kind == CHARTK || maintable.element[ x ].kind == CINTCON 205 || maintable.element[ x ].kind == CCHARCON || maintable.element[ x ].kind == PARA ) && strcmp(maintable.element[ x ].name, procname) != 0 ) { 206 maintable.element[ x ].kind = 0; 207 maintable.element[ x ].address = 0; 208 maintable.element[ x ].paranum = 0; 209 maintable.element[ x ].value = 0; 210 y = 0; 211 while ( y<30 ) 212 maintable.element[ x ].name[ y++ ] = '\0'; 213 x--; 214 } 215 maintable.index = x + 1; 216 return; 217 } 218 219 //9.<程序> ::= [<常量说明>][<变量说明>]{<有返回值函数定义>|<无返回值函数定义>}<主函数> 220 void program(){ 221 getsym(); 222 223 if ( symid == CONSTTK ) { 224 //调用常量说明子程序 225 conststate(); 226 //如果是分号,则是正常的 227 } 228 229 //变量定义和有返回值的函数是相同的声明头部。因此预读3个单词用于判断 230 while ( symid == INTTK || symid == CHARTK ) { 231 int tempid = symid;//恢复现场用 232 char tempch = ch;//恢复现场用 233 int tempcnum = cnum;//恢复现场用 234 kind = symid; 235 getsym(); 236 strcpy(name, id.c_str());//拷贝名字 237 238 //如果标识符合法 239 if ( symid != IDEN ) { 240 error(IDENTIFIERLACK);//notdone 241 continue; 242 } 243 getsym(); 244 //如果是逗号或者分号,则是变量定义 245 if ( symid == COMMA || symid == LBRACK ) { 246 symid = tempid; 247 cnum = tempcnum; 248 ch = tempch; 249 varstate(); 250 continue; 251 } 252 else if ( symid == SEMICN ) { 253 value = 0; 254 address = 0; 255 paranum = 0; 256 pushtable(name, kind, value, address, paranum); 257 if ( kind == INTTK ) insmidcode("int", " ", " ", name); 258 else if ( kind == CHARTK ) insmidcode("char", " ", " ", name); 259 getsym(); 260 continue; 261 } 262 else{ 263 symid = tempid; 264 cnum = tempcnum; 265 ch = tempch; 266 break; 267 } 268 } 269 if ( symid == CONSTTK ) { 270 errnum++; 271 printf("Error %d: Line %d, 常量定义位置错误!\n", errnum, lnum); 272 conststate(); 273 //如果是分号,则是正常的 274 } 275 sislob = 0; 276 //进入函数部分 277 while ( symid == INTTK || symid == CHARTK || symid == VOIDTK ) { 278 int temp = symid; 279 280 //19.<有返回值函数定义> ::= <声明头部>‘(’<参数>‘)’ ‘{’<复合语句>‘}’ 281 if ( symid == INTTK || symid == CHARTK ) { 282 defhead(); 283 if ( symid != LPARENT ) { 284 error(LEFTPARENTLACK); 285 continue; 286 } 287 varcnt = 0; //临时变量重新开始计数 288 returnnum = 0;//将是否存在返回值的标记初始化,0表示无返回值,即未出现return 289 kind = FUNCTION;//表示当前的函数是子程序,即非主函数 290 value = 1;//1对于函数来说,表示返回值为Int 0返回值为void 291 address = 0; 292 paranum = 0; 293 pushtable(name, kind, value, address, paranum); 294 strcpy(procname, name);//函数名拷贝 295 if ( temp == INTTK ) insmidcode("func", "int", " ", procname); 296 if ( temp == CHARTK ) insmidcode("func", "char", " ", procname); 297 getsym(); 298 parametertable(); 299 //缺'('<参数>')'的右小括号 300 if ( symid != RPARENT ){ 301 error(RIGHTPARENTLACK); 302 continue; 303 } 304 getsym(); 305 //缺'{'<复合语句>'}'的左大括号 306 if ( symid != LBRACE ) { 307 error(LEFTBRACELACK); 308 continue; 309 } 310 getsym(); 311 complexsentence(); 312 //缺'{'<复合语句>'}'的右大括号 313 if ( symid != RBRACE ) { 314 error(RIGHTBRACELACK); 315 continue; 316 } 317 318 //函数缺少返回值 319 if ( returnnum == 0 ) { 320 error(NONERETURN); 321 continue; 322 } 323 getsym(); 324 insmidcode("end", " ", " ", procname);//函数部分四元式结束 325 flushst();//清除符号表,这里清空的是此子函数的符号表,不清除子函数名 326 } 327 328 if ( symid == VOIDTK ) { 329 getsym(); 330 //如果下一个单词是main,则是<主函数> ::= void main '(' ')' '{'<复合语句>'}' 331 if ( symid == MAINTK ) { 332 varcnt = 0; //临时变量重新开始计数 333 strcpy(name, "main"); 334 kind = FUNCTION; 335 value = 0; 336 address = 0; 337 paranum = 0; 338 pushtable(name, kind, value, address, paranum); 339 strcpy(procname, name); 340 insmidcode("func", " ", " ", procname); 341 getsym(); 342 if ( symid != LPARENT ) { 343 error(LEFTPARENTLACK); 344 continue; 345 } 346 getsym(); 347 if ( symid != RPARENT ) { 348 error(RIGHTPARENTLACK); 349 continue; 350 } 351 getsym(); 352 if ( symid != LBRACE ) { 353 error(LEFTBRACELACK); 354 continue; 355 } 356 getsym(); 357 complexsentence(); 358 mf++; //主函数的个数+1 359 insmidcode("end", " ", " ", procname); 360 if ( symid != RBRACE ) 361 { 362 error(RIGHTBRACELACK); 363 continue; 364 } 365 return; //源程序结束,跳出 366 } 367 368 //20.<无返回值函数定义> ::= void<标识符>‘(’<参数>‘)’ ‘{’<复合语句>‘}’ 369 if ( symid != IDEN ) { 370 error(IDENTIFIERLACK); 371 continue; 372 } 373 varcnt = 0; //临时变量重新开始计数 374 strcpy(name, id.c_str()); 375 376 kind = FUNCTION; 377 value = 0; 378 address = 0; 379 paranum = 0; 380 pushtable(name, kind, value, address, paranum); 381 strcpy(procname, name); 382 insmidcode("func", "void", " ", procname); 383 getsym(); 384 if ( symid != LPARENT ) { 385 error(LEFTPARENTLACK); 386 continue; 387 } 388 getsym(); 389 parametertable(); 390 if ( symid != RPARENT ) { 391 error(RIGHTPARENTLACK); 392 continue; 393 } 394 getsym(); 395 if ( symid != LBRACE ) { 396 error(LEFTBRACELACK); 397 continue; 398 } 399 getsym(); 400 complexsentence(); 401 if ( symid != RBRACE ) { 402 error(RIGHTBRACELACK); 403 continue; 404 } 405 getsym(); 406 insmidcode("end", " ", " ", procname); 407 flushst(); 408 } 409 } 410 } 411 412 413 //18.<类型标识符> ::= int | float | char 414 //22.<参数> ::= <参数表> 415 //23.<参数表> ::= <类型标识符><标识符>{,<类型标识符><标识符>}| <空> 416 void parametertable() 417 { 418 int i = 0; //记录参数个数 419 int temp; 420 if ( symid == INTTK || symid == CHARTK ) { 421 do{ 422 if ( symid == COMMA ) 423 getsym(); 424 temp = symid; 425 defhead(); //函数参数和变量定义时完全相同的,只是最后不是以分号结尾 426 kind = PARA; //4表示为函数参数 427 value = 0; 428 address = i; //地址为i,即参数的位置,地址全部为相对地址? 429 paranum = 0; 430 pushtable(name, kind, value, address, paranum); //将行数参数插入符号表 431 if ( temp == INTTK ) insmidcode("para", "int", " ", name); 432 else if ( temp == CHARTK ) insmidcode("para", "char", " ", name); 433 i++;//参数个数加一 434 } while ( symid == COMMA );//如果是逗号,则还有其他的参数 435 } 436 paranum = i;//当前的参数个数 437 insertproc(paranum);//插入函数的参数个数 438 return; 439 } 440 441 //10.<常量说明> ::= const<常量定义>;{ const<常量定义>;} 442 //ATTENTION:在这里会直接读出类型 443 void conststate(){ 444 while ( symid == CONSTTK ) { 445 getsym(); 446 int tclass; 447 if ( symid == INTTK || symid == CHARTK ) { 448 kind = ( symid == INTTK ) ? CINTCON : CCHARCON; 449 address = 0; 450 paranum = 0; 451 tclass = symid; 452 getsym(); 453 constdef(tclass); 454 while ( symid == COMMA ) { 455 getsym(); 456 constdef(tclass); 457 } 458 //定义结束,下一个字符一定是分号 459 if ( symid != SEMICN ) { 460 error(SEMICOLONLACK); 461 return; 462 } 463 hsymid = symid; 464 getsym(); 465 } 466 else{ 467 error(KEYWORDERROR); 468 return; 469 } 470 } 471 return; 472 } 473 474 //11.<常量定义> ::= int<标识符>=<整数>{,<标识符>=<整数>} | char<标识符>=<字符>{,<标识符>=<字符>} 475 //ATTENTION:这里不包含int和char, int, 这两者将从tclass传入 476 void constdef(int tclass){ 477 //without int or char 478 char temp[ 200 ]; 479 //结构:IDEN = XXXX 480 if ( symid == IDEN ) { 481 strcpy(name, id.c_str()); 482 getsym(); 483 //if is '=' 484 if ( symid == ASSIGN ) { 485 getsym(); 486 // if is '+' or '-' 487 if ( symid == PLUS || symid == MINU ) { 488 int symb = symid; 489 getsym(); 490 // if is integer 491 if ( tclass == INTTK && symid == INTCON ) { 492 if ( symb == PLUS ) { 493 value = num; 494 } 495 else{ 496 value = 0 - num; 497 } 498 pushtable(name, kind, value, address, paranum); 499 sprintf(temp, "%d", value); 500 insmidcode("const", "int", temp, name); 501 } 502 503 // if is char 504 } 505 else if ( symid == CHARCON ){ 506 value = id.c_str()[ 0 ]; 507 pushtable(name, kind, value, address, paranum); 508 sprintf(temp, "%d", value); 509 insmidcode("const", "char", temp, name); 510 } 511 else if ( symid == INTCON ){ 512 value = num; 513 pushtable(name, kind, value, address, paranum); 514 sprintf(temp, "%d", value); 515 insmidcode("const", "int", temp, name); 516 } 517 else{ 518 error(UNKNOWRIGHTSYM); 519 return; 520 } 521 }else{ 522 error(CONSTNOTINIT); 523 return; 524 } 525 } 526 else{ 527 error(CSTDEFINEFAIL); 528 } 529 getsym(); 530 return; 531 } 532 533 //15.<声明头部> ::= int<标识符> | char<标识符> 534 //ATTENTION: 读到的是int/char和标识符以及其后面的一个单词!! 535 void defhead() 536 { 537 if ( symid == INTTK || symid == CHARTK ) { 538 kind = symid; 539 getsym(); 540 541 if ( symid != IDEN ) { 542 error(IDENTIFIERLACK, 1); 543 return; 544 } 545 else { 546 strcpy(name, id.c_str());//拷贝函数的名字 547 } 548 } 549 else{ 550 error(KEYWORDERROR, 1); 551 return; 552 } 553 getsym(); 554 return; 555 } 556 557 //16.<变量说明> ::= <变量定义>;{<变量定义>;} 558 void varstate() 559 { 560 vardef(); 561 //缺少';' 562 if ( symid != SEMICN ) { 563 error(SEMICOLONLACK, 1); 564 } 565 getsym(); 566 return; 567 } 568 569 570 //17.<变量定义> ::= <类型标识符>(<标识符>|<标识符>‘[’<无符号整数>‘]’){,(<标识符>|<标识符>‘[’<无符号整数>‘]’ )} 571 void vardef() 572 { 573 if ( symid == INTTK || symid == CHARTK ) { 574 kind = symid; 575 getsym(); 576 577 if ( symid != IDEN ) { 578 error(IDENTIFIERLACK, 2); 579 return; 580 } 581 else { 582 strcpy(name, id.c_str());//拷贝函数的名字 583 } 584 } 585 else{ 586 error(KEYWORDERROR, 2); 587 return; 588 } 589 getsym(); 590 int isVec = ( symid == LBRACK ); 591 value = 0; 592 address = 0; 593 paranum = 0; 594 if ( isVec ) { //如果是数组 595 getsym(); 596 if ( symid != INTCON ) { 597 error(IMMLACK); 598 return; 599 } 600 else{ 601 pushtable(name, kind, value, address, paranum, num); 602 if ( kind == INTTK ) 603 insmidcode("inta", 0, num, name); 604 else if ( kind == CHARTK ) 605 insmidcode("chara", 0, num, name); 606 getsym(); 607 if ( symid != RBRACK ) { 608 error(RIGHTBRACKLACK, 1); 609 return; 610 } 611 else{ 612 getsym(); 613 } 614 } 615 } 616 else{ 617 pushtable(name, kind, value, address, paranum, isVec); 618 if ( kind == INTTK ) 619 insmidcode("int", " ", " ", name); 620 else if ( kind == CHARTK ) 621 insmidcode("char", " ", " ", name); 622 } 623 624 //如果后面是逗号,那么变量定义未结束 625 while ( symid == COMMA ) { 626 getsym(); 627 //出现不合法的标志符 628 if ( symid != IDEN ) { 629 error(IDENTIFIERLACK, 2); 630 return; 631 } 632 strcpy(name, id.c_str()); 633 getsym(); 634 isVec = ( symid == LBRACK ); 635 if ( isVec ) { //如果是数组 636 getsym(); 637 if ( symid != INTCON ) { 638 error(IMMLACK); 639 return; 640 } 641 else{ 642 pushtable(name, kind, value, address, paranum, num); 643 if ( kind == INTTK ) 644 insmidcode("int", 0, num, name); 645 else if ( kind == CHARTK ) 646 insmidcode("char", 0, num, name); 647 getsym(); 648 if ( symid != RBRACK ) { 649 error(RIGHTBRACKLACK); 650 return; 651 } 652 else{ 653 getsym(); 654 } 655 } 656 } 657 else{ 658 pushtable(name, kind, value, address, paranum, isVec); 659 if ( kind == INTTK ) 660 insmidcode("int", " ", " ", name); 661 else if ( kind == CHARTK ) 662 insmidcode("char", " ", " ", name); 663 } 664 } 665 return; 666 } 667 668 //21.<复合语句> ::= [<常量说明>][<变量说明>]<语句列> 669 void complexsentence() 670 { 671 if ( symid == CONSTTK ) { 672 //调用常量说明子程序 673 conststate(); 674 //如果是分号,则是正常的 675 while ( hsymid == SEMICN ) { 676 if ( symid == CONSTTK ) 677 conststate(); 678 else break; 679 } 680 } 681 682 //判断是否为变量说明 683 //设置部分变量用于恢复现场 684 while ( symid == INTTK || symid == CHARTK ) { 685 int tempid = symid;//恢复现场用 686 char tempch = ch;//恢复现场用 687 int tempcnum = cnum;//恢复现场用 688 kind = symid; 689 getsym(); 690 strcpy(name, id.c_str());//拷贝名字 691 692 //如果标识符合法 693 if ( symid != IDEN ) { 694 error(IDENTIFIERLACK, 2); 695 return; 696 } 697 getsym(); 698 //如果是逗号或者分号,则是变量定义 699 if ( symid == COMMA || symid == LBRACK) { 700 symid = tempid; 701 cnum = tempcnum; 702 ch = tempch; 703 varstate(); 704 continue; 705 } 706 else if ( symid == SEMICN ) { 707 value = 0; 708 address = 0; 709 paranum = 0; 710 pushtable(name, kind, value, address, paranum); 711 if ( kind == INTTK ) insmidcode("int", " ", " ", name); 712 else if ( kind == CHARTK ) insmidcode("char", " ", " ", name); 713 getsym(); 714 continue; 715 } 716 else{ 717 error(SEMICOLONLACK, 1); 718 return; 719 } 720 } 721 722 //语句列 723 sentencelist(); 724 return; 725 } 726 727 //37.<语句列> ::= {<语句>} 728 void sentencelist() 729 { 730 sentence(); 731 //语句,如果读到的是如下的东西,那么还是语句 732 while ( symid == IFTK || symid == WHILETK || symid == FORTK || symid == LBRACE 733 || symid == IDEN || symid == RETURNTK || symid == SCANFTK || symid == PRINTFTK ) { 734 sentence(); 735 } 736 } 737 738 //30.<条件语句> ::= if ‘(’<条件>‘)’<语句>[else<语句>] 739 void ifsentence() 740 { 741 char label1[ 10 ], label2[ 10 ], conditionvalue[ 30 ]; 742 strcpy(label1, nextlab()); //如果不满足if,则跳过label1,label1是if的结束部分 743 strcpy(label2, nextlab()); //如果还有else,则else的结束位置是label2 744 getsym(); 745 //少“(” 746 if ( symid != LPARENT ) { 747 error(LEFTPARENTLACK, 1); 748 return; 749 } 750 getsym(); 751 //<条件> 752 condition(); 753 strcpy(conditionvalue, nowitem); //条件计算的值在nowitem里面,此处应该是个临时变量$_x 754 insmidcode("jne", " ", " ", label1); //比较,为假的时候跳转 755 if ( symid != RPARENT ) { 756 error(RIGHTPARENTLACK, 1); 757 return; 758 } 759 getsym(); 760 sentence(); 761 insmidcode("jmp", " ", " ", label2);//不执行else的部分 762 insmidcode("lab:", " ", " ", label1); 763 if ( symid == ELSETK ) { 764 getsym(); 765 sentence(); 766 } 767 insmidcode("lab:", " ", " ", label2); 768 return; 769 } 770 771 //31.<条件> ::= <表达式><关系运算符><表达式>|<表达式> 772 void condition() 773 { 774 char place1[ 30 ], place2[ 30 ]; 775 expression(); 776 strcpy(place1, nowitem); //条件至少有一个表达式 777 //关系运算符 778 if ( symid == LSS || symid == LEQ || symid == GRE || symid == GEQ || symid == NEQ || symid == EQL ) { 779 if ( symid == LSS ) { 780 getsym(); 781 expression(); 782 strcpy(place2, nowitem); 783 insmidcode("<", place1, place2, " "); 784 } 785 else if ( symid == LEQ ) { 786 getsym(); 787 expression(); 788 strcpy(place2, nowitem); 789 insmidcode("<=", place1, place2, " "); 790 } 791 else if ( symid == GRE ) { 792 getsym(); 793 expression(); 794 strcpy(place2, nowitem); 795 insmidcode(">", place1, place2, " "); 796 } 797 else if ( symid == GEQ ) { 798 getsym(); 799 expression(); 800 strcpy(place2, nowitem); 801 insmidcode(">=", place1, place2, " "); 802 } 803 else if ( symid == NEQ ) { 804 getsym(); 805 expression(); 806 strcpy(place2, nowitem); 807 insmidcode("!=", place1, place2, " "); 808 } 809 else if ( symid == EQL ) { 810 getsym(); 811 expression(); 812 strcpy(place2, nowitem); 813 insmidcode("==", place1, place2, " "); 814 } 815 return; 816 } 817 strcpy(place2, "0"); 818 insmidcode("!=", place1, place2, " "); 819 return; 820 } 821 822 //32.<循环语句> ::= while '('<条件>')'<语句> 823 // | for'('<标识符>=<表达式>;<条件>;<标识符>=<标识符>(+|-)<步长>')'<语句> 824 void loopsentence() 825 { 826 int s = 0; 827 char names[ 30 ], names1[ 30 ], names2[ 30 ], place2[ 30 ], place3[ 30 ]; 828 char label1[ 10 ], label2[ 10 ], op_flag[ 5 ]; 829 strcpy(label1, nextlab()); 830 strcpy(label2, nextlab()); 831 if ( symid == WHILETK ) { 832 getsym(); 833 if ( symid != LPARENT ) { 834 error(LEFTPARENTLACK, 1); 835 return; 836 } 837 insmidcode("lab:", " ", " ", label1); 838 getsym(); 839 condition(); 840 if ( symid != RPARENT ) { 841 error(RIGHTPARENTLACK, 1); 842 return; 843 } 844 insmidcode("jne", " ", " ", label2); 845 getsym(); 846 sentence(); 847 insmidcode("jmp", " ", " ", label1); 848 insmidcode("lab:", " ", " ", label2); 849 return; 850 } 851 852 if ( symid == FORTK ) { //for|(...) 853 getsym(); 854 if ( symid != LPARENT ) {//for(|...) 855 error(LEFTPARENTLACK, 1); 856 return; 857 } 858 getsym(); 859 860 if ( symid != IDEN ) { //for(i|=x;...;...) 861 error(UNACCEPTABLESENTENCE);//不合法的句子 862 return; 863 } 864 strcpy(names, id.c_str()); 865 getsym(); 866 if ( symid != ASSIGN ) { //for(i=|..;...;...) 867 error(UNACCEPTABLESENTENCE); 868 return; 869 } 870 s = searchst(names, 0); 871 if ( s < 0 ) { //如果是常量 872 if ( s == -1 ) error(VARNOTDEFINE, 1); //"="左边是不合法的标识符 873 else error(ASSIGNCONST); 874 return; 875 } 876 getsym(); 877 expression(); //for(i=a+b|;...;...) 878 insmidcode("=", nowitem, " ", names); 879 if ( symid != SEMICN ) { 880 error(SEMICOLONLACK, 2); 881 return; 882 } 883 getsym();//for(i=a+b;|...;...) 884 insmidcode("lab:", " ", " ", label1); 885 condition();//for(i=a+b;...;|...) 886 insmidcode("jne", " ", " ", label2); 887 if ( symid != SEMICN ) { 888 error(SEMICOLONLACK, 2); 889 return; 890 } 891 getsym(); //for(i=a+b;...;|...) 892 //<标识符>=<标识符>(+|-)<步长>!!!!!!!!!!! 893 if ( symid != IDEN ) { 894 error(IDENTIFIERLACK, 3); 895 return; 896 } 897 strcpy(names1, id.c_str()); 898 s = searchst(names1, 0); 899 if ( s < 0 ) { //如果是常量 900 if ( s == -1 ) error(VARNOTDEFINE, 1); //"="左边是不合法的标识符 901 else error(ASSIGNCONST); 902 return; 903 } 904 getsym(); 905 if ( symid != ASSIGN ) { 906 error(UNACCEPTABLESENTENCE); 907 return; 908 } 909 getsym(); 910 if ( symid != IDEN ) { 911 error(IDENTIFIERLACK, 3); 912 return; 913 } 914 strcpy(names2, id.c_str()); 915 s = searchst(names2, 0); 916 if ( s < 0 ) { //如果是常量 917 if ( s == -1 ) error(VARNOTDEFINE, 1); //"="左边是不合法的标识符 918 else error(ASSIGNCONST); 919 return; 920 } 921 922 getsym(); 923 if ( symid != PLUS && symid != MINU ) { 924 error(PLUSMINULACK); 925 return; 926 } 927 if ( symid == PLUS ) strcpy(op_flag, "+ "); 928 else if ( symid == MINU ) strcpy(op_flag, "- "); 929 930 getsym(); 931 if ( symid != INTCON || num == 0 ) { 932 error(UNKNOWRIGHTSYM, 1); //等号右边不是合法的整数 933 return; 934 } 935 strcpy(place2, id.c_str()); 936 937 getsym(); 938 if ( symid != RPARENT ) { 939 error(RIGHTPARENTLACK, 1); 940 return; 941 } 942 943 getsym(); 944 sentence(); 945 strcpy(place3, nextvar()); 946 insmidcode(op_flag, names2, place2, place3); 947 insmidcode("=", place3, " ", names1); 948 949 insmidcode("jmp", " ", " ", label1); 950 insmidcode("lab:", " ", " ", label2); 951 return; 952 } 953 } 954 955 //28.<语句> ::= <条件语句>|<循环语句>|‘{’<语句列>‘}’|<有返回值函数调用语句>; 956 //|<无返回值函数调用语句>;|<赋值语句>;|<读语句>;|<写语句>;|<空>;|<返回语句>; 957 void sentence(){ 958 int s; 959 960 //条件语句 961 if ( symid == IFTK ) { 962 ifsentence(); 963 return; 964 } 965 966 //循环语句 967 if ( symid == WHILETK || symid == FORTK ) { 968 loopsentence(); 969 return; 970 } 971 972 //{‘语句列’} 973 if ( symid == LBRACE ) { 974 getsym(); 975 sentencelist(); 976 //缺“}” 977 if ( symid != RBRACE ) { 978 error(RIGHTBRACELACK, 1); 979 return; 980 } 981 //不缺“}” 982 getsym(); 983 return; 984 } 985 986 //函数调用语句|<赋值语句>; 987 988 if ( symid == IDEN ) { 989 int isVec = 0; 990 char names[ MAXIDENLEN ]; 991 strcpy(names, id.c_str()); 992 getsym(); 993 //<赋值语句>; 994 //29.<赋值语句> ::= <标识符>=<表达式>|<标识符>'['<表达式>']'=<表达式> 995 char place2[ 100 ]; 996 if ( symid == LBRACK ){ //如果是数组 997 s = searchst(names, 0); 998 if ( s == -1 ) 999 { 1000 error(VARNOTDEFINE, 1); 1001 return; 1002 } 1003 getsym(); 1004 expression(); 1005 strcpy(place2, nowitem); 1006 if (isdigit(nowitem[0])){ 1007 int arrnums = 0; 1008 arrnums = arrnum(names); 1009 if (atoi(nowitem) >= arrnums){ 1010 printf("Warning: Line:%d index of array out of boundary, which should be less than %d.\n",lnum, atoi(nowitem)); 1011 } 1012 } 1013 isVec = 1; 1014 if ( symid != RBRACK ) { 1015 error(RIGHTBRACKLACK, 1); 1016 return; 1017 } 1018 getsym(); 1019 } 1020 if ( symid == ASSIGN ) { 1021 s = searchst(names, 0); 1022 if ( s < -1 ) { //如果是常量 1023 error(ASSIGNCONST); //"="左边是不合法的标识符 1024 return; 1025 } 1026 getsym(); 1027 expression(); 1028 if ( isVec ){ 1029 insmidcode("[]=", names, place2, nowitem); 1030 } 1031 else{ 1032 insmidcode("=", nowitem, " ", names); 1033 } 1034 1035 if ( symid != SEMICN ) { 1036 error(SEMICOLONLACK, 2); 1037 return; 1038 } 1039 getsym(); 1040 return; 1041 } 1042 1043 //函数调用语句 1044 if ( symid == LPARENT ) { 1045 getsym(); 1046 valueofpara(); //计算并记录参数的值以及个数 1047 if ( symid != RPARENT ) { 1048 error(RIGHTPARENTLACK, 1); 1049 return; 1050 } 1051 s = searchst(names, 1); 1052 if ( s == -1 * FUNCTIONNOTFOUND ) { 1053 error(FUNCTIONNOTFOUND); 1054 return; 1055 } 1056 else if ( s == -1 * FORMALPARANUMUNMATCH ){ 1057 error(FORMALPARANUMUNMATCH, 1); 1058 return; 1059 } 1060 insmidcode("call", names, " ", " "); 1061 getsym(); 1062 if ( symid != SEMICN ) { 1063 error(SEMICOLONLACK, 2); 1064 return; 1065 } 1066 getsym(); 1067 } 1068 1069 else { 1070 error(UNACCEPTABLESENTENCE); //不合法的句子 1071 return; 1072 } 1073 return; 1074 } 1075 1076 //读语句 1077 if ( symid == SCANFTK ) { 1078 scanfsentence(); 1079 if ( symid != SEMICN ) { 1080 error(SEMICOLONLACK, 2); 1081 return; 1082 } 1083 getsym(); 1084 return; 1085 } 1086 1087 //写语句 1088 if ( symid == PRINTFTK ) { 1089 printfsentence(); 1090 if ( symid != SEMICN ) { 1091 error(SEMICOLONLACK, 2); 1092 return; 1093 } 1094 getsym(); 1095 return; 1096 } 1097 1098 //返回语句 1099 if ( symid == RETURNTK ) { 1100 returnsentence(); 1101 //返回语句后缺“;” 1102 if ( symid != SEMICN ) { 1103 error(SEMICOLONLACK, 2); 1104 return; 1105 } 1106 getsym(); 1107 return; 1108 } 1109 if ( symid == SEMICN ) 1110 { 1111 getsym(); 1112 return; 1113 } 1114 1115 //不合法的句子 1116 error(UNACCEPTABLESENTENCE); 1117 return; 1118 } 1119 1120 //36.<值参数表> ::= <表达式>{,<表达式>}|<空> 1121 void valueofpara() 1122 { 1123 int j = 0; 1124 vector<string> paraqueue; 1125 do { 1126 if ( symid == COMMA ) 1127 getsym(); 1128 if ( symid == PLUS || symid == MINU || symid == IDEN || symid == LPARENT || symid == CHARCON || symid == INTCON ) { 1129 expression(); 1130 paraqueue.push_back(nowitem); 1131 j++; 1132 } 1133 } while ( symid == COMMA ); 1134 char tc[ 20 ]; 1135 for ( int i = 0; i < paraqueue.size(); i++ ) { 1136 strcpy(tc, paraqueue[ i ].c_str()); 1137 insmidcode("fupa", " ", " ", tc); 1138 } 1139 paranum = j; 1140 paraqueue.~vector(); 1141 return; 1142 } 1143 1144 //38.<读语句> ::= scanf ‘(’<标识符>{,<标识符>}‘)’ 1145 void scanfsentence() 1146 { 1147 char names[ 30 ]; 1148 int s; 1149 getsym(); 1150 if ( symid != LPARENT ) { 1151 error(LEFTPARENTLACK, 1); 1152 return; 1153 } 1154 1155 do{ 1156 getsym(); 1157 if ( symid != IDEN ) { 1158 error(IDENTIFIERLACK, 3); //不合法的标志符 1159 return; 1160 } 1161 strcpy(names, id.c_str()); 1162 s = searchst(names, 0); 1163 if ( s < 0 ) { 1164 if ( s == -1 ) 1165 error(VARNOTDEFINE, 1); //未定义标志符 1166 else 1167 error(ASSIGNCONST, 1); 1168 return; 1169 } 1170 insmidcode("scf", " ", " ", names); 1171 getsym(); 1172 } while ( symid == COMMA ); 1173 1174 if ( symid != RPARENT ) { 1175 error(RIGHTPARENTLACK, 1); 1176 return; 1177 } 1178 getsym(); 1179 return; 1180 } 1181 1182 //39.<写语句> ::= printf ‘(’<字符串>,<表达式>‘)’| 1183 // printf ‘(’<字符串>‘)’| printf ‘(’<表达式>‘)’ 1184 void printfsentence() 1185 { 1186 char place1[ 200 ] = "", place2[ 30 ] = ""; //place1是字符串,place2是表达式 1187 getsym(); 1188 if ( symid != LPARENT ) { 1189 error(LEFTPARENTLACK, 1); 1190 return; 1191 } 1192 getsym(); 1193 if ( symid == STRCON ) { 1194 strcpy(place1, id.c_str()); 1195 getsym(); 1196 if ( symid == COMMA ) { 1197 getsym(); 1198 expression(); 1199 strcpy(place2, nowitem); 1200 } 1201 } 1202 else { 1203 expression(); 1204 strcpy(place2, nowitem); 1205 } 1206 if ( symid != RPARENT ) { 1207 error(RIGHTPARENTLACK, 1); 1208 return; 1209 } 1210 insmidcode("prt", place1, place2, (factclass == CHAR) ? "char" : "int"); 1211 getsym(); 1212 return; 1213 } 1214 1215 //40.<返回语句> ::= return[‘(’<表达式>‘)’] 1216 void returnsentence() 1217 { 1218 char place3[ 30 ]; 1219 getsym(); 1220 if ( symid == LPARENT ) { 1221 getsym(); 1222 expression();//表达式子程序 1223 strcpy(place3, nowitem); 1224 if ( symid != RPARENT ) { 1225 error(RIGHTPARENTLACK, 1); 1226 return; 1227 } 1228 insmidcode("ret", " ", " ", place3); 1229 returnnum++; 1230 getsym(); 1231 return; 1232 } 1233 insmidcode("ret", " ", " ", " "); 1234 return; 1235 } 1236 1237 //25.<表达式> ::= [+|-]<项>{<加法运算符><项>} 1238 void expression() 1239 { 1240 factclass = 0; 1241 char place1[ 30 ], place2[ 30 ], place3[ 30 ]; 1242 //有+|-的情况 1243 if ( symid == PLUS || symid == MINU ) { 1244 factclass = INT; 1245 if ( symid == PLUS ) { 1246 getsym(); 1247 item();//项,结束后,项的结果会放入全局变量nowitem 1248 strcpy(place3, nowitem);//把项的结果放入临时变量的位置 1249 } 1250 if ( symid == MINU ) { 1251 getsym(); 1252 item();//项 1253 strcpy(place1, nowitem); 1254 strcpy(place3, nextvar()); 1255 insmidcode("-", "0 ", place1, place3); //place3 = 0 - (place1) 1256 } 1257 } 1258 else { 1259 item(); 1260 strcpy(place3, nowitem); 1261 } 1262 while ( symid == PLUS || symid == MINU ) { 1263 factclass = INT; 1264 strcpy(place1, place3); 1265 if ( symid == PLUS ) { 1266 getsym(); 1267 item(); 1268 strcpy(place2, nowitem); 1269 strcpy(place3, nextvar()); 1270 insmidcode("+", place1, place2, place3); 1271 continue; 1272 } 1273 else { 1274 getsym(); 1275 item(); 1276 strcpy(place2, nowitem); 1277 strcpy(place3, nextvar()); 1278 insmidcode("-", place1, place2, place3); 1279 continue; 1280 } 1281 } 1282 strcpy(nowitem, place3);//把表达式的最终值存放在p之中 1283 return; 1284 } 1285 1286 //26.<项> ::= <因子>{<乘法运算符><因子>} 1287 void item() 1288 { 1289 char place1[ 200 ], place2[ 200 ], place3[ 200 ]; 1290 factor(); 1291 strcpy(place3, nowitem);//这种操作是为了对付只有赋值的情况 1292 while ( symid == MULT || symid == DIV ) { 1293 factclass = INT; 1294 strcpy(place1, place3); 1295 if ( symid == MULT ) { 1296 getsym(); 1297 factor(); 1298 strcpy(place2, nowitem); 1299 strcpy(place3, nextvar());//申请临时变量 1300 insmidcode("*", place1, place2, place3); 1301 continue; 1302 } 1303 if ( symid == DIV ) { 1304 getsym(); 1305 factor(); 1306 strcpy(place2, nowitem); 1307 strcpy(place3, nextvar()); 1308 insmidcode("/", place1, place2, place3); 1309 continue; 1310 } 1311 } 1312 strcpy(nowitem, place3); //每一个项,计算后的值都在变量nowitem里面 1313 return; 1314 } 1315 1316 1317 //27.<因子> ::= <标识符>|<标识符>‘[’<表达式>‘]’|<整数>|<字符>|<有返回值函数调用语句>|‘(’<表达式>‘)’ 1318 void factor() 1319 { 1320 int t = -1; 1321 char names[ 30 ], place3[ 30 ]; 1322 //<标识符>|<有返回值函数调用语句> 1323 if ( symid == IDEN ) { 1324 strcpy(names, id.c_str()); 1325 getsym(); 1326 //如果有左括号,则是<有返回值函数调用语句> 1327 if ( symid == LPARENT ) { 1328 getsym(); 1329 valueofpara(); 1330 if ( symid != RPARENT ) { 1331 error(LEFTPARENTLACK, 2); 1332 return; 1333 } 1334 t = searchst(names, 1); 1335 if ( t < 0 ) { 1336 if ( t == -1 * FUNCTIONRETURNNULL ) 1337 error(FUNCTIONRETURNNULL); //函数无返回值,不能出现在表达式中 1338 else if ( t == -1 * FUNCTIONNOTFOUND ) 1339 error(FUNCTIONNOTFOUND, 1); 1340 return; 1341 } 1342 strcpy(place3, nextvar());//生成临时变量 1343 insmidcode("call", names, " ", place3);//将调用的返回值存放在临时变量里面 1344 strcpy(nowitem, place3); 1345 getsym(); 1346 return; 1347 } 1348 1349 //如果是变量、数组、 1350 else if ( symid != LBRACK ){ 1351 t = searchst(names, 0); //查表,查找到标识符对应的地址 1352 if (t == -1) { 1353 error(IDENTIFIERLACK, 4); 1354 return; 1355 } 1356 if ( t < -1 ) { 1357 t = -t / 2; 1358 } 1359 strcpy(nowitem, names); 1360 } 1361 else if ( symid == LBRACK ){ //如果是数组 1362 getsym(); 1363 int tclass = factclass; 1364 expression(); 1365 factclass = tclass; 1366 char ttt[ 30 ]; 1367 strcpy(ttt, nowitem); 1368 1369 if (isdigit(nowitem[0])){ 1370 int arrnums = 0; 1371 arrnums = arrnum(names); 1372 if (atoi(ttt) >= arrnums){ 1373 printf("Warning: Line:%d index of array out of boundary, which should be less than %d.\n",lnum, atoi(ttt)); 1374 } 1375 } 1376 if ( symid != RBRACK ) { 1377 error(RIGHTBRACKLACK); 1378 return; 1379 } 1380 else{ 1381 strcpy(nowitem, nextvar()); 1382 insmidcode("geta", names, ttt, nowitem); 1383 getsym(); 1384 } 1385 } 1386 return; 1387 } 1388 1389 //'('<表达式>')' 1390 if ( symid == LPARENT ) { 1391 getsym(); 1392 expression(); 1393 if ( symid != RPARENT ) { 1394 error(RIGHTPARENTLACK, 2); 1395 return; 1396 } 1397 getsym(); 1398 return; 1399 } 1400 1401 // <整数>|<字符> 1402 if ( symid == PLUS || symid == MINU || symid == INTCON || symid == CHARCON ) { 1403 int temp = 1; 1404 if ( symid == PLUS ) 1405 getsym(); 1406 else if ( symid == MINU ) { 1407 temp = -1; 1408 getsym(); 1409 } 1410 if ( symid != INTCON ) { 1411 if ( symid == CHARCON ){ 1412 if ( factclass != INT ) { 1413 factclass = CHAR; 1414 } 1415 sprintf(nowitem, "%d", id.c_str()[0]); 1416 getsym(); 1417 return; 1418 } 1419 error(IMMLACK); 1420 return; 1421 } 1422 sprintf(nowitem, "%d", temp * num); 1423 factclass = INT; 1424 getsym(); 1425 return; 1426 } 1427 1428 error(EXPRESSIONERROR); //表达式缺失或错误 1429 return; 1430 }
1 // 2 // midcode.cpp 3 // exc0compiler 4 // 5 // Created by sciencefans on 14/11/29. 6 // Copyright (c) 2014年 sciencefans. All rights reserved. 7 // 8 9 10 11 #include "glob.h" 12 13 fourvarcode midcode[ MAXMIDCODE ]; 14 int midcodeiter = 0; 15 int labelcnt = 0; 16 int varcnt = 0; 17 vector <char*> hisvar; 18 19 char* itoa(int i){ 20 char *temp = (char*)malloc(sizeof(char) * 10); 21 sprintf(temp, "%d", i); 22 return temp; 23 } 24 25 //插入中间代码 26 void insmidcode(char* op, char* t1, char* t2, char* t3){ 27 if ( strcmp(op, "func") == 0 ){ 28 midcoderst << endl << endl; 29 } 30 midcoderst << "\t\t"; 31 midcoderst << op << "\t," << t1 << "\t," << t2 << "\t," << t3 << endl; 32 strcpy(midcode[ midcodeiter ].op, op); 33 strcpy(midcode[ midcodeiter ].var1, t1); 34 strcpy(midcode[ midcodeiter ].var2, t2); 35 strcpy(midcode[ midcodeiter ].var3, t3); 36 midcodeiter++; 37 } 38 void insmidcode(char* op, int t1, int t2, char* t3){ 39 midcoderst << "\t\t"; 40 midcoderst << op << "\t," << t1 << "\t," << t2 << "\t," << t3 << endl; 41 strcpy(midcode[ midcodeiter ].op, op); 42 char *t; 43 44 strcpy(midcode[ midcodeiter ].var1, strcmp(t = itoa(t1), "0") == 0 ? " " : t); 45 strcpy(midcode[ midcodeiter ].var2, t = itoa(t2)); 46 strcpy(midcode[ midcodeiter ].var3, t3); 47 midcodeiter++; 48 free(t); 49 } 50 void insmidcode(char* op, char* t1, int t2, char* t3){ 51 midcoderst << "\t\t"; 52 midcoderst << op << "\t," << t1 << "\t," << t2 << "\t," << t3 << endl; 53 strcpy(midcode[ midcodeiter ].op, op); 54 char *t; 55 strcpy(midcode[ midcodeiter ].var1, t1); 56 strcpy(midcode[ midcodeiter ].var2, t = itoa(t2)); 57 strcpy(midcode[ midcodeiter ].var3, t3); 58 midcodeiter++; 59 free(t); 60 } 61 //生成新的标记 62 char* nextlab(){ 63 char *label = (char*)malloc(sizeof(char) * 20); 64 strcpy(label, "_LABEL_"); 65 sprintf(label, "_LABEL_%d", labelcnt++); 66 return label; 67 } 68 69 //生成新的变量 70 char* nextvar() 71 { 72 char *var = (char*)malloc(sizeof(char) * 20); 73 sprintf(var, "$_%d", varcnt++); 74 //insmidcode("int", " ", " ", var); 75 hisvar.push_back(var); 76 return var; 77 } 78 79 void freetempvar(){ 80 for ( int i = 0; i < hisvar.size(); i++ ) { 81 free(hisvar[ i ]); 82 } 83 }
1 // 2 // main.cpp 3 // exc0compiler 4 // 5 // Created by sciencefans on 14/11/22. 6 // Copyright (c) 2014年 sciencefans. All rights reserved. 7 // 8 9 10 #include "glob.h" 11 #include "err.h" 12 int mf; 13 ofstream laxrst, midcoderst, asmrst, symtablehis; 14 FILE* optcodefile; 15 int main(int argc, char **argv){ 16 char filename[500] = "in.c"; 17 printf("Input the source file:\n"); 18 char tempsrc[ 500 ]; 19 gets(tempsrc); 20 if ( strlen(tempsrc) > 2 ) 21 if ( tempsrc[ 0 ] == '\"' ){ 22 strcpy(filename, tempsrc + 1 ); 23 filename[ strlen(filename) - 1 ] = 0; 24 }else 25 strcpy(filename, tempsrc); 26 src = fopen(filename, "r"); 27 if ( src == NULL ) 28 { 29 error(NOSUCHFILE); 30 system("pause"); 31 return 0; 32 } 33 laxrst.open("laxrst.txt"); 34 midcoderst.open("midcode.txt"); 35 asmrst.open("asmrst.asm"); 36 symtablehis.open("symbolTable.txt"); 37 symtablehis << "index" << "\t" << "name" << "\t" << "kind" << "\t" << "value" << "\t" << "address" << "\t" << "paranum" << "\t" << "isVec" << endl; 38 getch(); 39 program(); 40 41 if ( mf < 1 ) error(MAINLACK); //没有定义主函数 42 do getsym(); while ( ch == '\n' || ch == ' ' || ch == '\t' ); 43 if ( symid != -1 ) error(MOREWORD); //主函数后有多余的代码 44 45 if ( errnum == 0 ) { 46 printf("\n\n编译成功,没有语法语义错误!\n\n"); 47 printOptimize(); //打印优化后的四元式 48 printf("四元式 生成完成...\n"); 49 midcode2asm(); //生成汇编码 50 printf("汇编指令 生成完成...\n"); 51 scan(); //扫描四元式结构数组,完成优化 52 printOptimize(); 53 printf("优化后的四元式 生成完成...\n"); 54 } 55 56 laxrst.close(); 57 asmrst.close(); 58 midcoderst.close(); 59 symtablehis.close(); 60 fclose(src); 61 62 printf("\n-----------------------------\n"); 63 if ( errnum == 0 ) 64 { 65 printf("Compile Success.\n"); 66 } 67 printf("Errors:\t%d\tTotal Line: %d\n", errnum, lnum); 68 system("pause"); 69 return 0; 70 }
1 #include "err.h" 2 #include "glob.h" 3 4 #define QUIT 1 5 #define DONOTHING 2 6 #define ICV 3 7 #define CICVIFIRSP 4 8 #define CS 5 9 #define CLR 6 10 #define IWFRSPIFCV 7 11 #define IWFLIRSPE 8 12 #define IWFXXXANE 9 13 int errnum = 0; 14 15 void error(int _errsig, int signal){ 16 int errclass = -1; 17 errnum++; 18 printf("Error %d: LINE %d, COLUMN %d: Near \"%s\" : ", errnum, cnum == 0 ? lnum - 1 : lnum, cnum == 0 ? prllen : cnum + 1, prid.c_str()); 19 switch ( _errsig ) { 20 case NOSUCHFILE: errclass = QUIT; printf("NO SUCH FILE\n"); break; 21 case FILEINCOMPLETE: errclass = DONOTHING; printf("FILEINCOMPLETE\n"); break; 22 case DOUBLEQUOTESLACK: errclass = DONOTHING; printf("DOUBLEQUOTESLACK\n"); break; 23 case UNACCEPTATLECHAR: errclass = DONOTHING; printf("UNACCEPTATLECHAR\n"); break; 24 case SINGLEQUOTESLACK: errclass = DONOTHING; printf("SINGLEQUOTESLACK\n"); break; 25 case OUTOFTABLE: errclass = QUIT; printf("OUT OF TABLE\n"); break; 26 case SYMBOLCONFLICT: errclass = DONOTHING; printf("SYMBOL CONFLICT\n"); break; 27 case CSTDEFINEFAIL: errclass = CS; printf("CST DEFINE FAIL\n"); break; 28 case VARNOTINIT: errclass = DONOTHING; printf("VARNOTINIT\n"); break; 29 case UNKNOWRIGHTSYM: errclass = 30 signal == 0 ? CS : 31 signal == 1 ? IWFLIRSPE : 32 -1; 33 printf("UNKNOWRIGHTSYM\n"); break; 34 case SEMICOLONLACK: errclass = 35 signal == 0 ? CICVIFIRSP : 36 signal == 1 ? IWFRSPIFCV : 37 signal == 2 ? IWFLIRSPE : 38 -1; 39 printf("SEMICOLONLACK\n"); 40 break; 41 case KEYWORDERROR: 42 errclass = signal == 0 ? CICVIFIRSP : 43 signal == 1 ? CLR : 44 signal == 2 ? IWFRSPIFCV : 45 printf("KEYWORDERROR\n"); 46 break; 47 case IDENTIFIERLACK: errclass = 48 signal == 0 ? ICV : 49 signal == 1 ? CLR : 50 signal == 2 ? IWFRSPIFCV : 51 signal == 3 ? IWFLIRSPE : 52 signal == 4 ? IWFXXXANE : 53 -1; 54 printf("IDENTIFIER LACK\n"); 55 break; 56 case RIGHTBRACKLACK: errclass = 57 signal == 0 ? IWFXXXANE : 58 signal == 1 ? IWFRSPIFCV : 59 -1; 60 printf("RIGHT BRACK LACK\n"); 61 break; 62 case FUNCTIONNOTFOUND: errclass = 63 signal == 0 ? IWFLIRSPE : 64 signal == 1 ? IWFXXXANE : 65 -1; 66 printf("FUNCTION NOT FOUND\n"); break; 67 case FORMALPARANUMUNMATCH: errclass = 68 signal == 0 ? DONOTHING : 69 signal == 1 ? IWFLIRSPE : 70 -1; 71 printf("FORMAL PARA NUM UNMATCH\n"); break; 72 case VARNOTDEFINE: errclass = 73 signal == 0 ? DONOTHING : 74 signal == 1 ? IWFLIRSPE : 75 -1; 76 printf("VAR NOT DEFINE\n"); break; 77 case LEFTPARENTLACK: errclass = 78 signal == 0 ? ICV : 79 signal == 1 ? IWFLIRSPE : 80 signal == 2 ? IWFXXXANE : 81 -1; 82 printf("LEFT PARENT LACK\n"); break; 83 case RIGHTPARENTLACK: errclass = 84 signal == 0 ? ICV : 85 signal == 1 ? IWFLIRSPE : 86 signal == 2 ? IWFXXXANE : 87 -1; 88 printf("RIGHT PARENT LACK\n"); break; 89 case IMMLACK: errclass = IWFRSPIFCV; printf("IMM LACK\n"); break; 90 case RIGHTBRACELACK: errclass = 91 signal == 0 ? ICV : 92 signal == 1 ? IWFLIRSPE : 93 -1; printf("RIGHT BRACE LACK\n"); break; 94 case FUNCTIONRETURNNULL: errclass = IWFXXXANE; printf("FUNCTION RETURN NULL\n"); break; 95 case EXPRESSIONERROR: errclass = IWFXXXANE; printf("EXPRESSION ERROR\n"); break; 96 case UNACCEPTABLESENTENCE: errclass = IWFLIRSPE; printf("UNACCEPTABLE SENTENCE\n"); break; 97 case ASSIGNCONST: errclass = 98 signal == 0 ? IWFLIRSPE : 99 signal == 1 ? IWFLIRSPE : 100 -1; 101 printf("ASSIGN CONST\n"); break; 102 case LEFTBRACELACK: errclass = ICV; printf("LEFT BRACE LACK\n"); break; 103 case NONERETURN: errclass = ICV; printf("NON ERETURN\n"); break; 104 case PLUSMINULACK: errclass = IWFLIRSPE; printf("PLUS or MINU LACK\n"); break; 105 case MAINLACK: errclass = DONOTHING; printf("MAIN LACK\n"); break; 106 case MOREWORD: errclass = DONOTHING; printf("MORE WORD\n"); break; 107 case CONSTNOTINIT: errclass = CS; printf("CONST NOT INIT\n"); break; 108 default: errclass = QUIT; printf("Unknow error occurs! [error code: %d]\n", _errsig); 109 } 110 /* 111 laxrst.close(); 112 asmrst.close(); 113 midcoderst.close(); 114 symtablehis.close(); 115 fclose(src); 116 system("pause"); 117 exit(0); 118 */ 119 switch ( errclass ){ 120 case QUIT: 121 system("pause"); 122 exit(0); 123 break; 124 case DONOTHING: 125 break; 126 case ICV: 127 while ( symid != INTTK && symid != CHARTK && symid != VOIDTK ) { 128 if ( symid == -1 ) 129 { 130 system("pause"); exit(0); 131 } 132 getsym(); 133 } 134 break; 135 case CICVIFIRSP: 136 while ( symid != CONSTTK && symid != INTTK && symid != CHARTK && symid != VOIDTK && symid != IFTK && symid != WHILETK 137 && symid != FORTK && symid != IDEN && symid != RETURNTK && symid != SCANFTK && symid != PRINTFTK ){ 138 if ( symid == -1 ) { system("pause"); exit(0); } 139 getsym(); 140 } 141 break; 142 case CS: 143 while ( symid != COMMA && symid != SEMICN ) { 144 if ( symid == -1 ) { system("pause"); exit(0); } 145 getsym(); 146 } 147 break; 148 case CLR: 149 while ( symid != COMMA && symid != LPARENT && symid != RPARENT ) { 150 if ( symid == -1 ) { system("pause"); exit(0); } 151 getsym(); 152 } 153 break; 154 case IWFRSPIFCV: 155 while ( symid != IFTK && symid != WHILETK && symid != FORTK && symid != RETURNTK && symid != SCANFTK 156 && symid != PRINTFTK && symid != INTTK && symid != CHARTK && symid != VOIDTK ) { 157 if ( symid == -1 ) { system("pause"); exit(0); } 158 getsym(); 159 } 160 break; 161 case IWFLIRSPE: 162 while ( symid != IFTK && symid != WHILETK && symid != FORTK && symid != LBRACK && symid != IDEN 163 && symid != RETURNTK && symid != SCANFTK && symid != PRINTFTK && symid != ELSETK && symid != RBRACE) { 164 if ( symid == -1 ) { system("pause"); exit(0); } 165 getsym(); 166 } 167 break; 168 case IWFXXXANE: 169 while ( symid != IFTK && symid != WHILETK && symid != FORTK && symid != LBRACK && symid != IDEN && symid != RETURNTK 170 && symid != SCANFTK && symid != PRINTFTK && symid != SEMICN && symid != ELSETK && symid != RPARENT 171 && symid != COMMA && symid != PLUS && symid != MINU && symid != MULT && symid != DIV 172 && symid != LSS && symid != LEQ && symid != GRE && symid != GEQ && symid != NEQ && symid != EQL ) { 173 if ( symid == -1 ) { system("pause"); exit(0); } 174 getsym(); 175 } 176 break; 177 default: 178 break; 179 } 180 181 }
1 #include <string.h> 2 #include "glob.h" 3 4 int codeindex = 0; 5 6 7 //扫描这个四元式数组,处理所有的基本块 8 void scan() 9 { 10 //找到函数开始 11 while ( strcmp(midcode[ codeindex ].op, "func") != 0 ) codeindex++; 12 13 while ( codeindex < midcodeiter ) { 14 combine(); 15 delpublic(); 16 codeindex++; 17 } 18 delsetlab(); 19 return; 20 } 21 22 //合并常数 23 void combine() { 24 int i = codeindex, num1, num2, temp; 25 char sum[ 30 ]; 26 while ( strcmp(midcode[ i ].op, "+") == 0 || strcmp(midcode[ i ].op, "-") == 0 || strcmp(midcode[ i ].op, "*") == 0 || strcmp(midcode[ i ].op, "/") == 0 ) { 27 if ( isconst(midcode[ i ].var1) && isconst(midcode[ i ].var2) ) { 28 num1 = atoi(midcode[ i ].var1); 29 num2 = atoi(midcode[ i ].var2); 30 if ( strcmp(midcode[ i ].op, "+") == 0 ) temp = num1 + num2; 31 if ( strcmp(midcode[ i ].op, "-") == 0 ) temp = num1 - num2; 32 if ( strcmp(midcode[ i ].op, "*") == 0 ) temp = num1*num2; 33 if ( strcmp(midcode[ i ].op, "/") == 0 ) temp = num1 / num2; 34 sprintf(sum, "%d", temp); 35 strcpy(midcode[ i ].op, "="); 36 strcpy(midcode[ i ].var1, sum); 37 strcpy(midcode[ i ].var2, " "); 38 } 39 i++; 40 } 41 } 42 43 //删除公共子表达式 44 void delpublic() 45 { 46 int i, j, h, k; 47 //划分基本块 48 for ( i = codeindex; strcmp(midcode[ i ].op, "+") == 0 || strcmp(midcode[ i ].op, "-") == 0 || strcmp(midcode[ i ].op, "*") == 0 || strcmp(midcode[ i ].op, "/") == 0 || strcmp(midcode[ i ].op, "=") == 0; i++ ) { 49 if ( i >= midcodeiter ){ 50 return; 51 } 52 if ( midcode[ i ].var3[ 0 ] == '$' ) { 53 for ( j = i + 1; strcmp(midcode[ j ].op, "+") == 0 || strcmp(midcode[ j ].op, "-") == 0 || strcmp(midcode[ j ].op, "*") == 0 || strcmp(midcode[ j ].op, "/") == 0 || strcmp(midcode[ j ].op, "=") == 0; j++ ) { 54 if ( j >= midcodeiter ){ 55 return; 56 } 57 //寻找公共子表达式 58 if ( strcmp(midcode[ j ].op, midcode[ i ].op) == 0 && strcmp(midcode[ j ].var1, midcode[ i ].var1) == 0 && strcmp(midcode[ j ].var2, midcode[ i ].var2) == 0 && midcode[ j ].var3[ 0 ] == '$' ) { 59 //修改变量的名字 60 for ( h = j + 1; strcmp(midcode[ h ].op, "+") == 0 || strcmp(midcode[ h ].op, "-") == 0 || strcmp(midcode[ h ].op, "*") == 0 || strcmp(midcode[ h ].op, "/") == 0 || strcmp(midcode[ h ].op, "=") == 0; h++ ) { 61 if ( h >= midcodeiter ){ 62 return; 63 } 64 if ( strcmp(midcode[ h ].var1, midcode[ j ].var3) == 0 ) 65 strcpy(midcode[ h ].var1, midcode[ i ].var3); 66 if ( strcmp(midcode[ h ].var2, midcode[ j ].var3) == 0 ) 67 strcpy(midcode[ h ].var2, midcode[ i ].var3); 68 } 69 for ( k = j; k< midcodeiter; k++ ) { 70 strcpy(midcode[ k ].op, midcode[ k + 1 ].op); //删除 71 strcpy(midcode[ k ].var1, midcode[ k + 1 ].var1); 72 strcpy(midcode[ k ].var2, midcode[ k + 1 ].var2); 73 strcpy(midcode[ k ].var3, midcode[ k + 1 ].var3); 74 } 75 midcodeiter--; 76 j--; 77 } 78 } 79 } 80 } 81 } 82 83 //删除冗余跳转代码 84 void delsetlab() 85 { 86 int i, k, j, t, flag; 87 char temp[ 30 ][ 10 ]; 88 for ( i = 0; i < midcodeiter; i++ ) { 89 if ( i >= midcodeiter ){ 90 return; 91 } 92 if ( strcmp(midcode[ i ].op, "lab:") == 0 ) { 93 j = 0; 94 flag = i; 95 i = i + 1; 96 while ( strcmp(midcode[ i ].op, "lab:") == 0 ) { 97 strcpy(temp[ j++ ], midcode[ i ].var3); 98 for ( k = i; k<midcodeiter; k++ ) { 99 strcpy(midcode[ k ].op, midcode[ k + 1 ].op); //删除 100 strcpy(midcode[ k ].var1, midcode[ k + 1 ].var1); 101 strcpy(midcode[ k ].var2, midcode[ k + 1 ].var2); 102 strcpy(midcode[ k ].var3, midcode[ k + 1 ].var3); 103 } 104 midcodeiter--; 105 } 106 if ( j == 0 ) continue; 107 for ( k = 0; k <= midcodeiter; k++ ) { 108 if ( k >= midcodeiter ){ 109 return; 110 } 111 if ( strcmp(midcode[ k ].op, "jmp") == 0 || strcmp(midcode[ k ].op, "jne") == 0 ) { 112 for ( t = 0; t<j; t++ ) { 113 if ( strcmp(midcode[ k ].var3, temp[ t ]) == 0 ) 114 strcpy(midcode[ k ].var3, midcode[ flag ].var3); 115 } 116 } 117 } 118 } 119 } 120 } 121 122 //判断是不是数字 123 int isconst(char name[]) 124 { 125 int i = 0; 126 if ( name[ i ] == '-' ) i++; 127 while ( name[ i ] != '\0' ) { 128 if ( name[ i ]>'9' || name[ i ]<'0' ) return 0; 129 i++; 130 } 131 return 1; 132 } 133 134 //打印优化后的四元式 135 void printOptimize() 136 { 137 optcodefile = fopen("optMidCode.txt", "w"); 138 int i = 0; 139 while ( i<midcodeiter ) { 140 fprintf(optcodefile, "%s,\t", midcode[ i ].op); 141 fprintf(optcodefile, "%s,\t", midcode[ i ].var1); 142 fprintf(optcodefile, "%s,\t", midcode[ i ].var2); 143 fprintf(optcodefile, "%s;\n", midcode[ i ].var3); 144 if ( strcmp(midcode[ i ].op, "end") == 0 ) 145 fprintf(optcodefile, "\n\n"); 146 i++; 147 } 148 fclose(optcodefile); 149 return; 150 }
1 #include "glob.h" 2 #define rsT asmrst 3 #define VOID 0 4 #define INT 1 5 #define CHAR 2 6 #define WINT 3 7 #define WCHAR 4 8 #define INITSTACK 0x7fffeffc 9 #define INITDATA 0x10010000 10 #define OPTFLAG 0 //优化开关 11 12 int mi = 0; //四元式处理的行数 13 int sp = INITSTACK; //栈指针,此地址为即将分配的!!相对fp!!地址 14 int fp = 0;//帧指针 15 int ap;//地址表计数器 16 int paran = 0; 17 int constedge = 0; 18 int tmi; 19 int ismain = 0; 20 int tlabelnum = 0; 21 int isglob; 22 int funckin; 23 int funcnum = 0; 24 25 typedef struct { 26 char name[ 100 ]; 27 int kind; 28 }funcclass; 29 vector<funcclass> fc;//函数表 30 31 typedef struct { 32 char name[ 100 ]; 33 int address; 34 int kind; 35 int cnt; 36 }tempvaraddress;//变量表 37 tempvaraddress addrtable[ 1000 ];//临时变量在栈中的地址表 38 39 typedef struct { 40 int symbnum; 41 int cnt; 42 }cntstruct; 43 cntstruct cnttable[200];//计数器 44 int cntindex = 0; 45 46 int varreg[ 200 ]; 47 48 bool cmpcnt(cntstruct a, cntstruct b) { 49 return a.cnt > b.cnt; 50 } 51 52 int funckind(char *fname) { 53 for ( int i = 0; i < fc.size(); i++ ) { 54 if ( strcmp(fc[i].name, fname) == 0 ) { 55 return fc[ i ].kind; 56 } 57 } 58 } 59 60 int findvartable(char *name) { 61 int t = ap - 1; 62 if ( name[ 0 ] == '+' || name[ 0 ] == '-' || name[ 0 ] >= '0'&&name[ 0 ] <= '9' ) 63 return -1; 64 while ( t >= 0 ) { 65 if ( strcmp(addrtable[ t ].name, name) == 0 ) 66 return t; 67 t--; 68 } 69 return -1; 70 } 71 72 int varkind(char *name) { 73 int t = ap - 1; 74 if ( name[ 0 ] == '+' || name[ 0 ] == '-' || name[ 0 ] >= '0'&&name[ 0 ] <= '9' ) 75 return -1; 76 while ( t >= 0 ) { 77 if ( strcmp(addrtable[ t ].name, name) == 0 ) 78 return addrtable[ t ].kind; 79 t--; 80 } 81 return -1; 82 } 83 84 void midcode2asm(){ 85 memset(varreg, 0xff, sizeof(int) * 200); 86 rsT << "\t.text" << endl; 87 rsT << "\t\tori\t$fp\t$sp\t0" << endl; 88 rsT << "\t\tli\t$t9\t0x7fffeffc\t#global stack bottom" << endl; 89 rsT << "\t\tli\t$t8\t0x10010000\t#save word" << endl; 90 sp = 0; 91 mi = ap = 0; 92 93 while ( mi < midcodeiter ){ 94 //全局常量定义 95 while ( strcmp(midcode[ mi ].op, "const") == 0 ) { 96 pushstack(midcode[ mi ].var2); 97 if ( strcmp(midcode[ mi ].var1, "int") == 0 ) { 98 insertaddress(WINT); 99 } else { 100 insertaddress(WCHAR); 101 } 102 mi++; 103 } 104 //全局变量定义 105 while ( strcmp(midcode[ mi ].op, "int") == 0 || strcmp(midcode[ mi ].op, "char") == 0 ) { 106 pushstack("0"); 107 if ( strcmp(midcode[ mi ].op, "int") == 0 ) { 108 insertaddress(WINT); 109 } else { 110 insertaddress(WCHAR); 111 } 112 mi++; 113 } 114 //全局数组定义 115 while ( strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) { 116 pushstack("0", atoi(midcode[mi].var2)); 117 if ( strcmp(midcode[ mi ].op, "inta") == 0 ) { 118 insertaddress(WINT); 119 } else { 120 insertaddress(WCHAR); 121 } 122 mi++; 123 } 124 rsT << "\t\tj\t__main" << endl; 125 constedge = ap; 126 //函数定义 127 funcclass tfc; 128 while ( strcmp(midcode[mi].op, "func") == 0 ) { 129 funcnum++; 130 if ( strcmp(midcode[ mi ].var1, "char") == 0 ) { 131 tfc.kind = CHAR; 132 strcpy(tfc.name, midcode[ mi ].var3); 133 fc.push_back(tfc); 134 } else if ( strcmp(midcode[ mi ].var1, "int") == 0 ) { 135 tfc.kind = INT; 136 strcpy(tfc.name, midcode[ mi ].var3); 137 fc.push_back(tfc); 138 } else { 139 tfc.kind = VOID; 140 strcpy(tfc.name, midcode[ mi ].var3); 141 fc.push_back(tfc); 142 } 143 if ( strcmp(midcode[ mi ].var3, "main") == 0 ) { 144 ismain = 1; 145 rsT << "__main:" << endl; 146 } else { 147 ismain = 0; 148 rsT << midcode[ mi ].var3 << ":" << endl; 149 } 150 mi++; 151 funcasm(); 152 } 153 } 154 } 155 156 //给地址表插入相对地址,sp不变 157 void insertaddress(int kind, int addr, int nmi) { 158 if ( nmi == -1 ) { 159 strcpy(addrtable[ ap ].name, midcode[ mi ].var3); 160 } else { 161 strcpy(addrtable[ ap ].name, midcode[ nmi ].var3); 162 } 163 if ( addr == -1 ) { 164 addrtable[ ap ].address = sp + 4; 165 } else { 166 addrtable[ ap ].address = addr; 167 } 168 addrtable[ ap ].kind = kind; 169 addrtable[ ap ].cnt = 0; 170 ap++; 171 } 172 173 void pushstack(char* item, int lenth) { 174 if ( lenth == 1 ) { 175 rsT << "\t\tli\t$t0\t" << item << "\t#" << midcode[tmi].var3 << endl; //li $t0 item 176 rsT << "\t\tsw\t$t0\t($sp)" << endl; //sw $t0 $sp 177 } 178 sp -= ( 4 * lenth ); 179 rsT << "\t\tsubi\t$sp\t$sp\t" << 4 * lenth << endl; //subi $sp $sp 4 180 return; 181 } 182 183 //处理函数内容,不处理最后的end和开始的func 184 void funcasm() { 185 memset(varreg, 0xff, sizeof(int) * 200); 186 sp = 0;//相对偏移为0 187 //保存现场 188 rsT << "\t\t#Save Register" << endl;// 189 savesreg(); 190 rsT << "\t\tsw\t$fp\t($sp)" << endl;//保存上一个函数的$fp 191 rsT << "\t\tadd\t$fp\t$sp\t$0" << endl;//设置本函数$fp:$fp=$sp 192 sp -= 4; 193 rsT << "\t\tsubi\t$sp\t$sp\t4" << endl;//$sp-=4 194 rsT << "\t\tsw\t$ra\t($sp)" << endl;//保存$ra 195 sp -= 4; 196 rsT << "\t\tsubi\t$sp\t$sp\t4" << endl;//$sp-=4 197 rsT << "\t\t#Save Register Done!" << endl;// 198 199 //while ( strcmp(midcode[ mi ].op, "int") == 0 || strcmp(midcode[ mi ].op, "char") == 0 200 // || strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) { 201 // ////变量定义 202 // //while ( strcmp(midcode[ mi ].op, "int") == 0 || strcmp(midcode[ mi ].op, "char") == 0 ) { 203 // // pushstack("0"); 204 // // if ( strcmp(midcode[ mi ].var1, "int") == 0 ) { 205 // // insertaddress(INT); 206 // // } else { 207 // // insertaddress(CHAR); 208 // // } 209 // // mi++; 210 // //} 211 // ////数组定义 212 // //while ( strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) { 213 // // pushstack("0", atoi(midcode[ mi ].var2)); 214 // // if ( strcmp(midcode[ mi ].var1, "inta") == 0 ) { 215 // // insertaddress(INT); 216 // // } else { 217 // // insertaddress(CHAR); 218 // // } 219 // // mi++; 220 // //} 221 //} 222 //临时变量定义 223 tmi = mi; 224 while ( strcmp(midcode[ tmi ].op, "end") != 0 ) { 225 char v1[100], v2[100], v3[100]; 226 strcpy(v1, midcode[ tmi ].var1); 227 strcpy(v2, midcode[ tmi ].var2); 228 strcpy(v3, midcode[ tmi ].var3); 229 230 231 if ( v1[ 0 ] == '$' && varaddr(v1) == -1 ) { 232 pushstack("0"); 233 insertaddress(INT, -1, tmi); 234 } 235 if ( v2[ 0 ] == '$' && varaddr(v2) == -1 ) { 236 pushstack("0"); 237 insertaddress(INT, -1, tmi); 238 } 239 if ( v3[0] == '$' && varaddr(v3) == -1 ) { 240 pushstack("0"); 241 if ( strcmp(midcode[tmi].op, "call") == 0 ) { 242 insertaddress(funckind(midcode[tmi].var1), -1, tmi); 243 } 244 else if ( strcmp(midcode[ tmi ].op, "geta") == 0 ){ 245 insertaddress(varkind(v1), -1, tmi); 246 } 247 else{ 248 insertaddress(INT, -1, tmi); 249 } 250 } 251 tmi++; 252 } 253 254 while ( strcmp(midcode[ mi ].op, "end") != 0 ) { 255 paran = 0; 256 for ( int i = 0; i < strlen(midcode[ mi ].op); i++ ) { 257 if ( midcode[ mi ].op[ i ] == ' ' ) { 258 midcode[ mi ].op[ i ] = '\0'; 259 break; 260 } 261 } 262 if ( strcmp(midcode[ mi ].op, "+") == 0 ) addasm(); 263 if ( strcmp(midcode[ mi ].op, "-") == 0 ) subasm(); 264 if ( strcmp(midcode[ mi ].op, "*") == 0 ) mulasm(); 265 if ( strcmp(midcode[ mi ].op, "/") == 0 ) divasm(); 266 if ( strcmp(midcode[ mi ].op, ">") == 0 ) greasm(); 267 if ( strcmp(midcode[ mi ].op, ">=") == 0 ) geqasm(); 268 if ( strcmp(midcode[ mi ].op, "<") == 0 ) lssasm(); 269 if ( strcmp(midcode[ mi ].op, "<=") == 0 ) leqasm(); 270 if ( strcmp(midcode[ mi ].op, "!=") == 0 ) neqasm(); 271 if ( strcmp(midcode[ mi ].op, "==") == 0 ) eqlasm(); 272 if ( strcmp(midcode[ mi ].op, "=") == 0 ) assasm(); 273 if ( strcmp(midcode[ mi ].op, "[]=") == 0 ) aassasm(); 274 if ( strcmp(midcode[ mi ].op, "geta") == 0 ) assaasm(); 275 if ( strcmp(midcode[ mi ].op, "lab:") == 0 ) setlabasm(); 276 if ( strcmp(midcode[ mi ].op, "scf") == 0 ) { 277 scfasm(); 278 } 279 if ( strcmp(midcode[ mi ].op, "prt") == 0 ) { 280 prtasm(); 281 } 282 if ( strcmp(midcode[ mi ].op, "jne") == 0 ) jneasm(); 283 if ( strcmp(midcode[ mi ].op, "jmp") == 0 ) jmpasm(); 284 if ( strcmp(midcode[ mi ].op, "fupa") == 0 ) fupaasm(); 285 if ( strcmp(midcode[ mi ].op, "call") == 0 ) callasm(); 286 if ( strcmp(midcode[ mi ].op, "ret") == 0 ) retasm(); 287 if ( strcmp(midcode[ mi ].op, "para") == 0 ) paraasm(); 288 if ( OPTFLAG ) { 289 int flag = 0; 290 while ( strcmp(midcode[ mi ].op, "int") == 0 291 || strcmp(midcode[ mi ].op, "char") == 0 ) { 292 flag = 1; 293 intcharasm(); 294 mi++; 295 } 296 if (flag) mi--; 297 //引用计数优化 298 cntopt(); 299 } else { 300 if ( strcmp(midcode[ mi ].op, "int") == 0 301 || strcmp(midcode[ mi ].op, "char") == 0 ) intcharasm(); 302 } 303 304 if ( strcmp(midcode[ mi ].op, "const") == 0 ) constdefasm(); 305 if ( strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) intcharaasm(); 306 mi++; 307 } 308 ap = constedge; 309 //恢复现场 310 rsT << "__FEND_LAB_" << funcnum << ":" << endl;//结束开始 311 rsT << "\t\tlw\t$ra\t-4($fp)" << endl;//恢复$ra 312 rsT << "\t\tadd\t$sp\t$fp\t$0" << endl;//退栈,恢复$sp 313 rsT << "\t\tlw\t$fp\t($fp)" << endl;//恢复上一个函数的fp 314 loadsreg();//恢复$s0-$s7 315 if ( ismain ) { 316 rsT << "\t\tli\t$v0\t10" << endl; 317 rsT << "\t\tsyscall" << endl;//终止程序 318 } else { 319 rsT << "\t\tjr\t$ra\t" << endl;//返回 320 } 321 mi = mi + 1; 322 return; 323 } 324 325 //查找汇编变量地址 326 int varaddr(char *name) { 327 int t = ap - 1; 328 isglob = 0; 329 if ( name[ 0 ] == '+' || name[ 0 ] == '-' || name[ 0 ] >= '0'&&name[ 0 ] <= '9' ) 330 return -1; 331 while ( t >= 0 ) { 332 if ( strcmp(addrtable[ t ].name, name) == 0 ) { 333 if ( t < constedge ) { 334 isglob = 1; 335 } 336 return addrtable[ t ].address; 337 } 338 t--; 339 } 340 return -1; 341 } 342 343 //void dataseg() { 344 // rsT << "\t.data" << endl; 345 // while ( strcmp(midcode[mi].op, "const") == 0 ) { 346 // if ( strcmp(midcode[mi].var1, "int") == 0 || 347 // strcmp(midcode[mi].var1, "char") == 0 ) { 348 // rsT << ".word" << endl; 349 // } 350 // } 351 //} 352 353 // jmp , , , 354 void jmpasm() { 355 rsT << "\t\tj\t" << midcode[ mi ].var3 << endl; 356 } 357 358 // jne 359 void jneasm() { 360 rsT << "\t\tbne\t$t0\t1\t" << midcode[ mi ].var3 << endl; 361 } 362 363 // call, f , , a 364 void callasm() { 365 rsT << "\t\tjal\t" << midcode[ mi ].var1 << endl; 366 rsT << "\t\tnop\n"; 367 if ( midcode[ mi ].var3[ 0 ] != ' ' && midcode[ mi ].var3[ 0 ] != '\0' ) { 368 int addr2; 369 addr2 = varaddr(midcode[ mi ].var3); 370 if ( isglob ) 371 rsT << "\t\tsw\t$v0\t" << addr2 << "($t9)" << endl; 372 else 373 rsT << "\t\tsw\t$v0\t" << addr2 << "($fp)" << endl; 374 } 375 } 376 377 // lab, , , 378 void setlabasm() { 379 rsT << midcode[ mi ].var3 << ":\n"; 380 } 381 382 // add, a, b, c 383 void addasm() { 384 int addr1, addr2, addr3; 385 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 386 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 387 } else { 388 addr1 = varaddr(midcode[ mi ].var1); 389 if ( isglob ) 390 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 391 else 392 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 393 } 394 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 395 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 396 } else { 397 addr2 = varaddr(midcode[ mi ].var2); 398 if ( isglob ) 399 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 400 else 401 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 402 } 403 addr3 = varaddr(midcode[ mi ].var3); 404 rsT << "\t\tadd\t$t0\t$t0\t$t1" << endl; 405 if ( isglob ) 406 rsT << "\t\tsw\t$t0\t" << addr1 << "($t9)" << endl; 407 else 408 rsT << "\t\tsw\t$t0\t" << addr3 << "($fp)" << endl; 409 } 410 411 // sub, a, b, c 412 void subasm() { 413 int addr1, addr2, addr3; 414 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 415 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 416 } else { 417 addr1 = varaddr(midcode[ mi ].var1); 418 if ( isglob ) 419 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 420 else 421 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 422 } 423 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 424 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 425 } else { 426 addr2 = varaddr(midcode[ mi ].var2); 427 if ( isglob ) 428 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 429 else 430 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 431 } 432 addr3 = varaddr(midcode[ mi ].var3); 433 rsT << "\t\tsub\t$t0\t$t0\t$t1" << endl; 434 if ( isglob ) 435 rsT << "\t\tsw\t$t0\t" << addr3 << "($t9)" << endl; 436 else 437 rsT << "\t\tsw\t$t0\t" << addr3 << "($fp)" << endl; 438 } 439 440 // mul, a, b, c 441 void mulasm() { 442 int addr1, addr2, addr3; 443 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 444 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 445 } else { 446 addr1 = varaddr(midcode[ mi ].var1); 447 if ( isglob ) 448 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 449 else 450 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 451 } 452 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 453 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 454 } else { 455 addr2 = varaddr(midcode[ mi ].var2); 456 if ( isglob ) 457 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 458 else 459 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 460 } 461 addr3 = varaddr(midcode[ mi ].var3); 462 rsT << "\t\tmul\t$t0\t$t0\t$t1" << endl; 463 if ( isglob ) 464 rsT << "\t\tsw\t$t0\t" << addr3 << "($t9)" << endl; 465 else 466 rsT << "\t\tsw\t$t0\t" << addr3 << "($fp)" << endl; 467 } 468 469 // div, a, b, c 470 void divasm() { 471 int addr1, addr2, addr3; 472 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 473 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 474 } else { 475 addr1 = varaddr(midcode[ mi ].var1); 476 if ( isglob ) 477 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 478 else 479 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 480 } 481 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 482 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 483 } else { 484 addr2 = varaddr(midcode[ mi ].var2); 485 if ( isglob ) 486 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 487 else 488 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 489 } 490 addr3 = varaddr(midcode[ mi ].var3); 491 rsT << "\t\tdiv\t$t0\t$t0\t$t1" << endl; 492 if ( isglob ) 493 rsT << "\t\tsw\t$t0\t" << addr3 << "($t9)" << endl; 494 else 495 rsT << "\t\tsw\t$t0\t" << addr3 << "($fp)" << endl; 496 } 497 498 // > , a, b, c 499 void greasm() { 500 int addr1, addr2; 501 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 502 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 503 } else { 504 addr1 = varaddr(midcode[ mi ].var1); 505 if ( isglob ) 506 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 507 else 508 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 509 } 510 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 511 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 512 } else { 513 addr2 = varaddr(midcode[ mi ].var2); 514 if ( isglob ) 515 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 516 else 517 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 518 } 519 rsT << "\t\tslt\t$t0\t$t1\t$t0" << endl; 520 } 521 522 // >= 523 void geqasm() { 524 int addr1, addr2; 525 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 526 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 527 } else { 528 addr1 = varaddr(midcode[ mi ].var1); 529 if ( isglob ) 530 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 531 else 532 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 533 } 534 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 535 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 536 } else { 537 addr2 = varaddr(midcode[ mi ].var2); 538 if ( isglob ) 539 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 540 else 541 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 542 } 543 rsT << "\t\tslt\t$t0\t$t0\t$t1" << endl; 544 rsT << "\t\tli\t$t1\t1" << endl; 545 rsT << "\t\tsub\t$t0\t$t1\t$t0" << endl; 546 } 547 548 // < 549 void lssasm() { 550 int addr1, addr2; 551 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 552 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 553 } else { 554 addr1 = varaddr(midcode[ mi ].var1); 555 if ( isglob ) 556 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 557 else 558 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 559 } 560 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 561 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 562 } else { 563 addr2 = varaddr(midcode[ mi ].var2); 564 if ( isglob ) 565 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 566 else 567 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 568 } 569 rsT << "\t\tslt\t$t0\t$t0\t$t1" << endl; 570 } 571 572 // <= 573 void leqasm() { 574 int addr1, addr2; 575 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 576 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 577 } else { 578 addr1 = varaddr(midcode[ mi ].var1); 579 if ( isglob ) 580 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 581 else 582 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 583 } 584 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 585 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 586 } else { 587 addr2 = varaddr(midcode[ mi ].var2); 588 if ( isglob ) 589 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 590 else 591 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 592 } 593 rsT << "\t\tslt\t$t0\t$t1\t$t0" << endl; 594 rsT << "\t\tli\t$t1\t1" << endl; 595 rsT << "\t\tsub\t$t0\t$t1\t$t0" << endl; 596 } 597 598 // == 599 void eqlasm() { 600 int addr1, addr2; 601 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 602 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 603 } else { 604 addr1 = varaddr(midcode[ mi ].var1); 605 if ( isglob ) 606 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 607 else 608 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 609 } 610 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 611 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 612 } else { 613 addr2 = varaddr(midcode[ mi ].var2); 614 if ( isglob ) 615 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 616 else 617 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 618 } 619 620 int t1 = tlabelnum++; 621 int t2 = tlabelnum++; 622 rsT << "\t\tbne\t$t0\t$t1\t__tLABEL" << t1 << endl; 623 rsT << "\t\tli\t$t0\t1" << endl; 624 rsT << "\t\tj\t__tLABEL" << t2 << endl; 625 rsT << "__tLABEL" << t1 << ":" << endl; 626 //cout << "__tLABEL" << t1 << ":" << endl; 627 rsT << "\t\tli\t$t0\t0" << endl; 628 rsT << "__tLABEL" << t2 << ":" << endl; 629 } 630 631 // != 632 void neqasm() { 633 int addr1, addr2; 634 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 635 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 636 } else { 637 addr1 = varaddr(midcode[ mi ].var1); 638 if ( isglob ) 639 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 640 else 641 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 642 } 643 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 644 rsT << "\t\tli\t$t1\t" << midcode[ mi ].var2 << endl; 645 } else { 646 addr2 = varaddr(midcode[ mi ].var2); 647 if ( isglob ) 648 rsT << "\t\tlw\t$t1\t" << addr2 << "($t9)" << endl; 649 else 650 rsT << "\t\tlw\t$t1\t" << addr2 << "($fp)" << endl; 651 } 652 int t1 = tlabelnum++; 653 int t2 = tlabelnum++; 654 rsT << "\t\tbeq\t$t0\t$t1\t__tLABEL" << t1 << endl; 655 rsT << "\t\tli\t$t0\t1" << endl; 656 rsT << "\t\tj\t__tLABEL" << t2 << endl; 657 rsT << "__tLABEL" << t1 << ":" << endl; 658 //cout << "__tLABEL" << t1 << ":" << endl; 659 rsT << "\t\tli\t$t0\t0" << endl; 660 rsT << "__tLABEL" << t2 << ":" << endl; 661 } 662 663 // = 664 void assasm() { 665 int addr1, addr2; 666 if ( isdigit(midcode[ mi ].var1[ 0 ]) || midcode[ mi ].var1[ 0 ] == '-' || midcode[ mi ].var1[ 0 ] == '+' ) { 667 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var1 << endl; 668 } else { 669 addr1 = varaddr(midcode[ mi ].var1); 670 if ( isglob ) 671 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 672 else 673 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 674 } 675 addr2 = varaddr(midcode[ mi ].var3); 676 if (isglob ) 677 rsT << "\t\tsw\t$t0\t" << addr2 << "($t9)" << endl; 678 else 679 rsT << "\t\tsw\t$t0\t" << addr2 << "($fp)" << endl; 680 } 681 682 // []= , a , i , t 683 void aassasm() { 684 int addr1, addr2, addrt; 685 addr1 = varaddr(midcode[ mi ].var1); 686 int tisglob = isglob; 687 if ( isdigit(midcode[ mi ].var2[0]) ) { 688 addr1 += (atoi(midcode[ mi ].var2) * 4); 689 if ( isdigit(midcode[ mi ].var3[ 0 ]) || midcode[ mi ].var3[ 0 ] == '-' || midcode[ mi ].var3[ 0 ] == '+' ) { 690 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var3 << endl; 691 } else { 692 addr2 = varaddr(midcode[ mi ].var3); 693 if ( isglob ) { 694 rsT << "\t\tlw\t$t0\t" << addr2 << "($t9)" << endl; 695 }else 696 rsT << "\t\tlw\t$t0\t" << addr2 << "($fp)" << endl; 697 } 698 if (isglob) 699 rsT << "\t\tsw\t$t0\t" << addr1 << "($t9)" << endl; 700 else 701 rsT << "\t\tsw\t$t0\t" << addr1 << "($fp)" << endl; 702 } else { 703 //求数组元素a[i]地址 704 addrt = varaddr(midcode[ mi ].var2);//addrt = &i 705 if (isglob) 706 rsT << "\t\tlw\t$t1\t" << addrt << "($t9)" << endl; //t1 = i 707 else 708 rsT << "\t\tlw\t$t1\t" << addrt << "($fp)" << endl; //t1 = i 709 rsT << "\t\tmul\t$t1\t$t1\t4\n"; //t1 = t1 * 4 (t1 = offset) 710 rsT << "\t\taddi\t$t1\t$t1\t" << addr1 << endl; //t1 = &a[i] - $fp 711 rsT << "\t\tadd\t$t1\t$t1\t$fp" << endl;//t1 = &a[i] 712 if ( isdigit(midcode[ mi ].var3[ 0 ]) || midcode[ mi ].var3[ 0 ] == '-' || midcode[ mi ].var3[ 0 ] == '+' ) { 713 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var3 << endl; 714 } else { 715 addr2 = varaddr(midcode[ mi ].var3); 716 if ( isglob ) { 717 rsT << "\t\tlw\t$t0\t" << addr2 << "($t9)" << endl; 718 } else { 719 rsT << "\t\tlw\t$t0\t" << addr2 << "($fp)" << endl; 720 } 721 722 } 723 rsT << "\t\tsw\t$t0\t0($t1)" << endl; 724 } 725 } 726 727 //geta, a, n, b 728 void assaasm() { 729 int addr1 = varaddr(midcode[ mi ].var1); 730 int tisglob = isglob; 731 int addr2; 732 if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 733 addr1 += ( atoi(midcode[ mi ].var2) * 4 ); //addr1 = &a[n] 734 addr2 = varaddr(midcode[ mi ].var3); //addr2 = &b 735 if ( tisglob ) { 736 rsT << "\t\tlw\t$t0\t" << addr1 << "($t9)" << endl; 737 }else 738 rsT << "\t\tlw\t$t0\t" << addr1 << "($fp)" << endl; 739 if ( isglob ) { 740 rsT << "\t\tsw\t$t0\t" << addr2 << "($t9)" << endl; 741 }else 742 rsT << "\t\tsw\t$t0\t" << addr2 << "($fp)" << endl; 743 } else { 744 //求数组元素a[i]地址 745 int addrt = varaddr(midcode[ mi ].var2);//addrt = &i 746 if ( isglob ) { 747 rsT << "\t\tlw\t$t1\t" << addrt << "($t9)" << endl; //t1 = i 748 }else 749 rsT << "\t\tlw\t$t1\t" << addrt << "($fp)" << endl; //t1 = i 750 rsT << "\t\tmul\t$t1\t$t1\t4\n"; //t1 = t1 * 4 (t1 = offset) 751 rsT << "\t\taddi\t$t1\t$t1\t" << addr1 << endl; //t1 = &a[i] - $fp 752 rsT << "\t\tadd\t$t1\t$t1\t$fp" << endl; 753 rsT << "\t\tlw\t$t1\t0($t1)\n"; //t1 = a[i] 754 addr2 = varaddr(midcode[ mi ].var3); //addr2 = &b 755 if (isglob) 756 rsT << "\t\tsw\t$t1\t" << addr2 << "($t9)" << endl; 757 else 758 rsT << "\t\tsw\t$t1\t" << addr2 << "($fp)" << endl; 759 } 760 } 761 762 //scf , , , a 763 void scfasm() { 764 int addr = varaddr(midcode[ mi ].var3); 765 int ti = findvartable(midcode[ mi ].var3); 766 int kind = addrtable[ ti ].kind; 767 if ( kind == INT ) { 768 rsT << "\t\tli\t$v0\t5" << endl; 769 rsT << "\t\tsyscall" << endl; 770 //rsT << "\t\tsubi\t$v0\t$v0\t" << ( int )'0' << endl; 771 if (isglob) 772 rsT << "\t\tsw\t$v0\t" << addr << "($t9)" << endl; 773 else 774 rsT << "\t\tsw\t$v0\t" << addr << "($fp)" << endl; 775 } else { 776 rsT << "\t\tli\t$v0\t12" << endl; 777 rsT << "\t\tsyscall" << endl; 778 if ( isglob ) 779 rsT << "\t\tsw\t$v0\t" << addr << "($t9)" << endl; 780 else 781 rsT << "\t\tsw\t$v0\t" << addr << "($fp)" << endl; 782 } 783 } 784 785 //prt, a, b, symb 786 void prtasm() { 787 int addr; 788 if ( midcode[ mi ].var1[ 0 ] != '\0' ) { 789 int len = strlen(midcode[ mi ].var1); 790 for ( int i = 0; i < len; i++ ) { 791 rsT << "\t\tli\t$v0\t11" << endl; 792 rsT << "\t\tli\t$a0\t" << int(midcode[ mi ].var1[i]) << endl; 793 rsT << "\t\tsyscall" << endl; 794 } 795 } 796 if ( midcode[ mi ].var2[ 0 ] != ' ' && midcode[ mi ].var2[ 0 ] != '\0' ) { 797 if ( isdigit(midcode[mi].var2[0]) && strcmp(midcode[mi].var3, "char") == 0 ) { 798 rsT << "\t\tli\t$v0\t11" << endl; 799 rsT << "\t\tli\t$a0\t" << midcode[ mi ].var2 << endl; 800 rsT << "\t\tsyscall" << endl; 801 return; 802 } else if ( isdigit(midcode[ mi ].var2[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 803 rsT << "\t\tli\t$v0\t1" << endl; 804 rsT << "\t\tli\t$a0\t" << midcode[ mi ].var2 << endl; 805 rsT << "\t\tsyscall" << endl; 806 return; 807 } 808 addr = varaddr(midcode[ mi ].var2); 809 int ti = findvartable(midcode[ mi ].var2); 810 int kind = addrtable[ ti ].kind; 811 if ( kind == INT || kind == WINT) { 812 rsT << "\t\tli\t$v0\t1" << endl; 813 if ( isglob ) { 814 rsT << "\t\tlw\t$a0\t" << addr << "($t9)" << endl; 815 }else 816 rsT << "\t\tlw\t$a0\t" << addr << "($fp)" << endl; 817 rsT << "\t\tsyscall" << endl; 818 } else { 819 rsT << "\t\tli\t$v0\t11" << endl; 820 if ( isglob ) rsT << "\t\tlw\t$a0\t" << addr << "($t9)" << endl; 821 else rsT << "\t\tlw\t$a0\t" << addr << "($fp)" << endl; 822 rsT << "\t\tsyscall" << endl; 823 } 824 } 825 } 826 827 //fupa, , , a ==> a is a function parameter 828 void fupaasm() { 829 if ( isdigit(midcode[mi].var3[0]) ) { 830 rsT << "\t\tli\t$t0\t" << midcode[ mi ].var3 << endl; 831 } else { 832 rsT << "\t\tlw\t$t0\t" << varaddr(midcode[ mi ].var3); //li $t0 item 833 if(isglob){ 834 rsT << "($t9)" << endl; 835 }else{ 836 rsT << "($fp)" << endl; 837 } 838 } 839 rsT << "\t\tsw\t$t0\t($sp)" << endl; //sw $t0 $sp 840 sp -= 4; 841 rsT << "\t\tsubi\t$sp\t$sp\t4" << endl; //subi $sp $sp 4 842 } 843 844 //ret , , , (a) ==> return a / return 845 void retasm() { 846 if ( midcode[ mi ].var3[ 0 ] != ' ' && midcode[ mi ].var3[ 0 ] != '\0' ) { 847 if ( isdigit(midcode[ mi ].var3[ 0 ]) || midcode[ mi ].var2[ 0 ] == '-' || midcode[ mi ].var2[ 0 ] == '+' ) { 848 rsT << "\t\tli\t$v0\t" << midcode[ mi ].var3 << endl; 849 } else { 850 int addr2 = varaddr(midcode[ mi ].var3); 851 if ( isglob ) 852 rsT << "\t\tlw\t$v0\t" << addr2 << "($t9)" << endl; 853 else 854 rsT << "\t\tlw\t$v0\t" << addr2 << "($fp)" << endl; 855 } 856 } 857 rsT << "\t\tj\t__FEND_LAB_" << funcnum << endl;//跳至结束 858 } 859 860 //para, int, , a == > f(int a, ...) 861 void paraasm() { 862 paranum = 0; 863 for ( int i = mi; i < midcodeiter; i++ ) { 864 if ( strcmp(midcode[ i ].op, "para") == 0 ) 865 paranum++; 866 else 867 break; 868 } 869 for ( int i = 0; i < paranum; i++ ) { 870 int kind = (strcmp(midcode[ mi ].var1, "int") == 0) ? INT : CHAR; 871 insertaddress(kind, 4 * ( paranum - i )); 872 mi++; 873 } 874 mi--; 875 } 876 877 void intcharasm() { 878 if ( isdigit(midcode[ mi ].var2[0]) ) { 879 pushstack(midcode[ mi ].var2); 880 } else { 881 pushstack("0"); 882 } 883 if ( strcmp(midcode[ mi ].op, "int") == 0 ) { 884 insertaddress(INT); 885 } else { 886 insertaddress(CHAR); 887 } 888 } 889 890 void constdefasm() { 891 //常量定义 892 while ( strcmp(midcode[ mi ].op, "const") == 0 ) { 893 pushstack(midcode[ mi ].var2); 894 if ( strcmp(midcode[ mi ].var1, "int") == 0 ) { 895 insertaddress(INT); 896 } else { 897 insertaddress(CHAR); 898 } 899 mi++; 900 } 901 mi--; 902 } 903 904 void intcharaasm() { 905 //数组定义 906 while ( strcmp(midcode[ mi ].op, "inta") == 0 || strcmp(midcode[ mi ].op, "chara") == 0 ) { 907 pushstack("0", atoi(midcode[ mi ].var2)); 908 if ( strcmp(midcode[ mi ].op, "inta") == 0 ) { 909 insertaddress(INT); 910 } else { 911 insertaddress(CHAR); 912 } 913 mi++; 914 } 915 mi--; 916 917 } 918 919 void cntopt() { 920 //引用计数 921 int tmi; 922 if ( OPTFLAG ) { 923 tmi = mi; 924 while ( strcmp(midcode[ tmi ].op, "end") != 0 ) { 925 if ( !strcmp(midcode[ tmi ].op, "=") || !strcmp(midcode[ tmi ].op, "+") || !strcmp(midcode[ tmi ].op, "-") || !strcmp(midcode[ tmi ].op, "*") || !strcmp(midcode[ tmi ].op, "/") ) { 926 cnt(midcode[ tmi ].var1); 927 cnt(midcode[ tmi ].var2); 928 cnt(midcode[ tmi ].var3); 929 } 930 tmi++; 931 } 932 sort(cnttable, cnttable + cntindex, cmpcnt); 933 for ( int i = 0; i < 8; i++ ) { 934 varreg[ cnttable[ i ].symbnum ] = i; 935 int addr = addrtable[ cnttable[ i ].symbnum ].address; 936 rsT << "\t\tlw\t$s" << i << "\t" << addr << "($fp)" << endl; 937 } 938 } 939 } 940 941 void savesreg() { 942 if ( OPTFLAG ) { 943 for ( int i = 0; i < 8; i++ ) { 944 rsT << "\t\tsw\t$t" << i << "\t" << 4 * i << "($t8)" << endl; 945 } 946 } 947 } 948 949 void loadsreg() { 950 if ( OPTFLAG ) { 951 for ( int i = 0; i < 8; i++ ) { 952 rsT << "\t\tlw\t$t" << i << "\t" << 4 * i << "($t8)" << endl; 953 } 954 } 955 } 956 957 void cnt(char* name) { 958 int t = ap - 1; 959 isglob = 0; 960 if ( name[ 0 ] == '+' || name[ 0 ] == '-' || ( name[ 0 ] >= '0'&& name[ 0 ] <= '9' ) || name[ 0 ] == ' ' || name[ 0 ] == '\t' || name[ 0 ] == '\0' ) 961 return ; 962 while ( t >= constedge) { 963 if ( strcmp(addrtable[ t ].name, name) == 0 ) { 964 addrtable[ t ].cnt++; 965 for ( int q = 0; q <= cntindex; q++ ) { 966 if ( q == cntindex ) { 967 cnttable[ cntindex ].cnt = 1; 968 cnttable[ cntindex ].symbnum = t; 969 cntindex++; 970 break; 971 } 972 if ( cnttable[q].symbnum == t ) { 973 cnttable[ q ].cnt++; 974 break; 975 } 976 } 977 } 978 t--; 979 } 980 }
参考资料
- 《高级编译器设计与实现》 (美)Steven S. Muchnick著 赵克佳,沈志宇译 机械工与出版社
- 《编译原理及编译程序构造》 金茂忠,高仲仪编 北京航空航天大学出版社
- 《计算机组成与设计 –硬件/软件接口》(美)Pattersom,Hennessy著 郑纬民等译 机械工业出版社