编译原理 学习 2025年6月10日11:17:54

编译原理

将高级编程语言编写的源代码转换成机器可执行的代码(二进制或汇编代码)

核心任务:

词法分析(正则表达式和有限自动机):
示例Token分类:关键字:if, while
运算符:+, =
标识符:变量名

                分解源代码为单词 识别 其中关键字 变量名 运算符

语法分析(上下文无关文法CFG):
示例CFG规则:
E → E + T | T
T → T * F | F
F → (E) | id

                      根据语法规则 构建抽象语法树(AST) 检查程序结构 是否正确  

语义分析(语法制导翻译):

验证类型匹配,变量声明等语义规则

代码优化(数据流分析):

删除冗余代码、循环优化等技术提升程序性能。

目标代码生成:

优化过后转换成二进制或者汇编

应用场景:

编译器开发(GCC.LLVM等工具链实现)

静态分析工具(检测代码风格和漏洞 如:ESLint)

领域特定语言(DSL快速构建小型语言的处理工具)

使用现有的工具和库(如:Lex/Yacc/Bison/Flex)实践编译器开发

Windows环境安装工具flex bison

CMD管理员输入以下代码

choco install winflexbison3

当出现

Do you want to run the script?([Y]es/[A]ll - yes to all/[N]o/[P]rint):

回复A 运行所有脚本

如果遇到运行问题可把以下地址添加到PATH(环境变量))默认路径为 C:\Program Files (x86)\WinFlexBison 主要下图信息输出 比如说我的电脑 安装位置就为

C:\ProgramData\chocolatey\lib\winflexbison3\tools

检测是否安装成功

win_flex --version
win_bison --version

实战项目AI:实现一个简单的计算器(支持加减乘除)

编写 calc.l(Flex 文件)

%{
#include "y.tab.h"  // 包含 Yacc/Bison 生成的头文件,用于 token 类型定义// 文件名可能是 y.tab.h 或 calc.tab.h,取决于 Yacc/Bison 文件配置
%}
%option noyywrap  // 禁用 yywrap 函数,简化 Lex 程序
%%
// 模式匹配规则部分
[0-9]+      { yylval = atoi(yytext); return NUMBER; }  // 匹配数字并转换为整数
"+"         { return ADD; }  // 匹配加号运算符
"-"         { return SUB; }  // 匹配减号运算符
"*"         { return MUL; }  // 匹配乘号运算符
"/"         { return DIV; }  // 匹配除号运算符
"("         { return LPAREN; }  // 匹配左括号
")"         { return RPAREN; }  // 匹配右括号
[ \t\n]     ; // 忽略空格、制表符和换行符
.           { printf("未知字符: %s\n", yytext); }  // 处理其他未定义字符
%%
// 用户代码部分(此处为空)

编写 calc.y(Bison 文件)

%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();      // 声明词法分析器函数
extern FILE *yyin;       // 输入文件指针
void yyerror(const char *msg) {   // 错误处理函数
fprintf(stderr, "Error: %s\n", msg);
}
%}
%token ADD SUB MUL DIV LPAREN RPAREN  NUMBER  // 定义token类型
%left '+' '-'     // 定义运算符优先级和结合性
%left '*' '/'     // 乘法除法优先级高于加减法
%%
input:            // 输入规则
/* 空输入 */
| input line  // 多行输入处理
;
line:             // 行处理规则
'\n'          // 空行
| expr '\n' { printf("= %d\n", $1); }  // 表达式行,输出计算结果;
expr:             // 表达式规则
NUMBER            { $$ = $1; }  // 数字直接返回
| expr '+' expr   { $$ = $1 + $3; }  // 加法运算
| expr '-' expr   { $$ = $1 - $3; }  // 减法运算
| expr '*' expr   { $$ = $1 * $3; }  // 乘法运算
| expr '/' expr   { if ($3 == 0) yyerror("Division by zero"); else $$ = $1 / $3; }  // 除法运算,检查除零错误
| '(' expr ')'    { $$ = $2; }  // 括号表达式
;
%%
主程序部分
int main(int argc, char **argv) {
if (argc > 1) {          // 如果有命令行参数
yyin = fopen(argv[1], "r");  // 打开文件作为输入
} else {
yyin = stdin;        // 否则使用标准输入
}// 启用 Bison 调试模式yydebug = 1;yyparse();               // 调用语法分析器
return 0;}

Windows安装的工具需要在原代码调用的前提上添加 win_ 这样才会识别

下图是因为编译时被安全软件拦截生成的提示 

1.生成 .c 文件

//修改前  以下代码 Windows 环境不会识别
flex calc.l         # 生成 calc.yy.c
bison -dy calc.y    # 生成 calc.tab.c 和 calc.tab.h
//修改后 正常生成,如果出现还是不识别 返回文章前面寻找路径添加到 环境变量
win_flex calc.l
win_bison -dy calc.y
  • yylex():由词法分析器提供,负责返回词法单元。
  • yyerror():用户需实现的错误处理函数
  • yylval/yylloc:用于传递词法单元的属性和位置信息。
  • yyparse() 是由语法分析器生成工具(如 Bison 或 Yacc)自动生成的函数,用于执行语法分析过程。它通常与词法分析器(如 Lex 或 Flex 生成的 yylex())配合使用,构成编译器或解释器的核心部分。

可以看到生成了三个文件

  • lex.yy.c(由 Flex 生成)
  • y.tab.c(由 Bison 生成)
  • y.tab.h(定义 token)

 

 2.编译链接 

gcc lex.yy.c y.tab.c -o calc   //正常链接gcc lex.yy.c y.tab.c -DYYDEBUG=1 -o calc  //打开调试开关的链接
//lex.yy.c:由Lex(或Flex)生成的词法分析器源代码,负责将输入字符流分解为标记(tokens)。
//y.tab.c:由Yacc(或Bison)生成的语法分析器源代码,包含语法规则和语义动作,通常依赖词法分析器的输出。

可以看到生成了一个exe程序

 

 点击运行并输入算式:

Starting parse       // 开始语法分析(调用 yyparse())
Entering state 0     // 进入状态 0(初始状态)
Stack now 0          // 当前状态栈:[0]Reducing stack by rule 1 (line 15):   // 根据规则 1 归约(对应 input 规则)-> $$ = nterm input ()             // 将 input 规约为一个非终结符(空输入)Entering state 1     // 状态变为 1
Stack now 0 1        // 状态栈更新为 [0, 1]Reading a token      // 开始读取第一个 token
5 + 3                // 用户输入内容(注意这行是你手动或从文件输入的内容)Next token is token NUMBER ()        // 下一个 token 是 NUMBER(数字 5)
Shifting token NUMBER ()             // 将该 token 移入栈中
Entering state 3                     // 进入状态 3
Stack now 0 1 3                      // 状态栈变为 [0, 1, 3]Reducing stack by rule 5 (line 23):  // 根据规则 5 归约(exp: NUMBER)$1 = token NUMBER ()              // 使用 NUMBER 值(即 5)构造 exp-> $$ = nterm exp ()              // 将 NUMBER 归约为 exp(表达式)Entering state 7                     // 进入状态 7
Stack now 0 1 7                      // 状态栈变为 [0, 1, 7]Reading a token      // 继续读取下一个 tokenNext token is token '+' ()           // 下一个 token 是 '+'(加号)
Shifting token '+' ()                // 将 '+' 移入栈中
Entering state 9                     // 进入状态 9
Stack now 0 1 7 9                    // 状态栈变为 [0, 1, 7, 9]Reading a token      // 继续读取下一个 tokenNext token is token NUMBER ()  
// 下一个读取到的 token 是 NUMBER(即数字 "3")Shifting token NUMBER ()
// 将这个 token(数字 3)移入解析栈中Entering state 3
// 当前状态变为 3(通常是处理 NUMBER 的状态)Stack now 0 1 7 9 3  
// 当前解析栈的状态序列:[0, 1, 7, 9, 3]
// 表示当前处于状态 3,前面是状态 0 → 1 → 7 → 9 → 3Reducing stack by rule 5 (line 23):  
// 根据语法规则第 5 条进行归约(对应 exp: NUMBER)$1 = token NUMBER ()  
// 使用当前 token 的值(即 3)作为规则中的第一个操作数-> $$ = nterm exp ()  
// 将 NUMBER 归约为非终结符 exp(表达式)
// 即:把数字 3 看作是一个“表达式”expEntering state 15  
// 归约完成后进入新状态 15(通常是由 exp '+' exp 后匹配到新的 exp)Stack now 0 1 7 9 15  
// 当前状态栈更新为 [0, 1, 7, 9, 15]Reading a token  
// 准备读取下一个 token(输入结束或换行)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/83213.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

风中低语:Linux 信号处理的艺术与实践

文章目录 &#x1f307;前言&#x1f3d9;️正文1、信号的处理时机1.1、处理情况1.2、“合适” 的时机 2、用户态与内核态2.1、概念2.2、重谈进程地址空间2.3、信号的处理过程 3、信号的捕捉3.1、内核如何实现信号的捕捉&#xff1f;3.2、sigaction 4、信号部分小结 补充 5、可…

ASP.NET Core SignalR - 部分客户端消息发送

文章目录 前言一、消息发送的核心概念1.客户端标识2.消息接收范围 二、向特定用户发送消息管理员向指定用户发送私信&#xff0c;或用户之间一对一聊天。 三、向组发送消息聊天室、工作群组、通知订阅等。 四、广播消息系统公告、实时统计数据更新等。 五、向角色发送消息向管理…

前后端交互过程中—各类文件/图片的上传、下载、显示转换

前后端交互过程中—各类文件/图片的上传、下载、显示转换 图片上传下载常用函数&#xff1a;new Blob()**blobParts&#xff1a;&#xff08;必传&#xff09;****options&#xff1a;&#xff08;可选&#xff09;**blob的常见的MIME类型&#xff1a; URL.createObjectURL()替…

校园二手交易平台(微信小程序版)

文章目录 1. 项目概述2. 项目功能思维导图3. 技术架构1. 前端技术栈2. 后端技术栈 4. 核心模块实现5. 总结6. 项目实现效果截图7. 关于作者其它项目视频教程介绍 1. 项目概述 校园二手交易平台微信小程序旨在为在校学生提供一个便捷的二手物品交易渠道&#xff0c;包含用户模块…

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …

【芯片设计- RTL 数字逻辑设计入门 4.2 -- 组合逻辑赋值 + 时序逻辑状态保持】

文章目录 Overview原语句分析变量含义假设(根据命名推测)状态更新逻辑详解状态转移逻辑举个实际例子小结Overview 本文将详细介绍 verilog rtl 中 assign reg_halt_mode_nx = halt_taken | (reg_halt_mode & ~halt_return);的作用,以及这里为何要使用 reg_halt_mode,…

【单片机期末】汇编试卷

一、选择题 DPTR是16位的&#xff0c;所以寻址范围是64KB R1是8位的&#xff0c;只能寻址256 访问内部ROM只能用MOVC指令 一个指令周期是时钟周期的1/12 12个时钟周期是一个机器周期 单指令周期是指一个机器周期 T 1 / f 12MHz ~ 1us 13位计数16位计数8位自动重装载双8位计数器…

校验枚举类类型的入参合法性的统一方案

文章目录 背景解决实践定义枚举类 InEnum注解定义验证逻辑 InEnumValidator 实际使用 背景 业务要做电商平台做入参, 在电商平台被抽离成枚举类的情况下 &#xff0c;要怎么验证输入的参数是正确的呢? 解决 Constraint 实现自定义验证逻辑 Constraint 注解用于标注其他注解&am…

Unity-NavMesh详解-其一

今天我们来详细地探究一下Unity的NavMesh这一性能强大的组件&#xff1a; NavMesh基本使用 NavMesh简单地说本质上是一个自动寻路的AI组件&#xff0c;我们首先来学习基本的使用。 画面中我已经添加好了地面&#xff0c;目标&#xff0c;障碍物以及玩家四个要素。 注意我们要…

vue的created和mounted区别

在Vue.js中&#xff0c;created和mounted的核心区别在于调用时机和DOM可访问性‌&#xff1a;created钩子在组件实例创建后、DOM挂载前调用&#xff0c;适用于数据初始化&#xff1b;mounted钩子在DOM挂载后调用&#xff0c;支持DOM操作。‌‌ ‌调用时机与核心能力对比‌ ‌…

MySQL 8.0 OCP 英文题库解析(十四)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题121~130 试题1…

【HarmonyOS 5】拍摄美化开发实践介绍以及详细案例

以下是 HarmonyOS 5 拍摄美化功能的简洁介绍&#xff0c;整合核心能力与技术亮点&#xff1a; 一、AI 影像创新 ‌AI 魔法移图‌ 系统级图像分层技术实现人物/物体自由拖拽、缩放与复制&#xff0c;突破传统构图限制。自动分离主体与背景&#xff0c;一键生成错位创意照&…

【Java多线程从青铜到王者】懒汉模式的优化(九)

懒汉模式的问题 我们看上述的代码&#xff0c;当第一次调用getIntance的时候&#xff0c;intance为null&#xff0c;就会进入if里面&#xff0c;创建出实例&#xff0c;当不是第一次调用的时候&#xff0c;此时的intandce不是null&#xff0c;不进入循环&#xff0c;直接return…

SCI期刊查重参考文献会被查重吗?

查重的时候&#xff0c;参考文献不会被查重。 不管中文还是英文查重系统里一般都有排除参考文献的设置。 比如英文查重系统iThenticate 的排除文献的设置如下&#xff1a; 在iThenticate在线报告界面的右下角点击“漏斗”图标&#xff08;Filter&#xff09;&#xff0c; ✔…

OpenLayers 获取地图状态

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图状态信息包括中心点、当前缩放级别、比例尺以及当前鼠标移动位置信息等&#xff0c;在WebGIS开发中&#xff0c;地图状态可以方便快捷的向用户展示基…

JxBrowser 8.8.0 版本发布啦!

一次调用即可下载文件精准清除浏览数据右键点击位置检测获取元素在视口中的位置 &#x1f517; 点击此处了解更多详情。 &#x1f193; 获取 30 天免费试用。

React 中的TypeScript开发范式

在 TypeScript 中使用 React 可以提高代码的可维护性、可读性和可靠性。TypeScript 提供了静态类型检查和丰富的类型系统&#xff0c;这些功能在 React 开发中非常有用。下面详细介绍如何在 React 项目中使用 TypeScript&#xff0c;并结合泛型和 infer 来定义类型。 1. 项目初…

72道Nginx高频题整理(附答案背诵版)

1. 简述什么是Nginx &#xff1f; Nginx 是一个开源的高性能HTTP和反向代理服务器&#xff0c;也能够用作IMAP/POP3/SMTP代理服务器。它最初由Igor Sysoev为俄罗斯的一个大型网站Rambler开发&#xff0c;并在2004年首次公开发布。Nginx被设计用来解决C10k问题&#xff0c;即同…

AI时代,数据分析师如何成为不可替代的个体

在数据爆炸的 AI 时代&#xff0c;AI工具正以惊人的速度重塑数据分析行业&#xff0c;数据分析师的工作方式正在经历一场前所未有的变革。数据分析师又该如何破局&#xff0c;让自己不被AI取代呢&#xff1f; 一、AI工具对重复性工作的彻底解构 如以往我们需要花几天写一份数…

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…