当前位置: 首页 > news >正文

探秘 Lithp:John McCarthy 原始 Lisp 语言解释器代码与运行机制全解析

Lithp:John McCarthy 原始 Lisp 语言解释器

Lithp 是 John McCarthy 原始 Lisp 语言的解释器。Lithp 的详细注释代码可在 Github 上找到。

仅仅编写 Lisp 解释器还不够,开发者还想和大家分享所学。阅读这段源代码,能让我们一窥 John McCarthy、Steve Russell、Timothy P. Hart、Mike Levin 以及开发者自己的思路。以下是可供阅读的源文件:

  • atom.py
  • env.py
  • error.py
  • fun.py
  • interface.py
  • lisp.py
  • lithp.py(即本文档)
  • number.py
  • reader.py
  • seq.py
  • core.lisp

Lithp 解释器需要 Python 2.6.1 及以上版本才能运行。请在 Lithp 的 Github 项目页面 添加注释、报告错误或分享相关轶事等。

import pdb import getopt, sys, io from env import Environment from fun import Function from atom import TRUE from atom import FALSE from lisp import Lisp from reader import Reader from error import Error from fun import Lambda from fun import Closure NAME = "Lithp" VERSION = "v1.1" WWW = "http://fogus.me/fun/lithp/" PROMPT = "lithp" DEPTH_MARK = "."

Lithper 类的工作内容

Lithper 类是解释器的驱动程序,它主要完成以下工作:

class Lithp(Lisp):
  1. 初始化全局环境
  2. 解析命令行参数并做出相应处理
  3. 初始化基础 Lisp 函数
  4. 读取输入
  5. 进行求值
  6. 输出结果
  7. 回到步骤 4 继续循环
def __init__(self): iostreams = (sys.stdin, sys.stdout, sys.stderr) (self.stdin, self.stdout, self.stderr) = iostreams self.debug = False self.verbose = True self.core = True self.closures = True self.rdr = Reader() self.environment = Environment() self.init()
def init(self):
定义核心函数
self.environment.set("eq", Function(self.eq)) self.environment.set("quote", Function(self.quote)) self.environment.set("car", Function(self.car)) self.environment.set("cdr", Function(self.cdr)) self.environment.set("cons", Function(self.cons)) self.environment.set("atom", Function(self.atom)) self.environment.set("cond", Function(self.cond))
定义实用函数
self.environment.set("print", Function(self.println))
特殊形式
self.environment.set("lambda", Function(self.lambda_)) self.environment.set("label", Function(self.label))
定义核心符号
self.environment.set("t", TRUE)

只有一个空列表,名为 `nil`

self.environment.set("nil", FALSE)
定义元元素
self.environment.set("__lithp__", self) self.environment.set("__global__", self.environment)
def usage(self): self.print_banner() print print NAME.lower(), " <options> [lithp files]\n"
def print_banner(self): print "The", NAME, "programming shell", VERSION print " by Fogus,", WWW print " Type :help for more information" print
def print_help(self): print "Help for Lithp v", VERSION print " Type :help for more information" print " Type :env to see the bindings in the current environment" print " Type :load followed by one or more filenames to load source files" print " Type :quit to exit the interpreter"
def push(self, env=None): if env: self.environment = self.environment.push(env) else: self.environment = self.environment.push()
def pop(self): self.environment = self.environment.pop()
def repl(self): while True:

借鉴 CLIPS 的 s 表达式解析方法

source = self.get_complete_command()
检查是否有 REPL 指令
if source in [":quit"]: break elif source in [":help"]: self.print_help() elif source.startswith(":load"): files = source.split(" ")[1:] self.process_files(files) elif source in [":env"]: print(self.environment) else: self.process(source)

每次处理一个 s 表达式

def process(self, source): sexpr = self.rdr.get_sexpr(source) while sexpr: result = None try: result = self.eval(sexpr) except Error as err: print(err) if self.verbose: self.stdout.write(" %s\n" % result) sexpr = self.rdr.get_sexpr()

闭包与动态作用域问题

在开发者的学习过程中,常听说闭包和动态作用域不能共存。通过思考,能理解其中的原因。也就是说,闭包会捕获变量的上下文绑定,而动态作用域的查找是在动态栈上进行的。这意味着,只要变量是唯一的,就可以对其进行闭包操作,但一旦有人定义了同名变量,在该变量被弹出之前尝试查找闭包变量时,就会解析为动态栈上最顶层的绑定。虽然从概念上很容易理解,但开发者还是想看看实际情况会怎样,结果并不理想。

def lambda_(self, env, args): if self.environment != env.get("__global__") and self.closures: return Closure(env, args[0], args[1:]) else: return Lambda(args[0], args[1:])

将求值操作委托给表达式

def eval(self, sexpr): try: return sexpr.eval(self.environment) except ValueError as err: print(err) return FALSE

完整的命令定义为一个完整的 s 表达式。简单来说,它可以是任何原子或括号平衡的列表。

def get_complete_command(self, line="", depth=0): if line != "": line = line + " " if self.environment.level != 0: prompt = PROMPT + " %i%s " % (self.environment.level, DEPTH_MARK * (depth + 1)) else: if depth == 0: prompt = PROMPT + "> " else: prompt = PROMPT + "%s " % (DEPTH_MARK * (depth + 1)) line = line + self.read_line(prompt)
用于平衡括号
balance = 0 for ch in line: if ch == "(":

这并不完美,但暂时够用

balance = balance + 1 elif ch == ")":

右括号过多会有问题

balance = balance - 1 if balance > 0:

括号平衡时结果为零

return self.get_complete_command(line, depth + 1) elif balance < 0: raise ValueError("Invalid paren pattern") else: return line
def read_line(self, prompt): if prompt and self.verbose: self.stdout.write("%s" % prompt) self.stdout.flush() line = self.stdin.readline() if len(line) == 0: return "EOF" if line[-1] == "\n": line = line[:-1] return line

Lithp 也可以使用读取器机制处理文件

def process_files(self, files): self.verbose = False for filename in files: infile = open(filename, 'r') self.stdin = infile source = self.get_complete_command() while source not in ["EOF"]: self.process(source) source = self.get_complete_command() infile.close() self.stdin = sys.stdin self.verbose = True if __name__ == '__main__': lithp = Lithp() try: opts, files = getopt.getopt(sys.argv[1:], "hd", ["help", "debug", "no-core", "no-closures"]) except getopt.GetoptError as err:

打印帮助信息并退出

print(str(err)) # 会输出类似 "option -a not recognized" 的信息 lithp.usage() sys.exit(1) for opt, arg in opts: if opt in ("--help", "-h"): lithp.usage() sys.exit(0) elif opt in ("--debug", "-d"): lithp.verbose = True elif opt in ("--no-core"): lithp.core = False elif opt in ("--no-closures"): lithp.closures = False else: print("unknown option " + opt)

如果适用,处理核心 Lisp 函数

if lithp.core: lithp.process_files(["../core.lisp"]) if len(files) > 0: lithp.process_files(files) lithp.print_banner() lithp.repl()

参考文献

  • (McCarthy 1979) John MaCarthy 所著的History of Lisp
  • (McCarthy 1960) John McCarthy 所著的Recursive functions of symbolic expressions and their computation by machine, part I
  • (Church 1941) Alonzo Church 所著的The Calculi of Lambda-Conversion
  • (Baker 1993) Henry Baker 所著的Equal Rights for Functional Objects or, The More Things Change, The More They Are the Same
  • (Kleene 1952) Stephen Kleene 所著的Introduction of Meta-Mathematics
  • (McCarthy 1962) John McCarthy、Daniel Edwards、Timothy Hart 和 Michael Levin 所著的LISP 1.5 Programmer's Manual
  • (IBM 1955) IBM 704 操作手册
  • (Hart 1963) Timothy P. Hart 所著的AIM-57: MACRO Definitions for LISP
http://www.jsqmd.com/news/1076369/

相关文章:

  • 编译 llvm 的 libc++
  • Jeecg-Boot积木报表权限绕过漏洞深度剖析与修复指南
  • 技术迭代升级,GPT-Image-2领跑商用生图赛道
  • 终极指南:如何通过开源macOS应用集合彻底改变你的工作流
  • 【黑金云课堂】FPGA技术教程Linux开发:DP音频播放与VCU视频解码
  • 基于Transformer的Wi-Fi室内定位技术解析与实践
  • 10B参数小模型如何在边缘设备高效落地
  • AI光刻套刻优化:Overlay误差降低40%,提升先进制程良率
  • 从零到一:打造完全离线的多语言翻译服务实战指南
  • RAG实战:用LangGraph构建可信闭环问答系统
  • Vibe Coding 全栈开发常用 Skills
  • Docker on VMware环境安全加固 checklist(CIS Benchmark v2.0合规版):17项必须关闭的服务、9个默认暴露端口及3种网络隔离模式选择决策树
  • 终极指南:689款开源macOS应用完整清单,免费提升你的工作效率![特殊字符]
  • 如何科学筛选与验证计算机视觉顶会论文
  • LangGraph 实战 Demo7:反思式多Agent协作 — 让AI学会“自我审视与迭代“
  • 苹果Siri深度集成LLM:系统级大模型架构解析
  • 现代汽车3.25亿美元全资收购波士顿动力,欲借Atlas机器人布局全球工厂
  • 开源项目维护者应重代码质量而非来源!自主编程趋势不可挡
  • 终极Windows系统维护指南:Dism++让你的电脑重获新生!
  • 2026年AI生图工具盘点:自媒体人做配图,终于不用到处找了
  • DeepSpeed-Chat:工业级RLHF工程化实战框架解析
  • 七牛云送1000W大模型token,可用claude
  • SAP Signavio Process,流程透明化、流程挖掘和企业转型之间的那座桥
  • 终极指南:告别重复格式化,Ventoy打造你的万能启动U盘
  • 7个技巧快速掌握Ryzen系统调试工具:终极AMD处理器优化指南
  • 分数阶拉普拉斯算子:定义的非唯一性如何影响科学与工程计算
  • H800+DeepSeek-R1:开源大模型训练的工程真相与实操指南
  • ISC.AI 2026在京开幕:智能体时代安全治理从共识走向行动
  • 飞时达FastTFT软件安装步骤(附安装包)FastTFT v17.1 超详细下载安装教程
  • 5分钟学会Android自动打卡:DailyTask让你的考勤更智能