简介:面向哈工大编译原理期末备考的完整PDF复习资料,按课程知识体系系统覆盖编译系统结构、语言及文法、词法分析、语法分析、语义分析、中间代码生成、目标代码生成与代码优化等全部核心模块,适合高校计算机相关专业学生考前集中梳理、查漏补缺与快速回顾。资源包内含单个PDF文档,大小31.14MB,内容均根据课堂笔记整理,穿插正则表达式、有穷自动机(DFA与NFA)、语法分析树、三地址码及四元式等关键知识点的讲解与示例,结构清晰,便于按章节顺序阅读。已有2311人学习下载,可帮助读者从源代码到目标代码完整理解编译过程,掌握各阶段输入输出与实现思路,并了解寄存器分配、指令选择与调度等代码优化基本方法;对准备期末考试的读者,是一份可以直接拿来背诵要点、对照例题自测的实用资料。
1. 编译原理期末复习:一份完整版资料,先回答“背什么”再解决“怎么背”
很多人复习编译原理的第一反应是翻开课件从头看,结果看到正则表达式就开始犯困,看到 LR 分析表直接放弃。我见过不少同学,平时作业能写,一到期末考试就卡在“概念太多、算法流程太长”上。这份“完整版”资料最大的价值,是把词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生成这六条主线一次性整理在同一套笔记里,并且按考点权重标好了重点。它不是什么高深理论,而是一份可以直接照着画重点、做计划的期末复习地图。适合两类人:一是想用两周左右速成的,二是已经学过一遍但需要系统串起来查漏补缺的。
2. 考点地图:把编译器的六个阶段拆成六个得分模块
拿到资料第一件事不是从头背,而是先看目录结构。这份资料按照编译器的工作流程组织,从字符流到最终目标代码,每个阶段独立成章,每章开头都有一张“考点权重表”和“复习时长建议”。我习惯先把这张表抄下来贴在手边,它决定了你的时间往哪儿砸。
| 编译阶段 | 核心内容 | 常见题型 | 备考权重 |
|---|---|---|---|
| 词法分析 | 正则表达式、NFA/DFA、最小化 | 构造NFA/DFA、最小化 | ★★★ |
| 语法分析 | 上下文无关文法、LL/LR | 推导、分析表、冲突判断 | ★★★★★ |
| 语义分析 | 属性文法、中间代码 | 写语义动作、三地址码 | ★★★★ |
| 代码优化 | 基本块、DAG、常用优化点 | 优化判断、构造DAG | ★★★ |
| 目标代码生成 | 寄存器分配、指令选择 | 简答为主 | ★★ |
| 符号表与运行时 | 作用域、存储分配 | 问答、简答 | ★★ |
这张表不是官方划题,而是从历年考卷里统计出来的规律。语法分析永远是大头,词法分析虽然分少,但属于“送分题”,必须拿满。语义和中间代码的题型相对固定,适合考前突击刷熟。代码优化部分是选择题和简答题的常客,不需要太深,但要能说出典型优化名。下面我把六个阶段拆开讲,每个阶段都对应资料里的一段完整笔记。
2.1 词法分析:正则表达式、状态转换图与最小化 DFA 的拿分点
词法分析是整个编译原理里最“动手”的板块。资料里从正则表达式讲起,然后过渡到 NFA,再通过子集构造法转 DFA,最后做最小化。复习时不要光看概念,要找一道经典例题走一遍完整流程。我一般是这么练的:给定一个正则表达式如(a|b)*abb,先画出 NFA,再用子集构造法列出状态转移表,然后对 DFA 做最小化。资料里把这三步的表格模板都给了,包括填表时“是否接受状态”的标记方式。
做题时最容易翻车的一点,是把 NFA 的初始状态和接受状态搞混。尤其是涉及 ε 闭包时,很多人忘了把初始状态的 ε 闭包加入 DFA 的初态集合。资料里特意用红色批注标了“先求 ε-闭包,再做 move”,这句话就是评分点。正则表达式的部分还要区分它与正则文法的关系:正则语言对应 3 型文法,能用有限自动机识别,但像a^n b^n这种上下文无关语言就不行。考试喜欢考这种“能不能用正则表示”的判断,记住几个经典反例就能应对。
这一阶段我不建议直接用教材刷题。先把资料里的“词法分析三步走”流程图默写一遍,再去做十道构造题,十道里至少有九道是重复套路。状态转移表就是最好的记忆载体,比背定义高效得多。
2.2 语法分析:LL(1)、LR(1)、LALR——先看“冲突”再看“表”
语法分析是这份资料里篇幅最大、考点最密集的部分。它把自顶向下和自底向上两条路线放在一起对比,整理成一张横向比较表。复习顺序建议这样推进:先理解最左推导与最右推导的区别,再做 First 集和 Follow 集,然后构造预测分析表,判断一个文法是否是 LL(1)。这里有个血泪经验:Follow 集特别容易算错,尤其是右部出现多个非终结符时,要按“从右往左传播 First 集”的顺序处理。资料里给了口诀“First 看前看能否空,Follow 看右看后跟”,虽然有点土,但比死记规则管用。
LR 部分是真正的分水岭。很多同学卡在 LR(0) 项目集族构建上,资料把每个项目集都列出来,并标出了“核”和“闭包”的区别。复习时不能只读,要动手画状态转移图,再把 ACTION 表和 GOTO 表填出来。资料里给出了一个十八行的文法示例,从头到尾构造一遍 LR(0) 自动机,做完之后基本就理解了为什么 SLR 需要 Follow 集、LR(1) 需要向前看符号。常考的对比选项还有“LALR 和 LR(1) 的区别”——LALR 合并了同心的项目集,分析表比 LR(1) 小得多,但合并后可能产生归约-归约冲突。这个点几乎每年都会出现,一定要亲手构造一个合并后产生冲突的例子,否则永远只能背结论。
对于大题,我一般会先判断题型:是直接构造分析表,还是判断文法类型,还是分析冲突。资料里有一节叫“常见冲突的三种解法”,分别是修改文法、提取公共左因子、消除左递归。考试时如果时间紧张,先写“是否存在冲突”的判断依据,再写解决方向,即使表没构造完也能拿到一半步骤分。
2.3 语义分析与中间代码:属性文法、四元式、符号表的作用域
语义分析没有语法分析那么“死板”,但考点非常固定。资料把语义分析拆成两条线:一条是属性文法与语法制导翻译,另一条是中间代码的表示与生成。属性文法常考一类题:给定一个声明语句的背景,要求写出语法制导定义或翻译方案。比如声明语句int a, b;如何生成符号表条目。答题时最关键的是区分综合属性与继承属性:综合属性由子节点向上计算,继承属性由父节点或兄弟节点向下传递。资料里用箭头图把属性依赖画得很清楚,那个箭头方向就是阅卷时的评分点。
中间代码部分,四元式、三元式、三地址码三种形式各自的特点要能写出来。期末考试最常考四元式,因为它结构规整,两个临时变量一个操作符,适合按步骤给分。我一般会提醒自己:写四元式时,每个运算都生成一个新临时变量,不要把多个运算压缩成一行,比如t1 = a + b; t2 = t1 * c;,阅卷老师就是按行数给分,少写一行就没分。资料里给了带数组元素和函数调用的四元式生成模板,比如x = a[i]要拆成t1 = i * 4和t1 = a[t1]两步,这种细节在考场上最容易漏。
符号表部分,常见考点是作用域与嵌套。资料里专门讲了一个块结构语言的符号表栈式管理,考前要能徒手画出变量声明出栈入栈的过程。看这份资料时,先别背代码,拿张白纸,自己写一个两层嵌套的小程序,然后把符号表入栈过程画出来,画对了就通了。
2.4 代码优化与目标代码:常考优化点与基本块 DAG 构造
代码优化在期末复习里通常不会考太深,但往往以选择题或简答题出现,偶尔结合基本块出大题。资料整理了常见优化方法:公共子表达式删除、死代码删除、强度削减、循环不变式外提、复写传播。复习这些优化点,不要背定义,要看基本块是怎么划分的,以及 DAG 怎么表示基本块内的计算。考试常考“对给定的基本块构造 DAG,并写出优化后的代码”,资料里给出了 DAG 构造的六步规则,核心是注意公共子表达式对应的叶子节点编号是否一致。这里有个技巧:划 DAG 时,把赋值语句的左侧变量也当成一个节点,但要区分“当前值”和“后续使用”,否则很容易把重复计算的节点漏掉。
目标代码生成部分,常见考点是简单的寄存器分配和栈偏移量计算。资料里有一张“目标代码生成流程图”,把活跃变量分析、寄存器状态表、指令选择串在一起。考试时只要按这张表走一遍完整例子,比如把三地址码生成到类似 MIPS 的汇编指令,基本能拿到大部分基础分。这里不要求你会写完整汇编,但需要能识别哪些变量在基本块出口后仍然活跃,这决定了寄存器能不能复用。
3. 把复习资料拆成可执行计划:三周冲刺与每日任务表
光有考点地图还不够,资料里最值钱的其实是它末尾附带的一份“三周复习计划表”。我第一遍看的时候不以为然,直到自己照猫画狗排了一版,才发现按模块切碎时间比每天“看讲义”高效得多。计划的核心是“滚动复习”:第一天学的东西,第三天必须回顾,否则到第七天就忘光了。下面是我基于这份资料调整过的三周方案,适合每天有 2-3 小时空余时间的同学。
3.1 第一周:扫盲与串主线——词法+语法优先
第一周的目标不是刷题,而是建立主线。我把六阶段分成两块:先用四天把词法分析和语法分析的所有概念过一遍,再用两天专门做语法分析的 “First/Follow + 预测分析表” 的手动推导练习,最后一天做一次整套自测。
具体安排:周一从文法和 Chomsky 分类开始,只要求能判断一个文法是 1 型、2 型还是 3 型。周二和周三专门攻词法,顺序是“正则表达式 → NFA → DFA → 最小化”,当天只看一个转换步骤,确保自己能把 NFA 初态和接受态标对。周四进入语法分析,先读 LL(1) 部分,晚上抄一遍预测分析表的构造步骤,抄完就合上资料,自己默写一遍。周五和周六搞 LR 分析,这里不要贪多,先把 LR(0) 项目集构造练熟,再对比 SLR 和 LR(1) 的区别。周日拿出资料末尾的自测题,闭卷做一遍,错了的知识点记录到目录上。
这一周最容易出现的问题是“连线复习,每天看完就丢”。我的做法是每天开始前抽十分钟,拿一张白纸默写昨日的关键步骤:比如默写“子集构造法的第一步是求初始状态 ε-闭包”。写不出来就回到对应章节再看一遍,这比多刷十道题都管用。资料每一章后面都有一个“快速自测”小清单,正好可以当打卡项。
3.2 第二周:攻克语义与中间代码,开始刷综合题
第二周的重心转移到语义分析和中间代码生成,同时开始做跨章节的大题。周一到周三,每晚先看属性文法,再做一道四元式生成的例题。属性文法题通常是给出一个小语言的语法树,要求你为每个产生式写语义动作。注意资料里提示的综合属性和继承属性的区别,考试时要用箭头标好数据的流动方向。四元式部分,每天挑两个小程序从源码“翻译”一遍,比如for循环的条件判断和数组下标计算。周四到周五转向代码优化,重点是基本块划分和 DAG 构造。周六和周日做三套往年题,做完不要马上对答案,先对着资料目录,把自己不确定的考点标记出来。
这段时间需要刻意练习“先动笔再翻答案”的习惯。很多同学喜欢看例题解析,觉得自己懂了,一合上资料就懵。我一般会在资料里找一道完整的大题,先花 20 分钟自己作答,写不出就写“此步不会”,再翻开答案对照。资料里这道题的解析写了五个步骤,我自己写时只写出三步,缺口往往就在“中间代码生成时临时变量命名”或“基本块入口的确定”这种小细节上。把这些缺口记下来,它们就是后面冲刺的重点。
3.3 第三周:用“输出式复习”查漏,回归资料中的易错清单
第三周不再按章节推进,而是按题型反向定位。上午做一套模拟卷或往年真题,下午把错题对应的知识点在资料目录上做标记。比如选择 LR(1) 冲突判断的题错了,就翻到语法分析章节的对比表,把那条“LALR 合并后可能产生归约-归约冲突”一行重新背一遍,再找一道同类型的题做一次。这种“漏点回填”的复习方式,比单纯从头翻资料扎实。
资料末尾有一份“易错清单”,把高频失分点都列出来了,比如“Follow 集里右边界 # 不能丢”“三地址码中数组下标要算偏移”“DAG 节点合并时不要合并不同运算的根节点”。我会在最后一周每天晨读时扫描一遍这份清单,当天做的模拟题如果踩到其中某条,就在清单旁边画一个正字。等到考前最后一晚,不需要翻整本资料,只看画正字最多的三条就行。这个方法帮我避免过最典型的“整本书都看了,该错还错”的情况。
4. 避坑常见问题:这些复习翻车现场,希望你一个都别踩
资料再全,如果复习方法不对,照样过不了。下面几条是我从自己和其他人的“翻车现场”里提炼出来的,每条都按现象、原因、解决三个步骤写,基本覆盖期末复习时的高频死法。
4.1 现象:合上资料就忘,做题脑袋空白
很多人看资料时觉得“都懂了”,甚至能跟着例题思路走,但一到合书做题就完全不知道第一步写什么。原因很简单:看是“识别”,写是“回忆”,考试只考回忆不考识别。解决方法是改变阅读方式。我后来把资料里每个知识点都改写成问题,比如把“LL(1) 文法的条件”变成“什么情况下一个文法不是 LL(1)?”,复习时先看问题,自己口述答案,再打开资料核对。如果说不出来,就说明这个点还没真正进脑子。资料原文是讲义式的,你必须自己把陈述句改成疑问句,这一步不能省。
4.2 现象:正则语言和上下文无关语言分不清
有一类选择题经常给几个语言,问哪些是正则语言。很多同学看到a^* b^*觉得简单,看到a^n b^n觉得“也是两条规则”,结果选错。原因是把“有限自动机能识别的语言”和“允许递归推导的语言”混为一谈。解决方法是记住两个经典反例:a^n b^n需要计数,有限自动机只有有限个状态记不住;同理,匹配任意层嵌套括号的语言也不是正则的。资料里用“泵引理”来解释这一点,但考试不要求完整证明,只要能用“需要计数/需要嵌套匹配”来判断就够了。做题时拿这两个反例去套,基本不会错。
4.3 现象:LR(1) 和 LALR 的区别总是背混
选择或简答里出现“下列说法正确的是”,选项往往包含“LALR(1) 比 LR(1) 能力弱”“LALR 合并项目集后一定产生冲突”这类表述。很多人靠记结论,一旦题目换个说法就懵。根本原因是不理解“合并同心项目集”到底合了什么。解决方式是自己动手画一遍:找一个包含移进-归约冲突的 LR(1) 项目集,把两个同心项目集合并,观察表里 ACTION 是否冲突。资料里有一道“构造 LALR 分析表”的例子,考前强迫自己不看答案从头走一遍,只要做过一次,所有相关判断题都迎刃而解。
4.4 现象:考场上时间不够用,大题后半段空白
这是最可惜的丢分方式。原因通常是死磕语法分析大题,比如非要在一道 LR(1) 项目集构造上磨四十分钟,导致后面的四元式题没时间写。解决方法是考前做一次时间分配:词法题 15 分钟,语义和中间代码 20 分钟,语法大题放到最后写,先保证自己能拿到的步骤分都拿到。资料里的习题集虽然没有按时间标注,但我自己做模拟卷时会强制限定单题用时,超过就跳过。考场上遇到没思路的大题,先写上“该文法存在移进-归约冲突”这种判断句,也能拿一分。
4.5 现象:资料太厚,不知道从哪开始背
完整版资料意味着内容多,很多同学一翻开就焦虑,觉得必须全部看完才安心。原因是没有用真题定位高频考点。解决方法是先拿近三年的试卷,统计哪一章出题最多,再回资料里找到对应章节的第一页。资料里每个章节开头都有“考点权重”和“复习优先级”,先处理标了三星以上且真题反复出现的部分,比如 LR 分析表构造、四元式生成、First/Follow 集计算。冷门章节比如寄存器分配细节,考前一周看两遍即可,不必死磕。
5. 把文档转成自己的知识库:按章节重排、标注和自测清单
资料是别人的,复习笔记是自己的。很多同学拿着一份完整版资料直接硬啃,看完就忘,问题在于没有对内容做二次加工。下面这一套方法是我从整理资料时摸索出来的,本质是把“阅读型文本”变成“检索型题库”。核心思路是:知识不是被动读进去的,而是主动写出来的。
5.1 重排章节:把资料变成“问题-答案”题库
我不建议直接在资料上涂高亮,因为高亮只是复习工具,不是检测工具。更好的做法是准备一个笔记软件或活页本,把资料里的每个小节改写成问题表单。例如资料里介绍“符号表的作用域”时,写了一整段嵌套例子,我会把它改成三个问题:“块结构语言的符号表什么时候入栈?什么时候出栈?”“查符号表时按什么顺序找?”“同一层有两个同名变量会发生什么?”。然后自己在下方写出答案,再与资料原文核对。
这样重排过的笔记,到复习后期可以直接当题库用。每天随机抽几个问题,说不上来就打问号,下次优先复习。资料本身是“陈述句”的,你需要把它转成“疑问句”,这个过程本身就是强制回忆。我一般会给问题打上标签,比如“LR 冲突”“四元式”“符号表”,这样考前能按标签批量抽取。如果用的是 Markdown 格式,还能利用搜索功能把某个知识点快速定位回资料原章节,比翻纸质书快得多。
5.2 制作一页纸速查表:考试当天只看这几种算法
资料有几百页,但考场上能带进去的只有记忆。考前两天我会用一张 A4 纸,把最容易在考场上卡住的几种流程画成速查表。正面写语法分析:First 集计算口诀、Follow 集计算步骤、LL(1) 判定条件、LR(0) 项目集构造路径。背面写词法与中间代码:NFA 转 DFA 的子集构造法步骤、四元式的标准格式、DAG 构造的六步规则。这张纸不是抄资料,而是只写“触发词”,比如看见“移进-归约冲突”就写“检查 FOLLOW 与 ACTION 交集”,看见“数组赋值”就写“先算偏移,再生成 t = i * w”。制作过程本身就是一次浓缩训练,做完后再默写一遍,比反复翻资料有效。
速查表不需要精美,只要你自己认得就行。我那时因为字丑,被迫把很多长句子缩成几个英文缩写,比如ε-closure、FOLLOW,没想到考场上这些缩写反而更容易被大脑提取。资料里也有一张类似的一页总结,但那是别人整理的,还得多一步“亲手抄写”才能真正变成自己的。
5.3 用“错题定位法”反向修正资料标记
很多同学整理错题时,只把错题抄一遍,却不回到资料里标注对应知识点。我建议反过来:每次做完模拟卷,把错题对应的资料章节号写在这道题旁边,然后回到资料的目录页,用正字标记。比如错了一道“基本块划分”的题,就在“代码优化”那一章划一笔。三周后翻开目录,哪一章正字最多,哪里就是薄弱区。
这个方法初期会让人觉得“怎么这么多不会”,但两周后标记的密度会明显下降。我那时用到第五天,发现“语义分析”那章正字特别多,于是专门花一个晚上把属性文法的例题重新做了三遍。如果只是盲目从第一章往后刷,可能到考试都没发现自己弱点在语义分析。资料里每章之间的衔接是有顺序的,但你的弱点不一定是按顺序分布的,所以要用错题反向定位,而不是线性扫荡。
6. 一个具体技巧:用“编译器流水线”视角做考试时间分配
最后分享一个我考编译原理时用的小技巧:把整场考试当成一次编译器执行过程,先“取指”再“访存”,按阶段分配时间。编译器的流水线每个阶段都有自己的职责,考试也一样,找对每个题型的“阶段”比按题目顺序作答更容易拿分。
先看试卷整体结构。选择题和判断题属于“词法层”,考察零散概念,建议一上来先扫一遍,会写的直接写上,不会的先跳过,不要纠结。接下来做语义和中间代码题,这类题只要写对四元式或语义动作,分比较稳。语法分析大题放在后面,因为它最耗时,而且容易在冲突判断上卡住。最后的代码优化简答题,写的就算不完全准确,答出优化名称也能得一半分。我习惯用一张表给自己卡时间,比如选择 10 分钟,词法大题 15 分钟,语义/中间代码 20 分钟,语法大题 30 分钟,剩下时间检查和涂卡。这个分配比例在资料里没有,但实际用下来很稳。
为什么这个技巧有效?因为它把“难题”和“送分题”分开处理了。语法分析大题即使给你四十分钟也可能做不出来,但语义分析的四元式题只要步骤清晰就能拿分。考场上任何一道题卡超过五分钟,立刻做一个“标记”,先继续往下走,回头再看。我见过很多同学栽在“死磕 LR(1) 项目集构造,最后有四元式的临时变量没写完”上,那年我差点也这样。从那以后,每次考编译原理前我都会先画一遍“流水线顺序”贴在资料首页,强制自己把复习重心放在步骤明确的题型上。这个方法陪伴我通过了这门最像“黑匣子”的考试,希望帮到你。
本文还有配套的精品资源,点击获取