Sat Jun 10 17:35:41 2023 UTC ()
indent: fix stack overflow, add more tests

For several parser symbols, 2 symbols are pushed in a row, which led to
an out-of-bounds write.


(rillig)
diff -r1.6 -r1.7 src/tests/usr.bin/indent/opt_cli.c
diff -r1.4 -r1.5 src/tests/usr.bin/indent/psym_else.c
diff -r1.34 -r1.35 src/tests/usr.bin/indent/t_errors.sh
diff -r1.71 -r1.72 src/usr.bin/indent/parse.c

cvs diff -r1.6 -r1.7 src/tests/usr.bin/indent/opt_cli.c (expand / switch to unified diff)

--- src/tests/usr.bin/indent/opt_cli.c 2023/06/06 04:37:27 1.6
+++ src/tests/usr.bin/indent/opt_cli.c 2023/06/10 17:35:41 1.7
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: opt_cli.c,v 1.6 2023/06/06 04:37:27 rillig Exp $ */ 1/* $NetBSD: opt_cli.c,v 1.7 2023/06/10 17:35:41 rillig Exp $ */
2 2
3/* 3/*
4 * Tests for the option '-cli' ("case label indentation"), which sets the 4 * Tests for the option '-cli' ("case label indentation"), which sets the
5 * amount of indentation of a 'case' relative to the surrounding 'switch', 5 * amount of indentation of a 'case' relative to the surrounding 'switch',
6 * measured in indentation levels. 6 * measured in indentation levels.
7 * 7 *
8 * See also: 8 * See also:
9 * lsym_case_label.c 9 * lsym_case_label.c
10 */ 10 */
11 11
12//indent input 12//indent input
13void 13void
14classify(int n) 14classify(int n)
@@ -87,13 +87,64 @@ classify(int n) @@ -87,13 +87,64 @@ classify(int n)
87 case 2: 87 case 2:
88 case 3: 88 case 3:
89 print("prime"); 89 print("prime");
90 break; 90 break;
91 case 4: 91 case 4:
92 print("square"); 92 print("square");
93 break; 93 break;
94 default: 94 default:
95 print("large"); 95 print("large");
96 break; 96 break;
97 } 97 }
98} 98}
99//indent end 99//indent end
 100
 101
 102/*
 103 * Test the combination of left-aligned braces and a deep case indentation.
 104 *
 105 * When the 'case' labels are that deeply indented, the distance between the
 106 * braces and the 'case' is between 1 and 2 indentation levels.
 107 */
 108//indent input
 109{
 110switch (expr)
 111{
 112case 1:
 113}
 114}
 115//indent end
 116
 117//indent run -br -cli3.25
 118{
 119 switch (expr) {
 120 case 1:
 121 }
 122}
 123//indent end
 124
 125//indent run -bl -cli3.25
 126{
 127 switch (expr)
 128 {
 129 case 1:
 130 }
 131}
 132//indent end
 133
 134//indent run -bl -cli2.75
 135{
 136 switch (expr)
 137 {
 138 case 1:
 139 }
 140}
 141//indent end
 142
 143//indent run -bl -cli1.25
 144{
 145 switch (expr)
 146 {
 147 case 1:
 148 }
 149}
 150//indent end

cvs diff -r1.4 -r1.5 src/tests/usr.bin/indent/psym_else.c (expand / switch to unified diff)

--- src/tests/usr.bin/indent/psym_else.c 2022/04/24 10:36:37 1.4
+++ src/tests/usr.bin/indent/psym_else.c 2023/06/10 17:35:41 1.5
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: psym_else.c,v 1.4 2022/04/24 10:36:37 rillig Exp $ */ 1/* $NetBSD: psym_else.c,v 1.5 2023/06/10 17:35:41 rillig Exp $ */
2 2
3/* 3/*
4 * Tests for the parser symbol psym_else, which represents the keyword 'else' 4 * Tests for the parser symbol psym_else, which represents the keyword 'else'
5 * that is being shifted on the parser stack. 5 * that is being shifted on the parser stack.
6 * 6 *
7 * This parser symbol never ends up on the stack itself. 7 * This parser symbol never ends up on the stack itself.
8 */ 8 */
9 9
10/* 10/*
11 * When parsing nested incomplete 'if' statements, the problem of the 11 * When parsing nested incomplete 'if' statements, the problem of the
12 * 'dangling else' occurs. It is resolved by binding the 'else' to the 12 * 'dangling else' occurs. It is resolved by binding the 'else' to the
13 * innermost incomplete 'if' statement. 13 * innermost incomplete 'if' statement.
14 * 14 *
@@ -61,13 +61,28 @@ function(void) @@ -61,13 +61,28 @@ function(void)
61} 61}
62//indent end 62//indent end
63 63
64//indent run 64//indent run
65void 65void
66function(void) 66function(void)
67{ 67{
68 if (var > 0) 68 if (var > 0)
69 var = 0; 69 var = 0;
70 else 70 else
71 (var = 3); 71 (var = 3);
72} 72}
73//indent end 73//indent end
 74
 75
 76//indent input
 77{
 78 else
 79}
 80//indent end
 81
 82//indent run
 83error: Standard Input:2: Unmatched 'else'
 84{
 85 else
 86}
 87exit 1
 88//indent end

cvs diff -r1.34 -r1.35 src/tests/usr.bin/indent/t_errors.sh (expand / switch to unified diff)

--- src/tests/usr.bin/indent/t_errors.sh 2023/06/09 11:22:31 1.34
+++ src/tests/usr.bin/indent/t_errors.sh 2023/06/10 17:35:41 1.35
@@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
1#! /bin/sh 1#! /bin/sh
2# $NetBSD: t_errors.sh,v 1.34 2023/06/09 11:22:31 rillig Exp $ 2# $NetBSD: t_errors.sh,v 1.35 2023/06/10 17:35:41 rillig Exp $
3# 3#
4# Copyright (c) 2021 The NetBSD Foundation, Inc. 4# Copyright (c) 2021 The NetBSD Foundation, Inc.
5# All rights reserved. 5# All rights reserved.
6# 6#
7# Redistribution and use in source and binary forms, with or without 7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions 8# modification, are permitted provided that the following conditions
9# are met: 9# are met:
10# 1. Redistributions of source code must retain the above copyright 10# 1. Redistributions of source code must retain the above copyright
11# notice, this list of conditions and the following disclaimer. 11# notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright 12# 2. Redistributions in binary form must reproduce the above copyright
13# notice, this list of conditions and the following disclaimer in the 13# notice, this list of conditions and the following disclaimer in the
14# documentation and/or other materials provided with the distribution. 14# documentation and/or other materials provided with the distribution.
15# 15#
@@ -475,26 +475,52 @@ int @@ -475,26 +475,52 @@ int
475f(void) 475f(void)
476{ 476{
477 if (0) 477 if (0)
478 /* 478 /*
479 * 0123456789012345678901 479 * 0123456789012345678901
480 */; 480 */;
481} 481}
482EOF 482EOF
483 483
484 atf_check -o 'file:expected.out' \ 484 atf_check -o 'file:expected.out' \
485 "$indent" -l34 code.c -st 485 "$indent" -l34 code.c -st
486} 486}
487 487
 488atf_test_case 'stack_overflow'
 489stack_overflow_body()
 490{
 491 cat <<-EOF > code.c
 492 {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
 493 {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
 494 {{{{{{{{{{ {{{{{{{{{{ {{{{{{{
 495 EOF
 496
 497 atf_check \
 498 -s 'exit:1' \
 499 -e 'inline:error: code.c:3: Stuff missing from end of file\n' \
 500 "$indent" code.c
 501
 502 cat <<-EOF > code.c
 503 {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
 504 {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
 505 {{{{{{{{{{ {{{{{{{{{{ {{{{{{{ {
 506 EOF
 507
 508 atf_check \
 509 -s 'exit:1' \
 510 -e 'inline:indent: Parser stack overflow\n' \
 511 "$indent" code.c
 512}
 513
488 514
489atf_init_test_cases() 515atf_init_test_cases()
490{ 516{
491 atf_add_test_case 'option_unknown' 517 atf_add_test_case 'option_unknown'
492 atf_add_test_case 'option_bool_trailing_garbage' 518 atf_add_test_case 'option_bool_trailing_garbage'
493 atf_add_test_case 'option_int_missing_argument' 519 atf_add_test_case 'option_int_missing_argument'
494 atf_add_test_case 'option_profile_not_found' 520 atf_add_test_case 'option_profile_not_found'
495 atf_add_test_case 'option_buffer_overflow' 521 atf_add_test_case 'option_buffer_overflow'
496 atf_add_test_case 'option_typedefs_not_found' 522 atf_add_test_case 'option_typedefs_not_found'
497 atf_add_test_case 'option_special_missing_param' 523 atf_add_test_case 'option_special_missing_param'
498 atf_add_test_case 'option_tabsize_negative' 524 atf_add_test_case 'option_tabsize_negative'
499 atf_add_test_case 'option_tabsize_zero' 525 atf_add_test_case 'option_tabsize_zero'
500 atf_add_test_case 'option_tabsize_large' 526 atf_add_test_case 'option_tabsize_large'
@@ -514,14 +540,15 @@ atf_init_test_cases() @@ -514,14 +540,15 @@ atf_init_test_cases()
514 atf_add_test_case 'argument_output_equals_input_name' 540 atf_add_test_case 'argument_output_equals_input_name'
515 atf_add_test_case 'argument_output_equals_input_file' 541 atf_add_test_case 'argument_output_equals_input_file'
516 atf_add_test_case 'argument_output_enoent' 542 atf_add_test_case 'argument_output_enoent'
517 atf_add_test_case 'argument_too_many' 543 atf_add_test_case 'argument_too_many'
518 atf_add_test_case 'unexpected_end_of_file' 544 atf_add_test_case 'unexpected_end_of_file'
519 atf_add_test_case 'unexpected_closing_brace_top_level' 545 atf_add_test_case 'unexpected_closing_brace_top_level'
520 atf_add_test_case 'unexpected_closing_brace_decl' 546 atf_add_test_case 'unexpected_closing_brace_decl'
521 atf_add_test_case 'preprocessing_overflow' 547 atf_add_test_case 'preprocessing_overflow'
522 atf_add_test_case 'preprocessing_unrecognized' 548 atf_add_test_case 'preprocessing_unrecognized'
523 atf_add_test_case 'unbalanced_parentheses' 549 atf_add_test_case 'unbalanced_parentheses'
524 atf_add_test_case 'gcc_statement_expression' 550 atf_add_test_case 'gcc_statement_expression'
525 atf_add_test_case 'crash_comment_after_controlling_expression' 551 atf_add_test_case 'crash_comment_after_controlling_expression'
526 atf_add_test_case 'comment_fits_in_one_line' 552 atf_add_test_case 'comment_fits_in_one_line'
 553 atf_add_test_case 'stack_overflow'
527} 554}

cvs diff -r1.71 -r1.72 src/usr.bin/indent/parse.c (expand / switch to unified diff)

--- src/usr.bin/indent/parse.c 2023/06/10 16:43:56 1.71
+++ src/usr.bin/indent/parse.c 2023/06/10 17:35:40 1.72
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: parse.c,v 1.71 2023/06/10 16:43:56 rillig Exp $ */ 1/* $NetBSD: parse.c,v 1.72 2023/06/10 17:35:40 rillig Exp $ */
2 2
3/*- 3/*-
4 * SPDX-License-Identifier: BSD-4-Clause 4 * SPDX-License-Identifier: BSD-4-Clause
5 * 5 *
6 * Copyright (c) 1985 Sun Microsystems, Inc. 6 * Copyright (c) 1985 Sun Microsystems, Inc.
7 * Copyright (c) 1980, 1993 7 * Copyright (c) 1980, 1993
8 * The Regents of the University of California. All rights reserved. 8 * The Regents of the University of California. All rights reserved.
9 * All rights reserved. 9 * All rights reserved.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -28,27 +28,27 @@ @@ -28,27 +28,27 @@
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE. 37 * SUCH DAMAGE.
38 */ 38 */
39 39
40#include <sys/cdefs.h> 40#include <sys/cdefs.h>
41__RCSID("$NetBSD: parse.c,v 1.71 2023/06/10 16:43:56 rillig Exp $"); 41__RCSID("$NetBSD: parse.c,v 1.72 2023/06/10 17:35:40 rillig Exp $");
42 42
43#include <err.h> 43#include <err.h>
44 44
45#include "indent.h" 45#include "indent.h"
46 46
47/* 47/*
48 * Try to combine the statement on the top of the parse stack with the symbol 48 * Try to combine the statement on the top of the parse stack with the symbol
49 * directly below it, replacing these two symbols with a single symbol. 49 * directly below it, replacing these two symbols with a single symbol.
50 */ 50 */
51static bool 51static bool
52psyms_reduce_stmt(struct psym_stack *psyms) 52psyms_reduce_stmt(struct psym_stack *psyms)
53{ 53{
54 switch (psyms->sym[psyms->top - 1]) { 54 switch (psyms->sym[psyms->top - 1]) {
@@ -91,37 +91,33 @@ psyms_reduce_stmt(struct psym_stack *psy @@ -91,37 +91,33 @@ psyms_reduce_stmt(struct psym_stack *psy
91} 91}
92 92
93static int 93static int
94decl_level(void) 94decl_level(void)
95{ 95{
96 int level = 0; 96 int level = 0;
97 for (int i = ps.psyms.top - 1; i > 0; i--) 97 for (int i = ps.psyms.top - 1; i > 0; i--)
98 if (ps.psyms.sym[i] == psym_decl) 98 if (ps.psyms.sym[i] == psym_decl)
99 level++; 99 level++;
100 return level; 100 return level;
101} 101}
102 102
103static void 103static void
104ps_push(parser_symbol psym) 104ps_push(parser_symbol psym, bool follow)
105{ 
106 ps.psyms.sym[++ps.psyms.top] = psym; 
107 ps.psyms.ind_level[ps.psyms.top] = ps.ind_level; 
108} 
109 
110static void 
111ps_push_follow(parser_symbol psym) 
112{ 105{
 106 if (ps.psyms.top + 1 >= STACKSIZE)
 107 errx(1, "Parser stack overflow");
113 ps.psyms.sym[++ps.psyms.top] = psym; 108 ps.psyms.sym[++ps.psyms.top] = psym;
114 ps.psyms.ind_level[ps.psyms.top] = ps.ind_level_follow; 109 ps.psyms.ind_level[ps.psyms.top] =
 110 follow ? ps.ind_level_follow : ps.ind_level;
115} 111}
116 112
117/* 113/*
118 * Repeatedly try to reduce the top two symbols on the parse stack to a single 114 * Repeatedly try to reduce the top two symbols on the parse stack to a single
119 * symbol, until no more reductions are possible. 115 * symbol, until no more reductions are possible.
120 */ 116 */
121static void 117static void
122psyms_reduce(struct psym_stack *psyms) 118psyms_reduce(struct psym_stack *psyms)
123{ 119{
124again: 120again:
125 if (psyms->sym[psyms->top] == psym_stmt && psyms_reduce_stmt(psyms)) 121 if (psyms->sym[psyms->top] == psym_stmt && psyms_reduce_stmt(psyms))
126 goto again; 122 goto again;
127 if (psyms->sym[psyms->top] == psym_while_expr && 123 if (psyms->sym[psyms->top] == psym_while_expr &&
@@ -170,94 +166,91 @@ parse(parser_symbol psym) @@ -170,94 +166,91 @@ parse(parser_symbol psym)
170 || psyms->sym[psyms->top] == psym_stmt_list) 166 || psyms->sym[psyms->top] == psym_stmt_list)
171 ++ps.ind_level_follow; 167 ++ps.ind_level_follow;
172 else if (code.len == 0) { 168 else if (code.len == 0) {
173 /* It is part of a while, for, etc. */ 169 /* It is part of a while, for, etc. */
174 --ps.ind_level; 170 --ps.ind_level;
175 171
176 /* for a switch, brace should be two levels out from 172 /* for a switch, brace should be two levels out from
177 * the code */ 173 * the code */
178 if (psyms->sym[psyms->top] == psym_switch_expr 174 if (psyms->sym[psyms->top] == psym_switch_expr
179 && opt.case_indent >= 1.0F) 175 && opt.case_indent >= 1.0F)
180 --ps.ind_level; 176 --ps.ind_level;
181 } 177 }
182 178
183 ps_push(psym); 179 ps_push(psym, false);
184 ps_push_follow(psym_stmt); 180 ps_push(psym_stmt, true);
185 break; 181 break;
186 182
187 case psym_rbrace: 183 case psym_rbrace:
188 /* stack should have <lbrace> <stmt> or <lbrace> <stmt_list> */ 184 /* stack should have <lbrace> <stmt> or <lbrace> <stmt_list> */
189 if (!(psyms->top > 0 185 if (!(psyms->top > 0
190 && is_lbrace(psyms->sym[psyms->top - 1]))) { 186 && is_lbrace(psyms->sym[psyms->top - 1]))) {
191 diag(1, "Statement nesting error"); 187 diag(1, "Statement nesting error");
192 break; 188 break;
193 } 189 }
194 ps.ind_level = ps.ind_level_follow = 190 ps.ind_level = ps.ind_level_follow =
195 psyms->ind_level[--psyms->top]; 191 psyms->ind_level[--psyms->top];
196 psyms->sym[psyms->top] = psym_stmt; 192 psyms->sym[psyms->top] = psym_stmt;
197 break; 193 break;
198 194
199 case psym_decl: 195 case psym_decl:
200 if (psyms->sym[psyms->top] == psym_decl) 196 if (psyms->sym[psyms->top] == psym_decl)
201 break; /* only put one declaration onto stack */ 197 break; /* only put one declaration onto stack */
202 198
203 ps.break_after_comma = true; 199 ps.break_after_comma = true;
204 ps_push_follow(psym_decl); 200 ps_push(psym_decl, true);
205 201
206 if (opt.left_justify_decl) 202 if (opt.left_justify_decl)
207 ps.ind_level_follow = ps.ind_level = decl_level(); 203 ps.ind_level_follow = ps.ind_level = decl_level();
208 break; 204 break;
209 205
210 case psym_stmt: 206 case psym_stmt:
211 ps.break_after_comma = false; 207 ps.break_after_comma = false;
212 ps_push(psym_stmt); 208 ps_push(psym_stmt, false);
213 break; 209 break;
214 210
215 case psym_if_expr: 211 case psym_if_expr:
216 if (psyms->sym[psyms->top] == psym_if_expr_stmt_else 212 if (psyms->sym[psyms->top] == psym_if_expr_stmt_else
217 && opt.else_if_in_same_line) 213 && opt.else_if_in_same_line)
218 ps.ind_level_follow = psyms->ind_level[psyms->top--]; 214 ps.ind_level_follow = psyms->ind_level[psyms->top--];
219 /* FALLTHROUGH */ 215 /* FALLTHROUGH */
220 case psym_do: 216 case psym_do:
221 case psym_for_exprs: 217 case psym_for_exprs:
222 ps.ind_level = ps.ind_level_follow++; 218 ps.ind_level = ps.ind_level_follow++;
223 ps_push(psym); 219 ps_push(psym, false);
224 break; 220 break;
225 221
226 case psym_else: 222 case psym_else:
227 if (psyms->sym[psyms->top] != psym_if_expr_stmt) { 223 if (psyms->sym[psyms->top] != psym_if_expr_stmt) {
228 diag(1, "Unmatched 'else'"); 224 diag(1, "Unmatched 'else'");
229 break; 225 break;
230 } 226 }
231 ps.ind_level = psyms->ind_level[psyms->top]; 227 ps.ind_level = psyms->ind_level[psyms->top];
232 ps.ind_level_follow = ps.ind_level + 1; 228 ps.ind_level_follow = ps.ind_level + 1;
233 psyms->sym[psyms->top] = psym_if_expr_stmt_else; 229 psyms->sym[psyms->top] = psym_if_expr_stmt_else;
234 break; 230 break;
235 231
236 case psym_switch_expr: 232 case psym_switch_expr:
237 ps_push_follow(psym_switch_expr); 233 ps_push(psym_switch_expr, true);
238 ps.ind_level_follow += (int)opt.case_indent + 1; 234 ps.ind_level_follow += (int)opt.case_indent + 1;
239 break; 235 break;
240 236
241 case psym_while_expr: 237 case psym_while_expr:
242 if (psyms->sym[psyms->top] == psym_do_stmt) { 238 if (psyms->sym[psyms->top] == psym_do_stmt) {
243 ps.ind_level = ps.ind_level_follow = 239 ps.ind_level = ps.ind_level_follow =
244 psyms->ind_level[psyms->top]; 240 psyms->ind_level[psyms->top];
245 ps_push(psym_while_expr); 241 ps_push(psym_while_expr, false);
246 } else { 242 } else {
247 ps_push_follow(psym_while_expr); 243 ps_push(psym_while_expr, true);
248 ++ps.ind_level_follow; 244 ++ps.ind_level_follow;
249 } 245 }
250 break; 246 break;
251 247
252 default: 248 default:
253 diag(1, "Unknown code to parser"); 249 diag(1, "Unknown code to parser");
254 return; 250 return;
255 } 251 }
256 252
257 if (psyms->top >= STACKSIZE - 1) 
258 errx(1, "Parser stack overflow"); 
259 
260 debug_psyms_stack("before reduction"); 253 debug_psyms_stack("before reduction");
261 psyms_reduce(&ps.psyms); 254 psyms_reduce(&ps.psyms);
262 debug_psyms_stack("after reduction"); 255 debug_psyms_stack("after reduction");
263} 256}