基于扩展C0文法的编译器设计(Part1)

啊(充满哲♂学的呻吟)
终于在上学期完成了我航课程中的三巨头之一——编译,有了一点微不足道的收获。现在才有时间整理一下整个过程,发到博客上以记录自己的成果,顺便如果有学弟学妹需要也可以参考借鉴(但是别照搬——有查重!!

一.需求说明

1.文法说明

文法无需改写,符合要求,解读如下:
<加法运算符> ::= +|-
分析:定义加减法运算符
样例:a+b a-b
<乘法运算符> ::= *|/
分析:定义乘除法运算符
样例:a*b a/b
<关系运算符> ::= <|<=|>|>=|!=|==
分析:定义关系运算符小于,不大于,不小于,大于,不等于,等于
样例:a>b a<=b a!=b
<字母> ::= _|a|...|z|A|...|Z
分析:定义字母,是由下划线 _ 和26个字母的大小写组成的,不允许除此之外的其他字符
样例:_ a b z A B Z
<数字> ::= 0|<非零数字>
分析:定义数字的形式,0~9
样例:0 1 2 3 4 9
<非零数字> ::= 1|...|9
分析:定义非零数字,是1~9
样例:1 2 3 4 9

<字符> ::= ‘<加法运算符>’|’<乘法运算符>’|’<字母>’|’<数字>’
分析:定义字符的形式,它是被‘’包裹的加法运算符或者乘法运算符或者字母或者数字
样例:‘+’‘-’‘*’‘a’‘_’

<字符串> ::= “{十进制编码为32,33,35-126的ASCII字符}”
分析:定义字符串的格式,字符串是被“”包裹的若干个(可以是0个)十进制ascii码值为32,33,35~126的字符组合
样例:“abcd”

<程序> ::= [<常量说明>][<变量说明>]{<有返回值函数定义>|<无返回值函数定义>}<主函数>
分析:程序定义为严格顺序的 常量说明-字符串说明-有返回值函数定义-无返回值函数定义-主函数 的字符串组合,其中常量说明和变量说明可以没有,如果有,只能出现一次(即不存在多个常量或者变量说明语句),有返回值函数定义和无返回值函数定义可以有若干个,以主程序结尾。
样例:
const int a,b,c;
int q,w,e;
void func1(){


Int func2(){


Void main(){

}

<常量说明> ::= const<常量定义>;{ const<常量定义>;}
分析:定义常量说明的格式,以const开头,后接常量定义,以;结尾,这样形式的字符串可以有多个
样例:
const int a = 1 ;
const int b = 2 ;

<常量定义> ::= int<标识符>=<整数>{,<标识符>=<整数>}| char<标识符>=<字符>{,<标识符>=<字符>}
分析:定义常量定义的格式,常量定义可以是以int 开始后面接一个或者多个顺序如 标识符、=、整数 这样的字符串(如果是多个,则中间以 , 隔开)的整型常量定义,字符型常量定义与整型类似。
样例:
int a = 1,b = 2,c = 3
char a = ‘1’,b = ‘2’,c = ‘3’

<无符号整数> ::= <非零数字>{<数字>}
分析:定义无符号整数的格式,是以非零数字(1~9)开始,后面接若干个数字(0~9)的字符串集合
样例:12345 230

<整数> ::= [+|-]<无符号整数>|0
分析:定义整数的格式,是可能存在前置符号的无符号整数或者0,其中若是存在符号的无符号整数,则只能有一个符号,要么为+,要么为-
样例:+9 -1 0 10

<标识符> ::= <字母>{<字母>|<数字>}
分析:定义标识符的格式,是以字母开头的后面接若干个字母或数字的字符串集合
样例:a1 aa1 aa

<声明头部> ::= int<标识符>|char<标识符>
分析:定义声明头部的格式,以int或char开头的后接标识符的字符串
样例:int a char b

<变量说明> ::= <变量定义>;{<变量定义>;}
分析:定义变量说明语句的格式,是一个或更多的形如 变量定义; 的字符串
样例:无,见下一句文法

<变量定义> ::= <类型标识符>(<标识符>|<标识符>‘[’<无符号整数>‘]’){,(<标识符>|<标识符>‘[’<无符号整数>‘]’) }
分析:描述变量定义的形式,一个或者多个 类型标识符后接标识符或标识符[无符号整数] 的形式,如果有多个,则中间以 , 联接
样例:
int a, b
int c[3], b[3]

<类型标识符> ::= int | char
分析:描述类型标识符的形式,整型为int,字符型为char
样例:int char

<有返回值函数定义> ::= <声明头部>‘(’<参数>‘)’ ‘{’<复合语句>‘}’
分析:描述有返回值函数定义的格式,包含声明头部,被()的参数,被{}包裹的复合语句,三者严格有序
样例:
int cmp(int a, int b){

}

<无返回值函数定义> ::= void<标识符>‘(’<参数>‘)’‘{’<复合语句>‘}’
分析:描述无返回值函数定义的格式,以void开始,被()包裹的参数,被{}包裹的复合语句,三者严格有序
样例:
void cmp(int a, int b){

}

<复合语句> ::= [<常量说明>][<变量说明>]<语句列>
分析:描述复合语句的格式,由常量说明、变量说明、语句列组成,三者严格有序,其中常量说明,变量说明可有可无,若存在,顺序不可逆
样例:
const int a =1 ;
int b = 4 ;

<参数> ::= <参数表>
分析:描述参数的形式为参数表
样例:无

<参数表> ::= <类型标识符><标识符>{,<类型标识符><标识符>}| <空>
分析:描述参数表的格式,由一个或者多个 类型标识符接标识符 的形式组成,若有多个,则中间以,分割,参数表可以为空,参数表中不能出现数组
样例:
int a,int b, int c

<主函数> ::= void main‘(’‘)’ ‘{’<复合语句>‘}’
分析:描述主函数的格式,以 void main()开始,后接被{}包裹的复合语句
样例:
void main(){

}

<表达式> ::= [+|-]<项>{<加法运算符><项>}
分析:描述表达式的格式,以项开始,后接若干个 加法运算符 项 的组合,注意,第一个项前面可能有正负号,如果有,则只能有一个。
样例:
a + b – (a+b)

<项> ::= <因子>{<乘法运算符><因子>}
分析:描述项的组成格式,以因子开始,后面接若干个 乘法运算符 因子 的组合
样例:a a*b

<因子> ::= <标识符>|<标识符>‘[’<表达式>‘]’|<整数>|<字符>|<有返回值函数调用语句>|‘(’<表达式>‘)’
分析:描述因子的格式,因子是以标识符或者标识符[表达式]或者整数或者字符或者有返回值函数的调用语句或者(表达式)
样例:a[2] num b (a-b+c*d)

<语句> ::= <条件语句>|<循环语句>|‘{’<语句列>‘}’|<有返回值函数调用语句>;|<无返回值函数调用语句>;|<赋值语句>;|<读语句>;|<写语句>;|<空>;|<返回语句>;
分析:描述语句的格式,语句是条件语句或者循环语句或者{语句列}或者有返回值函数调用语句;或者无返回值函数调用语句;或者赋值语句;或者读语句;或者写语句;或者空;或者返回语句;
样例:无,见后文

<赋值语句> ::= <标识符>=<表达式>|<标识符>‘[’<表达式>‘]’=<表达式>
分析:描述赋值语句的格式,是 标识符=表达式 或者 标识符[表达式] = 表达式的形式
样例:a = b a[m-1] = c + d

<条件语句> ::= if ‘(’<条件>‘)’<语句>[else<语句>]
分析:描述条件语句的格式,else 可有可无,若出现仅一次,但是允许嵌套
样例:
if(a>1)

else

或者
if(a > 1){

}

<条件> ::= <表达式><关系运算符><表达式>|<表达式> //表达式为0条件为假,否则为真
分析:描述条件的格式,条件为 表达式-关系运算符-表达式 或者 表达式 的格式,若表达式为0则认为假,否则认为真,注意关系运算符只含有>、>=等
样例:a>b a

<循环语句> ::= do<语句>while ‘(’<条件>‘)’ |for‘(’<标识符>=<表达式>;<条件>;<标识符>=<标识符>(+|-)<步长>‘)’<语句>
分析:描述循环语句的格式,包括 do while 类型的循环,和for循环,其中,do while循环的格式为,do开始的后接 语句 while(条件)的形式,for循环为for开始的后接 (标识符=表达式);条件;标识符=标识符+(或者-)步长),以语句结尾的形式。
样例:
do{

}while(a>1)
for(a = 0 ; a < 100 ; a = a +1){


注:不允许a++之类的形式出现
<步长>::= <无符号整数>
分析:描述步长的格式,步长是一个无符号整数
样例:9 1

<有返回值函数调用语句> ::= <标识符>‘(’<值参数表>‘)’
分析:描述又返回值函数调用语句的格式,以标识符开始后接(值参数表)的形式
样例:int f(a, b)

<无返回值函数调用语句> ::= <标识符>‘(’<值参数表>‘)’
分析:描述无返回值函数调用语句的格式,以标识符开始后接 (值参数表),类似上一条语句
样例:f(a,b)

<值参数表> ::= <表达式>{,<表达式>}|<空>
分析:描述值参数表的格式,是若干个表达式或者空,若为多个表达式,则中间以,分割
样例:a,b

<语句列> ::={<语句>}
分析:描述语句列的格式,是包裹在{}中的语句
样例:
{

}

<读语句> ::= scanf ‘(’<标识符>{,<标识符>}‘)’
分析:描述读语句的格式,sacnf(若干个标识符(至少一个))
样例:scanf(a,b,c)

<写语句> ::= printf‘(’<字符串>,<表达式>‘)’|printf ‘(’<字符串>‘)’|printf ‘(’<表达式>‘)’
分析:描述写语句的格式,printf(字符串,表达式)或者printf(字符串)或者printf(表达式)
样例:
printf(“hello world”)
printf(“%d”,a)
printf(a)

<返回语句> ::= return[‘(’<表达式>‘)’]
分析:描述返回语句的格式,return或者return(表达式)
样例:
return
return a

附加说明:

(1)char类型的表达式,用字符的ASCII码对应的整数参加运算,在写语句中输出字符

(2)标识符区分大小写字母

(3)写语句中的字符串原样输出

(4)数组的下标从0开始

2.目标代码说明

目标代码为MIPS指令代码,具体细节详见第二部分。

3. 优化方案

未做到完全优化,只有窥孔优化,常数合并和全局变量替换优化,具体细节见第二部分和代码。

你可能感兴趣的:(编译原理,编译器)