问题描述
我正在尝试在textx中创建语法。
语法应如下所示:
name_a name_a,name_b name_a,name_b: name_c,* name_a,*,name_d *,name_d *
@H_502_7@星号(
*
)表示“全部”。我不想重复。当前的语法是这样的:Subsets: ColumnsSet*; ColumnsSet: SetItem (',' ColumnsSet)*; SetItem: ColumnName | Star; Star: '*'; ColumnName: name=ID (':' rename=ID)*;
@H_502_7@它允许重复星号。我想防止这种情况,以使这些行无效:
name_a,name_b,* *,name_a,*
@H_502_7@我应该如何重写语法?
有没有一种方法可以使嵌套规则的输出变平:
ColumnsSet: SetItem (',' ColumnsSet)*;
?解决方法
您的语法有几个问题。首先,在textX中,您需要使用assignments来收集相关数据。使用
*=
和+=
分配样式表示许多零/一个或多个。使用separator repetition modifiers来避免Something (',' Something)*
的重复。为防止
*
多次发生,您可以注册object processor来检查语义错误。此外,要确保语言是面向行的,您可能需要研究noskipws规则修饰符。
textX不仅仅是语法分析器,它还从语法中推断出you can visualize
的语言元模型。这是一个(可能是不完整的)解决方案,可能是一个很好的开始。
from textx import metamodel_from_str,TextXSemanticError from textx.scoping.tools import get_location grammar = r''' Subsets: col_sets+=ColumnsSet; ColumnsSet: set_items+=SetItem[',']; SetItem: ColumnName | Star; Star: '*'; ColumnName: name=ID (':' rename=ID)?; ''' def column_set_proc(cs): if len([x for x in cs.set_items if x == '*']) > 1: raise TextXSemanticError('Cannot use multiple * in a single line',**get_location(cs)) mm = metamodel_from_str(grammar) mm.register_obj_processors({'ColumnsSet': column_set_proc}) # This will pass model = mm.model_from_str(r'''name_a name_a,name_b name_a,name_b: name_c,* name_a,*,name_d *,name_d * ''') # Each of these raise TextXSemanticError count = 0 for invalid in ['name_a,*',' name_a,name_b,' *,name_a,*']: try: mm.model_from_str(invalid) except TextXSemanticError: count += 1 assert count == 3