如何限制 textx 语法中的重复?
How to limit repetitions in textx grammar?
我正在尝试在 textx 中创建语法。
语法应如下所示:
name_a
name_a, name_b
name_a, name_b: name_c, *
name_a, name_b: name_c, *, name_d
*, name_d
*
其中星号 (*
) 表示“全部”。我希望它不再重复。当前语法是这样的:
Subsets: ColumnsSet*;
ColumnsSet: SetItem (',' ColumnsSet)*;
SetItem: ColumnName | Star;
Star: '*';
ColumnName: name=ID (':' rename=ID)*;
允许重复星号。我想防止这种情况,因此这些行无效:
name_a, *, *
name_a, *, name_b, *
*, name_a, *
我应该如何重写语法?
有没有办法展平嵌套规则的输出:ColumnsSet: SetItem (',' ColumnsSet)*;
?
你的语法有几个问题。首先在 textX 中你需要使用 assignments to collect relevant data. Use *=
, +=
style of assignment to denote many zero/one-or-more. Use separator repetition modifiers 来避免 Something (',' Something)*
样板文件。
为了防止 *
多次发生,您可以注册 object processor,它可以检查语义错误。
此外,为确保语言是面向行的,您可能需要查看 noskipws 规则修饰符。
textX 不仅仅是一个解析器,它从语法中推导出 meta-model you can visualize
的语言
这是一个(可能 non-complete)解决方案,可以作为一个好的开始。
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_b: name_c, *, 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
我正在尝试在 textx 中创建语法。
语法应如下所示:
name_a
name_a, name_b
name_a, name_b: name_c, *
name_a, name_b: name_c, *, name_d
*, name_d
*
其中星号 (*
) 表示“全部”。我希望它不再重复。当前语法是这样的:
Subsets: ColumnsSet*;
ColumnsSet: SetItem (',' ColumnsSet)*;
SetItem: ColumnName | Star;
Star: '*';
ColumnName: name=ID (':' rename=ID)*;
允许重复星号。我想防止这种情况,因此这些行无效:
name_a, *, *
name_a, *, name_b, *
*, name_a, *
我应该如何重写语法?
有没有办法展平嵌套规则的输出:ColumnsSet: SetItem (',' ColumnsSet)*;
?
你的语法有几个问题。首先在 textX 中你需要使用 assignments to collect relevant data. Use *=
, +=
style of assignment to denote many zero/one-or-more. Use separator repetition modifiers 来避免 Something (',' Something)*
样板文件。
为了防止 *
多次发生,您可以注册 object processor,它可以检查语义错误。
此外,为确保语言是面向行的,您可能需要查看 noskipws 规则修饰符。
textX 不仅仅是一个解析器,它从语法中推导出 meta-model you can visualize
的语言这是一个(可能 non-complete)解决方案,可以作为一个好的开始。
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_b: name_c, *, 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