如何管理相互递归,并保留关联性规则?

时间:2018-10-05 14:04:30

标签: bison yacc

总体问题是:

我的语法看起来应该如何允许任意嵌套的expr := '(' expr ')' => expr | expr_without_short_closureexpr_without_short_closure := [expr_without_short_closure => expr] | yield expr_without_short_closure => expr | expr_without_short_closure 'or' expr | '(' expr ')',同时仍然允许像expr_without_short_closure 'or' expr这样的低序左联想运算符?


当前,LALR(1)野牛语法的结构如下(表示实际语法文件的独立部分,略有简化):

%left ','
%left T_LOGICAL_OR /* or */
%right T_YIELD
%right T_DOUBLE_ARROW /* => */
%left '+'

expr: /* entry point as well */
                expr_without_short_closure %prec ',' { $$ = $1; }
        |       expr_with_short_closure { $$ = $1; }
;

expr_with_short_closure:
                short_closure
        |       T_YIELD expr_without_short_closure T_DOUBLE_ARROW expr_with_short_closure { $$ = zend_ast_create(ZEND_AST_YIELD, $4, $2); }
;

short_closure:
                T_IDENTIFIER T_DOUBLE_ARROW expr { /* ... */ }
        |       '(' expr ')' T_DOUBLE_ARROW expr { /* ... */ }
;

expr_without_short_closure:
                T_IDENTIFIER %prec T_DOUBLE_ARROW { $$ = $1; }
        |       '(' expr ')' %prec T_DOUBLE_ARROW { $$ = $2; }
        |       T_YIELD expr_without_short_closure { $$ = zend_ast_create(ZEND_AST_YIELD, $2, NULL); }
        |       '[' array_pair_list ']' { $$ = $2; }
        |       T_YIELD expr_without_short_closure T_DOUBLE_ARROW expr_without_short_closure { $$ = zend_ast_create(ZEND_AST_YIELD, $4, $2); }
        |       expr_without_short_closure T_LOGICAL_OR expr_without_short_closure       { $$ = zend_ast_create_binary_op(ZEND_AST_OR, $1, $3); }
        |       expr_without_short_closure '+' expr_without_short_closure       { $$ = zend_ast_create_binary_op(ZEND_ADD, $1, $3); }
/*      | and about thirty similar alternate rules like the previous one */
;

non_empty_array_pair_list:
                non_empty_array_pair_list ',' array_pair { $$ = zend_ast_list_add($1, $3); }
        |       array_pair { $$ = zend_ast_create_list(1, ZEND_AST_ARRAY, $1); }
;

array_pair:
                expr_without_short_closure T_DOUBLE_ARROW expr
                        { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $3, $1); }
        |       expr_without_short_closure
                        { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $1, NULL); }
;

本质上,我试图引入“箭头函数”,在左侧包含一个参数列表,在右侧包含一个任意表达式,中间包含一个T_DOUBLE_ARROW。

现在的挑战是T_DOUBLE_ARROW令牌已经在两个地方使用,即expr_without_short_closure T_DOUBLE_ARROW expr规则中的array_pair替代和T_YIELD expr_without_short_closure T_DOUBLE_ARROW expr_without_short_closure中的expr_without_short_closure。 / p>

目前这种语法的作品,但是(显然)无法解析,例如:

[T_YIELD T_IDENTIFIER => T_IDENTIFIER => T_IDENTIFIER + T_IDENTIFIER => T_YIELD T_IDENTIFIER]
// must be grouped as:
[(T_YIELD T_IDENTIFIER => T_IDENTIFIER) => (T_IDENTIFIER + (T_IDENTIFIER => (T_YIELD T_IDENTIFIER)))]

在这种情况下,expr_without_short_closure '+' expr_without_short_closure替代项失败了,因为它仅接受右侧的expr_without_short_closure,显然不允许在那里的short_closure。

但是,我不能简单地用expr_without_short_closure替换expr,因为这与expr_without_short_closure T_DOUBLE_ARROW expr表达式(array_pair规则)或T_YIELD expr_without_short_closure T_DOUBLE_ARROW expr_without_short_closure表达式({ {1}}规则。

现在,我可以尝试仅将expr_without_short_closure放在表达式的右侧。很好,除了左联想操作。现在,突然expr被分组为T_IDENTIFIER + T_IDENTIFIER T_LOGICAL_OR T_IDENTIFIER而不是所需的T_IDENTIFIER + (T_IDENTIFIER T_LOGICAL_OR T_IDENTIFIER)。 (为什么?)

我也很想避免使用(T_IDENTIFIER + T_IDENTIFIER) T_LOGICAL_OR T_IDENTIFIER中的%precexpr_without_short_closure %prec ','规则)。由于某种原因,它是必需的(删除它会导致expr中的每个规则上的移位/减少冲突),我想这也是问题的根源,尽管我并不十分了解为什么(搜索产生的答案,例如“关联规则不会通过间接传递”-但我真的看不到如何完全避免间接传递。)


我正在尝试使问题保持​​独立,但是如果我错过了某些内容-实际的语法文件可以在https://github.com/bwoebi/php-src/blob/0d98d8060bde88ac2e5904cb55ecb13d15316053/Zend/zend_language_parser.y#L898上找到-我认为很明显一个人真的不想复制所有从expr_without_short_closureexpr_without_short_closure的规则(而且我什至不确定这是否真的有助于低优先级的左关联运算符)。

0 个答案:

没有答案