保留注释并从错误中恢复的解析器
Parser that preserves comments and recover from error
我正在为专有配置格式开发 GUI 编辑器。基本上,编辑器将解析配置文件,显示对象属性,以便用户可以从 GUI 进行编辑,然后将对象写回文件。
我已经完成了解析-编辑-编写部分,除了:
- 解析后的数据结构仅包含对象属性信息,因此写入时注释和空格会丢失
- 如果有任何语法错误,将跳过文件的其余部分
您将如何解决这些问题?解决这个问题的通常方法是什么?我正在使用 Python 和 Parsec 模块 https://pythonhosted.org/parsec/documentation.html,但是,感谢您的帮助和总体指导。
我也尝试过 Pylens (https://pythonhosted.org/pylens/),它非常接近我需要的,除了它不能跳过语法错误。
最终我 运行 研究时间用完了,不得不通过相当手动的跳过来解决。基本上每次解析器失败时,我们都会尝试将光标前进一个字符并重复。该过程跳过的任何部分,无论 whitespace/comment/syntax 错误如何,都会转储到 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)
另一方面,我想真正的问题是我使用的是解析器组合器库,而不是正确的两阶段解析过程。在传统的解析中,标记器将处理 retaining/skipping 任何 whitespace/comment/syntax 错误,使它们都有效地成为空白并且对解析器不可见。
您询问了解决此问题的典型方法。这里有两个项目解决了与您描述的项目类似的挑战:
sketch-n-sketch:"Direct manipulation" 矢量图像界面,您可以在其中编辑描述图像的源语言,或直接编辑它表示的图像并查看源代码中反映的这些更改。看看视频演示,超级酷。
Boomerang:使用镜头"focus"一些具体语法的抽象含义,改变抽象模型,然后在原始源中反映这些变化。
这两个项目都发表了几篇论文,描述了作者所采用的方法。据我所知,Lens 方法很流行,其中解析和打印成为 Lens 的 get
和 put
函数,它采用一些源代码并专注于该代码描述的抽象概念.
我正在为专有配置格式开发 GUI 编辑器。基本上,编辑器将解析配置文件,显示对象属性,以便用户可以从 GUI 进行编辑,然后将对象写回文件。
我已经完成了解析-编辑-编写部分,除了:
- 解析后的数据结构仅包含对象属性信息,因此写入时注释和空格会丢失
- 如果有任何语法错误,将跳过文件的其余部分
您将如何解决这些问题?解决这个问题的通常方法是什么?我正在使用 Python 和 Parsec 模块 https://pythonhosted.org/parsec/documentation.html,但是,感谢您的帮助和总体指导。
我也尝试过 Pylens (https://pythonhosted.org/pylens/),它非常接近我需要的,除了它不能跳过语法错误。
最终我 运行 研究时间用完了,不得不通过相当手动的跳过来解决。基本上每次解析器失败时,我们都会尝试将光标前进一个字符并重复。该过程跳过的任何部分,无论 whitespace/comment/syntax 错误如何,都会转储到 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)
另一方面,我想真正的问题是我使用的是解析器组合器库,而不是正确的两阶段解析过程。在传统的解析中,标记器将处理 retaining/skipping 任何 whitespace/comment/syntax 错误,使它们都有效地成为空白并且对解析器不可见。
您询问了解决此问题的典型方法。这里有两个项目解决了与您描述的项目类似的挑战:
sketch-n-sketch:"Direct manipulation" 矢量图像界面,您可以在其中编辑描述图像的源语言,或直接编辑它表示的图像并查看源代码中反映的这些更改。看看视频演示,超级酷。
Boomerang:使用镜头"focus"一些具体语法的抽象含义,改变抽象模型,然后在原始源中反映这些变化。
这两个项目都发表了几篇论文,描述了作者所采用的方法。据我所知,Lens 方法很流行,其中解析和打印成为 Lens 的 get
和 put
函数,它采用一些源代码并专注于该代码描述的抽象概念.