首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 汽车 游戏 社会热点 开源推荐 医疗健康 归档 标签 关于

用 1024 字节制作一个 Python 解释器

2026-09-07 1 阅读 约7分钟阅读 azhenley
分享:
字号:
Austin Z. Henley 我为人们构建工具 用 1024 字节制作 Python 解释器 9/6/2026 为了感觉人性化,我在周末手工编写代码。我最近的挑战?用 512 1024 字节的良好 ole C 代码制作一个 Python 解释器。哦,也没有宏观恶作剧或图书馆的愚蠢行为。 defuzz(): for n in range(101): if n % 15 == 0: print("FizzBu​​zz") else: if n % 3 == 0: print("Fizz") else: if n % 5 == 0: print("Buzz") else: print(n)uzz() 我可能无法将所有 Python 语言放入只有 1024 字节代码的解释器中。那么我可以安装什么看起来像 Python 的东西呢?这个 fizzbuzz 程序看起来明显是 Python 的。它有 def 、冒号、缩进,并且 if 语句没有括号。对我来说看起来像Python!当然,除了语法的子集之外,我还必须添加一些额外的限制。但我的第一次尝试很糟糕。第一次尝试:512字节不够!我已经编写了许多递归下降解析器,那么这有什么不同呢? Python 的一个子集应该与我实现的其他语言类似。我从我能想到的最基本的代码开始: 1 + 2 然后我把它变得更复杂: x = 1 + 2 * 3 然后我什至添加了语句: if x > y: z = 3 太棒了,我做了一个计算器...这不是我这个挑战的意思!我也已经超过极限了。就在那时,我缩小了范围,制作了一个看起来 Pythony 的元素列表,同时也意识到我的代码高尔夫技巧不足以使其适合 512 字节。也许我可以用 1024 字节来完成?首先,让它发挥作用,然后再让它变小。解析器 实际的 CPython 实现将 Python 源代码标记化,将其解析为抽象语法树,执行一些分析和优化,发出字节码,然后解释字节码。这实际上不会做任何事情。状态保存在少数全局变量中。它使用固定长度数组(目前为 999)来保存原始 Python 代码。变量和函数名称都适合一个数组。字符源[999]; /* 整个程序没有大部分空格。 */ int 变量[256]; /* 符号表。 */ int 位置; /* src 中的下一个字符。 */ int 通道; /* src 中的当前字符。 */ int line_start; /* 当前行的开始位置。 */ 表达式的处理方式与任何其他递归下降解析器一样,并且它们会一路执行。例如: int parse_sum(void) { int value = parse_term(); while (ch == '+' || ch == '-') { if (ch == '+') value = value + parse_term();否则值 = 值 - parse_term();返回值;到目前为止很简单。没有任何类型的错误处理!它基于代码的正确性做出了很多假设。例如,它假设关键字都正确输入。 if (ch == 'w' || ch == 'i' || ch == 'f') { /* ---- while / if / for ---- */ int keywords = ch; int 循环变量 = 0; if (keyword == 'f') { /* "for K in range(N):" */ pos += 2; /* 跳过“或”。 */ 循环变量=下一个();位置 += 8; /* 跳过 "inrange(". */ vars[loop_var] = 0; } else if (keyword == 'w') pos += 4; /* 跳过 "hile". */ else pos += 1; /* 跳过 "if" 的 "f"。 */ 它还假设标记边界是正确的并去掉大部分空白。它在字符串文字中保留缩进和空格。它仅限于单个变量名称,小写字符,它允许我们直接进行符号表查找: if (ch > 96) { value = vars[ch]; next(); } 控制流魔术 执行代码块的函数会继续执行,直到缩进减少,然后由调用者来处理下一行。因此,它使用 C 程序的调用堆栈来处理递归。 indent = read_indent(); if (ch == '\n') continue; if (indent < min_indent || ch == 0) { pos = line_start; return; } 但是循环呢?!由于每次迭代都不会向后跳转并重新解析源代码,因此 while 和 for 循环都会跟踪条件表达式的位置。函数以同样的方式工作,当解析函数调用时,符号表会保存调用者位置,解析器跳转到函数体,执行函数体,并在到达末尾时恢复调用者位置。即使没有中间表示,我们也能做到这一点!空格是显而易见的,但是我如何保存大字节呢?有一个古老的、被遗忘的网站,过去的代码魔术师分享了他们的知识,因为规则只存在于你的想象中,所以我确实必须发挥创意。这不是愚蠢的做法!
这篇文章对您有帮助吗?

订阅66必读

每日精选科技资讯,直达你的邮箱