Python PLY Parser-将矩阵解析为列表列表



我正在使用PLY创建一个计算器,我希望能够将矩阵(如[[11,1];[22,4];[13,3]](解析为列表列表,并将其提供给我自己的Matrix类以进行进一步计算。

到目前为止,这是我的代码。这里的三个重要函数是p_commap_semicolonp_brack。其余部分纯粹用于计算和优先级。

def p_operations(p): 
""" expression : sixth
sixth : fifth
fifth : fourth
fourth : third
third : second
second : first
first : NUMBER
first : IMAGINE
"""
p[0] = p[1]
def p_comma(p):
""" sixth : sixth ',' fifth """
if isinstance(p[1], list):
p[1].append(p[3])
p[0] = p[1]
else:
p[0] = [p[1],p[3]]
def p_semicolon(p):
""" sixth : sixth ';' fifth """
if isinstance(p[1], list):
p[1].append(p[3])
p[0] = p[1]
else:
p[0] = [p[1],p[3]]
def p_plus(p):
""" fifth : fifth '+' fourth """
p[0] = p[1] + p[3]
def p_minus(p):
""" fifth : fifth '-' fourth """
p[0] = p[1] - p[3]
def p_implicit_times(p):
""" fourth : fourth second """
p[0] = p[1] * p[2]
def p_times(p):
""" fourth : fourth '*' third """
p[0] = p[1] * p[3]
def p_divide(p):
""" fourth : fourth '/' third """
p[0] = p[1] / p[3]
def p_modulo(p):
""" fourth : fourth '%' third """
p[0] = p[1] % p[3]
def p_floor_divide(p):
""" fourth : fourth FLOORDIV third """
p[0] = p[1] // p[3]
def p_unary_minus(p):
""" third : '-' third """
p[0] = -p[2]
def p_power(p):
""" second : first '^' third """
p[0] = p[1] ** p[3]
def p_paren(p):
""" first : '(' expression ')' """
p[0] = p[2]
def p_brack(p):
""" first : '[' expression ']' """
if type(p[2][0]) == list:
p[0] = [p[2]]
else:
p[0] = Matrix.Matrix(p[2])

这里的问题是,我的解决方案不能很好地处理一些棘手的东西:[[1]],而且即使没有括号,解析也能工作,这不是我想要的。

最重要的是,我坚信还有更好的解决方案。

有人能帮我吗?

并非所有东西都是expression:-(

特别是,在矩阵括号内的是一个由分号分隔的行列表,每一行都是由逗号分隔的表达式列表。您的语法应该反映这个简单的事实,而不仅仅是将这些列表集中到expression非终端中。否则,您会发现它接受断章取义的分号和逗号分隔的列表。我想这就是你问题的基础。

此外,正如我认为我们已经讨论过的,如果你的动作函数需要进行测试,这可能表明你没有利用你的语法。这里的情况确实如此。

所以让我们从顶部开始。矩阵是一个以分号分隔的、用方括号括起来的行列表。换句话说:

matrix     : '[' row_list ']'
row_list   : row
| row_list ';' row

一行是一个逗号分隔的值列表(目前是表达式(,用方括号括起来:

row        : '[' value_list ']'
value_list : expression
| value_list ',' expression

现在,我们可以编写动作函数了。这些也很简单。

def p_list_first(p):
"""value_list : expression
row_list   : row
"""
p[0] = [ p[1] ]

def p_list_extend(p):
"""value_list : value_list ','  expression
row_list   : row_list ';' row
"""
p[0] = p[1]
p[0].append(p[3])
# Another way of writing this action:
#     p[0] = p[1] + [ p[3] ]
# That's cleaner, in that it doesn't modify the previous value.
# But it's less efficient because it creates a new list every time.
def p_row(p):
"""row       : '[' value_list ']' """
p[0] = p[2]
def p_matrix(p):
"""matrix    : '[' row_list ']' """
p[0] = Matrix.Matrix(p[2])

它取代了逗号、分号、brack和第六条规则。剩下的就是添加first : matrix。(此外,p_row操作与p_paren操作相同,因此如果您愿意,可以将它们组合在一起。(

两个要点:

  1. 如果你能用自己的母语描述语法,你就可以为它写一个语法。语法只是一种更正式的表达方式。(至少,一旦你不再被递归吓倒,这也不复杂:"列表是一个值,或者你可以通过添加逗号和值来扩展列表"应该很容易理解。(

  2. 语法应该能够解析输入,而不必测试之前解析的内容。

第二个原则不是绝对的。例如,在这种情况下,您可能希望禁止row中的值嵌套为matrix元素。你可以把它写成语法,但它会涉及大量令人讨厌的重复;CCD_ 13动作验证它们正在处理的CCD_ 14不是CCD_。

最新更新