#include <sys/cdefs.h>
__RCSID("$NetBSD: parse.c,v 1.85 2025/01/07 03:55:00 rillig Exp $");
#include <stdlib.h>
#include "indent.h"
static void
ps_psyms_replace2(parser_symbol psym)
{
ps.psyms.len--;
ps.psyms.sym[ps.psyms.len - 1] = psym;
ps.ind_level_follow = ps.psyms.ind_level[ps.psyms.len - 1];
}
static int
left_justify_decl_level(void)
{
int level = 0;
for (size_t i = ps.psyms.len - 2; i > 0; i--)
if (ps.psyms.sym[i] == psym_decl)
level++;
return level;
}
void
ps_psyms_push(parser_symbol psym, int ind_level)
{
if (ps.psyms.len == ps.psyms.cap) {
ps.psyms.cap += 16;
ps.psyms.sym = nonnull(realloc(ps.psyms.sym,
sizeof(ps.psyms.sym[0]) * ps.psyms.cap));
ps.psyms.ind_level = nonnull(realloc(ps.psyms.ind_level,
sizeof(ps.psyms.ind_level[0]) * ps.psyms.cap));
}
ps.psyms.len++;
ps.psyms.sym[ps.psyms.len - 1] = psym;
ps.psyms.ind_level[ps.psyms.len - 1] = ind_level;
}
static void
psyms_reduce(void)
{
again:
if (ps.psyms.len >= 2 && ps.psyms.sym[ps.psyms.len - 1] == psym_stmt) {
switch (ps.psyms.sym[ps.psyms.len - 2]) {
case psym_decl:
case psym_stmt:
case psym_for_exprs:
case psym_if_expr_stmt_else:
case psym_switch_expr:
case psym_while_expr:
ps_psyms_replace2(psym_stmt);
goto again;
case psym_if_expr:
ps_psyms_replace2(psym_if_expr_stmt);
goto again;
case psym_do:
ps_psyms_replace2(psym_do_stmt);
goto again;
default:
return;
}
}
if (ps.psyms.sym[ps.psyms.len - 1] == psym_while_expr &&
ps.psyms.sym[ps.psyms.len - 2] == psym_do_stmt) {
ps.psyms.len -= 2;
goto again;
}
}
static bool
is_lbrace(parser_symbol psym)
{
return psym == psym_lbrace_block
|| psym == psym_lbrace_struct
|| psym == psym_lbrace_union
|| psym == psym_lbrace_enum;
}
void
parse(parser_symbol psym)
{
debug_blank_line();
debug_println("parse: %s", psym_name[psym]);
if (psym != psym_else) {
while (ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt) {
ps.psyms.sym[ps.psyms.len - 1] = psym_stmt;
psyms_reduce();
ps.ind_level = ps.ind_level_follow
= ps.psyms.ind_level[ps.psyms.len - 1];
}
}
switch (psym) {
case psym_lbrace_block:
case psym_lbrace_struct:
case psym_lbrace_union:
case psym_lbrace_enum:
ps.break_after_comma = false;
if (ps.psyms.sym[ps.psyms.len - 1] == psym_decl
|| ps.psyms.sym[ps.psyms.len - 1] == psym_stmt)
ps.ind_level_follow++;
else if (code.len == 0) {
ps.ind_level--;
if (ps.psyms.sym[ps.psyms.len - 1] == psym_switch_expr
&& opt.case_indent >= 1.0F)
ps.ind_level--;
}
ps_psyms_push(psym, ps.ind_level);
ps_psyms_push(psym_stmt, ps.ind_level_follow);
break;
case psym_rbrace:
if (!(ps.psyms.len >= 2
&& is_lbrace(ps.psyms.sym[ps.psyms.len - 2]))) {
diag(1, "Statement nesting error");
break;
}
ps_psyms_replace2(psym_stmt);
ps.ind_level = ps.ind_level_follow;
break;
case psym_decl:
if (ps.psyms.sym[ps.psyms.len - 1] == psym_decl)
break;
ps.break_after_comma = true;
ps_psyms_push(psym_decl, ps.ind_level_follow);
if (opt.left_justify_decl) {
ps.ind_level = left_justify_decl_level();
ps.ind_level_follow = ps.ind_level;
}
break;
case psym_stmt:
ps.break_after_comma = false;
ps_psyms_push(psym_stmt, ps.ind_level);
break;
case psym_if_expr:
if (ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt_else
&& opt.else_if_in_same_line) {
ps.ind_level_follow =
ps.psyms.ind_level[ps.psyms.len - 1];
ps.psyms.len--;
}
case psym_do:
case psym_for_exprs:
ps.ind_level = ps.ind_level_follow;
ps.ind_level_follow = ps.ind_level + 1;
ps_psyms_push(psym, ps.ind_level);
break;
case psym_else:
if (ps.psyms.sym[ps.psyms.len - 1] != psym_if_expr_stmt) {
diag(1, "Unmatched 'else'");
break;
}
ps.ind_level = ps.psyms.ind_level[ps.psyms.len - 1];
ps.ind_level_follow = ps.ind_level + 1;
ps.psyms.sym[ps.psyms.len - 1] = psym_if_expr_stmt_else;
break;
case psym_switch_expr:
ps_psyms_push(psym_switch_expr, ps.ind_level_follow);
ps.ind_level_follow += (int)opt.case_indent + 1;
break;
case psym_while_expr:
if (ps.psyms.sym[ps.psyms.len - 1] == psym_do_stmt) {
ps.ind_level = ps.psyms.ind_level[ps.psyms.len - 1];
ps.ind_level_follow = ps.ind_level;
ps_psyms_push(psym_while_expr, ps.ind_level);
} else {
ps_psyms_push(psym_while_expr, ps.ind_level_follow);
ps.ind_level_follow++;
}
break;
default:
diag(1, "Unknown code to parser");
return;
}
#if debug
static struct buffer before, after;
buf_clear(&before);
ps_psyms_to_string(&before, &ps);
#endif
psyms_reduce();
#if debug
buf_clear(&after);
ps_psyms_to_string(&after, &ps);
if (strcmp(before.s, after.s) != 0) {
debug_println("psyms before: %s", before.s);
debug_println("psyms after: %s", after.s);
} else
debug_println("psyms: %s", after.s);
#endif
}