
一般的源代码程序经过编译器解析生成解析树。Lisp的奇特之处就在于,你可以完全卸除程序,控制这种解析树,进行任意的存取操作,也就是可以用程序生成程序。
Python号称最接近Lisp的语言,但它终究不是。但是因为几乎所有语言都是图灵完备的,所以即使Python无法实现Lisp的某个功能,也可以通过在Python中写一个Lisp解释器来实现那个功能。很奇妙是不是?
我们来写一个简单的基于Scheme语法的Lisp解析器吧:
先导入库
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ################ 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 importmathimportoperator as opfromcollections importChainMapfromitertools importchainfromtyping importAny, NoReturnfromtyping importUnion, List, MutableMapping, Optional, Iterator Symbol =strAtom =Union[float, int, Symbol]Expression =Union[Atom, List] Environment =MutableMapping[Symbol, object] print(Atom, Expression)print(Environment) | 
创建Parse解析
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | defparse(program: str) -> Expression:    "Read a Scheme expression from a string."    returnread_from_tokens(tokenize(program)) deftokenize(s: str) -> List[str]:    "Convert a string into a list of tokens."    returns.replace('(', ' ( ').replace(')', ' ) ').split() defread_from_tokens(tokens: List[str]) -> Expression:    "Read an expression from a sequence of tokens."    iflen(tokens) ==0:        raiseSyntaxError('unexpected EOF while reading')    token =tokens.pop(0)    if'('==token:        exp =[]        whiletokens[0] !=')':            exp.append(read_from_tokens(tokens))        tokens.pop(0)  # discard ')'        returnexp    elif')'==token:        raiseSyntaxError('unexpected )')    else:        returnparse_atom(token) defparse_atom(token: str) -> Atom:    "Numbers become numbers; every other token is a symbol."    try:        returnint(token)    exceptValueError:        try:            returnfloat(token)        exceptValueError:            returnSymbol(token) | 
创建环境
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | defstandard_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': lambdaproc, args: proc(*args),            'begin': lambda*x: x[-1],            '起': lambda*x: x[-1],            'car': lambdax: x[0],            'cdr': lambdax: x[1:],            'cons': lambdax, y: [x] +y,            'eq?': op.is_,            'equal?': op.eq,            'filter': lambda*args: list(filter(*args)),            'length': len,            'list': lambda*x: list(x),            'list?': lambdax: isinstance(x, list),            'map': lambda*args: list(map(*args)),            'max': max,            'min': min,            'not': op.not_,            'null?': lambdax: x ==[],            'number?': lambdax: isinstance(x, (int, float)),            'procedure?': callable,            'round': round,            'symbol?': lambdax: isinstance(x, Symbol),            'display': lambdax: print(lispstr(x), end=''),            '显': lambdax: print(lispstr(x), end=''),            'newline': lambda: print(),        }    )    returnenv | 
执行函数
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | defevaluate(x: Expression, env: Environment) -> Any:    "Evaluate an expression in an environment."    ifisinstance(x, str):                       # variable reference        returnenv[x]    elifnotisinstance(x, list):                # constant literal        returnx    elifx[0] =='define':                       # (define var exp)        _, var, exp =x        env[var] =evaluate(exp, env)    elifx[0] =='lambda':                       # (lambda (var...) body)        _, parms, body =x        returnProcedure(parms, body, env)    elifx[0] =='quote':                        # (quote exp)        _, exp =x        returnexp    elifx[0] =='if':                           # (if test consequence alternative)        _, test, consequence, alternative =x        ifevaluate(test, env):            returnevaluate(consequence, env)        else:            returnevaluate(alternative, env)    elifx[0] =='设':                       # (define var exp)        _, var, exp =x        env[var] =evaluate(exp, env)    elifx[0] =='函':                       # (lambda (var...) body)        _, parms, body =x        returnProcedure(parms, body, env)    elifx[0] =='引':                        # (quote exp)        _, exp =x        returnexp    elifx[0] =='若':                           # (if test consequence alternative)        _, test, consequence, alternative =x        ifevaluate(test, env):            returnevaluate(consequence, env)        else:            returnevaluate(alternative, env)    else:                                        # (proc arg...)        proc_exp, *args =x        proc =evaluate(proc_exp, env)        arg_values =[evaluate(exp, env) forexp inargs]        returnproc(*arg_values) | 
交互执行函数
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | defrun_lines(source: str, env: Optional[Environment] =None) -> Iterator[Any]:    global_env: Environment =ChainMap({}, standard_env())    ifenv isnotNone:        global_env.update(env)    tokens =tokenize(source)    whiletokens:        exp =read_from_tokens(tokens)        yieldevaluate(exp, global_env)  defrun(source: str, env: Optional[Environment] =None) -> Any:    # 实际上,这个函数只是简单地迭代了run_lines的所有结果,并没有对其进行任何操作。    # 最后,返回run_lines的最后一个结果。    forresult inrun_lines(source, env):        pass    returnresult | 
运行测试
| 1 2 3 4 5 6 | percent ="""(define a 126)(define b (* 6 50))(* (/ a b) 100)"""run(percent) | 
输出:42
当然我们也可以用中文关键字:
| 1 2 3 4 5 6 | 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语言解释器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
 
                                 
                                
.png)
.png)
.png) 
 .png) 
 .png) 
 .png) 
 .png) 
 .png) 
 .png) 
 .png) 
 .png) 
 .png) 
  
                 
             
                             
                            
最新评论