首页 > 开源 > 在 1024 字节里塞进一个 Python 解释器

在 1024 字节里塞进一个 Python 解释器

OSChina资讯 2026-09-07 19:40 2 阅读 查看原文

为了感受自己还活着,Austin Z. Henley 在周末手写代码。

他的最新挑战:用 1024 字节的 C 代码写一个 Python 解释器。不用宏花招,不用库诡计。

目标很明确——能让这段代码跑起来:

def buzz():
    for n in range(101):
        if n % 15 == 0:
            print("FizzBuzz")
        else:
            if n % 3 == 0:
                print("Fizz")
            else:
                if n % 5 == 0:
                    print("Buzz")
                else:
                    print(n)
buzz()

一个完整的 FizzBuzz,有 def、有缩进、有冒号、有 for range 循环、有嵌套 if else。不是 Python 的子集,是 Python 的样子。

Python 1024

第一次尝试,512 字节不够。

Henley 写过很多递归下降解析器,但这回不一样。从 1+2 开始,到 x = 1 + 2 * 3,再到 if x > y: z = 3。然后他意识到自己只是做了一个计算器——而且已经超了字节限制。

于是退一步,把目标放宽到 1024 字节。先做出来,再把它变小。

解析器没有任何错误处理。

状态在几个全局变量里:一个 999 字节的 src 数组存原始 Python 代码,vars[256] 做符号表,posch 跟踪位置。表达式用递归下降解析,边解析边执行,例子就是教科书式的 parse_sum——先算 term,遇到 +- 就继续。

但真正有意思的是,它对输入做了大量假设。关键字必须拼写正确,token 边界必须刚好,变量名只能是单个小写字母(直接用 ASCII 值索引符号表,省掉哈希的开销)。它甚至假设 for 关键字出现时,紧跟着的文本一定是 or K in range(N):——所以它跳过 "or" 两个字符,再跳过 "inrange(" 八个字符,直接读循环变量。

这种假设在正常编译器里是不可接受的,但在 1024 字节的游戏里,每一个假设都等于省下几十字节。

控制流靠 C 的调用栈。

run_block 函数执行一个缩进块,直到缩进减少就返回。循环没有编译,每次迭代跳回源码位置重新解析。forwhile 都记住条件表达式的位置,执行完循环体后跳回去。函数调用同理——符号表里存的是函数在源码中的位置,调用时保存调用者位置,跳过去执行,结束再跳回来。

不生成中间表示,不产生字节码,靠原始源码反复跳转。维护的状态极少,但执行逻辑出奇地优雅。

然后开始 code golf。

‌Code Golf‌(代码高尔夫)是一种编程挑战,核心目标是用‌最少的字符数‌实现特定功能,字符越少排名越高 。你可以把它理解为编程界的“高尔夫”,杆数(字符数)越少成绩越好。‌‌‌

860 字节。

Henley 从 Stack Overflow 上一个古老的帖子《Tips for golfing in C》里学了不少技巧,再加上一些自己的创造:

  • 所有变量和函数名单字母
  • 依赖编译器默认链接 libc
  • 全局变量当临时变量用(零初始化是免费的)
  • C89 允许隐式 int 声明、函数默认返回 int
  • 函数参数当临时变量(保存在调用栈上)
  • ASCII 值代替字符字面量
  • 三元运算符和逗号运算符
  • 位运算代替逻辑运算

一个例子:原来读得懂的 parse_sum 变成了 e(){for(z=t();c-43u<3;)y=44-c,z+=y*t();return z;}c-43+ 的 ASCII 值,44-c 同时处理了 +- 两个方向。

另一个例子:跳过行尾的函数从 5 行递归变成了 Y(){c&&c-10&&Y(G());}——用 && 代替 if,用 c-10 检查换行符,用 Y(G()) 代替 G();Y(),又省一个字节。

可读版超过 4800 字节,最终 golf 到 1024 字节

如果只跑 FizzBuzz,他估计能压到 800 字节以下。

最终支持的特性清单:

  • 整型变量(单字母)和字面量
  • 变量赋值
  • + - * % 四则运算,带优先级
  • 比较运算 < > <= >= ==(每次表达式一个)
  • 整数的真值判断
  • ifelse
  • while 循环,包括 else
  • for x in range(y) 循环,包括 else
  • 无参函数定义
  • 函数调用,支持递归
  • 基于缩进的代码块(无作用域)
  • print 支持字符串字面量或整数表达式
  • 注释

Henley 说他短时间内不会再做 code golf 了,过程太折磨——在 golf 版本和原始版本之间来回切换,试图理解两分钟前自己改了什么。

源代码在 GitHub 上。

参考来源: