Не все является 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])
Это заменяет запятую, точку с запятой, скобку и шестое правило. Осталось только добавить first : matrix
. (Кроме того, действие p_row
идентично вашему действию p_paren
, поэтому их можно объединить, если хотите.)
Два выноса:
если вы можете описать синтаксис на своем родном языке, вы можете написать для него грамматику. Грамматика - это просто более формальный способ сказать то же самое. (По крайней мере, после того, как вы перестанете запугиваться рекурсией, что тоже не сложно: «список - это значение, или вы можете расширить список, добавив запятую и значение», это будет довольно легко понять.)
Грамматика должна иметь возможность анализировать входные данные без проверки того, что было проанализировано ранее.
Этот второй принцип не является абсолютным. В этом случае, например, вы можете запретить вложенным элементам matrix
значения в row
. Вы могли бы написать это как грамматику, но это будет включать раздражающее количество дублирования; для действий row_list
может быть проще проверить, что expression
, который они обрабатывают, не является Matrix
.