/* Copyright (c) 1999, 2000 Carlo Wood. All rights reserved. * Copyright (c) 1994 Joseph Arceneaux. All rights reserved. * Copyright (c) 1985 Sun Microsystems, Inc. Copyright (c) 1980 The Regents * of the University of California. Copyright (c) 1976 Board of Trustees of * the University of Illinois. All rights reserved. * * Redistribution and use in source and binary forms are permitted provided * that the above copyright notice and this paragraph are duplicated in all * such forms and that any documentation, advertising materials, and other * materials related to such distribution and use acknowledge that the * software was developed by the University of California, Berkeley, the * University of Illinois, Urbana, and Sun Microsystems, Inc. The name of * either University or Sun Microsystems may not be used to endorse or * promote products derived from this software without specific prior written * permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include "sys.h" #include "indent.h" #include "parse.h" #include "globs.h" RCSTAG_CC ("$Id: parse.c,v 1.31 2002/08/04 17:08:41 david Exp $"); parser_state_ty *parser_state_tos = NULL; #define INITIAL_BUFFER_SIZE 1000 #define INITIAL_STACK_SIZE 2 void init_parser (void) { parser_state_tos = (parser_state_ty *) xmalloc (sizeof (parser_state_ty)); /* GDB_HOOK_parser_state_tos */ parser_state_tos->p_stack_size = INITIAL_STACK_SIZE; parser_state_tos->p_stack = (codes_ty *) xmalloc (INITIAL_STACK_SIZE * sizeof (codes_ty)); parser_state_tos->il = (int *) xmalloc (INITIAL_STACK_SIZE * sizeof (int)); parser_state_tos->cstk = (int *) xmalloc (INITIAL_STACK_SIZE * sizeof (int)); parser_state_tos->paren_indents_size = 8; parser_state_tos->paren_indents = (short *) xmalloc (parser_state_tos->paren_indents_size * sizeof (short)); /* Although these are supposed to grow if we reach the end, * I can find no place in the code which does this. */ combuf = (char *) xmalloc (INITIAL_BUFFER_SIZE); labbuf = (char *) xmalloc (INITIAL_BUFFER_SIZE); codebuf = (char *) xmalloc (INITIAL_BUFFER_SIZE); save_com.size = INITIAL_BUFFER_SIZE; save_com.end = save_com.ptr = xmalloc (save_com.size); save_com.len = save_com.column = 0; di_stack_alloc = 2; di_stack = (int *) xmalloc (di_stack_alloc * sizeof (*di_stack)); } void reset_parser (void) { parser_state_tos->next = 0; parser_state_tos->tos = 0; parser_state_tos->p_stack[0] = stmt; /* this is the parser's stack */ parser_state_tos->last_nl = true; /* this is true if the last thing * scanned was a newline */ parser_state_tos->last_token = start_token; parser_state_tos->last_saw_nl = false; parser_state_tos->broken_at_non_nl = false; parser_state_tos->box_com = false; parser_state_tos->cast_mask = 0; parser_state_tos->noncast_mask = 0; parser_state_tos->sizeof_mask = 0; parser_state_tos->block_init = 0; parser_state_tos->block_init_level = 0; parser_state_tos->col_1 = false; parser_state_tos->com_col = 0; parser_state_tos->dec_nest = 0; parser_state_tos->i_l_follow = 0; parser_state_tos->ind_level = 0; parser_state_tos->last_u_d = false; parser_state_tos->p_l_follow = 0; parser_state_tos->paren_level = 0; parser_state_tos->paren_depth = 0; parser_state_tos->search_brace = false; parser_state_tos->use_ff = false; parser_state_tos->its_a_keyword = false; parser_state_tos->sizeof_keyword = false; parser_state_tos->in_parameter_declaration = false; parser_state_tos->just_saw_decl = 0; parser_state_tos->in_decl = false; parser_state_tos->decl_on_line = false; parser_state_tos->in_or_st = 0; parser_state_tos->want_blank = false; parser_state_tos->in_stmt = false; parser_state_tos->ind_stmt = false; parser_state_tos->procname = "\0"; parser_state_tos->procname_end = "\0"; parser_state_tos->classname = "\0"; parser_state_tos->classname_end = "\0"; parser_state_tos->pcase = false; parser_state_tos->dec_nest = 0; parser_state_tos->can_break = bb_none; parser_state_tos->saw_double_colon = false; parser_state_tos->il[0] = 0; parser_state_tos->cstk[0] = 0; save_com.len = save_com.column = 0; di_stack[parser_state_tos->dec_nest] = 0; l_com = combuf + INITIAL_BUFFER_SIZE - 5; l_lab = labbuf + INITIAL_BUFFER_SIZE - 5; l_code = codebuf + INITIAL_BUFFER_SIZE - 5; combuf[0] = codebuf[0] = labbuf[0] = ' '; combuf[1] = codebuf[1] = labbuf[1] = '\0'; else_or_endif = false; s_lab = e_lab = labbuf + 1; s_code = e_code = codebuf + 1; s_com = e_com = combuf + 1; line_no = 1; had_eof = false; break_comma = false; bp_save = 0; be_save = 0; if (settings.tabsize <= 0) { settings.tabsize = 1; } prefix_blankline_requested = 0; } /* like ++parser_state_tos->tos but checks for stack overflow and extends * stack if necessary. */ int inc_pstack (void) { if (++parser_state_tos->tos >= parser_state_tos->p_stack_size) { parser_state_tos->p_stack_size *= 2; parser_state_tos->p_stack = (codes_ty *) xrealloc ((char *) parser_state_tos->p_stack, parser_state_tos->p_stack_size * sizeof (codes_ty)); parser_state_tos->il = (int *) xrealloc ((char *) parser_state_tos->il, parser_state_tos->p_stack_size * sizeof (int)); parser_state_tos->cstk = (int *) xrealloc ((char *) parser_state_tos->cstk, parser_state_tos->p_stack_size * sizeof (int)); } parser_state_tos->cstk[parser_state_tos->tos] = parser_state_tos->cstk[parser_state_tos->tos - 1]; return parser_state_tos->tos; } #ifdef DEBUG static char **debug_symbol_strings; void debug_init (void) { int size = ((int) number_of_codes) * sizeof (char *); debug_symbol_strings = (char **) xmalloc (size); debug_symbol_strings[code_eof] = "code_eof"; debug_symbol_strings[newline] = "newline"; debug_symbol_strings[lparen] = "lparen"; debug_symbol_strings[rparen] = "rparen"; debug_symbol_strings[start_token] = "start_token"; debug_symbol_strings[unary_op] = "unary_op"; debug_symbol_strings[binary_op] = "binary_op"; debug_symbol_strings[postop] = "postop"; debug_symbol_strings[question] = "question"; debug_symbol_strings[casestmt] = "casestmt"; debug_symbol_strings[colon] = "colon"; debug_symbol_strings[doublecolon] = "doublecolon"; debug_symbol_strings[semicolon] = "semicolon"; debug_symbol_strings[lbrace] = "lbrace"; debug_symbol_strings[rbrace] = "rbrace"; debug_symbol_strings[ident] = "ident"; debug_symbol_strings[overloaded] = "overloaded"; debug_symbol_strings[cpp_operator] = "cpp_operator"; debug_symbol_strings[comma] = "comma"; debug_symbol_strings[comment] = "comment"; debug_symbol_strings[cplus_comment] = "cplus_comment"; debug_symbol_strings[swstmt] = "swstmt"; debug_symbol_strings[preesc] = "preesc"; debug_symbol_strings[form_feed] = "form_feed"; debug_symbol_strings[decl] = "decl"; debug_symbol_strings[sp_paren] = "sp_paren"; debug_symbol_strings[sp_nparen] = "sp_nparen"; debug_symbol_strings[sp_else] = "sp_else"; debug_symbol_strings[ifstmt] = "ifstmt"; debug_symbol_strings[elseifstmt] = "elseifstmt"; debug_symbol_strings[whilestmt] = "whilestmt"; debug_symbol_strings[forstmt] = "forstmt"; debug_symbol_strings[stmt] = "stmt"; debug_symbol_strings[stmtl] = "stmtl"; debug_symbol_strings[elselit] = "elselit"; debug_symbol_strings[dolit] = "dolit"; debug_symbol_strings[dohead] = "dohead"; debug_symbol_strings[dostmt] = "dostmt"; debug_symbol_strings[ifhead] = "ifhead"; debug_symbol_strings[elsehead] = "elsehead"; debug_symbol_strings[struct_delim] = "struct_delim"; debug_symbol_strings[attribute] = "attribute"; } #endif exit_values_ty parse ( codes_ty tk) /* the code for the construct scanned */ { int i; #ifdef DEBUG if (debug) { if (tk >= code_eof && tk < number_of_codes) { printf ("Parse: %s\n", debug_symbol_strings[tk]); } else { printf ("Parse: Unknown code: %d for %s\n", (int) tk, token ? token : "NULL"); } } #endif while ((parser_state_tos->p_stack[parser_state_tos->tos] == ifhead) && (tk != elselit)) { /* true if we have an if without an else */ /* apply the if(..) stmt ::= stmt reduction */ parser_state_tos->p_stack[parser_state_tos->tos] = stmt; reduce (); /* see if this allows any reduction */ } switch (tk) { /* go on and figure out what to do with the input */ case decl: /* scanned a declaration word */ parser_state_tos->search_brace = settings.braces_on_struct_decl_line; /* indicate that following brace should be on same line */ if ((parser_state_tos->p_stack[parser_state_tos->tos] != decl) && (parser_state_tos->block_init == 0)) { /* only put one declaration onto stack */ break_comma = true; /* while in declaration, newline should be * forced after comma */ inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = decl; parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; if (settings.ljust_decl) { /* only do if we want left justified * declarations */ parser_state_tos->ind_level = 0; for (i = parser_state_tos->tos - 1; i > 0; --i) { if (parser_state_tos->p_stack[i] == decl) { /* indentation is number of declaration levels deep we are * times spaces per level */ parser_state_tos->ind_level += settings.ind_size; } } parser_state_tos->i_l_follow = parser_state_tos->ind_level; } } break; case ifstmt: /* scanned if (...) */ if (parser_state_tos->p_stack[parser_state_tos->tos] == elsehead) { parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos]; } case dolit: /* 'do' */ case forstmt: /* for (...) */ case casestmt: /* case n: */ inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = tk; parser_state_tos->ind_level = parser_state_tos->i_l_follow; parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level; if (tk != casestmt) { parser_state_tos->i_l_follow += settings.ind_size; /* subsequent statements * should be indented */ } parser_state_tos->search_brace = settings.btype_2; break; case lbrace: /* scanned { */ break_comma = false; /* don't break comma in an initial list */ if (parser_state_tos->p_stack[parser_state_tos->tos] == stmt || parser_state_tos->p_stack[parser_state_tos->tos] == stmtl) { /* it is a random, isolated stmt group or a declaration */ parser_state_tos->i_l_follow += settings.ind_size; } else if (parser_state_tos->p_stack[parser_state_tos->tos] == decl) { parser_state_tos->i_l_follow += settings.ind_size; if ( ( (parser_state_tos->last_rw == rw_struct_like) || (parser_state_tos->last_rw == rw_enum)) && ( (parser_state_tos->block_init != 1) || (parser_state_tos->block_init_level == 0)) && (parser_state_tos->last_token != rparen) && (!settings.braces_on_struct_decl_line)) { parser_state_tos->ind_level += settings.struct_brace_indent; parser_state_tos->i_l_follow += settings.struct_brace_indent; } } else if (parser_state_tos->p_stack[parser_state_tos->tos] == casestmt) { parser_state_tos->ind_level += settings.case_brace_indent - settings.ind_size; parser_state_tos->i_l_follow += settings.case_brace_indent; } else { /* It is a group as part of a while, for, etc. */ /* Only do this if there is nothing on the line */ if (s_code == e_code) { parser_state_tos->ind_level -= settings.ind_size; } /* For -bl formatting, indent by settings.brace_indent additional spaces * e.g. if (foo == bar) { <--> settings.brace_indent spaces (in this * example, 4) */ if (!settings.btype_2) { parser_state_tos->ind_level += settings.brace_indent; parser_state_tos->i_l_follow += settings.brace_indent; } if (parser_state_tos->p_stack[parser_state_tos->tos] == swstmt) { parser_state_tos->i_l_follow += settings.case_indent; } } inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = lbrace; parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level; inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = stmt; /* allow null stmt between braces */ parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; break; case whilestmt: /* scanned while (...) */ if (parser_state_tos->p_stack[parser_state_tos->tos] == dohead) { /* it is matched with do stmt */ parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos]; parser_state_tos->ind_level = parser_state_tos->il[parser_state_tos->tos]; inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = whilestmt; parser_state_tos->ind_level = parser_state_tos->i_l_follow; parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; } else { /* it is a while loop */ inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = whilestmt; parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; parser_state_tos->i_l_follow += settings.ind_size; parser_state_tos->search_brace = settings.btype_2; } break; case elselit: /* scanned an else */ if (parser_state_tos->p_stack[parser_state_tos->tos] != ifhead) { ERROR (_("Unmatched 'else'"), 0, 0); } else { /* indentation for else should be same as for if */ parser_state_tos->ind_level = parser_state_tos->il[parser_state_tos->tos]; /* everything following should be in 1 level */ parser_state_tos->i_l_follow = (parser_state_tos->ind_level + settings.ind_size); parser_state_tos->p_stack[parser_state_tos->tos] = elsehead; /* remember if with else */ parser_state_tos->search_brace = true; } break; case rbrace: /* scanned a } */ /* stack should have or */ if (parser_state_tos->p_stack[parser_state_tos->tos - 1] == lbrace) { parser_state_tos->i_l_follow = parser_state_tos->il[--parser_state_tos->tos]; parser_state_tos->ind_level = parser_state_tos->i_l_follow; parser_state_tos->p_stack[parser_state_tos->tos] = stmt; } else { ERROR (_("Stmt nesting error."), 0, 0); } break; case swstmt: /* had switch (...) */ inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = swstmt; parser_state_tos->cstk[parser_state_tos->tos] = settings.case_indent + parser_state_tos->i_l_follow; if (!settings.btype_2) { parser_state_tos->cstk[parser_state_tos->tos] += settings.brace_indent; } /* save current case indent level */ parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; /* case labels should be one level down from switch, plus * `settings.case_indent' if any. Then, statements should be the `settings.ind_size' * further. */ parser_state_tos->i_l_follow += settings.ind_size; parser_state_tos->search_brace = settings.btype_2; break; case semicolon: /* this indicates a simple stmt */ break_comma = false; /* turn off flag to break after commas in a * declaration */ if (parser_state_tos->p_stack[parser_state_tos->tos] == dostmt) { parser_state_tos->p_stack[parser_state_tos->tos] = stmt; } else { inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = stmt; parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level; } break; /* This is a fatal error which cases the program to exit. */ default: fatal (_("Unknown code to parser"), 0); } reduce (); /* see if any reduction can be done */ #ifdef DEBUG if (debug) { printf ("\n"); printf (_("ParseStack [%d]:\n"), (int) parser_state_tos->p_stack_size); for (i = 1; i <= parser_state_tos->tos; ++i) { printf (_(" stack[%d] => stack: %d ind_level: %d\n"), (int) i, (int) parser_state_tos->p_stack[i], (int) parser_state_tos->il[i]); } printf ("\n"); } #endif return total_success; } /* NAME: reduce * * FUNCTION: Implements the reduce part of the parsing algorithm * * ALGORITHM: The following reductions are done. Reductions are repeated until * no more are possible. * * Old TOS New TOS * do dohead * if "ifstmt" switch * decl "ifelse" for * while * "dostmt" while * * On each reduction, parser_state_tos->i_l_follow (the indentation for the * following line) is set to the indentation level associated with the old * TOS. * * PARAMETERS: None * * RETURNS: Nothing * * GLOBALS: parser_state_tos->cstk parser_state_tos->i_l_follow = * parser_state_tos->il parser_state_tos->p_stack = parser_state_tos->tos = * * CALLS: None * * CALLED BY: parse * * HISTORY: initial coding November 1976 D A Willcox of CAC * */ /*----------------------------------------------*\ | REDUCTION PHASE | \*----------------------------------------------*/ void reduce (void) { int i; for (;;) { /* keep looping until there is nothing left to reduce */ switch (parser_state_tos->p_stack[parser_state_tos->tos]) { case stmt: switch (parser_state_tos->p_stack[parser_state_tos->tos - 1]) { case stmt: case stmtl: /* stmtl stmt or stmt stmt */ parser_state_tos->p_stack[--parser_state_tos->tos] = stmtl; break; case dolit: /* */ parser_state_tos->p_stack[--parser_state_tos->tos] = dohead; parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos]; break; case ifstmt: /* */ parser_state_tos->p_stack[--parser_state_tos->tos] = ifhead; for (i = parser_state_tos->tos - 1; ( (parser_state_tos->p_stack[i] != stmt) && (parser_state_tos->p_stack[i] != stmtl) && (parser_state_tos->p_stack[i] != lbrace)); --i) { } parser_state_tos->i_l_follow = parser_state_tos->il[i]; /* for the time being, we will assume that there is no else on * this if, and set the indentation level accordingly. If an * else is scanned, it will be fixed up later */ break; case swstmt: /* */ case decl: /* finish of a declaration */ case elsehead: /* < else> */ case forstmt: /* */ case casestmt: /* */ case whilestmt: /* */ parser_state_tos->p_stack[--parser_state_tos->tos] = stmt; parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos]; break; default: /* */ return; } /* end of section for on top of stack */ break; case whilestmt: /* while (...) on top */ if (parser_state_tos->p_stack[parser_state_tos->tos - 1] == dohead) { /* it is termination of a do while */ parser_state_tos->p_stack[--parser_state_tos->tos] = dostmt; break; } else return; default: /* anything else on top */ return; } } } /* This kludge is called from main. It is just like parse(semicolon) except * that it does not clear break_comma. Leaving break_comma alone is * necessary to make sure that "int foo(), bar()" gets formatted correctly * under -bc. */ void parse_lparen_in_decl (void) { inc_pstack (); parser_state_tos->p_stack[parser_state_tos->tos] = stmt; parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level; reduce (); }