当前位置:
首页 > Python基础教程 >
-
使用Python编写一个Lisp语言的解释器
一般的源代码程序经过编译器解析生成解析树。Lisp的奇特之处就在于,你可以完全卸除程序,控制这种解析树,进行任意的存取操作,也就是可以用程序生成程序。
Python号称最接近Lisp的语言,但它终究不是。但是因为几乎所有语言都是图灵完备的,所以即使Python无法实现Lisp的某个功能,也可以通过在Python中写一个Lisp解释器来实现那个功能。很奇妙是不是?
我们来写一个简单的基于Scheme语法的Lisp解析器吧:
先导入库
################ lis.py: Scheme Interpreter in Python 3.10
## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html
## Type hints and minor additions by Luciano Ramalho
import math
import operator as op
from collections import ChainMap
from itertools import chain
from typing import Any, NoReturn
from typing import Union, List, MutableMapping, Optional, Iterator
Symbol = str
Atom = Union[float, int, Symbol]
Expression = Union[Atom, List]
Environment = MutableMapping[Symbol, object]
print(Atom, Expression)
print(Environment)
创建Parse解析
def parse(program: str) -> Expression:
"Read a Scheme expression from a string."
return read_from_tokens(tokenize(program))
def tokenize(s: str) -> List[str]:
"Convert a string into a list of tokens."
return s.replace('(', ' ( ').replace(')', ' ) ').split()
def read_from_tokens(tokens: List[str]) -> Expression:
"Read an expression from a sequence of tokens."
if len(tokens) == 0:
raise SyntaxError('unexpected EOF while reading')
token = tokens.pop(0)
if '(' == token:
exp = []
while tokens[0] != ')':
exp.append(read_from_tokens(tokens))
tokens.pop(0) # discard ')'
return exp
elif ')' == token:
raise SyntaxError('unexpected )')
else:
return parse_atom(token)
def parse_atom(token: str) -> Atom:
"Numbers become numbers; every other token is a symbol."
try:
return int(token)
except ValueError:
try:
return float(token)
except ValueError:
return Symbol(token)
创建环境
def standard_env() -> Environment:
"An environment with some Scheme standard procedures."
env: Environment = {}
env.update(vars(math)) # sin, cos, sqrt, pi, ...
env.update(
{
'+': op.add,
'-': op.sub,
'*': op.mul,
'/': op.truediv, # 小数除
'quotient': op.floordiv, # 商 地板除法 整数除
'>': op.gt,
'<': op.lt,
'>=': op.ge,
'<=': op.le,
'=': op.eq,
'abs': abs,
'append': lambda *args: list(chain(*args)),
'apply': lambda proc, args: proc(*args),
'begin': lambda *x: x[-1],
'起': lambda *x: x[-1],
'car': lambda x: x[0],
'cdr': lambda x: x[1:],
'cons': lambda x, y: [x] + y,
'eq?': op.is_,
'equal?': op.eq,
'filter': lambda *args: list(filter(*args)),
'length': len,
'list': lambda *x: list(x),
'list?': lambda x: isinstance(x, list),
'map': lambda *args: list(map(*args)),
'max': max,
'min': min,
'not': op.not_,
'null?': lambda x: x == [],
'number?': lambda x: isinstance(x, (int, float)),
'procedure?': callable,
'round': round,
'symbol?': lambda x: isinstance(x, Symbol),
'display': lambda x: print(lispstr(x), end=''),
'显': lambda x: print(lispstr(x), end=''),
'newline': lambda: print(),
}
)
return env
执行函数
def evaluate(x: Expression, env: Environment) -> Any:
"Evaluate an expression in an environment."
if isinstance(x, str): # variable reference
return env[x]
elif not isinstance(x, list): # constant literal
return x
elif x[0] == 'define': # (define var exp)
_, var, exp = x
env[var] = evaluate(exp, env)
elif x[0] == 'lambda': # (lambda (var...) body)
_, parms, body = x
return Procedure(parms, body, env)
elif x[0] == 'quote': # (quote exp)
_, exp = x
return exp
elif x[0] == 'if': # (if test consequence alternative)
_, test, consequence, alternative = x
if evaluate(test, env):
return evaluate(consequence, env)
else:
return evaluate(alternative, env)
elif x[0] == '设': # (define var exp)
_, var, exp = x
env[var] = evaluate(exp, env)
elif x[0] == '函': # (lambda (var...) body)
_, parms, body = x
return Procedure(parms, body, env)
elif x[0] == '引': # (quote exp)
_, exp = x
return exp
elif x[0] == '若': # (if test consequence alternative)
_, test, consequence, alternative = x
if evaluate(test, env):
return evaluate(consequence, env)
else:
return evaluate(alternative, env)
else: # (proc arg...)
proc_exp, *args = x
proc = evaluate(proc_exp, env)
arg_values = [evaluate(exp, env) for exp in args]
return proc(*arg_values)
交互执行函数
def run_lines(source: str, env: Optional[Environment] = None) -> Iterator[Any]:
global_env: Environment = ChainMap({}, standard_env())
if env is not None:
global_env.update(env)
tokens = tokenize(source)
while tokens:
exp = read_from_tokens(tokens)
yield evaluate(exp, global_env)
def run(source: str, env: Optional[Environment] = None) -> Any:
# 实际上,这个函数只是简单地迭代了run_lines的所有结果,并没有对其进行任何操作。
# 最后,返回run_lines的最后一个结果。
for result in run_lines(source, env):
pass
return result
运行测试
percent = """
(define a 126)
(define b (* 6 50))
(* (/ a b) 100)
"""
run(percent)
输出:42
当然我们也可以用中文关键字:
percent = """
(设 a 126)
(设 b (* 6 50))
(* (/ a b) 100)
"""
run(percent)
这样看起来是不是更亲切一些了呢?
以上代码节选自:https://github.com/fluentpython/lispy
附:
scheme学习资料:The Scheme Programming Language, 4th Edition
到此这篇关于使用Python编写一个Lisp语言的解释器的文章就介绍到这了,更多相关Python Lisp语言解释器内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持
原文链接:https://blog.csdn.net/skywalk8163/article/details/134523836
栏目列表
最新更新
详解MyBatis延迟加载是如何实现的
IDEA 控制台中文乱码4种解决方案
SpringBoot中版本兼容性处理的实现示例
Spring的IOC解决程序耦合的实现
详解Spring多数据源如何切换
Java报错:UnsupportedOperationException in Col
使用Spring Batch实现批处理任务的详细教程
java中怎么将多个音频文件拼接合成一个
SpringBoot整合ES多个精确值查询 terms功能实
Java使用poi生成word文档的简单实例
计算机二级考试MySQL常考点 8种MySQL数据库
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比