资讯动态

自制编程语言实战:从yacc/lex到解释器与编译器

发布时间:2026/10/17 14:24:43 来源:尧图企业网站定制
简介这是一份围绕《自制编程语言》展开的系统性学习资料面向编程语言设计与编译器/解释器实现爱好者旨在帮助读者打通从需求分析、语法设计到代码生成和运行时管理的全流程。资源包内为1个PDF文档压缩包大小仅2.38MB却浓缩了丰富的实践内容覆盖bison/flex、yacc/lex等词法语法分析工具结合MinGW、Cygwin等Windows下的编译环境详细展示了Crowbar和Diksam两套自制语言从0.1到0.4各版本逐步演进的过程涉及数组、GC垃圾回收等特性的实现思路并在Linux与Windows双平台给出make/gmake脚本和常见问题排错方法。PDF目录结构清晰由浅入深适合有一定C语言基础、希望亲手构建小型编程语言的开发者作为参考。目前该资源已有870人学习下载是编译原理入门与项目实践相结合的高性价比资料。1. 自制编程语言为什么我把这套资料当作入门主线想写一个计算器谁都能在两小时内糊出来但要写一个能跑条件语句、循环、函数、甚至类机制的语言呢大多数人的编译原理课就停在了“看过龙书背过词法分析定义”这一层真正动手时连 yacc 生成的头文件去哪了都找不到。这套自制编程语言资料我推荐给三类人编译原理课设选了“设计并实现一门语言”的同学、想搞清楚解释器和编译器到底差在哪里的从业者以及那些不想把 Lex 和 Yacc 当黑匣子用的人。它不是一个讲原理的 PDF而是一组能直接跑、能对照改、能拆开看的源码工程从 yacc/lex 写计算器起步一直演进到带内存管理、字符串池和类机制的完整语言实现相当于把一门语言从出生到能用的全过程完整留档了。下面这篇方案就讲清楚怎么把这份资料变成你答辩时能讲明白的完整项目。2. 资源主线拆解从 mycalc 到 crowbar 再到 Diksam 的三级跳2.1 三个实现各解决什么问题这套资料里最容易被忽略的是 mycalc 和 mycalc_ex 这两个小工程。它们用 yacc/lex 实现了最简单的四则运算计算器代码量很小但意义在于让你第一次看到“词法文件 .l 语法文件 .y gcc 编译”这条完整链路跑通是什么样。很多人第一次在这条链路上翻车就是因为还没见过“能用的最小例子”长什么样一上来就啃完整语言的源码心态直接崩掉。我的建议是不管你的目标是 crowbar 还是 Diksam先把 mycalc 在本地跑起来再去看大工程。再往上一步是 llparser 和 llparser_ex这两个工程是手写递归下降解析器不依赖 yacc。它们的价值在于让你明白 yacc 自动生成的解析器内部到底在做什么遇到冲突时它在烦什么。很多学生答辩时被问“LALR 冲突是怎么解决的”就卡住其实就是没做过手写解析器的对照。llparser 这一层就是给你补这个对照的。真正的重头戏是 crowbar 和 Diksam。crowbar 是一个树遍历型解释器读入源码后构建抽象语法树然后直接在这棵树上做求值Diksam 则是编译器路线先把源码编译成中间代码字节码再交给虚拟机执行。这两套工程放在一起恰好构成了“解释执行 vs 编译执行”的完整对比。对课设来说拿其中一个做主线、另一个做对照答辩时能讲的内容就非常厚了。2.2 版本演进从 0.1 到 0.4每次都在加什么再看版本号这是这套资料最有价值的地方。crowbar 从 crowbar_book_0_1 一路到 crowbar_book_0_4Diksam 也是 diksam_book_0_1 到 diksam_book_0_4每一版都是一个独立可构建的完整工程。这意味着你不用一上来就啃最终版那几千行代码而是可以按版本顺序读 diff。从资料内附的记录来看crowbar 0.1 是基础语法树执行先把程序、语句、表达式的基本结构跑通0.2 引入了 GC对应源码里增加了内存管理相关模块0.3 继续扩展语言特性0.4 开始引入更复杂的运行时能力比如字符串和正则相关的支持。Diksam 的演进路径类似但它从 0.1 开始就是编译为中间代码的架构后面版本逐步把数组、对象等特性补进编译器前端和虚拟机。这种按版本演进的写法比给你一个“最终版源码”要友好得多。读 0.1 到 0.2 的差异你看到的是“为什么要加 GC加了之后哪些模块要跟着改”读 0.2 到 0.3 的差异你看到的是“语法扩展如何从词法、语法、AST、执行器四个层面同时渗入”。对做课设的同学来说你完全可以只复刻到 0.1再挑 0.2 的一个特性比如 GC作为自己的加分项这个尺度刚刚好。2.3 为什么说这是可照抄的工程而不是能跑的代码包一个直接可以照抄的工程至少要满足三个条件环境可复现、构建可一键执行、报错有记录。这套资料在这三方面都做得比较到位。构建脚本层面Linux 下用 make.shWindows 下用 make.batcrowbar 和 Diksam 都优先用 make/gmake 驱动子模块 memory 目录也有自己的构建逻辑。这不是那种“源码扔给你你自己凑环境”的代码包而是把“下载依赖 → 构建 → 出可执行文件”整条路都给你铺好了。更难得的是资料里保留了大量的报错与问答记录。比如 bison 装在带空格的路径下导致 m4 打不开文件、y.tab.c 没有生成就误以为编译失败、Windows 换行符导致 Linux 下源码解析报 0x0d 非法字符、链接时找不到 msvcp60 库等等这些都属于实际动手后才能踩到的坑却被整理成了类似“排雷日志”的东西。我建议你把这份日志当成一个“摸底测试”如果你能理解其中任意三条错误的成因那这套源码你已经入门了一半如果一条都看不懂说明前面的 mycalc 步骤被跳过了倒回去重来。3. 环境构建Linux 与 Windows 两条路径的完整走法3.1 Linux 路径make.sh 一把梭但要先补齐依赖在 Linux 下构建这套工程理论上是最顺的因为 gcc、make 通常都是现成的。但有两个前置依赖很容易缺bison/flex 和 oniguruma 正则库。oniguruma 是 crowbar 0.4 之后处理正则表达式时用到的底层库资料里给出的版本是 5.9.4。wget http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.9.4.tar.gz tar -xvf onig-5.9.4.tar.gz cd onig-5.9.4 ./configure make make install这段是标准的 autotools 流程configure 检查当前系统的编译器和头文件生成 Makefilemake 编译出 libonig.amake install 把库和头文件装到 /usr/local 下。注意这里如果之前装过别的版本的 oniguruma建议先确认一下 /usr/local/include 和 /usr/local/lib 里没有残留的老版本否则链接时可能“病急乱投医”找到旧头文件报一些莫名其妙的类型不匹配错误。装完 oniguruma 之后再确认 bison 和 flex 是否已安装。在 Debian/Ubuntu 系是apt install bison flex在 Red Hat/CentOS 系是yum install bison flex。装完后不要急着 make先在 mycalc 目录下试跑一次完整构建把 yacc/lex 的工具链问题提前暴露出来比直接去编译 crowbar 要好排查得多。3.2 Windows 路径MinGW 与 Cygwin 怎么选Windows 下构建这套源码历史上主要有两条路线一个是 MinGW一个是 Cygwin。两者的选择会直接影响你后续遇到的错误类型。MinGW 的定位是“在 Windows 上原生编译”它不依赖 cygwin.dll编出来的 exe 可以直接分发。但 MinGW 不自带 bison也不自带完整的 make所以通常需要额外下载 GnuWin32 的 bison 和 flex 安装包。而 Cygwin 则是在 Windows 上提供一个 POSIX 兼容层里面可以装完整的 gcc、make、bison、m4体验最接近 Linux。我的建议是如果你只是要跑通工程验证功能直接用 Cygwin因为它把 bison、m4、make 的依赖一套打包了后续的坑最少如果你要交付一个“能在 Windows 上独立运行的 exe”给答辩演示那用 MinGW 更合适因为 MinGW 编出来的程序不依赖 Cygwin 的 DLL。MinGW 的标准安装方式是下载 mingw-get-setup.exe装完后在 MinGW Installation Manager 里勾选 mingw32-base把 gcc 和 make 装好然后把D:\MinGW\bin加进系统 PATH。之后用mingw32-make.exe替代 make 执行构建。需要特别提醒的是MinGW 的 mingw32-make.exe 和 Cygwin 的 gmake.exe 不是同一个东西。一个常见翻车场景是在 MinGW 环境里直接敲 make 发现报“No targets specified and no makefile found”但实际上 Makefile 就在当前目录。原因往往是 PATH 里同时混入了 Cygwin 的工具导致 make 被解析成了 Cygwin 版本工作目录或者文件系统视图都不一样。我的习惯是在 cmd 里用全路径调用D:\MinGW\bin\mingw32-make.exe每一步都用全路径不赌 PATH。3.3 bison/flex 的安装细节与 DLL 依赖性检查bison 和 flex 在 Windows 上最省事的来源是 GnuWin32 的安装包。下载 bison 的 Complete packageexcept sources和 flex 的 Complete package装上之后关键检查点是 PATH 里不要出现带空格的路径。GnuWin32 的默认安装在C:\Program Files (x86)\GnuWin32这个路径里有空格而 bison 内部会调用 m4m4 拿到带空格的路径时经常只截取到空格前的部分于是报出类似这样的错误m4: cannot open Files: No such file or directory m4: cannot open (x86)\GnuWin32\Bison/share/bison: No such file or directory遇到这个错误最好的解决方式不是去改 bison 的安装位置而是把 GnuWin32 整个重装到不带空格的路径例如C:\GnuWin32。我见过有人花一下午调 m4 的环境变量最后发现就是路径空格这一点破事。至于 oniguruma 在 Windows 下的构建通常需要在 Cygwin 环境下执行 configure/make生成 libonig.a 后再拷贝到 MinGW 的 lib 目录下。如果 make install 时出错可以退一步手动处理静态库进入.libs目录执行ranlib libonig.a再把它复制到 MinGW 的 lib 目录这条手动路线在资料记录里是被验证过的。4. 源码实现解读词法、语法到执行的三个落地阶段4.1 词法分析.l 文件与状态切换的设计套路crowbar 系列和 mycalc 的词法文件都使用 flex 语法结构上分三段定义区、规则区、用户代码区。mycalc 的一个极简例子大致长这样%{ #include y.tab.h %} %% [0-9] { yylval.int_value atoi(yytext); return INT_LITERAL; } { return PLUS; } * { return MULT; } [ \t] { /* skip whitespace */ } \n { return NEWLINE; } . { fprintf(stderr, lexical error: %s\n, yytext); } %%这里每个规则的模式对应一个动作数字被转换成INT_LITERALtoken 并附带整数值运算符返回对应 token空白直接跳过。注意yylval是 flex 与 bison 共享的全局变量token 的语义值比如数字的值就是靠它传递的。.l文件里最容易出错的地方是规则顺序flex 默认按最长匹配优先但相同长度时靠前的规则优先。所以注释、字符串、标识符这类需要较长模式的规则必须放在数字和关键字之前否则会被前面的规则“截胡”。到 crowbar 这个级别词法文件里会涉及更复杂的状态管理。资料里提到过 crowbar.l 中使用了%start COMMENT STRING_LITERAL_STATE这样的起始状态声明这是 flex 的状态机用法注释和字符串字面量内部可以包含空格、换行甚至与普通代码歧义的字符必须进入独立状态来处理。比如进入字符串状态后直到遇见结束引号才切回初始状态进入注释状态后直到遇见注释结束标记才恢复。这个机制是词法分析里最值得讲给答辩老师听的部分因为它是“词法分析的阶段划分”在实际工程中的体现。4.2 语法分析.y 文件中的优先级、结合性与冲突处理语法文件 .y 的结构与 .l 类似也是定义区、规则区、用户代码区三段。以 mycalc 的四则运算为例核心规则大致如下%token INT_LITERAL %left - %left * / %% expression : expression expression | expression - expression | expression * expression | expression / expression | INT_LITERAL ; %%%left声明解决了运算优先级问题写在后面的运算符优先级更高所以*和/会比和-结合得更紧。如果没有这几行声明bison 会在生成解析器时报告大量的 shift/reduce 冲突因为它不知道1 2 * 3应该是(12)*3还是1(2*3)。很多人在这一步摔过跟头看到几十行冲突报告就慌了其实八成只是忘了声明优先级。到 crowbar 和 Diksam 的语法文件里规则会扩展到程序结构、语句、表达式三个层级并有%union来定义不同 token 的语义值类型。读 .y 文件时我建议你先画出三张图程序级的文法结构、语句级的文法结构、表达式级的文法结构。画完之后你会发现整个语言的骨架其实就是三条递归规则互相嵌套。答辩时能徒手在黑板上画出这三层结构比背一百行源码都管用。4.3 执行阶段树遍历解释器与字节码虚拟机的设计差异crowbar 和 Diksam 的分水岭不在前端而在后端设计。crowbar 的 execute.c 和 eval.c 是典型的树遍历执行器语法分析阶段构建出 AST执行器递归地访问每个节点对表达式求值、对语句执行副作用。这种设计的优点是结构简单、易于调试每个节点对应一个执行函数缺点是每执行一次都要重新遍历节点没有编译成中间代码的性能优化空间。Diksam 则完全不同。它的前端产出的是中间代码字节码由虚拟机加载执行。这意味着 Diksam 需要设计一套操作码opcode体系、一个执行栈、一套指令分发的循环结构。资料里 Diksam 各版本都有相对独立的 compiler 目录和 main 驱动构建时也是分别编译编译器前端与虚拟机后端这是一个非常清晰的模块划分。你可以在答辩时直接讲这个对比crowbar 是“边解析边执行”Diksam 是“先编译后执行”两者代表了两条最典型的技术路线。在执行层面还有一个值得单独讲的模块是 string_pool.c字符串池。字符串在语言运行时里是最常见的对象如果一个程序里多次出现同一个字符串字面量每次都重新分配内存就浪费了。字符串池的做法是运行时维护一张全局的字符串表每次创建字符串前先在表里查找找到就直接复用。这个设计在很多脚本语言的实现里都能看到但大部分人第一次接触它就是在 crowbar 的源码里。答辩时能把这个机制讲清楚再点出它与 GC 的关系会是很加分的细节。5. 常见问题排查从 bison 路径到换行符的五个翻车点5.1 bison 装在带空格路径下m4 打不开文件现象在 Windows 上执行 make报错信息是m4: cannot open Files: No such file or directory后面还跟着一串带有(x86)\GnuWin32\Bison/share/bison的错误。看起来是 m4 无法读取 bison 目录下的 m4sugar 宏文件。原因GnuWin32 默认安装路径C:\Program Files (x86)\GnuWin32含空格。bison 生成解析器时需要调用 m4 处理宏定义路径在传递过程中被空格截断m4 把半截路径当成文件名自然找不到。解决把 GnuWin32 卸载后重装到不带空格的路径例如C:\GnuWin32并把C:\GnuWin32\bin加入 PATH。注意重装后要重新打开 cmd让新的 PATH 生效。这条经验适用于所有 GNU 工具链家族的 Windows 移植版只要发现工具的报错里出现了Files、(x86)这类片段第一反应就应该是检查路径空格而不是去翻 m4 的配置。5.2 y.tab.c / y.tab.h 缺失gcc 找不到头文件现象编译 mycalc.l 时报mycalc.l:3:19: error: y.tab.h: No such file or directory或者 gcc 报gcc: y.tab.c: No such file or directory。看起来像是 flex 或 gcc 出了问题。原因y.tab.c 和 y.tab.h 是 bison 处理 .y 文件后生成的中间产物。如果 bison 这一步没有成功执行或者 Makefile 中 bison 目标的产出文件与 gcc 编译目标依赖的文件名不一致就会导致 gcc 启动时发现依赖文件根本不存在。很多时候 bison 其实是报错了的但错误信息被 make 的输出吞掉或被人忽略大家只看到 gcc 这一层的报错。解决直接在命令行手动执行一次bison --yacc -dv crowbar.y观察是否真的生成了 y.tab.c 和 y.tab.h。如果这一步本身就报错回到 5.1 检查 bison 的环境如果生成成功再检查 Makefile 里依赖的目标名是否匹配。记住gcc 找不到 y.tab.h不是 gcc 的问题是它前面那个工具没干完活。5.3 make 报 e2 找不到指定文件bison 根本没被调用起来现象Windows 下执行mingw32-make报错process_begin: CreateProcess(NULL, bison --yacc -dv crowbar.y, ...) failed. make (e2): 系统找不到指定的文件。Makefile 里的 recipe 写得没问题但执行到 bison 这一步时进程起不来。原因make 在 PATH 里找不到 bison 这个可执行文件。这不是 bison 没装而是 bison 的安装目录没有加入 PATH或者加入 PATH 的是旧路径。MinGW 自带的 make 对 PATH 的解析方式和原生 cmd 不完全一样有时候你在 cmd 里能敲出 bison但 make 的子进程环境里就是没有它。解决先确认 bison 装在哪里然后把它所在目录比如C:\GnuWin32\bin加到系统 PATH 最前面重新打开 cmd 再构建。如果还不行走全路径把 Makefile 里的bison改成绝对路径或者用make.exe的环境变量BISON指定。这种问题不要靠改代码解决靠改环境解决。5.4 Linux 下源码文件报 0x0d 非法字符Windows 换行符引发的惨案现象在 Linux 下运行./crowbar test/test.crb报错指向第 5 行有非法字符(0x0d)或者编译时源码里多出\r。原因源码或测试用例文件是在 Windows 上用 CRLF 换行保存的而 Linux 下 flex 生成的词法分析器只认\n多出来的\r就成了非法字符。资料里也有对应记录解决方式是dos2unix test/test.crb。这句话本身就是一个完整的避坑记录。解决在项目根目录执行find . -name *.crb -o -name *.c -o -name *.h | xargs dos2unix把文本文件统一转成 LF。如果系统没装 dos2unix用sed -i s/\r$//批量处理也行。以后做跨平台项目建议先在 Git 里配好.gitattributes统一换行符从源头避免这个问题。5.5 oniguruma 的 make install 失败ranlib 找不到 libonig.a现象在 Windows/Cygwin 下编译 oniguruma 5.9.4configure 和 make 都通过了但执行make install时报错ranlib.exe: /usr/local/lib/libonig.a: No such file随后整个 install 流程中断。原因oniguruma 的构建脚本在 Cygwin/MinGW 混合环境下libtool 生成的中间文件路径与实际安装路径不一致。静态库其实已经生成在.libs目录下了但 install 流程去找的是安装目标路径跨文件系统时路径映射出了问题。解决不依赖 make install手动完成安装。进入C:\onig-5.9.4\.libs执行ranlib libonig.a生成索引然后把 libonig.a 复制到 MinGW 的 lib 目录把 oniguruma.h 复制到 include 目录。最后用一个小测试程序验证头文件和库能被正常链接。这条手动路径在资料里有明确记录也提醒我autotools 的 make install 在 Windows 环境下并不总是可靠手动拷贝静态库反而是更可控的方案。6. 验收与答辩怎么把“能跑”讲成“我理解了这个语言实现”6.1 用“最小复现 增量修改”建立验收清单很多人的课设演示是“运行一下自带脚本看到输出就结束”这太容易被追问击穿。我一般会建议学生把验收拆成四个等级第一级工具链完整跑通 mycalc能计算四则运算并输出结果第二级用 llparser 手写解析器跑通同一个表达式并解释为什么同一套语法在手写解析器里需要显式处理优先级第三级crowbar 0.1 跑通自带测试脚本能执行 if/while/函数调用第四级从 0.1 到 0.2 挑一个特性增量说清楚词法、语法、AST、执行器四个层面各自改了哪里。答辩前把这四个等级做成一张表格每一级对应一个可运行的命令和一条你准备好的解释。老师问“这个语言支持什么特性”你直接说“请运行这个测试脚本”同时翻开对应版本的源码讲实现位置。这比背 PPT 有说服力得多。6.2 答辩时三个必讲的设计点第一个必讲点是“为什么要用 yacc/lex而不是手写”。正确回答不是“yacc 方便”而是“yacc 处理的是 LALR 文法它能把优先级和结合性声明化避免手写解析器里大量的预判逻辑但代价是冲突报告难以理解所以项目里用 llparser 做对照”。第二个必讲点是“树遍历解释器和字节码虚拟机的取舍”。要从性能、内存管理、调试难度三个维度对比说清楚 crowbar 选树遍历是为了实现简单Diksam 选字节码是为了后续优化空间。第三个必讲点是“内存管理在解释器里的地位”。crowbar 0.2 引入 GC 是一个真实的版本演进可以讲清楚为什么没有 GC 时字符串池和对象释放会变成一团乱账。6.3 我的收尾习惯每次我带这类项目最后都会强制自己走一遍“从干净环境开始构建”的流程换一台没有装过任何工具链的机器按照写好的环境文档从零装依赖、构建、跑测试。很多“在自己机器上能跑换台机器就翻车”的问题都是在这一步暴露出来的。这套自制编程语言资料本身就有大量环境相关的踩坑记录但它没法替你验证你的环境所以我养成的习惯是把环境搭建步骤做成脚本把测试用例做成命令每次答辩前跑一遍跑通了才算真的能演示。这个习惯帮我避免过太多次现场翻车希望你也能留着用希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑