使用Python编写一个Lisp语言的解释器

 更新时间:2023年11月22日 10:00:57   作者:skywalk8163  
这篇文章主要为大家详细介绍了如何使用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语言解释器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python3中在Anaconda环境下安装basemap包

    Python3中在Anaconda环境下安装basemap包

    今天小编就为大家分享一篇关于Python3中在Anaconda环境下安装basemap包的文章,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • Python实现TCP/IP协议下的端口转发及重定向示例

    Python实现TCP/IP协议下的端口转发及重定向示例

    这篇文章主要介绍了Python实现TCP/IP协议下的端口转发及重定向示例,以一个webpy站点在本机的两个端口双向通信下演示,需要的朋友可以参考下
    2016-06-06
  • Python numpy视图与副本

    Python numpy视图与副本

    这篇文章主要介绍了Python numpy视图与副本,继上一篇对numpy 模块之ndarray一文中对 ndarray 内存结构主要分为两部分metdata 、raw bata,下面来一起学习文章具体内容吧,需要的小伙伴也可以参考一下
    2022-01-01
  • 如何将python中的List转化成dictionary

    如何将python中的List转化成dictionary

    这篇文章主要介绍在python中如何将list转化成dictionary,通过提出两个问题来告诉大家如何解决,有需要的可以参考借鉴。
    2016-08-08
  • Django单元测试的具体使用

    Django单元测试的具体使用

    Django提供了一套强大的测试工具来帮助开发者编写和运行单元测试,本文就来介绍一下Django中的单元测试,包括测试原理、编写测试用例和运行测试,感兴趣的可以了解一下
    2023-11-11
  • Python中的迭代器你了解吗

    Python中的迭代器你了解吗

    迭代器是一种特殊的对象,它实现了迭代协议,允许按照一定的顺序逐个访问元素,本文就来带大家深入了解一下Python中迭代器的使用,需要的可以参考下
    2023-05-05
  • 使用Python openpyxl批量处理Excel的操作指南

    使用Python openpyxl批量处理Excel的操作指南

    本文详细介绍了如何使用Python的openpyxl库自动化处理Excel文件,从环境搭建到数据读写、样式设置、公式和图表生成,再到批量处理多个文件,通过一个综合实战案例,展示了如何自动生成月度部门薪资报告,需要的朋友可以参考下
    2026-03-03
  • Python实现绘制置信区间

    Python实现绘制置信区间

    置信区间是从观测数据的统计量计算的一种估计值,它给出了一个可能包含具有特定置信水平的总体参数的值范围,下面我们就来看看如何使用Python绘制置信区间吧
    2024-02-02
  • 从基础到高级详解Python数值格式化输出的完全指南

    从基础到高级详解Python数值格式化输出的完全指南

    在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙伴可以了解下
    2025-08-08
  • Python选择网卡发包及接收数据包

    Python选择网卡发包及接收数据包

    今天小编就为大家分享一篇关于Python选择网卡发包及接收数据包,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04

最新评论