实现一个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。因此,它的四个接受状态分别代表遇到了四种不同的单词。

clip_image002

设计好之后因为它包含很多的不确定分支和ε,所以需要做一次NFA->DFA的确定化。按照课本上的方法,用ε-闭包的方法就求得了一个DFA,用上图的例子,我们可以得到如下DFA,可以证明这个DFA和上图中的NFA是等价的。

clip_image002[5]

之后,可以采用直接状态机的编码方式来编写,也可以采用逐步判断分支的方式来编写,我采用的是后者,在程序中可以清晰的看见。

在编写的过程中也没有遇到太多困难,我觉得其中值得一提的就是预读行缓冲这个部分了。记得在做这个实验之前就已经阅读了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。为此我自己写了一个可证正确性的算法:

  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图中会出现临时变量重定义的情况。

                   因此,一旦出现任意两个临时变量有相同的子表达式,完全可以用其中一个代替全部。因此以上算法正确。

至此,整个编译器就已经实现了。

接下来说说具体实现:

 

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.类/方法/函数功能

image

函数功能见上图。

所有函数:

函数名

作用和功能

词法分析:

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.调用依赖关系

image


如图所示。

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.运行栈结构:

如下图所示:

image

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的程序。此即为编译器的主程序。

image

2.运行编译器程序。

3.将需要编译的文件拖入程序框内,如果路径存在空格,需要加上引号。之后按回车。如图所示:

image

4.如果编译成功,会出现如下提示,并跳转到第六步:

image

5.如果编译失败,会出现如下提示:

image

6.编译成功后,将会生成如下几个文件:

image

7.可以通过optMidCode.txt和midcode.txt进行比对来看优化效果

8.接下来打开MARS模拟器,导入asmrst.asm,如图:

image

9.编译执行即可,如图:

image

10.需要注意的是,任何输入都必须用换行符隔开,这是Mars定义的模拟特性。

下图就是一个正确的输入:

image

而下图用空格隔开将会导致程序出错:

image image

最后贴一下工程代码,需要注意的是这个代码是历史版本存在一些漏洞:

  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 }

 

 

 

参考资料

  1. 《高级编译器设计与实现》 (美)Steven S. Muchnick著  赵克佳,沈志宇译  机械工与出版社
  2. 《编译原理及编译程序构造》 金茂忠,高仲仪编  北京航空航天大学出版社
  3. 《计算机组成与设计 –硬件/软件接口》(美)Pattersom,Hennessy著 郑纬民等译  机械工业出版社
posted @ 2015-01-20 04:30  sciencefans  阅读(7368)  评论(4编辑  收藏  举报