用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

相关推荐
黑客-雨4 分钟前
从零开始:如何用Python训练一个AI模型(超详细教程)非常详细收藏我这一篇就够了!
开发语言·人工智能·python·大模型·ai产品经理·大模型学习·大模型入门
孤独且没人爱的纸鹤18 分钟前
【机器学习】深入无监督学习分裂型层次聚类的原理、算法结构与数学基础全方位解读,深度揭示其如何在数据空间中构建层次化聚类结构
人工智能·python·深度学习·机器学习·支持向量机·ai·聚类
l1x1n021 分钟前
No.35 笔记 | Python学习之旅:基础语法与实践作业总结
笔记·python·学习
是Dream呀1 小时前
Python从0到100(八十五):神经网络-使用迁移学习完成猫狗分类
python·神经网络·迁移学习
小林熬夜学编程1 小时前
【Python】第三弹---编程基础进阶:掌握输入输出与运算符的全面指南
开发语言·python·算法
hunter2062063 小时前
用opencv生成视频流,然后用rtsp进行拉流显示
人工智能·python·opencv
Johaden5 小时前
EXCEL+Python搞定数据处理(第一部分:Python入门-第2章:开发环境)
开发语言·vscode·python·conda·excel
小虎牙^O^6 小时前
2024春秋杯密码题第一、二天WP
python·密码学
梦魇梦狸º7 小时前
mac 配置 python 环境变量
chrome·python·macos
查理零世7 小时前
算法竞赛之差分进阶——等差数列差分 python
python·算法·差分