用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·机器学习·线性回归·scikit-learn
电商API&Tina5 分钟前
电商API接口的应用与简要分析||taobao|jd|微店
大数据·python·数据分析·json
向前V13 分钟前
Flutter for OpenHarmony轻量级开源记事本App实战:笔记编辑器
开发语言·笔记·python·flutter·游戏·开源·编辑器
snow_star_dream38 分钟前
(笔记)VSC python应用--函数补全注释添加
笔记·python
郝学胜-神的一滴1 小时前
Python中的Mixin继承:灵活组合功能的强大模式
开发语言·python·程序人生
叫我:松哥1 小时前
基于python强化学习的自主迷宫求解,集成迷宫生成、智能体训练、模型评估等
开发语言·人工智能·python·机器学习·pygame
2301_764441331 小时前
2025年YOLO算法案例应用领域应用趋势
python·yolo
汗流浃背了吧,老弟!1 小时前
构建RAG系统时,如何选择合适的嵌入模型(Embedding Model)?
人工智能·python·embedding
盐真卿1 小时前
python第四部分:模块(每日更新)
开发语言·python
喵手2 小时前
Python爬虫零基础入门【第九章:实战项目教学·第2节】“接口优先“项目:从 Network 还原 JSON 接口分页!
爬虫·python·python爬虫实战·python爬虫工程化实战·python爬虫零基础入门·接口优先·json接口分页