【发布时间】:2018-10-05 14:04:30
【问题描述】:
总的问题是:
在允许任意嵌套的expr := '(' expr ')' => expr | expr_without_short_closure 和expr_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 令牌已在两个地方使用,即array_pair 规则中的expr_without_short_closure T_DOUBLE_ARROW expr 交替和expr_without_short_closure 中的T_YIELD expr_without_short_closure T_DOUBLE_ARROW expr_without_short_closure。
这种当前的语法类型有效,但它(显然)无法解析例如:
[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 表达式(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。 (为什么?)
我也想避免expr_without_short_closure %prec ',' 中的%prec(expr 规则)。出于某种原因,它是必需的(删除它会导致expr_without_short_closure 中每条规则的移位/减少冲突),我想这也是我的问题的根源,虽然我不太明白为什么(搜索产生的答案,如“关联性规则不通过间接”-但我真的不知道如何在这里避免间接)。
我试图让问题保持独立,但万一我遗漏了什么 - 实际的语法文件可以在 https://github.com/bwoebi/php-src/blob/0d98d8060bde88ac2e5904cb55ecb13d15316053/Zend/zend_language_parser.y#L898 找到 - 我认为很明显,人们并不想复制所有规则expr_without_short_closure 转换为 expr_with_short_closure(我什至不确定这是否真的有助于低优先级左关联运算符)。
【问题讨论】:
-
您能否澄清“数组列表中的
yield”示例中“必须分组为”的含义?我的印象是 php 会将[yield $a => 2 + 2]解析为产生一个键/值对,然后创建一个数组列表,其中包含发送到生成器的值。当您写[(T_YIELD T_IDENTIFIER) => (T_IDENTIFIER + (T_IDENTIFIER => (T_YIELD T_IDENTIFIER)))]时,我将其解释为yield仅产生第一个标识符的值,而第一个粗箭头是数组列表语法的一部分,在我看来这不是现有的解析。 -
@rici 你是对的,这将被分组为
[(T_YIELD T_IDENTIFIER => (T_IDENTIFIER + (T_IDENTIFIER => (T_YIELD T_IDENTIFIER))))]。我一定是把例子简化得太多了,试试[T_YIELD T_IDENTIFIER => T_IDENTIFIER => T_IDENTIFIER + T_IDENTIFIER => T_YIELD T_IDENTIFIER]和[(T_YIELD T_IDENTIFIER => T_IDENTIFIER) => (T_IDENTIFIER + (T_IDENTIFIER => (T_YIELD T_IDENTIFIER)))]——我想强调的是,最左边yield 的右手部分不能被解析为“箭头函数”。