如何打开 pyparsing 辅助函数的结果?
How can I unwrap results from pyparsing helper functions?
我目前正在 python 中实现 prolog 方言。为此,我正在使用很棒的 pyparsing
模块,我发现它对涉及上下文无关语法的其他项目非常有效。
随着我转向上下文相关语法,我逐渐习惯了 pyparsing
的风格。 pyparsing.nestedExpr
和 pyparsing.delimitedList
是我仍然熟悉的两件事。现在我遇到了 pyparsing.delimitedList
的问题;它实现了我正在寻找的东西,但是下面示例代码中的每个人 term
都在列表中返回,我没有在任何条件下使用 pyparsing.Group
。
重构以使用 pyparsing.nestedExpr
和 pyparsing.infixNotation
是我解决此问题后的下一个待办事项,所以请不要惊慌我还没有使用它们。我还怀疑,但还不知道,我必须阻止规则表达式左侧的 term_list
匹配。这就是说,该代码是一项正在进行的工作,随着我对库的进一步试验,它会随着时间的推移而发生重大变化。
我觉得用pyparsing.ungroup
可以解决问题,但是pyparsing.ungroup(pyparsing.delimitedList...
在这种情况下好像没有什么作用
输出逻辑
result = root.parseString('''
A :- True
Z :- 5
''')
print(result.dump())
print(result.rules[0].goals)
结果
[['A', 'True'], ['Z', '5']]
- rules: [['A', 'True'], ['Z', '5']]
[0]:
['A', 'True']
- goals: [['True']]
[0]:
['True']
[1]:
['Z', '5']
- goals: [['5']]
[0]:
['5']
[['True']]
预期结果
[['A', 'True'], ['Z', '5']]
- rules: [['A', 'True'], ['Z', '5']]
[0]:
['A', 'True']
- goals: ['True']
[1]:
['Z', '5']
- goals: ['5']
['True']
完整代码
import pyparsing as pp
# These types are the language primitives
atom = pp.Word(pp.alphanums)
number = pp.Word(pp.nums)
variable = pp.Word(pp.alphanums)
string = pp.quotedString
# Terms are the basic unit of expression here
compound_term = pp.Forward()
term = (atom ^ number ^ variable ^ pp.Group(compound_term))('terms*')
# A compound term includes a few rules for term composition, such as lists or an atom containing arguments
term_list = pp.Forward()
compound_term <<= \
string ^ \
term_list ^ \
atom('functor') + pp.Suppress('(') + pp.delimitedList(term('arguments*')) + pp.Suppress(')')
term_list <<= pp.Suppress('[') + pp.delimitedList(term('items*')) + pp.Suppress(']')
# The rule operator is an infix operator represented by :-
# On the right side, multiple goals can be composed using AND or OR operators
rule = pp.Group(
term + pp.Suppress(':-') + \
pp.delimitedList(term('goals*')) \
)('rules*')
root = pp.ZeroOrMore(rule)
result = root.parseString(
'''
A :- True
Z :- 5
''')
print(result.dump())
print(result.rules[0].goals)
最初的问题是 Group
在 compound_term
中的存在:
term = (atom ^ number ^ variable ^ pp.Group(compound_term))('terms*')
应该是
term = (atom ^ number ^ variable ^ (compound_term))('terms*')
进行更改并在您的规则中添加“lhs”结果名称后(见下文),我得到:
[['A', 'True'], ['Z', '5']]
- rules: [['A', 'True'], ['Z', '5']]
[0]:
['A', 'True']
- goals: ['True']
- lhs: 'A'
[1]:
['Z', '5']
- goals: ['5']
- lhs: 'Z'
['True']
一些补充说明:
atom
定义为
atom = pp.Word(pp.alphanums)
这也将匹配“123”作为 atom
。为确保您只获得变量 names ,请使用 pp.Word(pp.alphas, pp.alphanums)
。这表示首字母必须是字母,任何后续字母都可以是字母或数字(与 variable
相同)。
我不会在术语上添加结果名称“terms*”,因为它最终会在“:-”运算符的左右两侧使用。我建议人们 通常 保留结果名称的附件,直到表达式被用于更高级别的表达式中。例如,我将规则定义为:
rule = pp.Group(term("rule_lhs")
+ ":-"
+ pp.delimitedList(term)("goals")
)
我不会真正称“:-”为“中缀”运算符,我认为像“+”、“-”、“AND”、“OR”这样的运算符是中缀运算符。例如,我认为 x :- y :- z
无效。您可能会像这样添加“AND”和“OR”运算符:
logical_term_expression = pp.infixNotation(term,
[
("&&", 2, pp.opAssoc.LEFT,),
("||", 2, pp.opAssoc.LEFT,),
])
在 term
中有一个结果名称真的会把它弄得一团糟,更有可能在你的运算符元组上使用 类,正如你在像 [=60= 这样的 pyparsing 示例中看到的那样].
您提到使用 nestedExpr
- 请不要。该助手最适用于为 C 代码之类的东西编写扫描器,在这种情况下您可能只想跳过一些嵌套的大括号而不实际解析内容。在您的 DSL 中,您将希望正确解析所有内容 - 但我认为 infixNotation
可能就是您所需要的。
我目前正在 python 中实现 prolog 方言。为此,我正在使用很棒的 pyparsing
模块,我发现它对涉及上下文无关语法的其他项目非常有效。
随着我转向上下文相关语法,我逐渐习惯了 pyparsing
的风格。 pyparsing.nestedExpr
和 pyparsing.delimitedList
是我仍然熟悉的两件事。现在我遇到了 pyparsing.delimitedList
的问题;它实现了我正在寻找的东西,但是下面示例代码中的每个人 term
都在列表中返回,我没有在任何条件下使用 pyparsing.Group
。
重构以使用 pyparsing.nestedExpr
和 pyparsing.infixNotation
是我解决此问题后的下一个待办事项,所以请不要惊慌我还没有使用它们。我还怀疑,但还不知道,我必须阻止规则表达式左侧的 term_list
匹配。这就是说,该代码是一项正在进行的工作,随着我对库的进一步试验,它会随着时间的推移而发生重大变化。
我觉得用pyparsing.ungroup
可以解决问题,但是pyparsing.ungroup(pyparsing.delimitedList...
在这种情况下好像没有什么作用
输出逻辑
result = root.parseString('''
A :- True
Z :- 5
''')
print(result.dump())
print(result.rules[0].goals)
结果
[['A', 'True'], ['Z', '5']]
- rules: [['A', 'True'], ['Z', '5']]
[0]:
['A', 'True']
- goals: [['True']]
[0]:
['True']
[1]:
['Z', '5']
- goals: [['5']]
[0]:
['5']
[['True']]
预期结果
[['A', 'True'], ['Z', '5']]
- rules: [['A', 'True'], ['Z', '5']]
[0]:
['A', 'True']
- goals: ['True']
[1]:
['Z', '5']
- goals: ['5']
['True']
完整代码
import pyparsing as pp
# These types are the language primitives
atom = pp.Word(pp.alphanums)
number = pp.Word(pp.nums)
variable = pp.Word(pp.alphanums)
string = pp.quotedString
# Terms are the basic unit of expression here
compound_term = pp.Forward()
term = (atom ^ number ^ variable ^ pp.Group(compound_term))('terms*')
# A compound term includes a few rules for term composition, such as lists or an atom containing arguments
term_list = pp.Forward()
compound_term <<= \
string ^ \
term_list ^ \
atom('functor') + pp.Suppress('(') + pp.delimitedList(term('arguments*')) + pp.Suppress(')')
term_list <<= pp.Suppress('[') + pp.delimitedList(term('items*')) + pp.Suppress(']')
# The rule operator is an infix operator represented by :-
# On the right side, multiple goals can be composed using AND or OR operators
rule = pp.Group(
term + pp.Suppress(':-') + \
pp.delimitedList(term('goals*')) \
)('rules*')
root = pp.ZeroOrMore(rule)
result = root.parseString(
'''
A :- True
Z :- 5
''')
print(result.dump())
print(result.rules[0].goals)
最初的问题是 Group
在 compound_term
中的存在:
term = (atom ^ number ^ variable ^ pp.Group(compound_term))('terms*')
应该是
term = (atom ^ number ^ variable ^ (compound_term))('terms*')
进行更改并在您的规则中添加“lhs”结果名称后(见下文),我得到:
[['A', 'True'], ['Z', '5']]
- rules: [['A', 'True'], ['Z', '5']]
[0]:
['A', 'True']
- goals: ['True']
- lhs: 'A'
[1]:
['Z', '5']
- goals: ['5']
- lhs: 'Z'
['True']
一些补充说明:
atom
定义为atom = pp.Word(pp.alphanums)
这也将匹配“123”作为
atom
。为确保您只获得变量 names ,请使用pp.Word(pp.alphas, pp.alphanums)
。这表示首字母必须是字母,任何后续字母都可以是字母或数字(与variable
相同)。我不会在术语上添加结果名称“terms*”,因为它最终会在“:-”运算符的左右两侧使用。我建议人们 通常 保留结果名称的附件,直到表达式被用于更高级别的表达式中。例如,我将规则定义为:
rule = pp.Group(term("rule_lhs") + ":-" + pp.delimitedList(term)("goals") )
我不会真正称“:-”为“中缀”运算符,我认为像“+”、“-”、“AND”、“OR”这样的运算符是中缀运算符。例如,我认为
x :- y :- z
无效。您可能会像这样添加“AND”和“OR”运算符:logical_term_expression = pp.infixNotation(term, [ ("&&", 2, pp.opAssoc.LEFT,), ("||", 2, pp.opAssoc.LEFT,), ])
在
term
中有一个结果名称真的会把它弄得一团糟,更有可能在你的运算符元组上使用 类,正如你在像 [=60= 这样的 pyparsing 示例中看到的那样].您提到使用
nestedExpr
- 请不要。该助手最适用于为 C 代码之类的东西编写扫描器,在这种情况下您可能只想跳过一些嵌套的大括号而不实际解析内容。在您的 DSL 中,您将希望正确解析所有内容 - 但我认为infixNotation
可能就是您所需要的。