使用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语言解释器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python编程图形库之Pillow使用方法讲解

    Python编程图形库之Pillow使用方法讲解

    今天小编就为大家分享一篇关于Python编程图形库之Pillow使用方法讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • python下如何查询CS反恐精英的服务器信息

    python下如何查询CS反恐精英的服务器信息

    这篇文章主要介绍了python下如何查询CS反恐精英服务器信息的方法,分别分享了反恐精英1.5版本和反恐精英1.6版本的实现方法示例,有需要的朋友们可以参考借鉴,下面来一起学习学习吧。
    2017-01-01
  • python中pip的使用和修改下载源的方法

    python中pip的使用和修改下载源的方法

    这篇文章主要介绍了python中pip的使用和修改下载源的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-07-07
  • Python的Django框架中的数据库配置指南

    Python的Django框架中的数据库配置指南

    这篇文章主要介绍了Python的Django框架中的数据库配置指南,文中举了Python内置的SQLite的示例,需要的朋友可以参考下
    2015-07-07
  • python一键升级所有pip package的方法

    python一键升级所有pip package的方法

    下面小编就为大家带来一篇python一键升级所有pip package的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Python如何利用IMAP实现邮箱客户端功能

    Python如何利用IMAP实现邮箱客户端功能

    IMAP是另一种读取电子邮件的协议,IMAP是读取邮件服务器的电子邮件与公布栏信息的方法,也就是说IMAP 允许客户端的邮件程序存取远程的信息,这篇文章主要给大家介绍了关于Python如何利用IMAP实现邮箱客户端功能的相关资料,需要的朋友可以参考下
    2021-09-09
  • python Kmeans算法原理深入解析

    python Kmeans算法原理深入解析

    这篇文章主要介绍了python Kmeans算法深入解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • 提升Python项目整洁度使用import linter实例探究

    提升Python项目整洁度使用import linter实例探究

    在复杂的Python项目中,良好的代码组织结构是维护性和可读性的关键,本文将深入研究 import-linter 工具,它是一个强大的静态分析工具,旨在优化项目的模块导入,提高代码质量和可维护性
    2024-01-01
  • 利用python进行数据加载

    利用python进行数据加载

    今天给大家带来的是关于Python的相关知识,文章围绕着python数据加载展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • 如何使用python-dotenv解决代码与敏感信息的分离

    如何使用python-dotenv解决代码与敏感信息的分离

    我们开发的每个系统都离不开配置信息,这些信息都非常敏感,一旦泄露出去后果非常严重,被泄露的原因一般是程序员将配置信息和代码混在一起导致的,这篇文章主要给大家介绍了关于如何使用python-dotenv解决代码与敏感信息的分离,需要的朋友可以参考下
    2022-03-03

最新评论