我目前正在减少野牛,这是为了将逗号分隔的列表与几个可选的不同的规则相匹配:
arg_list
:
| expr_list
| assignment_list
| expr_list ',' assignment_list
| varargs
| expr_list ',' varargs
| assignment_list ',' varargs
| expr_list ',' assignment_list ',' varargs
| varkwdargs
| expr_list ',' varkwdargs
| assignment_list ',' varkwdargs
| expr_list ',' assignment_list ',' varkwdargs
| varargs ',' varkwdargs
| expr_list ',' varargs ',' varkwdargs
| assignment_list ',' varargs ',' varkwdargs
| expr_list ',' assignment_list ',' varargs ',' varkwdargs
;
如果不清楚,这是为了实现(伪代码):
arg_list
:
| expr_list [',' assignment_list] [',' varargs] [',' varkwdargs]
| assignment_list [',' varargs] [',' varkwdargs]
| varargs [',' varkwdargs]
| varkwdargs
;
执行此操作的方法是实施,例如:
optional_assignment_list:
:
| ',' assignment_list
;
然而,后一个公式不是LALR(1),因为在Bison看到逗号的每个步骤中,它必须决定是否转移并查找* assignment_list *或减少空* optional_assignment_list *然后继续寻找* optional_varargs *。
我试图找出是否有更好的方式来表示这一点。通过引入* optional_varkwdargs *,我已经能够减少备选方案的数量,但是仍然有九种替代方案可以减少,我想这比16更好:
optional_varkwdargs
:
| ',' varkwdargs
;
arg_list
:
| expr_list optional_varkwdargs
| assignment_list optional_varkwdargs
| expr_list ',' assignment_list optional_varkwdargs
| varargs optional_varkwdargs
| expr_list ',' varargs optional_varkwdargs
| assignment_list ',' varargs optional_varkwdargs
| expr_list ',' assignment_list ',' varargs optional_varkwdargs
| varkwdargs
;
任何想法都会受到赞赏。
答案 0 :(得分:3)
嗯,有一种可能性就是拥有一个更通用的arglist解析器,它允许以任何顺序列出任何这些内容:
arg_list: arg_item
{ $$ = CreateSingletonArgList($1); }
| arg_list ',' arg_item
{ if (CheckArgListOrdering($1, $3))
$$ = AppendArgList($1, $3);
else
$$ = $1; }
;
arg_item: expr
| assignment
| vararg
| varkwarg
;
然后,您对arg_list进行了解析后检查,以确保事情的顺序不正确。这样做的好处是,您可以为这些情况提供更好的错误消息(“kwarg必须在vararg之后”或某些此类情况),而不仅仅是通用的“语法错误”
修改强>
通过规则中的上述操作,CheckArgListOrdering函数会检查以确保arg_item可以追踪现有arg_list中的所有操作,如果没有则发出相应的错误消息。返回值告诉解析器是接受新的arg_item还是抛弃它。 Create / Append函数只管理arg_lists作为任何类型的有序集合数据结构(可能是链表,数组或其他任何适当的集合)。