解析器保留注释并从错误中恢复

时间:2017-09-25 03:34:27

标签: python parsing pyparsing parsec

我正在使用适当的配置格式的GUI编辑器。基本上编辑器将解析配置文件,显示对象属性,以便用户可以从GUI进行编辑,然后将对象写回文件。

我已经完成了解析 - 编辑 - 编写部分,除了:

  • 解析后的数据结构只包含对象属性信息,因此在写入
  • 时会丢失注释和空格
  • 如果有任何语法错误,则跳过文件的其余部分

您如何解决这些问题?解决这个问题的常用方法是什么?我使用的是Python和Parsec模块https://pythonhosted.org/parsec/documentation.html,但我们非常感谢帮助和总体方向。

我也尝试了Pylens(https://pythonhosted.org/pylens/),这非常接近我的需要,除了它不能跳过语法错误。

2 个答案:

答案 0 :(得分:1)

您询问了解决此问题的典型方法。以下是两个项目,可以解决您所描述的类似挑战:

sketch-n-sketch:矢量图像的“直接操作”界面,您可以在其中编辑描述图像的源语言,也可以直接编辑它所代表的图像,并查看源代码中反映的更改。查看视频演示,非常酷。

Boomerang:使用镜头“专注”某些具体语法的抽象含义,改变抽象模型,然后在原始来源中反映这些变化。

这两个项目都有几篇论文描述了作者所采用的方法。据我所知,镜头方法很受欢迎,其中解析和打印成为镜头的getput函数,它采用一些源代码并关注该代码描述的抽象概念

答案 1 :(得分:0)

最终我耗尽了研究时间,不得不采用相当手动的跳槽来解决问题。基本上每次解析器失败时我们都会尝试将光标前进一个字符并重复。无论空格/注释/语法错误如何,进程跳过的任何部分都将转储到Text结构中。代码是可以重复使用的,除了你必须将它包含在重复结果的所有地方并且原始解析器可能失败的部分。

这是代码,万一它可以帮助任何人。它是为Parsy编写的。

class Text(object):
    '''Structure to contain all the parts that the parser does not understand.
    A better name would be Whitespace
    '''
    def __init__(self, text=''):
        self.text = text

    def __repr__(self):
        return "Text(text='{}')".format(self.text)

    def __eq__(self, other):
        return self.text.strip() == getattr(other, 'text', '').strip()


def many_skip_error(parser, skip=lambda t, i: i + 1, until=None):
    '''Repeat the original `parser`, aggregate result into `values` 
    and error in `Text`.
    '''
    @Parser
    def _parser(stream, index):
        values, result = [], None

        while index < len(stream):
            result = parser(stream, index)
            # Original parser success
            if result.status:
                values.append(result.value)
                index = result.index
            # Check for end condition, effectively `manyTill` in Parsec
            elif until is not None and until(stream, index).status:
                break
            # Aggregate skipped text into last `Text` value, or create a new one
            else:
                if len(values) > 0 and isinstance(values[-1], Text):
                    values[-1].text += stream[index]
                else:
                    values.append(Text(stream[index]))
                index = skip(stream, index)
        return Result.success(index, values).aggregate(result)
    return _parser


# Example usage
skip_error_parser = many_skip_error(original_parser)

另一方面,我想这里真正的问题是我正在使用解析器组合器库而不是正确的两阶段解析过程。在传统的解析中,标记化器将处理保留/跳过任何空格/注释/语法错误,使它们全部有效地为空白并且对于解析器是不可见的。