解析器可以保留评论并从错误中恢复



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

我有解析 - 编辑 - 编写部分,除了:

  • 分析的数据结构仅包括对象属性信息,因此在写入
  • 上丢失了评论和空格
  • 如果存在任何语法错误,则文件的其余部分被跳过

您将如何解决这些问题?解决这个问题的通常方法是什么?我正在使用python和Parsec模块https://pythonhosted.org/parsec/documentation.html,但是,帮助和一般方向表示赞赏。

我还尝试了Pylens(https://pythonhosted.org/pylens/),它确实接近我所需要的东西,除了它无法跳过语法错误。

您询问了有关此问题的典型方法。这是两个项目应对您描述的挑战类似的挑战:

Sketch-n-Sketch:"直接操纵"接口的矢量图像,您可以在其中编辑图像描述的源语言,也可以直接编辑其代表的图像,并在源代码中看到这些更改。查看视频演示文稿,非常酷。

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

两个项目都产生了几篇论文,描述了作者采用的方法。据我所知,镜头方法很受欢迎,解析和打印成为镜头的getput功能,该功能采用了一些源代码,并专注于该代码描述的抽象概念。

最终我用完了研究时间,不得不进行手动跳过。基本上,每次解析器失败时,我们都会尝试推进光标一个字符并重复。不论空格/注释/语法错误如何转储到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)

另一方面,我想这里的真正问题是我正在使用解析器组合库,而不是一个适当的两个阶段解析过程。在传统解析中,令牌机将处理/跳过任何空格/注释/语法错误,使它们都有效地空白,并且对解析器是看不见的。

最新更新