From 64d5ee389912ea3e89eae18c0993a5728bc902dc Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 7 Jul 2026 15:01:01 +0200 Subject: [PATCH] grammar: eliminate backtracking in "lists" Currently these definitions do not result in an LL(k) generated parser. For in depth reasoning, see commit 296b39c32324 (grammar: fix ParamDeclList worst-case exponential time) --- doc/langref/grammar.peg | 10 +- lib/std/zig/parser_generated_oracle.zig | 127 ++++++++++-------------- 2 files changed, 56 insertions(+), 81 deletions(-) diff --git a/doc/langref/grammar.peg b/doc/langref/grammar.peg index bce5b0b94ad32be346c1d95cf6c5698df149897e..d56beb04243f42b2c0b9204207a1e0f7aa6c9672 100644 --- a/doc/langref/grammar.peg +++ b/doc/langref/grammar.peg @@ -441,13 +441,13 @@ ByteAlign <- KEYWORD_align LPAREN Expr RPAREN BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN # Lists -IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)? +IdentifierList <- (doc_comment? IDENTIFIER (COMMA IdentifierList)?)? -SwitchProngList <- (SwitchProng COMMA)* SwitchProng? +SwitchProngList <- (SwitchProng (COMMA SwitchProngList)?)? -AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? +AsmOutputList <- (AsmOutputItem (COMMA AsmOutputList)?)? -AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? +AsmInputList <- (AsmInputItem (COMMA AsmInputList)?)? ParamDeclList <- LPAREN ParamDeclListRest ParamDeclListRest @@ -455,7 +455,7 @@ ParamDeclListRest / DOT3 COMMA? RPAREN / ParamDecl (COMMA ParamDeclListRest / RPAREN) -ExprList <- (Expr COMMA)* (Expr / !ExprPrefix) +ExprList <- Expr (COMMA ExprList)? / !ExprPrefix ExprPrefix <- ASTERISK diff --git a/lib/std/zig/parser_generated_oracle.zig b/lib/std/zig/parser_generated_oracle.zig index 8327c715200d450cdf8ee8da8ec60be054d82ca9..0579dd91adcf7d3f66fa20e528e20aca6c6a62cb 100644 --- a/lib/std/zig/parser_generated_oracle.zig +++ b/lib/std/zig/parser_generated_oracle.zig @@ -2913,21 +2913,14 @@ const Parser = struct { defer p.depths[def_index] -= 1; return blk_0: { const pos_0 = p.i; - if (blk_1: { - var i_1: usize = 0; - while (blk_3: { - const pos_3 = p.i; - if ((try p.parsedoc_comment() or true) and try p.parseIDENTIFIER() and try p.parseCOMMA()) break :blk_3 true; - p.i = pos_3; - break :blk_3 false; - }) { - if (i_1 > max_depth) return error.MaxDepth; - i_1 += 1; - } - break :blk_1 true; - } and (blk_3: { + if ((blk_3: { const pos_3 = p.i; - if ((try p.parsedoc_comment() or true) and try p.parseIDENTIFIER()) break :blk_3 true; + if ((try p.parsedoc_comment() or true) and try p.parseIDENTIFIER() and (blk_6: { + const pos_6 = p.i; + if (try p.parseCOMMA() and try p.parseIdentifierList()) break :blk_6 true; + p.i = pos_6; + break :blk_6 false; + } or true)) break :blk_3 true; p.i = pos_3; break :blk_3 false; } or true)) break :blk_0 true; @@ -2942,19 +2935,17 @@ const Parser = struct { defer p.depths[def_index] -= 1; return blk_0: { const pos_0 = p.i; - if (blk_1: { - var i_1: usize = 0; - while (blk_3: { - const pos_3 = p.i; - if (try p.parseSwitchProng() and try p.parseCOMMA()) break :blk_3 true; - p.i = pos_3; - break :blk_3 false; - }) { - if (i_1 > max_depth) return error.MaxDepth; - i_1 += 1; - } - break :blk_1 true; - } and (try p.parseSwitchProng() or true)) break :blk_0 true; + if ((blk_3: { + const pos_3 = p.i; + if (try p.parseSwitchProng() and (blk_6: { + const pos_6 = p.i; + if (try p.parseCOMMA() and try p.parseSwitchProngList()) break :blk_6 true; + p.i = pos_6; + break :blk_6 false; + } or true)) break :blk_3 true; + p.i = pos_3; + break :blk_3 false; + } or true)) break :blk_0 true; p.i = pos_0; break :blk_0 false; }; @@ -2966,19 +2957,17 @@ const Parser = struct { defer p.depths[def_index] -= 1; return blk_0: { const pos_0 = p.i; - if (blk_1: { - var i_1: usize = 0; - while (blk_3: { - const pos_3 = p.i; - if (try p.parseAsmOutputItem() and try p.parseCOMMA()) break :blk_3 true; - p.i = pos_3; - break :blk_3 false; - }) { - if (i_1 > max_depth) return error.MaxDepth; - i_1 += 1; - } - break :blk_1 true; - } and (try p.parseAsmOutputItem() or true)) break :blk_0 true; + if ((blk_3: { + const pos_3 = p.i; + if (try p.parseAsmOutputItem() and (blk_6: { + const pos_6 = p.i; + if (try p.parseCOMMA() and try p.parseAsmOutputList()) break :blk_6 true; + p.i = pos_6; + break :blk_6 false; + } or true)) break :blk_3 true; + p.i = pos_3; + break :blk_3 false; + } or true)) break :blk_0 true; p.i = pos_0; break :blk_0 false; }; @@ -2990,19 +2979,17 @@ const Parser = struct { defer p.depths[def_index] -= 1; return blk_0: { const pos_0 = p.i; - if (blk_1: { - var i_1: usize = 0; - while (blk_3: { - const pos_3 = p.i; - if (try p.parseAsmInputItem() and try p.parseCOMMA()) break :blk_3 true; - p.i = pos_3; - break :blk_3 false; - }) { - if (i_1 > max_depth) return error.MaxDepth; - i_1 += 1; - } - break :blk_1 true; - } and (try p.parseAsmInputItem() or true)) break :blk_0 true; + if ((blk_3: { + const pos_3 = p.i; + if (try p.parseAsmInputItem() and (blk_6: { + const pos_6 = p.i; + if (try p.parseCOMMA() and try p.parseAsmInputList()) break :blk_6 true; + p.i = pos_6; + break :blk_6 false; + } or true)) break :blk_3 true; + p.i = pos_3; + break :blk_3 false; + } or true)) break :blk_0 true; p.i = pos_0; break :blk_0 false; }; @@ -3049,30 +3036,18 @@ const Parser = struct { defer p.depths[def_index] -= 1; return blk_0: { const pos_0 = p.i; + if (try p.parseExpr() and (blk_3: { + const pos_3 = p.i; + if (try p.parseCOMMA() and try p.parseExprList()) break :blk_3 true; + p.i = pos_3; + break :blk_3 false; + } or true)) break :blk_0 true; + p.i = pos_0; if (blk_1: { - var i_1: usize = 0; - while (blk_3: { - const pos_3 = p.i; - if (try p.parseExpr() and try p.parseCOMMA()) break :blk_3 true; - p.i = pos_3; - break :blk_3 false; - }) { - if (i_1 > max_depth) return error.MaxDepth; - i_1 += 1; - } - break :blk_1 true; - } and blk_2: { - const pos_2 = p.i; - if (try p.parseExpr()) break :blk_2 true; - p.i = pos_2; - if (blk_3: { - const pos_3 = p.i; - const match_3 = try p.parseExprPrefix(); - p.i = pos_3; - break :blk_3 !match_3; - }) break :blk_2 true; - p.i = pos_2; - break :blk_2 false; + const pos_1 = p.i; + const match_1 = try p.parseExprPrefix(); + p.i = pos_1; + break :blk_1 !match_1; }) break :blk_0 true; p.i = pos_0; break :blk_0 false; -- 2.54.0