我创建了一个小的测试用例来说明我看到的“^”操作符的问题。当我尝试使用^运算符而不是下面的|运算符时,我得到一个错误。在
编辑:只是为了让问题更清楚(尽管已经回答过了),其他人也可以阅读。问题是为什么我不能在下面的程序中用“^”运算符代替“|”运算符。在
测试用例:
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]))
当我使用|时,我得到的是:
^{pr2}$当我得到^时使用:
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)
这是一个困难的情况,需要对pyparsing的一些内部结构有一点了解,才能将解析器重构为一个工作版本。在
你的“完美风暴”结合了以下因素:
verilog_lits
)Or
表达式中的元素MatchFirst
(使用“|”运算符创建)可以遍历它的备选方案列表,尝试依次解析每个备选方案,并在其中一个成功时返回。在这样做时,如果有一个parse操作,那么在解析成功之后,parse操作将按预期运行。在您的例子中,这个解析操作为二进制、十六进制或十进制值的值部分注入正确的数值表达式。在但是
Or
不能遵循相同的策略。在编写pyparsing时,我无法预测任何给定的解析操作除了处理已解析的标记之外是否有副作用或其他含义。因此,当Or
遍历其替代项,寻找最长的匹配时,它必须在不调用parse操作的情况下这样做。如果有一个解析操作更新解析器中的动态元素,那么在选择成功的替代项之前不会调用该操作。因为您依赖parse操作来完成解析器,所以如果定义动态表达式的触发器是Or
的一部分,那么这将失败。在基于此,我重构了“基数后跟其类型特定的允许值”的定义,替换为:
与
^{pr2}$这可能没有动态子表达式的活力,但是通过将动态表达式扩展为一组3个特定的备选方案,该表达式现在可以安全地包含在“全部求值并选择最长”
Or
表达式中。在相关问题 更多 >
编程相关推荐