☰
Windows下自制编程语言环境搭建:Bison/Flex/Oniguruma三件套配置指南
2026/10/31 2:40:38 网站建设 项目流程

简介:本资源是一套面向编程语言学习者与编译原理初学者的《自制编程语言》系统性入门资料,聚焦语言设计、实现与工程实践全过程。内容覆盖语法语义设计原则、基于bison/flex的词法/语法分析器开发、MinGW环境下的编译器与解释器构建,以及Crowbar和Diksam两款真实自制语言的完整演进版本(v0.1–v0.4)源码与配套技术文档。资源为单个PDF文件,大小2.38MB,结构清晰,含Linux/Windows双平台构建脚本(make.sh/make.bat)、GCC/MinGW适配说明、Cygwin对比分析及详细编译实操步骤,便于读者边学边练、快速复现。目前已有870人学习下载,适合具备C语言基础、希望深入理解编程语言底层机制并动手实现简易语言的中初级开发者系统研习。

1. 别急着写 parser,先让bison在 Windows 上吐出y.tab.h:一套能跑通的自制编程语言环境,卡在第一步就放弃的人太多了

你下载了《自制编程语言》资料包,解压出crowbar_book_0_1,双击make.bat没反应;或者打开命令行,敲mingw32-make,报错process_begin: CreateProcess(...) failed;再一查日志,满屏m4: cannot open 'Files': No such file or directory——恭喜,你成功复现了 2013 年至今最经典的「自制语言入门幻灭时刻」。这不是你手残,是这套资料从诞生起就踩在 Windows 路径空格、MinGW 工具链缺失、bison/m4 环境变量错位三重雷区上。它不面向 IDE 新手,而是给已经用过gcc -E看预处理、手动改过Makefile依赖顺序、知道.PHONY是干啥的人准备的。如果你刚学完 C 语言指针,建议先拿mycalc(带完整yacc/lex示例)练手;如果你已部署过 Linux 下的onig-5.9.4,那crowbar_ver.0.4的 GC 模块就是你下一步要啃的硬骨头。本文不讲「什么是词法分析」,只解决「为什么y.tab.h死活不生成」「libonig.a放哪gcc才认」「crowbar test/test.crb报错0x0d怎么修」这三个真实发生过、有截图、有错误码、有修复命令的落地问题。


2. 环境底座:MinGW + Bison/Flex + Oniguruma,版本锁死与路径净化

自制编程语言不是搭乐高,少一个齿轮,整个解析器就停摆。这套资料里所有make.sh/make.bat脚本都默认你已配好三件套:MinGW 编译器(非 Cygwin)、Bison 2.7+(必须含m4运行时)、Oniguruma 5.9.4(正则引擎,Crowbar 字符串处理强依赖)。它们不是可选组件,而是呼吸系统——缺一个,crowbar就会因#include "y.tab.h"找不到而编译失败,或因libonig.a链接不上而ld报cannot find -lonig。下面每一步都经过crowbar_book_0_1到0_4全版本实测,拒绝“可能可以”“理论上支持”。

2.1 MinGW 安装:只装mingw32-base和msys,删掉所有带cygwin字样的幻想

crowbar明确要求MinGW,不是 Cygwin。Cygwin 的cygwin.dll会污染整个链接过程,导致crowbar.exe在无 Cygwin 环境下直接崩溃(报DLL not found),且其make会偷偷调用/usr/bin/sh,与make.bat中的cmd逻辑冲突。必须物理隔离。

提示:不要下载mingw-get-setup.exe后点“Continue”一路默认安装。它的默认选项会勾选gcc-g++(冗余)、mingw32-libz(Crowbar 不用),却漏掉最关键的msys——没有msys,./configure脚本根本跑不起来。

正确操作:

# 1. 下载官方精简版(2013 年资料适配性最好) # 访问 http://sourceforge.net/projects/mingw/files/Installer/mingw-get-setup.exe/download # 运行后,在 "Select Components" 页面,**仅勾选以下两项**: # - ☑ mingw32-base # - ☑ msys-base # 2. 安装路径必须**无空格、无中文、无括号**! # ✅ 推荐:C:\MinGW # ❌ 禁止:C:\Program Files\MinGW、D:\我的编译器\MinGW、C:\MinGW(x86) # 3. 安装完成后,将 C:\MinGW\bin 加入系统 PATH # 控制面板 → 系统 → 高级系统设置 → 环境变量 → 系统变量 → Path → 编辑 → 新建 → 输入 C:\MinGW\bin

验证是否成功:

C:\> gcc --version # 应输出类似:gcc.exe (MinGW.org GCC-6.3.0-1) 6.3.0 C:\> make --version # 应输出:GNU Make 3.81

若make --version报not recognized,说明PATH未生效,重启命令行或电脑。

2.2 Bison 2.7.1 + Flex 2.5.4a:绕过m4路径空格陷阱的唯一解法

crowbar.y用 Bison 生成解析器,但crowbar_book_0_1的Makefile调用的是bison --yacc -dv crowbar.y。Windows 下,如果 Bison 安装在C:\Program Files\GnuWin32\,m4(Bison 的宏处理器)在解析share/bison/m4sugar/m4sugar.m4时,会把Program Files拆成Program和Files两个参数,导致m4: cannot open 'Files': No such file or directory。这是 2013 年高频翻车点,网上所有“重装 Bison”的建议都治标不治本。

根治方案:不装 GnuWin32,改用 MinGW 自带的mingw32-bison(它已静态链接m4,无路径依赖):

# 1. 用 MinGW Installation Manager 安装 bison(不是 GnuWin32!) # 运行 C:\MinGW\msys\1.0\msys.bat $ mingw-get install mingw32-bison mingw32-flex # 2. 验证安装位置(必须是 C:\MinGW\bin 下的文件) $ ls /c/MinGW/bin/bison* # 应看到:/c/MinGW/bin/bison.exe /c/MinGW/bin/bison-simple.exe # 3. 强制让 make 使用 MinGW 版本(关键!) # 编辑 crowbar_book_0_1/Makefile,找到这一行: # BISON = bison # 改为: # BISON = C:/MinGW/bin/bison.exe # 同理,找到 FLEX = flex,改为 FLEX = C:/MinGW/bin/flex.exe

注意:crowbar_book_0_2及之后版本的Makefile中,BISON变量常被写成bison(无路径),这会导致make去PATH里找,而PATH里若有 GnuWin32 的bison,就会触发空格 bug。永远显式写死绝对路径,这是血泪经验。

验证 Bison 是否可用:

# 进入 crowbar_book_0_1 目录 C:\crowbar_book_0_1> C:\MinGW\bin\bison.exe --yacc -dv crowbar.y # 成功时会生成:crowbar.tab.c、crowbar.tab.h(注意:不是 y.tab.h!) # 若报错 "CreateProcess failed",99% 是路径含空格或 `bison.exe` 文件损坏,重装 `mingw32-bison`

2.3 Oniguruma 5.9.4:静态链接libonig.a,避开make install的权限地狱

crowbar的字符串处理模块(string.c)调用onig_new(),必须链接libonig.a。但onig-5.9.4的make install在 Windows 下极易失败(报No such file or directory或ranlib: '/usr/local/lib/libonig.a': No such file),因为它的Makefile默认走 Unix 路径/usr/local/lib,而 MinGW 根本没有这个目录。

正确姿势:不运行make install,手动提取libonig.a并指定链接路径:

# 1. 下载源码并解压(必须用 5.9.4,新版 API 不兼容) # http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.9.4.tar.gz # 解压到 C:\onig-5.9.4(路径无空格!) # 2. 在 MSYS 中配置编译(关键:禁用 shared library,只生成 .a) $ cd /c/onig-5.9.4 $ ./configure --enable-static --disable-shared --prefix=/c/MinGW # 3. 编译(不安装!) $ make # 4. 手动提取 libonig.a(这才是救命稻草) $ cd .libs $ cp libonig.a /c/MinGW/lib/ $ cp ../oniguruma.h /c/MinGW/include/

提示:--prefix=/c/MinGW让configure知道头文件和库该放哪;--enable-static --disable-shared确保只生成libonig.a(静态库),避免libonig.dll.a动态链接干扰;cp命令必须手动执行,make install就是玄学黑洞。

验证libonig.a是否就位:

C:\> dir C:\MinGW\lib\libonig.a # 应显示文件存在,大小约 1.2MB C:\> dir C:\MinGW\include\oniguruma.h # 应显示头文件存在

3. Crowbar 编译实战:从crowbar_book_0_1到0_4,逐版本修复 Makefile

crowbar_book_0_X是按时间演进的教程包:0_1是最简解释器,0_4加入 GC 和异常处理。但每个版本的Makefile都有专属坑——0_1缺onig链接,0_2的BISON路径写死,0_4的memory模块需额外-lws2_32。下面以crowbar_book_0_1为蓝本,给出可直接复制的修复步骤,其他版本只需微调。

3.1crowbar_book_0_1:修复y.tab.h生成与onig链接

原始Makefile问题:

  • YACC = yacc→ 应改为BISON = C:/MinGW/bin/bison.exe
  • 无onig链接 →LIBS = -lonig
  • CC = gcc→ 应明确CC = C:/MinGW/bin/gcc.exe

修复后的关键段落(crowbar_book_0_1/Makefile):

# ====== 修改开始 ====== CC = C:/MinGW/bin/gcc.exe BISON = C:/MinGW/bin/bison.exe FLEX = C:/MinGW/bin/flex.exe CFLAGS = -g -Wall -Wswitch-enum -ansi -pedantic -DDEBUG LIBS = -lonig -lws2_32 # 修正依赖:crowbar.tab.h 由 bison 生成,不是 y.tab.h crowbar.tab.h: crowbar.y $(BISON) --yacc -dv crowbar.y # 修正 lex.yy.c 依赖:必须等 crowbar.tab.h 生成后才 flex lex.yy.c: crowbar.l crowbar.tab.h $(FLEX) crowbar.l # 主程序链接:显式加入 -lonig crowbar: $(OBJS) crowbar.tab.o lex.yy.o $(CC) $(CFLAGS) -o $@ $^ $(LIBS) # ====== 修改结束 ======

编译命令(在crowbar_book_0_1目录下):

C:\crowbar_book_0_1> C:\MinGW\bin\mingw32-make.exe # 成功时输出: # gcc -g -Wall ... -o crowbar main.o interface.o ... lex.yy.o crowbar.tab.o -lonig -lws2_32 # 此时目录下生成 crowbar.exe

3.2crowbar_book_0_4:GC 模块与 Windows Socket 依赖补全

0_4版本新增内存管理(memory/目录),其Makefile会进入子目录cd ./memory; gmake,但原memory/Makefile未声明CC和LIBS,导致gcc找不到onig头文件。

修复crowbar_book_0_4/memory/Makefile:

# 在文件开头添加: CC = C:/MinGW/bin/gcc.exe CFLAGS = -g -Wall -Wswitch-enum -ansi -pedantic -DDEBUG -I../.. LIBS = -lonig -lws2_32 # 将所有 $(CC) 替换为 $(CC) $(CFLAGS) # 将所有 $(CC) ... -o ... 替换为 $(CC) $(CFLAGS) ... -o ... $(LIBS)

注意:-lws2_32是 Windows Socket 库,crowbar的网络相关功能(如socket内置函数)必需,否则链接时报undefined reference to 'WSAStartup'。

3.3 Diksam 编译:共享同一套 MinGW 环境,但需独立bison规则

Diksam是另一门教学语言,其diksam_book_0_1的Makefile也依赖bison,但语法文件是diksam.y。修复逻辑相同:

# diksam_book_0_1/Makefile BISON = C:/MinGW/bin/bison.exe diksam.tab.h: diksam.y $(BISON) --yacc -dv diksam.y lex.yy.c: diksam.l diksam.tab.h C:/MinGW/bin/flex.exe diksam.l

编译命令:

C:\diksam_book_0_1> C:\MinGW\bin\mingw32-make.exe

4. 常见问题排查:那些让你怀疑人生的报错,其实都有固定解法

这套资料的报错不是随机的,而是环境配置缺陷的精准映射。下面列出 5 条最高频、有截图、有修复命令的真问题,按「现象 → 原因 → 解决」结构整理,省去你百度 2 小时。

4.1 现象:process_begin: CreateProcess(NULL, bison ..., ...) failed

原因:Makefile中BISON路径错误,或bison.exe文件不存在/损坏,或路径含空格(如C:\Program Files\...)。
解决:

# 1. 检查 bison 是否存在 C:\> dir C:\MinGW\bin\bison.exe # 2. 在 Makefile 中写死绝对路径(不要用 "bison") BISON = C:/MinGW/bin/bison.exe # 3. 若仍失败,重装 mingw32-bison $ mingw-get remove mingw32-bison && mingw-get install mingw32-bison

4.2 现象:mycalc.l:3:19: error: 'y.tab.h' file not found

原因:flex在生成lex.yy.c时,#include "y.tab.h"的路径不对;crowbar的语法文件是crowbar.y,生成的是crowbar.tab.h,不是y.tab.h。
解决:

# 修改 mycalc.l 第 3 行: // #include "y.tab.h" ← 删除这行 #include "crowbar.tab.h" // ← 改为实际生成的头文件名 # 并确保 Makefile 中 flex 依赖正确: lex.yy.c: mycalc.l crowbar.tab.h C:/MinGW/bin/flex.exe mycalc.l

4.3 现象:/usr/bin/ld: cannot find -lmsvcp60

原因:crowbar链接时误用了 Visual C++ 运行库(msvcp60.dll),这是 Cygwin 环境残留或PATH混乱导致gcc调用了错误的链接器。
解决:

# 1. 彻底卸载 Cygwin(删除 C:\cygwin* 目录) # 2. 检查 PATH,删除所有含 "cygwin" 的路径 # 3. 用 MinGW 的 ld: C:\> C:\MinGW\bin\ld --version # 4. 编译时强制指定 MinGW 工具链: C:\crowbar_book_0_1> C:\MinGW\bin\gcc.exe -o crowbar *.o -lonig

4.4 现象:error_message.c:5:10: fatal error: 'oniguruma.h' file not found

原因:oniguruma.h未放入MinGW/include,或CFLAGS未加-I/c/MinGW/include。
解决:

# 1. 确认头文件位置 $ ls /c/MinGW/include/oniguruma.h # 2. 在 Makefile 中添加包含路径 CFLAGS = -g -Wall -I/c/MinGW/include ... # 3. 或编译时手动指定 C:\crowbar_book_0_1> C:\MinGW\bin\gcc.exe -I C:\MinGW\include -c error_message.c

4.5 现象:crowbar test/test.crb报错5: invalid character (0x0d)

原因:test.crb是 DOS 格式(CRLF 换行),crowbar解析器将\r\n中的\r(0x0d)识别为非法字符。这是 Windows 文本编辑器(如记事本)保存导致的。
解决:

# 方法 1:用 dos2unix 转换(推荐) C:\> dos2unix test/test.crb # 方法 2:用 vim 手动转换 C:\> vim test/test.crb # 在 vim 中输入 :set ff=unix :wq # 方法 3:用 PowerShell 一行搞定 C:\> (Get-Content test/test.crb -Raw) -replace "`r`n", "`n" | Set-Content test/test.crb

5. 验证与调试:用test.crb跑通第一行代码,再用gdb看清内存分配

装完不是终点,跑通才是。crowbar_book_0_1/test/test.crb是作者写的最小验证用例,内容只有:

print "Hello, Crowbar!";

但即使这样简单的代码,也会因环境差异失败。下面分三步验证:基础执行 → 错误注入 → 深度调试,每一步都给出可粘贴的命令和预期输出。

5.1 基础执行:确认crowbar.exe能解析并输出

C:\crowbar_book_0_1> .\crowbar.exe test\test.crb # ✅ 正确输出: # Hello, Crowbar! # ❌ 若报错 "Segmentation fault",说明 onig 链接失败,检查: C:\crowbar_book_0_1> dumpbin /dependents crowbar.exe | findstr onig # 应看到 onig.dll 或 onig(静态链接时无此行,但需确保 libonig.a 已链接)

5.2 错误注入:故意写错语法,看错误定位是否精准

修改test.crb,加入语法错误:

print "Hello, Crowbar!" # ← 删除分号

运行:

C:\crowbar_book_0_1> .\crowbar.exe test\test.crb # ✅ 正确输出(应精确到行号): # test/test.crb:1: syntax error near '!' # 1: print "Hello, Crowbar!" # ^

如果错误提示是invalid character或行号错乱,说明crowbar.tab.c未正确生成,回退检查bison步骤。

5.3 深度调试:用gdb跟踪string_pool内存分配

crowbar的字符串池(string_pool.c)是理解其 GC 机制的关键。用gdb单步执行,观察内存变化:

# 1. 重新编译带调试信息的 crowbar C:\crowbar_book_0_1> C:\MinGW\bin\gcc.exe -g -o crowbar_debug.exe *.c -lonig # 2. 启动 gdb,加载 test.crb C:\crowbar_book_0_1> C:\MinGW\bin\gdb.exe crowbar_debug.exe (gdb) run test/test.crb # 程序会快速执行完,看不到细节,需打断点 # 3. 在字符串创建处打断点(string.c 第 42 行 create_string 函数) (gdb) break string.c:42 (gdb) run test/test.crb # 程序停在 create_string,此时查看局部变量: (gdb) print str (gdb) print len # 应看到 str 指向 "Hello, Crowbar!",len=16 # 4. 继续执行,看内存池增长 (gdb) continue # 重复几次,观察 string_pool 的 size 字段变化

提示:crowbar_book_0_4的memory/目录下有gc.c,用同样方法在gc_mark()打断点,就能亲眼看到标记-清除过程。这是比读文档高效十倍的理解方式。

5.4 验证表:各版本核心文件生成状态速查

版本必须生成的文件生成命令验证命令常见缺失原因
crowbar_book_0_1crowbar.tab.h,lex.yy.c,crowbar.exemingw32-make.exedir crowbar.tab.h lex.yy.c crowbar.exeBISON路径错、onig未链接
crowbar_book_0_4crowbar.exe,memory/libmemory.amingw32-make.exedir memory\libmemory.amemory/Makefile未加-I../..
diksam_book_0_2diksam.tab.h,diksam.exemingw32-make.exedir diksam.tab.h diksam.exediksam.l中#include名不匹配

从那以后我每次拿到新的自制语言资料包,第一件事不是看README,而是打开Makefile,用Ctrl+F搜BISON、FLEX、LIBS三个关键词,把路径全部改成C:/MinGW/bin/xxx.exe,再检查C:\MinGW\lib\下有没有libonig.a。这套动作 3 分钟内完成,比反复重装 Cygwin、百度报错快得多。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询