extern 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 (); }
void print_comment () { register int column, format; enum codes comment_type; int start_column, found_column; int first_comment_line, right_margin; int boxed_comment, stars, blankline_delims, paragraph_break, merge_blank_comment_lines; int two_contiguous_comments = 0; int save_length = 0; char *save_ptr = 0; char *text_on_line = 0; char *line_break_ptr = 0; char *start_delim; char *line_preamble; int line_preamble_length, visible_preamble; int suppress_cdb = 0; /* GDB_HOOK_print_comment() */ /* Increment the parser stack, as we will store some things there for dump_line to use. */ inc_pstack (); /* Have to do it this way because this piece of shit program doesn't always place the last token code on the stack. */ if (*(token + 1) == '/') comment_type = cplus_comment; else comment_type = comment; /* First, decide what kind of comment this is: C++, C, or boxed C. Even if this appears to be a normal C comment, we may change our minds if we find a star in the right column of the second line, in which case that's a boxed comment too. */ if (comment_type == cplus_comment) { start_delim = "//"; line_preamble = "// "; line_preamble_length = 3; visible_preamble = 1; boxed_comment = 0; stars = 0; blankline_delims = 0; } else if (*buf_ptr == '*' || *buf_ptr == '-' || *buf_ptr == '=' || *buf_ptr == '_' || (parser_state_tos->col_1 && !format_col1_comments)) /* Boxed comment. This block of code will return. */ { int comment_lines_count = 1; found_column = start_column = current_column () - 2; parser_state_tos->box_com = 1; parser_state_tos->com_col = found_column; if (blanklines_before_blockcomments) prefix_blankline_requested = 1; *e_com++ = '/'; *e_com++ = '*'; while (1) { do { if (*buf_ptr == EOL) /* Count line numbers within comment blocks */ ++line_no; *e_com++ = *buf_ptr++; CHECK_COM_SIZE; } while (*buf_ptr != '*' && buf_ptr < buf_end); /* We have reached the end of the comment, and it's all on this line. */ if (*buf_ptr == '*' && *(buf_ptr + 1) == '/') { if (buf_ptr == buf_end) fill_buffer (); buf_ptr += 2; if (buf_ptr == buf_end) fill_buffer (); *e_com++ = '*'; *e_com++ = '/'; *e_com = '\0'; parser_state_tos->tos--; /* If this is the only line of a boxed comment, it may be after some other text (e.g., #if foo <comment>), in which case we want to specify the correct column. In the other cases, the leading spaces account for the columns and we start it in column 1. */ if (comment_lines_count > 1) parser_state_tos->com_col = 1; else parser_state_tos->com_col = found_column; return; } /* End of the line, or end of file. */ if (buf_ptr == buf_end) { if (*(buf_ptr - 1) == EOL) { *(--e_com) = '\0'; dump_line (true); comment_lines_count++; parser_state_tos->com_col = 1; } fill_buffer (); if (had_eof) { *e_com++ = '\0'; parser_state_tos->tos--; parser_state_tos->com_col = start_column; return; } } } } else { start_delim = "/*"; line_preamble = 0; line_preamble_length = 0; visible_preamble = 0; boxed_comment = 0; stars = star_comment_cont; blankline_delims = comment_delimiter_on_blankline; } paragraph_break = 0; merge_blank_comment_lines = 0; first_comment_line = com_lines; right_margin = comment_max_col; /* Now, compute the correct indentation for this comment and whether or not it should be formatted. */ found_column = current_column () - 2; if ((s_lab == e_lab) && (s_code == e_code)) /* First handle comments which begin the line. */ { if (parser_state_tos->col_1 && !format_col1_comments) { format = format_col1_comments; start_column = 1; } else if (s_com != e_com) /* The fool has a line consisting of two contiguous comments. In this case, we don't try too hard, 'cause nothing will look good. */ { format = 0; start_column = found_column; two_contiguous_comments = 1; } else { format = format_comments; if (parser_state_tos->ind_level <= 0 && (!parser_state_tos->in_stmt || (parser_state_tos->in_decl && parser_state_tos->paren_level == 0))) start_column = found_column; else /* This comment is within a procedure or other code. */ { start_column = compute_code_target () - unindent_displace; if (start_column < 0) start_column = 1; } } } else /* This comment follows code of some sort. */ { int target; suppress_cdb = 1; /* First, compute where the comment SHOULD go. */ if (parser_state_tos->decl_on_line) target = decl_com_ind; else if (else_or_endif) target = else_endif_col; else target = com_ind; /* Now determine if the code on the line is short enough to allow the comment to begin where it should. */ if (s_code != e_code) start_column = count_columns (compute_code_target (), s_code, NULL_CHAR); else /* s_lab != e_lab : there is a label here. */ start_column = count_columns (compute_label_target (), s_lab, NULL_CHAR); if (start_column < target) start_column = target; else { /* If the too-long code is a pre-processor command, start the comment 1 space afterwards, otherwise start at the next tab mark. */ if (else_or_endif) { start_column++; else_or_endif = false; } else start_column += tabsize - ((start_column - 1) % tabsize); } format = format_comments; } if (!line_preamble) { line_preamble_length = 3; if (stars) { line_preamble = " * "; visible_preamble = 1; } else { line_preamble = " "; visible_preamble = 0; } } /* These are the parser stack variables used to communicate formatting information to dump_line (). */ parser_state_tos->com_col = (two_contiguous_comments ? 1 : start_column); parser_state_tos->box_com = boxed_comment; /* Output the beginning comment delimiter. They are both two characters long. */ *e_com++ = *start_delim; *e_com++ = *(start_delim + 1); column = start_column + 2; /* If the user specified -cdb, put the delimiter on one line. */ if (blankline_delims && !suppress_cdb) { char *p = buf_ptr; *e_com = '\0'; dump_line (true); /* Check if the delimiter was already on a line by itself, and skip whitespace if formating. */ while (*p == ' ' || *p == TAB) p++; if (*p == EOL) buf_ptr = p + 1; else if (format) buf_ptr = p; if (buf_ptr >= buf_end) fill_buffer (); column = start_column; goto begin_line; } else if (format) { *e_com++ = ' '; column = start_column + 3; while (*buf_ptr == ' ' || *buf_ptr == TAB) if (++buf_ptr >= buf_end) fill_buffer (); } /* Iterate through the lines of the comment */ while (!had_eof) { /* Iterate through the characters on one line */ while (!had_eof) { CHECK_COM_SIZE; switch (*buf_ptr) { case ' ': case TAB: /* If formatting, and previous break marker is nonexistant, or before text on line, reset it to here. */ if (format && line_break_ptr < text_on_line) line_break_ptr = e_com; if (format) { /* Don't write two spaces after another, unless the first space it preceeded by a dot. */ if (e_com == s_com || e_com[-1] != ' ' || e_com - 1 == s_com || e_com[-2] == '.') { *e_com++ = ' '; column++; } } else if (*buf_ptr == ' ') { *e_com++ = ' '; column++; } else { /* Convert the tab to the appropriate number of spaces, based on the column we found the comment in, not the one we're printing in. */ int tab_width = (tabsize - ((column + found_column - start_column - 1) % tabsize)); column += tab_width; while (tab_width--) *e_com++ = ' '; } break; case EOL: /* We may be at the end of a C++ comment */ if (comment_type == cplus_comment) { cplus_exit: parser_state_tos->tos--; parser_state_tos->com_col = (two_contiguous_comments ? 1 : start_column); parser_state_tos->box_com = boxed_comment; *e_com = 0; return; } if (format) { /* Newline and null are the two characters which end an input line, so check here if we need to get the next line. */ if (*buf_ptr == EOL) ++line_no; buf_ptr++; if (buf_ptr >= buf_end) fill_buffer (); /* If there are any spaces between the text and this newline character, remove them. */ if (e_com > line_break_ptr && text_on_line < line_break_ptr) e_com = line_break_ptr; /* If this is "\n\n", or "\n<whitespace>\n", it's a paragraph break. */ while (*buf_ptr == TAB || *buf_ptr == ' ') if (++buf_ptr >= buf_end) fill_buffer (); if (*buf_ptr == EOL || !text_on_line) { paragraph_break = 1; goto end_line; } /* Also need to eat the preamble. */ if (!boxed_comment && current_column () == found_column + 1 && buf_ptr[0] == '*' && buf_ptr[1] != '/') { if (++buf_ptr >= buf_end) fill_buffer (); if (*buf_ptr == ' ' && ++buf_ptr >= buf_end) fill_buffer (); } /* This is a single newline. Transform it (and any following whitespace) into a single blank. */ if (e_com[-1] != ' ') { line_break_ptr = e_com; *e_com++ = ' '; column++; } continue; } /* We are printing this line "as is", so output it and continue on to the next line. */ goto end_line; case '*': /* Check if we've reached the end of the comment. */ if (comment_type == comment) { if (*(buf_ptr + 1) == '/') { /* If it's not a boxed comment, put some whitespace before the ending delimiter. Otherwise, simply insert the delimiter. */ if (!boxed_comment) { if (text_on_line) { if (blankline_delims && !suppress_cdb) { *e_com = '\0'; dump_line (true); *e_com++ = ' '; } else /* Insert space before closing delim */ if (*(e_com - 1) != ' ' && *(e_com - 1) != TAB) *e_com++ = ' '; } /* If no text on line, then line is completely empty or starts with preamble, or is beginning of comment and starts with beginning delimiter. */ else if (s_com == e_com || *s_com != '/') { e_com = s_com; *e_com++ = ' '; } else /* This is case of first comment line. Test with: if (first_comment_line != com_lines) abort (); */ if (*(e_com - 1) != ' ' && *(e_com - 1) != TAB) *e_com++ = ' '; } /* Now insert the ending delimiter */ *e_com++ = '*'; *e_com++ = '/'; *e_com = '\0'; /* Skip any whitespace following the comment. If there is only whitespace after it, print the line. NOTE: We're not printing the line: TRY IT! */ buf_ptr += 2; while (*buf_ptr == ' ' || *buf_ptr == TAB) buf_ptr++; if (buf_ptr >= buf_end) fill_buffer (); parser_state_tos->tos--; parser_state_tos->com_col = (two_contiguous_comments ? 1 : start_column); parser_state_tos->box_com = boxed_comment; return; } /* If this star is on the second line of the comment in the same column as the star of the beginning delimiter, then consider it a boxed comment. */ if (first_comment_line == com_lines - 1 && e_com == s_com + line_preamble_length && current_column () == found_column + 1) { /* Account for change in line_preamble_length: */ column -= line_preamble_length - 1; line_preamble = " "; line_preamble_length = 1; boxed_comment = 1; format = 0; blankline_delims = 0; *s_com = ' '; *(s_com + 1) = '*'; text_on_line = e_com = s_com + 2; column++; break; } } /* If it was not the end of the comment, drop through and insert the star on the line. */ default: /* Some textual character. */ text_on_line = e_com; *e_com++ = *buf_ptr; column++; break; } /* If we are formatting, check that we haven't exceeded the line length. If we haven't set line_break_ptr, keep going. */ if (format && column > right_margin && line_break_ptr) { if (line_break_ptr < e_com - 1) /* Here if we are really "breaking" the line: the line break is before some text we've seen. */ { *line_break_ptr = '\0'; save_ptr = line_break_ptr + 1; save_length = e_com - save_ptr; e_com = line_break_ptr; /* If we had to go past `right_margin' to print stuff out, extend `right_margin' out to this point. */ if ((column - save_length) > right_margin) right_margin = column - save_length; } else /* The line break is after the last text; we're really truncating the line. */ { if (comment_type == cplus_comment) { while (*buf_ptr == TAB || *buf_ptr == ' ') buf_ptr++; buf_ptr--; if (*buf_ptr == EOL) goto cplus_exit; } else { while (*buf_ptr == TAB || *buf_ptr == ' ' || *buf_ptr == EOL) buf_ptr++; buf_ptr--; } *e_com = '\0'; } goto end_line; } if (*buf_ptr == EOL) ++line_no; buf_ptr++; if (buf_ptr == buf_end) fill_buffer (); } end_line: /* Compress pure whitespace lines into newlines. */ if (!text_on_line && !visible_preamble && !(first_comment_line == com_lines)) e_com = s_com; *e_com = '\0'; dump_line (true); /* We're in the middle of a C-comment, don't add blank lines! */ prefix_blankline_requested = 0; /* If formatting (paragraph_break is only used for formatted comments) and user wants blank lines merged, kill all white space after the "\n\n" indicating a paragraph break. */ if (paragraph_break) { if (merge_blank_comment_lines) while (*buf_ptr == EOL || *buf_ptr == ' ' || *buf_ptr == TAB) { if (*buf_ptr == EOL) ++line_no; if (++buf_ptr >= buf_end) fill_buffer (); } paragraph_break = 0; } else { /* If it was a paragraph break (`if' clause), we scanned ahead one character. So, here in the `else' clause, advance buf_ptr. */ if (*buf_ptr == EOL) ++line_no; buf_ptr++; if (buf_ptr >= buf_end) fill_buffer (); } begin_line: if (had_eof) break; /* Indent the line properly. If it's a boxed comment, align with the '*' in the beginning slash-star and start inserting there. Otherwise, insert blanks for alignment, or a star if the user specified -sc. */ if (line_preamble) { (void) memcpy (e_com, line_preamble, line_preamble_length); e_com += line_preamble_length; column = start_column + line_preamble_length; } else column = start_column; line_break_ptr = 0; /* If we have broken the line before the end for formatting, copy the text after the break onto the beginning of this new comment line. */ if (save_ptr) { while ((*save_ptr == ' ' || *save_ptr == TAB) && save_length) { save_ptr++; save_length--; } (void) memcpy (e_com, save_ptr, save_length); text_on_line = e_com; e_com += save_length; /* We only break if formatting, in which cases there are no tabs, only spaces. */ column += save_length; save_ptr = 0; save_length = 0; } else { while (*buf_ptr == ' ' || *buf_ptr == TAB) if (++buf_ptr >= buf_end) fill_buffer (); text_on_line = 0; } } parser_state_tos->tos--; parser_state_tos->com_col = (two_contiguous_comments ? 1 : start_column); parser_state_tos->box_com = boxed_comment; }
extern 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]; } /* fall through */ 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 <lbrace> <stmt> or <lbrace> <stmtl> */ 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; }