使用 PyParsing 解析带有重要换行符的语言(如 Python)

2024-01-25

我正在实现一种语言,其中换行符有时很重要,就像在 Python 中一样,具有完全相同的规则。

出于我的问题的目的,我们可以采用与赋值、括号以及换行符和分号处理有关的 Python 片段。

例如,可以这样写:

a = 1 + 2 + 3    # ok
b = c

but not

a = 1 + 2 + 3     b = c   # incorrect

因为需要一个换行符来分隔两个语句。

然而我们可以有

a = 1 + 2 + 3;     b = c   # ok

使用分号。

也不允许有

a = 1 + 2 +   # incorrect
3
b = c

因为语句中不能有换行符。

然而,有可能有

a = 1 + 2 + (     # ok
3)
b = c

or

a = 1 + 2 + \     # ok
3
b = c

我一直在尝试执行上述规则,但我陷入困境。

首先,我使用

ParserElement.setDefaultWhitespaceChars(' \t')

所以现在\n是重要的。

我很好地使用换行符作为分隔符

lines = ZeroOrMore(line + OneOrMore(LineEnd()))

这种变化允许有;也作为分隔符。 (我不太能处理继续括号\.)

I use infixNotation界定+, -, /, *.

我遇到的问题是括号内的换行符应该被忽略,就像在这种情况下:

a = 1 + 2 + ( 
3 +
1)

我认为这里可以发挥作用的是使用setWhitespaceChars在括号表达式上(LPAR + term + RPAR)然而, infixNotation 生成的代码不起作用,因为较低的表达式不会继承空白字符。

有人有任何提示吗?

我的问题也可以表达为“如何使用 pyParsing 解析 Python(的片段)?”。我以为我可以找到一些示例项目,但我没有。谷歌搜索,我看到人们引用了 pyParsing 存储库中的示例,但是parsePythonValue.py是关于解析值(我已经可以做到)并且不处理重要的换行符,并且pythongGrammarParsing.py是关于解析 Python 的 BNF 语法,而不是解析 Python。


注意:这不是一个可行的解决方案(至少目前还不是)。它依赖于未发布的 pyparsing 更改,这些更改甚至还没有通过所有单元测试。我发布它只是为了描述解决方案的可能方法。

噢!这比我想象的要困难得多。为了实现,我使用了 pyparsing 的忽略机制,并将解析操作附加到lpar and rpar要忽略的表达式<NL>位于括号内,但不在括号外。这还需要添加清除的能力ignoreExprs通过调用列出expr.ignore(None)。您的代码可能如下所示:

import pyparsing as pp

# works with and without packrat
pp.ParserElement.enablePackrat()

pp.ParserElement.setDefaultWhitespaceChars(' \t')

operand = pp.Word(pp.nums)
var = pp.Word(pp.alphas)

arith_expr = pp.Forward()
arith_expr.ignore(pp.pythonStyleComment)
lpar = pp.Suppress("(")
rpar = pp.Suppress(")")

# code to implement selective ignore of NL's inside ()'s
NL = pp.Suppress("\n")
base_ignore = arith_expr.ignoreExprs[:]
ignore_stack = base_ignore[:]
def lpar_pa():
    ignore_stack.append(NL)
    arith_expr.ignore(NL)
    #~ print('post-push', arith_expr.ignoreExprs)
def rpar_pa():
    ignore_stack.pop(-1)
    arith_expr.ignore(None)
    for e in ignore_stack:
        arith_expr.ignore(e)
    #~ print('post-pop', arith_expr.ignoreExprs)
def reset_stack(*args):
    arith_expr.ignore(None)
    for e in base_ignore:
        arith_expr.ignore(e)
    #~ print('post-reset', arith_expr.ignoreExprs)
lpar.addParseAction(lpar_pa)
rpar.addParseAction(rpar_pa)
arith_expr.setFailAction(reset_stack)
arith_expr.addParseAction(reset_stack)

# now define the infix notation as usual
arith_expr <<= pp.infixNotation(operand | var,
    [
    ("-", 1, pp.opAssoc.RIGHT),
    (pp.oneOf("* /"), 2, pp.opAssoc.LEFT),
    (pp.oneOf("- +"), 2, pp.opAssoc.LEFT),
    ],
    lpar=lpar, rpar=rpar
    )

assignment = var + '=' + arith_expr

# Try it out!
assignment.runTests([
"""a = 1 + 3""",
"""a = (1 + 3)""",
"""a = 1 + 2 + ( 
3 +
1)""",
"""a = 1 + 2 + (( 
3 +
1))""",
"""a = 1 + 2 +   
3""",
], fullDump=False)

Prints:

a = 1 + 3
['a', '=', ['1', '+', '3']]
a = (1 + 3)
['a', '=', ['1', '+', '3']]
a = 1 + 2 + ( 
3 +
1)
['a', '=', ['1', '+', '2', '+', ['3', '+', '1']]]
a = 1 + 2 + (( 
3 +
1))
['a', '=', ['1', '+', '2', '+', ['3', '+', '1']]]
a = 1 + 2 +   
3
a = 1 + 2 +   
          ^
FAIL: Expected end of text, found '+'  (at char 10), (line:1, col:11)>Exit code: 0

因此,这并非不可能,但确实需要一些英勇的努力。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 PyParsing 解析带有重要换行符的语言(如 Python) 的相关文章

  • 使用 Boost::Spirit 解析 time_period 表达式

    我需要使用 Boost Spirit 解析以下 EBNF 表达式 period date part time part date part time part time part hours minutes seconds date par
  • 将 Matplotlib 误差线放置在不位于条形中心的位置

    我正在 Matplotlib 中生成带有错误栏的堆积条形图 不幸的是 某些层相对较小且数据多样 因此多个层的错误条可能重叠 从而使它们难以或无法读取 Example 有没有办法设置每个误差条的位置 即沿 x 轴移动它 以便重叠的线显示在彼此
  • OpenCV Python cv2.mixChannels()

    我试图将其从 C 转换为 Python 但它给出了不同的色调结果 In C Transform it to HSV cvtColor src hsv CV BGR2HSV Use only the Hue value hue create
  • Django:按钮链接

    我是一名 Django 新手用户 尝试创建一个按钮 单击该按钮会链接到我网站中的另一个页面 我尝试了一些不同的例子 但似乎没有一个对我有用 举个例子 为什么这不起作用
  • Python - StatsModels、OLS 置信区间

    在 Statsmodels 中 我可以使用以下方法拟合我的模型 import statsmodels api as sm X np array 22000 13400 47600 7400 12000 32000 28000 31000 6
  • 如何使用 Ansible playbook 中的 service_facts 模块检查服务是否存在且未安装在服务器中?

    我用过service facts检查服务是否正在运行并启用 在某些服务器中 未安装特定的软件包 现在 我如何知道这个特定的软件包没有安装在该特定的服务器上service facts module 在 Ansible 剧本中 它显示以下错误
  • python 相当于 R 中的 get() (= 使用字符串检索符号的值)

    在 R 中 get s 函数检索名称存储在字符变量 向量 中的符号的值s e g X lt 10 r lt XVI s lt substr r 1 1 X get s 10 取罗马数字的第一个符号r并将其转换为其等效整数 尽管花了一些时间翻
  • 使用 Tkinter 显示 numpy 数组中的图像

    我对 Python 缺乏经验 第一次使用 Tkinter 制作一个 UI 显示我的数字分类程序与 mnist 数据集的结果 当图像来自 numpy 数组而不是我的 PC 上的文件路径时 我有一个关于在 Tkinter 中显示图像的问题 我为
  • Python pickle:腌制对象不等于源对象

    我认为这是预期的行为 但想检查一下 也许找出原因 因为我所做的研究结果是空白 我有一个函数可以提取数据 创建自定义类的新实例 然后将其附加到列表中 该类仅包含变量 然后 我使用协议 2 作为二进制文件将该列表腌制到文件中 稍后我重新运行脚本
  • 如何使用 OpencV 从 Firebase 读取图像?

    有没有使用 OpenCV 从 Firebase 读取图像的想法 或者我必须先下载图片 然后从本地文件夹执行 cv imread 功能 有什么办法我可以使用cv imread link of picture from firebase 您可以
  • 如何使用Python创建历史时间线

    So I ve seen a few answers on here that helped a bit but my dataset is larger than the ones that have been answered prev
  • 每个 X 具有多个 Y 值的 Python 散点图

    我正在尝试使用 Python 创建一个散点图 其中包含两个 X 类别 cat1 cat2 每个类别都有多个 Y 值 如果每个 X 值的 Y 值的数量相同 我可以使用以下代码使其工作 import numpy as np import mat
  • 对年龄列进行分组/分类

    我有一个数据框说df有一个柱子 Ages gt gt gt df Age 0 22 1 38 2 26 3 35 4 35 5 1 6 54 我想对这个年龄段进行分组并创建一个像这样的新专栏 If age gt 0 age lt 2 the
  • 为字典中的一个键附加多个值[重复]

    这个问题在这里已经有答案了 我是 python 新手 我有每年的年份和值列表 我想要做的是检查字典中是否已存在该年份 如果存在 则将该值附加到特定键的值列表中 例如 我有一个年份列表 并且每年都有一个值 2010 2 2009 4 1989
  • 类型错误:预期单个张量时的张量列表 - 将 const 与 tf.random_normal 一起使用时

    我有以下 TensorFlow 代码 tf constant tf random normal time step batch size 1 1 我正进入 状态TypeError List of Tensors when single Te
  • 有人用过 Dabo 做过中型项目吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我们正处于一个新的 ERP 风格的客户端 服务器应用程序的开始阶段 该应用程序是作为 Python 富客户端开发的 我们目前正在评估 Dabo
  • 使用 Python 绘制 2D 核密度估计

    I would like to plot a 2D kernel density estimation I find the seaborn package very useful here However after searching
  • 使用 Python 的 matplotlib 选择在屏幕上显示哪些图形以及将哪些图形保存到文件中

    我想用Python创建不同的图形matplotlib pyplot 然后 我想将其中一些保存到文件中 而另一些则应使用show 命令 然而 show 显示all创建的数字 我可以通过调用来避免这种情况close 创建我不想在屏幕上显示的绘图
  • Python 类继承 - 诡异的动作

    我观察到类继承有一个奇怪的效果 对于我正在处理的项目 我正在创建一个类来充当另一个模块的类的包装器 我正在使用第 3 方 aeidon 模块 用于操作字幕文件 但问题可能不太具体 以下是您通常如何使用该模块 project aeidon P
  • 如何将输入读取为数字?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 Why are x and y下面的代码中使用字符串而不是整数 注意 在Python 2

随机推荐