我创建了一个小的测试用例来说明我用“^”运算符看到的问题。当我尝试使用^运算符而不是|下面的运算符,我收到一个错误。
编辑:只是为了让其他人阅读它,让问题更清晰(尽管已经得到了回答)。问题是为什么我不能使用“^”运算符代替“|”运算符在以下程序中。
测试用例:
import unittest
import pyparsing as pp
def _get_verilog_num_parse():
"""Get a parser that can read a verilog number
return: Parser for verilog numbers
rtype: PyParsing parser object
"""
apos = pp.Suppress(pp.Literal("'"))
radix = pp.Word('bdhBDH', exact=1).setResultsName('radix')
dec_num = pp.Word(pp.nums+'_' ).setParseAction(lambda x:int(x[0].replace('_', ''),10))
hex_num = pp.Word(pp.hexnums+'_').setParseAction(lambda x:int(x[0].replace('_', ''),16))
bin_num = pp.Word('01'+'_' ).setParseAction(lambda x:int(x[0].replace('_', ''),2))
size = pp.Optional(dec_num).setResultsName('size')
valid_nums = {'b':bin_num,'d':dec_num,'h':hex_num}
verilog_lits = pp.Forward()
def size_mask(parser):
size = parser.get('size')
if size is not None:
print("In size_mask. size: {} parser[value]: {}".format(size, parser['value']))
return parser['value'] & ((1<<size) -1)
else:
print("In size_mask. no size. parser[value]: {}".format(parser['value']))
return parser['value']
def radix_parse_action(toks):
verilog_lits << (valid_nums[toks.get('radix').lower()])
radix.addParseAction(radix_parse_action)
#return size, apos + radix + verilog_lits
return (size + apos + radix + verilog_lits.setResultsName('value')).addParseAction(size_mask)
class CheckPyParsing(unittest.TestCase):
'''Check that the Expression Parser works with the expressions
defined in this test'''
def test_or(self):
"""Check basic expressions not involving referenced parameters"""
expressions_to_test = [
("8'd255",255),
("'d255",255),
]
parser = _get_verilog_num_parse() | pp.Literal("Some_demo_literal")
for expr,expected in expressions_to_test:
result = parser.parseString(expr)
print("result: {}, val: {}".format(result, result[0]))
self.assertEqual(expected,result[0], "test_string: {} expected: {} result: {}".format(expr, expected, result[0]))
当我使用|我明白了:
test_or (yoda_interface.tests.CheckPyParsing_test.CheckPyParsing)
Check basic expressions not involving referenced parameters ... In size_mask. size: 8 parser[value]: 255
result: [255], val: 255
In size_mask. no size. parser[value]: 255
result: [255], val: 255
ok
当我使用^我得到:
test_or (yoda_interface.tests.CheckPyParsing_test.CheckPyParsing)
Check basic expressions not involving referenced parameters ... ERROR
======================================================================
ERROR: test_or (yoda_interface.tests.CheckPyParsing_test.CheckPyParsing)
Check basic expressions not involving referenced parameters
----------------------------------------------------------------------
Traceback (most recent call last):
File "c:\projects\check_private\yoda_interface\tests\CheckPyParsing_test.py", line 45, in test_or
result = parser.parseString(expr)
File "C:\Users\gkuhn\AppData\Local\Continuum\Anaconda3\lib\site-packages\pyparsing.py", line 1125, in parseString
raise exc
File "C:\Users\gkuhn\AppData\Local\Continuum\Anaconda3\lib\site-packages\pyparsing.py", line 1115, in parseString
loc, tokens = self._parse( instring, 0 )
File "C:\Users\gkuhn\AppData\Local\Continuum\Anaconda3\lib\site-packages\pyparsing.py", line 989, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "C:\Users\gkuhn\AppData\Local\Continuum\Anaconda3\lib\site-packages\pyparsing.py", line 2440, in parseImpl
raise maxException
pyparsing.ParseException: (at char 3), (line:1, col:4)
----------------------------------------------------------------------
Ran 1 test in 0.012s
FAILED (errors=1)
答案 0 :(得分:3)
这是一个很难的案例,它需要对一些pyparsing的内部结构有一点了解,才能将解析器重构为工作版本。
问题的“完美风暴”结合了以下因素:
verilog_lits
)Or
表达式 MatchFirst
(使用'|'运算符创建),可以直接查看其替代列表,尝试依次解析每个,并在成功时返回。这样做,如果存在解析操作,则在解析成功之后,解析操作将按预期运行。在您的情况下,此解析操作会为二进制,十六进制或十进制值的值部分注入正确的数值表达式。
但是Or
不能遵循同样的策略。在编写pyparsing时,除了只使用解析后的标记之外,我无法预测任何给定的解析操作是否有副作用或其他含义。因此,当Or
通过其替代方案,寻找最长的匹配时,它必须这样做而不用调用解析操作。如果存在更新解析器中的动态元素的解析操作,则在选择成功的替代选项之前不会调用该操作。由于您依赖解析操作来完成解析器,因此如果定义动态表达式的触发器是Or
的一部分,则会失败。
基于此,我通过替换以下内容重构了您对“基数后跟其类型特定允许值”的定义:
return (size + apos + radix + verilog_lits.setResultsName('value')).addParseAction(size_mask)
与
radix_int = pp.ungroup(pp.CaselessLiteral('d').suppress() + dec_num |
pp.CaselessLiteral('h').suppress() + hex_num |
pp.CaselessLiteral('b').suppress() + bin_num)
return (size + apos + radix_int('value')).addParseAction(size_mask)
这可能没有动态子表达式的魅力,但是通过将动态表达式扩展为一组3个特定的替代方案,这个表达式现在可以安全地包含在“全部计算并选择最长”{{1}表达。