用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

相关推荐
知乎的哥廷根数学学派16 分钟前
基于数据驱动的自适应正交小波基优化算法(Python)
开发语言·网络·人工智能·pytorch·python·深度学习·算法
sunfove29 分钟前
将 Python 仿真工具部署并嵌入个人博客
开发语言·数据库·python
Learner30 分钟前
Python类
开发语言·python
2501_941329721 小时前
门及其组件定位识别_YOLO13-C3k2-PoolingFormer改进模型研究
python
Ancelin安心1 小时前
kali-dirsearch的使用
linux·运维·服务器·python·计算机网络·web安全·网络安全
努力学习的小洋1 小时前
Python训练打卡Day5离散特征的处理-独热编码
人工智能·python·机器学习
Sherry Wangs2 小时前
【ML】机器学习进阶
人工智能·python·机器学习
X1A0RAN2 小时前
python 借助 paramiko 库执行 SSH命令报错:input is not a terminal 解决方式
开发语言·python·ssh
百***78752 小时前
Grok-4.1与GPT-5.2深度对比:技术差异、适用场景及Python集成指南
java·python·gpt
黎雁·泠崖3 小时前
吃透Java操作符进阶:算术+移位操作符 全解析(Java&C区别+完整案例+避坑指南)
java·c语言·python