> # ♻️ 资源
> **大小:** 208KB
> **文档链接:**[**https://www.yuque.com/sxbn/ks/100013298**](https://www.yuque.com/sxbn/ks/100013298)
> **➡️ 资源下载:**[**https://download.csdn.net/download/s1t16/88351487**](https://download.csdn.net/download/s1t16/88351487)
> **注:更多内容可关注微信公众号【神仙别闹】,如当前文章或代码侵犯了您的权益,请私信作者删除!**
> ![qrcode_for_gh_d52056803b9a_344.jpg](https://cdn.nlark.com/yuque/0/2023/jpeg/2469055/1692147256036-49ec7e0c-5434-4963-b805-47e7295c9cbc.jpeg#averageHue=%23a3a3a3&clientId=u8fb96484-770e-4&from=paste&height=140&id=u237e511a&originHeight=344&originWidth=344&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=8270&status=done&style=none&taskId=ud96bf5f7-fe85-4848-b9c2-82251181297&title=&width=140.1999969482422)
# 基于 Java 的 C 语言编译器
## 采用 LL(1)文法进行分析,文法是 C 语言文法的子集,支持报错,以及错误原因
以前只用编译器编译程序,现在学完编译原理这门课以后,通过编译大作业,我对编译器的工作原理有了比较清晰的认识
## 编译器的工作原理
编译器 (Compiler) 是一种将由一种语言编写的程序转换为另一种编程语言的可执行程序. 现代软件对于编译器的需求远甚从前, 究其原因很简单: 作为中间层, 编译器是构建更高层抽象的基础设施. 编译器意欲将人类可阅读的高阶代码, 翻译为机器能运行的低阶代码.
### 现代编译器的主要工作流程为:
源代码(source code)→ 预处理器(preprocessor)→ 编译器(compiler)→ 汇编程序(assembler)→ 目标代码(object code)→ 链接器(Linker)→ 可执行文件(executables)1.
其中, 编译器位于一个最重要的位置: 将源码转为汇编(上文提到的 css, js 也可认为是一种汇编).
### 词法分析:
词法分析器根据词法规则识别出源程序中的各个记号(token),每个记号代表一类单词(lexeme)。源程序中常见的记号可以归为几大类:关键字、标识符、字面量和特殊符号。词法分析器的输入是源程序,输出是识别的记号流。词法分析器的任务是把源文件的字符流转换成记号流。本质上它查看连续的字符然后把它们识别为“单词”。
### 语法分析:
语法分析器根据语法规则识别出记号流中的结构(短语、句子),并构造一棵能够正确反映该结构的语法树。
### 语义分析:
语义分析器根据语义规则对语法树中的语法单元进行静态语义检查,如果类型检查和转换等,其目的在于保证语法正确的结构在语义上也是合法的。
### 中间代码生成:
中间代码生成器根据语义分析器的输出生成中间代码。中间代码可以有若干种形式,它们的共同特征是与具体机器无关。最常用的一种中间代码是三地址码,它的一种实现方式是四元式。三地址码的优点是便于阅读、便于优化。
### 中间代码优化:
优化是编译器的一个重要组成部分,由于编译器将源程序翻译成中间代码的工作是机械的、按固定模式进行的,因此,生成的中间代码往往在时间和空间上有很大浪费。当需要生成高效目标代码时,就必须进行优化。
### 目标代码生成:
目标代码生成是编译器的最后一个阶段。在生成目标代码时要考虑以下几个问题:计算机的系统结构、指令系统、寄存器的分配以及内存的组织等。编译器生成的目标程序代码可以有多种形式:汇编语言、可重定位二进制代码、内存形式。
### 符号表管理:
符号表的作用是记录源程序中符号的必要信息,并加以合理组织,从而在编译器的各个阶段能对它们进行快速、准确的查找和操作。符号表中的某些内容甚至要保留到程序的运行阶段。
### 出错处理:
用户编写的源程序中往往会有一些错误,可分为静态错误和动态错误两类。所谓动态错误,是指源程序中的逻辑错误,它们发生在程序运行的时候,也被称作动态语义错误,如变量取值为零时作为除数,数组元素引用时下标出界等。静态错误又可分为语法错误和静态语义错误。语法错误是指有关语言结构上的错误,如单词拼写错、表达式中缺少操作数、begin 和 end 不匹配等。静态语义错误是指分析源程序时可以发现的语言意义上的错误,如加法的两个操作数中一个是整型变量名,而另一个是数组名等。
### 编译大作业:
**LL1 文法:
1、 文法开始: **
S->void main(){A}
**2、 声明: **
X->YZ;
Y->int|char|bool
Z->UZ’
Z’->,Z|U>idU′U′>=L|
**3、 赋值:**
R->id=L;
**4、 算术运算: **
L->TL’
L’->+L|-L|T>FT′T′>T|/T|
F->(L)
F->id|num
O->++|–|Q>idO|
**5、 布尔运算 **
E->HE’
E’->&&E|H>GH′H′>||HH′>
G->FDF
D-><|>|==|!=
G->(E)
G->!E
**5、控制语句 **
B->if (E){A}else{A}
B->while(E){A}
B->for(YZ;G;Q){A}
**6、功能函数 **
B->printf(P);
B->scanf(id);
P->id|ch|num
**7、复合语句 **
A->CA
C->X|B|R
A->$
**1、构造 LL1 属性翻译文法 **
构造 LL1 属性翻译文法即在原有 LL1 文法基础上加上动作符号,并给非终结符和终结符加上一定属性,给动作符号加上语义子程序。对原有 LL1 文法改进的地方如下:
**1、 赋值: **
产生式 语义子程序
R->[@ASS_R ](/ASS_R ) id =L@ EQ; @ASS{R.VAL=id 并压入语义栈}
@EQ{RES=R.VAL,OP=’=’,ARG1=L.VAL,
new fourElement(OP,ARG1,/, RES)}
U->@ASS_UidU’ {U.VAL=id 并压入语义栈}
U’->=L|$@EQ_U’ {RES=U.VAL,OP=’=’,ARG1=L.VAL,new fourElement(OP,ARG1,/, RES)}
**2、 算术运算: **
产生式 语义子程序
L->TL’[@ADD_SUB ](/ADD_SUB ) {If(OP!=null) RES= NEWTEMP; L.VAL=RES,并压入语义栈;New fourElement(OP, T.VAL;,L’VAL, RES),
}
L’->+L[@ADD ](/ADD ) {OP=+,ARG2=L.VAL}
L’->-L[@SUB ](/SUB ) {OP=-,ARG2=L.VAL}
L’->$
T->FT’[@DIV_MUL ](/DIV_MUL ) { if (OP !=null) RES= NEWTEMP;T.VAL=RES;
new FourElement(OP,F.VAL,ARG2, RES)
else ARG1=F.VAL; }
T’->/T[@DIV ](/DIV ) {OP=/,ARG2=T.VAL}
T’->T[@MUL ](/MUL ) {OP=,ARG2=T.VAL}
T’->F>(L)@VOLF.VAL>L.VALF>@ASSFnum|idF.VAL=num|idQ>idO|
O->@SINGLE_OP++|– {OP=++|–}
**3、 布尔运算 **
产生式 语义子程序
G->FDF@COMPARE{OP=D.VAL;ARG1=F(1).VAL;ARG2=F(2).VAL,RES=NEWTEMP;
New fourElement(OP,F.VAL,ARG2, RES );G.VAL=RES 并压入语义栈}
D->@COMPARE_OP<|>||!={D.VAL=<|>||!=,并压入语栈}
**4、 控制语句 **
产生式 语义子程序
B->if (G)@IF_FJ{A}[@IF_BACKPATCH_FJ ](/IF_BACKPATCH_FJ ) [@IF_RJ ](/IF_RJ ) else{A}[@IF_BACKPATCH_RJ ](/IF_BACKPATCH_RJ )
@IF_FJ{OP=”FJ”;ARG1=G.VAL;RES=if_fj, New fourElement(OP,ARG1,/, RES ),将其插入到四元式列表中第 i 个}
@IF_BACKPATCH_FJ{回填前面假出口跳转四元式的跳转序号, BACKPATCH (i,if_fj)}
B->while(G)@WHILE_FJ{A}@WHILE_RJ[@WHILE_BACKPATCH_FJ ](/WHILE_BACKPATCH_FJ ) {参照 if else}
B->for(YZ;G@FOR_FJ;Q){A@SINGLE}@FOR_RJ[@FOR_BACKPATCH_FJ ](/FOR_BACKPATCH_FJ ) {参照 if else }
[@SINGLE ](/SINGLE ) {ARG1=id;RES=NEWTEMP;New fourElement(OP,ARG1,/,RES)}
说明:
(1)、R.VAL 表示符号 R 的值,VAL 是 R 的一个属性,其它类似。
(2)、NEWTEMP()函数:每调用一次生成一个临时变量,依次为 T1,T2,…Tn。
(3)、BACKPATCH (int i,int res):回填函数,用 res 回填第 i 个四元式的跳转地址。
(4)、new fourElement(String OP,String ARG1,String ARG2,String RES ):生成一个四元式
(OP,ARG1,ARG2,RES)
工程列表
![12f5be2aa7467b37742c97fdbd7e2c6a.png](https://cdn.nlark.com/yuque/0/2023/png/2469055/1695002739174-56a2d7ee-b4ce-4942-88bc-c80bb8325352.png#averageHue=%23f9f7f5&clientId=u8b03381f-c8a1-4&from=paste&height=4