python - 如何使用 pyparsing 解析缩进和缩进?

标签 python indentation parser-generator pyparsing

这是 Python 语法的一个子集:

single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE

small_stmt: pass_stmt
pass_stmt: 'pass'

compound_stmt: if_stmt
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]

suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

(您可以在 Python SVN 存储库中阅读完整语法:http://svn.python.org/.../Grammar)

我正在尝试使用此语法在 Python 中为 Python 生成解析器。我遇到的问题是如何表达 INDENTDEDENT标记作为 pyparsing 对象。

这是我实现其他终端的方式:

import pyparsing as p

string_start = (p.Literal('"""') | "'''" | '"' | "'")
string_token = ('\\' + p.CharsNotIn("",exact=1) | p.CharsNotIn('\\',exact=1))
string_end = p.matchPreviousExpr(string_start)

terminals = {
    'NEWLINE': p.Literal('\n').setWhitespaceChars(' \t')
        .setName('NEWLINE').setParseAction(terminal_action('NEWLINE')),
    'ENDMARKER': p.stringEnd.copy().setWhitespaceChars(' \t')
        .setName('ENDMARKER').setParseAction(terminal_action('ENDMARKER')),
    'NAME': (p.Word(p.alphas + "_", p.alphanums + "_", asKeyword=True))
        .setName('NAME').setParseAction(terminal_action('NAME')),
    'NUMBER': p.Combine(
            p.Word(p.nums) + p.CaselessLiteral("l") |
            (p.Word(p.nums) + p.Optional("." + p.Optional(p.Word(p.nums))) | "." + p.Word(p.nums)) +
                p.Optional(p.CaselessLiteral("e") + p.Optional(p.Literal("+") | "-") + p.Word(p.nums)) +
                p.Optional(p.CaselessLiteral("j"))
        ).setName('NUMBER').setParseAction(terminal_action('NUMBER')),
    'STRING': p.Combine(
            p.Optional(p.CaselessLiteral('u')) +
            p.Optional(p.CaselessLiteral('r')) +
            string_start + p.ZeroOrMore(~string_end + string_token) + string_end
        ).setName('STRING').setParseAction(terminal_action('STRING')),

    # I can't find a good way of parsing indents/dedents.
    # The Grammar just has the tokens NEWLINE, INDENT and DEDENT scattered accross the rules.
    # A single NEWLINE would be translated to NEWLINE + PEER (from pyparsing.indentedBlock()), unless followed by INDENT or DEDENT
    # That NEWLINE and IN/DEDENT could be spit across rule boundaries. (see the 'suite' rule)
    'INDENT': (p.LineStart() + p.Optional(p.Word(' '))).setName('INDENT'),
    'DEDENT': (p.LineStart() + p.Optional(p.Word(' '))).setName('DEDENT')
}

terminal_action是一个函数,它根据其参数返回相应的解析操作。

我知道 pyparsing.indentedBlock辅助函数,但我无法弄清楚如何在没有 PEER 的情况下将其应用于语法 token 。

(看看pyparsing souce code就明白我在说什么了)

您可以在此处查看我的完整源代码:http://pastebin.ca/1609860

最佳答案

在 pyparsing wiki 上有几个例子 Examples page这可以给你一些见解:

要使用 pyparsing 的 indentedBlock,我认为您可以将 suite 定义为:

indentstack = [1]
suite = indentedBlock(stmt, indentstack, True)

请注意,indentedGrammarExample.py 在 pyparsing 中包含 indentedBlock 之前,它自己的缩进解析实现也是如此。

关于python - 如何使用 pyparsing 解析缩进和缩进?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1547944/

相关文章:

python - "from __future__ imports must occur at the beginning of the file": what defines the beginning of the file?

python - 有没有办法在 Windows 中不加载 Python 来查看 cPickle 或 Pickle 文件内容?

eclipse - Eclipse 中的多行字符串对齐/缩进

ruby-on-rails - 缩进 Ruby on Rails 代码的正确样式是什么?

c++ - 防止 Visual Studio 2008 (C++) 删除仅空白行中的缩进制表符

带有 -m 的 Python 脚本完成但最后出错

python - Azure Function Python 模块兼容性问题

yacc - 多个 flex/bison 解析器

parsing - Lemon LALR 解析器的简单语法

bison - 空右手侧的符号