用Python实现一个Lisp解析器

一、模块代码

Talk is cheap, show the code:

python 复制代码
# lisp.py

import re

scanner = re.Scanner([
    (r'\s+', None),
    (r'[^"()\s]+|"[^"]*"', lambda scanner, token: ('NAME', token)),
    (r'\(', lambda scanner, token: (token, token)),
    (r'\)', lambda scanner, token: (token, token)),
])

class Node:
    def __init__(self, parent=None, name=None):
        self.parent = parent
        self.name = name if parent else 'root'
        self.children = []
        if parent:
            parent.children.append(self)

    @property
    def stripname(self):
        return self.name.strip('"')

    def __add__(self, item):
        assert isinstance(item, str), type(item)
        if self.name is None:
            self.name = item
        else:
            Node(self, item)
        return self

    def __contains__(self, item):
        return any(item == node for level, node in self)

    def __eq__(self, item):
        assert isinstance(item, str), type(item)
        return item == self.name

    def __getitem__(self, item):
        assert isinstance(item, (int, str)), type(item)
        if isinstance(item, int):
            return self.children[item]
        if isinstance(item, str):
            return (node for level, node in self if node == item)

    def __iter__(self, level=0):
        yield level, self
        for child in self.children:
             yield from child.__iter__(level + 1)

    def __repr__(self):
        return f'Node({self.name!r})'

    def __str__(self):
        lines = [level * '| ' + node.name for level, node in self]
        return '\n'.join(lines)

def ParseLisp(text):
    results, remainder = scanner.scan(text)
    assert remainder == '', repr(remainder[:200])
    types = [typ for typ, name in results]
    assert types.count('NEXT') == types.count('PREV'), (types.count('NEXT'), types.count('PREV'))
    root = node = Node()
    for typ, name in results:
        if typ == '(':
            node = Node(node)
        elif typ == ')':
            node = node.parent
        elif typ == 'NAME':
            node += name
    return root

二、用法参考

python 复制代码
import lisp

text = '''
    (status
      (written
        (timestamp 2022 3 17 10 33 1)
        (author "Mentor Graphics Corporation")
        (program "xDX Designer Edif Exporter"
          (version "X-ENTP VX.2.8 <17297288>  2020-10-02 15:37:39")
        )
      )
    )
    (status
      (written
        (timestamp 2024 6 1 6 3 19)
        (author "Shixian Li")
        (program "Lisp Parser"
          (version "v1.0.2  2024-06-01 15:22:31")
        )
      )
    )
'''

root = lisp.ParseLisp(text)

# 遍历节点
for status in root['status']:

    # 在节点下按照参数顺序遍历
    timestamp = status[0][0]

    # 获取节点下的一级子节点
    timestamp_string = '-'.join(child.name for child in timestamp.children)
    print('Timestamp:', timestamp_string)

    version = status[0][2][1]

    # 判断节点名称
    assert version == 'version'

    # 获取移除引号的节点名称
    print('Version:', version[0].stripname)

三、代码仓库

如果以后有更新,最新版在这里记录:

https://github.com/znsoooo/lisp-parser

相关推荐
Hoper.J4 分钟前
PyTorch 模型保存与加载的三种常用方式
人工智能·pytorch·python
弱冠少年42 分钟前
websockets库使用(基于Python)
开发语言·python·numpy
技术无疆1 小时前
【Python】Streamlit:为数据科学与机器学习打造的简易应用框架
开发语言·人工智能·python·深度学习·神经网络·机器学习·数据挖掘
羊小猪~~1 小时前
机器学习/数据分析--用通俗语言讲解时间序列自回归(AR)模型,并用其预测天气,拟合度98%+
人工智能·python·机器学习·数据挖掘·数据分析·回归·时序数据库
qq_273900231 小时前
解析TMalign文本文件中的转换矩阵
python·生物信息学
阿华的代码王国2 小时前
【JavaEE】——文件IO的应用
开发语言·python
电饭叔3 小时前
《python语言程序设计》2018版第8章19题几何Rectangle2D类(下)-头疼的几何和数学
开发语言·python
程序猿小D3 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa
杰哥在此5 小时前
Python知识点:如何使用Multiprocessing进行并行任务管理
linux·开发语言·python·面试·编程
zaim17 小时前
计算机的错误计算(一百一十四)
java·c++·python·rust·go·c·多项式