SZU 编译原理
总结自 深圳大学《编译原理》课程所学相关知识。
文章目录
- 文法
- 语法分析
- 自顶向下的语法分析
- 递归下降分析
- LL(1) 预测分析法
- FIRST 集合
- FOLLOW 集合
文法
乔姆斯基形式语言理论:
表达能力:0型文法 > 1型文法 > 2型文法 > 3型文法。
- 0 型文法(短语结构文法)
- 定义:
产生式规则为 α → β,其中 α 是至少包含一个非终结符的符号串,β 是任意符号串(终结符和非终结符的混合)。 - 特点:
限制最少,表达能力最强,能描述所有递归可枚举语言。
允许 “全局” 替换(不局限于单个非终结符),例如 AB → CD。 - 自动机:由图灵机识别。
- 应用:理论计算模型,几乎不用于实际编程。
- 定义:
- 1 型文法(上下文有关文法)
- 定义:
产生式规则为 αAβ → αγβ,其中 A 是非终结符,α, β, γ 是任意符号串,且 γ ≠ ε。
直观理解:只有当非终结符 A 出现在上下文 α 和 β 之间时,才能被替换为 γ。
等价形式:|α| ≤ |β|(产生式右部长度不小于左部,除了 S → ε,其中 S 是开始符号且不出现在其他产生式右部)。 - 特点:
表达能力仅次于 0 型文法,能描述上下文有关语言。
例如:a^n b^n c^n(n 个 a、n 个 b、n 个 c 的串)可用 1 型文法描述,但无法用 2 型文法描述。 - 自动机:由线性界限自动机识别。
- 应用:自然语言处理(理论模型),实际中较少使用。
- 定义:
- 2 型文法(上下文无关文法)
- 定义:
产生式规则为 A → β,其中 A 是非终结符,β 是任意符号串(终结符和非终结符的混合)。
直观理解:非终结符 A 可被替换为 β,无需考虑 A 出现的上下文。 - 特点:
表达能力强,能描述程序设计语言的语法(如表达式、语句结构)。
例如:算术表达式文法、括号匹配问题均属于 2 型文法。 - 自动机:由下推自动机(带栈的有限状态机)识别。
- 应用:编译器的语法分析阶段(如递归下降分析、LR 分析)。
- 定义:
- 3 型文法(正则文法)
- 定义:
产生式规则分为两类:
右线性文法:A → aB 或 A → a(右部符号串以终结符开头,后跟非终结符或空)。
左线性文法:A → Ba 或 A → a(右部符号串以非终结符开头,前跟终结符或空)。 - 特点:
表达能力最弱,只能描述线性结构(如标识符、关键字、数值常量)。
与正则表达式等价,可转换为有限状态自动机。 - 自动机:由有限状态自动机识别。
- 应用:编译器的词法分析阶段(用于识别单词符号)。
- 定义:
语法分析
Syntax Analysis
判断源代码是否符合语言的语法规则,符合可构建语法树/抽象语法树(AST),为后续的语义分析、优化和代码生成提供基础。
- 输入:
词法分析器输出的单词符号序列(Token流)
(如:int a = b + 1; 对应的 token 序列为:[int, id(a), '=', id(b), '+', num(1), ';']
) - 输出:
源程序对应的语法树(parse tree)或抽象语法树(AST)
语法分析的两大类方法:
- 自顶向下分析(Top-Down Parsing):从文法的开始符号出发,尝试推导输入串。
- 常见算法:递归下降分析、LL(1)分析
- 自底向上分析(Bottom-Up Parsing):从输入符号出发,逐步归约还原为文法的开始符号。
- 常见算法:LR(0)、SLR(1)、LALR(1)、LR(1)
算法 | 全称/关键含义 | 分析方向 | 向前看符号数 | 分析能力/特点 | 适用场景 |
---|---|---|---|---|---|
递归下降分析 | 每个非终结符对应一个递归函数,通过函数调用模拟推导过程 | 自顶向下 | 通常 1(LL(1)) | 实现简单直观,适合手工编写分析器,但需消除左递归和提取左公因子。 | 简单 LL(1) 文法 |
LL(1) | Left-to-right, Leftmost derivation, 1 lookahead symbol | 自顶向下 | 1 | 预测分析,根据当前非终结符和下一个输入符号选择产生式,需构造 FIRST 和 FOLLOW 集。 | 无左递归、无左公因子的简单文法 |
LR(0) | Left-to-right, Rightmost derivation in reverse, 0 lookahead | 自底向上 | 0 | 仅根据当前状态决定动作,能力弱,可能存在移进-归约冲突。 | 教学示例,极简单文法 |
SLR(1) | Simplified LR(1), 使用 FOLLOW 集解决冲突 | 自底向上 | 1 | 在 LR(0) 基础上,通过向前看 1 个符号(FOLLOW 集)解决冲突,实现较简单。 | 中等复杂度文法 |
LALR(1) | Look-Ahead LR(1), 合并同心项目集 | 自底向上 | 1 | 通过合并 LR(1) 的同心项目集减少状态数,能力接近 LR(1),是实际编译器常用的方法(如 Yacc、Bison)。 | 大多数程序设计语言的文法 |
LR(1) | Left-to-right, Rightmost derivation in reverse, 1 lookahead | 自底向上 | 1 | 能力最强,每个状态包含精确的向前看符号,但状态数多,实现复杂。 | 复杂文法,理论研究 |
自顶向下的语法分析
递归下降分析
Recursive Descent Parsing
递归下降分析 是一种自顶向下的语法分析方法,为文法中每个非终结符编写一个递归函数来尝试匹配输入的语句。
例题:
第二部分:基于递归下降分析法的简单算术表达式语法分析
选用课本的简单算术表达式的文法,设计基于递归下降分析法的程序,对输入的简单算术表达式,分析并按第一部分的输出格式,输出其对应的语法树(若存在)。
例如,如果输入文件是形如 i+i*i 的字符串,那么输出文件内容是:E(T(F(i)T')E'(+T(F(i)T'(*F(i)T'))E'))
解:
假设用的是如下简化文法(符合 LL(1))
E → T E' // 维护加法
E' → + T E' | ε
T → F T' // 维护乘法
T' → * F T' | ε
F → ( E ) | i【用于算术表达式的上下文无关文法(CFG)】
原始的算术表达式文法(如 E → E + T | T)存在左递归,会导致递归下降分析器陷入无限循环。
这个文法通过引入 E' 和 T' 消除了左递归。
T
项 (T的产生式维护了右边的一个可为空的乘积)
E'
处理右递归,这里维护 ’ + ’
T'
处理右递归,维护 ’ * ’
每个产生式写一个函数:调用谁就打印谁
void E(); // 处理 E → T E'
void E_(); // 处理 E' → + T E' | ε
void T(); // 处理 T → F T'
void T_(); // 处理 T' → * F T' | ε
void F(); // 处理 F → ( E ) | i
匹配流程:
1. 开始于 E
2. E → T E':T → F T'F → i → F(i)T' 当前输入是 +,不匹配 *,进入 ε → T'E' → + T E'匹配 + → +T → F T'F → i → F(i)T' → * F T'匹配 *F → i → F(i)T' → εE' → ε
LL(1) 预测分析法
L: 从左到右扫描输入串(Left-to-right)
L: 产生最左推导(Leftmost derivation)
1: 使用 1 个符号向前看(lookahead)
核心思想:使用一个 预测分析表(Parsing Table) 来决定根据当前的栈顶非终结符和当前输入符号应该使用哪个产生式。
第三部分: 基于LL(1)预测分析法的简单算术表达式语法分析
与第二部分相同,但采用LL(1)预测分析法进行分析程序的设计。注意:需要把LL(1)分析表设计为一个可配置(可初始化)的参数
仍是这个文法:
E → T E'
E' → + T E' | ε
T → F T'
T' → * F T' | ε
F → ( E ) | i
我们先构造 FIRST 和 FOLLOW 集合,再得出分析表。
FIRST 集合
FIRST(X) 是:从 X 推导出的所有串中能出现在最前面的终结符集合(或 ε)
FIRST(E) = FIRST(T) = FIRST(F) = { i, ( }
FIRST(E') = { +, ε }
FIRST(T') = { *, ε }
FIRST(F) = { i, ( }
FOLLOW 集合
FOLLOW(A) 是:在某些推导中,非终结符 A 后面可能出现的终结符集合
(如果 S 是开始符号,#(输入结束标志)
属于 FOLLOW(S))
若某个产生式是 B → α A β:将 FIRST(β)(去除 ε)加入 FOLLOW(A) // A 后的第一个给 A若 β 可推出 ε,则将 FOLLOW(B) 也加入 FOLLOW(A) // A 后的β是空的,那A后和B后是一样的
FOLLOW(E) = { ), # }
FOLLOW(E') = { ), # }
FOLLOW(T) = { +, ), # }
FOLLOW(T') = { +, ), # }
FOLLOW(F) = { *, +, ), # }
构造方式:
假设某个产生式 A → α:对于所有 a ∈ FIRST(α)(a ≠ ε),在表中 M[A][a] = α如果 ε ∈ FIRST(α),那么对于 b ∈ FOLLOW(A),令 M[A][b] = ε
构建的LL(1) 预测分析表:(行:非终结符,列:终结符)
非终结符 | i | + | * | ( | ) | #(终止符) |
---|---|---|---|---|---|---|
E | T E’ | T E’ | ||||
E’ | + T E’ | ε | ε | |||
T | F T’ | F T’ | ||||
T’ | ε | * F T’ | ε | ε | ||
F | F(i) | ( E ) |
初始化分析表:
map<string, map<string, string>> parsingTable;parsingTable["E"]["i"] = "T E'";
parsingTable["E"]["("] = "T E'";
parsingTable["E'"]["+"] = "+ T E'";
parsingTable["E'"][")"] = "ε";
parsingTable["E'"]["#"] = "ε";
...
相关文章:

SZU 编译原理
总结自 深圳大学《编译原理》课程所学相关知识。 文章目录 文法语法分析自顶向下的语法分析递归下降分析LL(1) 预测分析法FIRST 集合FOLLOW 集合 文法 乔姆斯基形式语言理论: 表达能力:0型文法 > 1型文法 > 2型文法 > 3型文法。 0 型文法&am…...
实时技术方案对比:SSE vs WebSocket vs Long Polling
早期网站仅展示静态内容,而如今我们更期望:实时更新、即时聊天、通知推送和动态仪表盘。 那么要如何实现实时的用户体验呢?三大经典技术各显神通: SSE(Server-Sent Events):轻量级单向数据流WebSocket:双向全双工通信Long Polling(长轮询):传统过渡方案假设目前有三…...

【程序员AI入门:模型】19.开源模型工程化全攻略:从选型部署到高效集成,LangChain与One-API双剑合璧
一、模型选型与验证:精准匹配业务需求 (一)多维度评估体系 通过量化指标权重实现科学选型,示例代码计算模型综合得分: # 评估指标权重与模型得分 requirements {"accuracy": 0.4, "latency": …...
北斗导航 | 基于深度学习的卫星导航数据训练——检测识别故障卫星
深度学习+故障卫星识别 **1. 数据准备与预处理****2. 模型选择与设计****3. 训练策略****4. 模型优化与验证****5. 实时部署与集成****6. 持续学习与更新****示例模型架构(LSTM + Attention)****挑战与解决方案**🥦🥦🥦🥦🥦🥦🥦🥕🥦🥦🥦🥦🥦🥦�…...

ARM Cortex-M3内核详解
目录 一、ARM Cortex-M3内核基本介绍 (一)基本介绍 (二)主要组成部分 (三)调试系统 二、ARM Cortex-M3内核的内核架构 三、ARM Cortex-M3内核的寄存器 四、ARM Cortex-M3内核的存储结构 五、ARM Co…...
基于Unity的简单2D游戏开发
基于Unity的简单2D游戏开发 摘要 本文围绕基于Unity的简单2D游戏开发进行深入探讨,旨在分析其开发过程中的技术架构与实现策略。通过文献综述与市场分析,研究发现,近年来Unity引擎因其优秀的跨平台特性及可视化编程理念,成为2D游戏开发的主要工具。文章首先梳理了游戏开发的…...
Linux系统编程——exec族函数
我们来完整、系统、通俗地讲解 Linux 系统编程中非常重要的一类函数:exec 族函数(也叫 exec family)。 一、什么是 exec? exec 系列函数的作用是: 用一个新的程序,替换当前进程的内容。 也就是说…...

ThinkStation图形工作站进入BIOS方法
首先视频线需要接在独立显卡上,重新开机,持续按F1,或者显示器出来lenovo的logo的时候按F1,这样就进到bios里了。联*想*坑,戴尔贵。靠。...

go 集成base64Captcha 支持多种验证码
base64Captcha 是一个基于 Go 语言开发的验证码生成库,主要用于在 Web 应用中集成验证码功能,以增强系统的安全性。以下是其主要特点和简介: base64Captcha主要功能 验证码类型丰富:支持生成多种类型的验证码,包括纯…...

【C语言字符函数和字符串函数(一)】--字符分类函数,字符转换函数,strlen,strcpy,strcat函数的使用和模拟实现
目录 一.字符分类函数 1.1--字符分类函数的理解 1.2--字符分类函数的使用 二.字符转换函数 2.1--字符转换函数的理解 2.2--字符转换函数的使用 三.strlen的使用和模拟实现 3.1--strlen的使用演示 3.2--strlen的返回值 3.3--strlen的模拟实现 四.strcpy的使用和模拟实现…...
deepseek问答记录:请讲解一下hugingface transformers中的AutoProcessor
Hugging Face Transformers库中的AutoProcessor是一个用于自动加载与预训练模型配套的处理器的工具类。它简化了预处理流程,特别适用于多模态模型(如同时处理文本、图像、音频的模型)。以下是详细讲解: 1. AutoProcessor的功能 •…...

大模型基础之量化
概述 量化,Quantization,机器学习和深度学习领域是一种用于降低计算复杂度、减少内存占用、加速推理的优化方法。定义:将模型中的数据从高精度表示转换为低精度表示。主要目的是为了减少模型的存储需求和计算复杂度,同时尽量减少…...

游戏引擎学习第286天:开始解耦实体行为
回顾并为今天的内容定下基调 我们目前正在进入实体系统的一个新阶段,之前我们已经让实体的移动系统变得更加灵活,现在我们想把这个思路继续延伸到实体系统的更深层次。今天的重点,是重新审视我们处理实体类型(entity type&#x…...

win10-django项目与mysql的基本增删改查
以下都是在win10系统下,django项目的orm框架对本地mysql的表的操作 models.py----->即表对应的类所在的位置 在表里新增数据 1.引入表对应的在models.py中的类class 2.在views.py中使用函数:类名.objects.create(字段名值,字段名"值"。。。…...
Windows 本地部署MinerU详细教程
📖 项目概述 MinerU是一款由OpenDataLab开发的开源PDF转Markdown工具,可以高质量地提取PDF文档内容,生成结构化的Markdown格式文本。本指南将帮助您在本地部署并使用MinerU。 ⭐ 功能特性 MinerU具有以下核心功能: ✨ 文档处理…...

动态范围调整(SEF算法实现)
一、背景介绍 继续在整理对比度调整相关算法,发现一篇单帧动态范围提升的算法:Simulated Exposure Fusion,论文表现看起来很秀,这里尝试对它进行了下效果复现。 二、实现流程 1、基本原理 整体来说,大致可以分为两步…...

SpringCloud微服务开发与实战
本节内容带你认识什么是微服务的特点,微服务的拆分,会使用Nacos实现服务治理,会使用OpenFeign实现远程调用(通过黑马商城来带你了解实际开发中微服务项目) 前言:从谷歌搜索指数来看,国内从自201…...

WAS和Tomcat的对比
一、WAS和Tomcat的对比 WebSphere Application Server (WAS) 和 Apache Tomcat 是两款常用的 Java 应用服务器,但它们有许多显著的区别。在企业级应用中,它们扮演不同的角色,各自有其特点和适用场景。以下是它们在多个维度上的详细对比&…...
Rust 数据结构:String
Rust 数据结构:String Rust 数据结构:String什么是字符串?创建新字符串更新字符串将 push_str 和 push 附加到 String 对象后使用 运算符和 format! 宏 索引到字符串字符串在内存中的表示字节、标量值和字形簇 分割字符串遍历字符串的方法 R…...

IntelliJ IDEA打开项目后,目录和文件都不显示,只显示pom.xml,怎样可以再显示出来?
检查.idea文件夹 如果项目目录中缺少.idea文件夹,可能导致项目结构无法正确加载。可以尝试删除项目根目录下的.idea文件夹,然后重新打开项目,IDEA会自动生成新的.idea文件夹和相关配置文件,从而恢复项目结构。 问题解决࿰…...

Hot100-链表-JS
160.相交链表 160. 相交链表 已解答 简单 相关标签 相关企业 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整…...

事件驱动架构:从传统服务到实时响应的IT新风潮
文章目录 事件驱动架构的本质:从请求到事件的范式转变在EDA中: 事件驱动架构的演进:从消息队列到云原生标配核心技术:事件驱动架构的基石与工具链1. 消息队列:事件传递的枢纽2. 消费者:异步处理3. 事件总线…...

网络流量分析 | NetworkMiner
介绍 NetworkMiner 是一款适用于Windows(也适用于Linux/Mac)的开源网络取证分析工具。它可被用作被动网络嗅探器/数据包捕获工具,也可被用于检测操作系统、会话、主机名、开放端口等,还能被用于解析pcap文件进行离线分析。点击此…...
弦理论的额外维度指的是什么,宇宙中有何依据
弦理论中的额外维度是解释微观世界与宏观宇宙矛盾的关键假设之一。它们并非科幻中的平行宇宙,而是通过严谨的数学框架提出,并可能留下可观测的宇宙学痕迹。以下是具体解析: 一、弦理论为何需要额外维度? 数学自洽性要求 弦理论中…...
std::tuple 用法
std::tuple 是 C11 引入的模板类,用来存储多个不同类型的值,类似于 Python 的元组。你可以把它看作是一种“组合多个变量在一个对象中”的方式。 ✅ 基本用法 #include <tuple> #include <iostream>int main() {std::tuple<int, std::st…...

深入理解 Git 分支操作的底层原理
在软件开发的世界里,Git 已经成为了版本控制的标配工具。而 Git 分支功能,更是极大地提升了团队协作和项目开发的效率。我们在日常开发中频繁地创建、切换和合并分支,但是这些操作背后的底层原理是怎样的呢?在之前的博客探秘Git底…...

Excel MCP: 自动读取、提炼、分析Excel数据并生成可视化图表和分析报告
最近,一款Excel MCP Server的开源工具火了,看起来功能很强大,咱们今天来一探究竟。 基础环境 最近两年,大家都可以看到AI的发展有多快,我国超10亿参数的大模型,在短短一年之内,已经超过了100个&…...

C语言:深入理解指针(4)
目录 一、字符指针变量 二、数组指针变量 三、二维数组传参的本质 四、函数指针变量 五、typedef 类型重命名 六、函数指针数组 一、字符指针变量 我们常见的字符指针变量是这样的: char a w; char* p &a; char arr[] "abcd"; char* pa ar…...
Gensim 是一个专为 Python 设计的开源库
Gensim 是一个专为 Python 设计的开源库,其核心代码和生态系统均基于 Python 构建,目前官方仅支持 Python 语言。如果你需要在其他编程语言中实现类似功能(如词向量训练、主题模型等),通常需要使用对应语言的替代库或通…...
质量管理工程师面试总结
今天闲着无聊参加了学校招聘会的一家双选会企业,以下是面试的过程。 此次面试采用的是一对多的形式。(此次三个求职者,一个面试官) 面试官:开始你们每个人先做个自我介绍吧。 哈哈哈哈哈哈哈哈,其实我们…...