Path: utzoo!attcan!uunet!lll-winken!csd4.milw.wisc.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!ucsd!nosc!cod!hall From: hall@cod.NOSC.MIL (Robert R. Hall) Newsgroups: comp.os.minix Subject: INDENT (part 2 of 2) Keywords: indent pretty-print formatter Message-ID: <1462@cod.NOSC.MIL> Date: 25 Mar 89 15:11:05 GMT Organization: Naval Ocean Systems Center, San Diego Lines: 2299 I tested indent out by formating the code presented here. I recomment you avoid using it on MINIX version 1.3 stuff for fear of making patch fail when on updates are released. ------------------- cut here ---------------------- echo x - args.c sed '/^X/s///' > args.c << '/' X/* X * Copyright (c) 1985 Sun Microsystems, Inc. X * Copyright (c) 1980 The Regents of the University of California. X * Copyright (c) 1976 Board of Trustees of the University of Illinois. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley, the University of Illinois, X * Urbana, and Sun Microsystems, Inc. The name of either University X * or Sun Microsystems may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)args.c 5.6 (Berkeley) 9/15/88"; X#endif /* not lint */ X X/* X * Argument scanning and profile reading code. Default parameters are set X * here as well. X */ X X#define PUBLIC extern X#include "globs.h" X#include X#include X Xchar * X getenv(), *index(); X X/* profile types */ X#define PRO_SPECIAL 1 /* special case */ X#define PRO_BOOL 2 /* boolean */ X#define PRO_INT 3 /* integer */ X#define PRO_FONT 4 /* troff font */ X X/* profile specials for booleans */ X#define ON 1 /* turn it on */ X#define OFF 0 /* turn it off */ X X/* profile specials for specials */ X#define IGN 1 /* ignore it */ X#define CLI 2 /* case label indent (float) */ X#define STDIN 3 /* use stdin */ X#define KEY 4 /* type (keyword) */ X X/* X * N.B.: because of the way the table here is scanned, options whose names are X * substrings of other options must occur later; that is, with -lp vs -l, -lp X * must be first. Also, while (most) booleans occur more than once, the last X * default value is the one actually assigned. X */ Xstruct pro X{ X char *p_name; /* name, eg -bl, -cli */ X int p_type; /* type (int, bool, special) */ X int p_default; /* the default value (if int) */ X int p_special; /* depends on type */ X int *p_obj; /* the associated variable */ X} pro[] = X X{ X X "T", PRO_SPECIAL, 0, KEY, 0, X "bacc", PRO_BOOL, false, ON, &bl_around, X "badp", PRO_BOOL, false, ON, &bl_at_proctop, X "bad", PRO_BOOL, false, ON, &bl_aft_decl, X "bap", PRO_BOOL, false, ON, &bl_a_procs, X "bbb", PRO_BOOL, false, ON, &bl_bef_bk, X "bc", PRO_BOOL, true, OFF, &ps.leave_comma, X "bl", PRO_BOOL, true, OFF, &btype_2, X "br", PRO_BOOL, true, ON, &btype_2, X "bs", PRO_BOOL, false, ON, &Bill_Shannon, X "cdb", PRO_BOOL, true, ON, &del_on_bl, X "cd", PRO_INT, 0, 0, &ps.decl_com_ind, X "ce", PRO_BOOL, true, ON, &cuddle_else, X "ci", PRO_INT, 0, 0, &continuation_indent, X "cli", PRO_SPECIAL, 0, CLI, 0, X "c", PRO_INT, 33, 0, &ps.com_ind, X "di", PRO_INT, 16, 0, &ps.decl_indent, X "dj", PRO_BOOL, false, ON, &ps.ljust_decl, X "d", PRO_INT, 0, 0, &ps.unindent_displace, X "eei", PRO_BOOL, false, ON, &ex_expr_indent, X "ei", PRO_BOOL, true, ON, &ps.else_if, X "fbc", PRO_FONT, 0, 0, (int *) &blkcomf, X "fbx", PRO_FONT, 0, 0, (int *) &boxcomf, X "fb", PRO_FONT, 0, 0, (int *) &bodyf, X "fc1", PRO_BOOL, true, ON, &format_col1_comments, X "fc", PRO_FONT, 0, 0, (int *) &scomf, X "fk", PRO_FONT, 0, 0, (int *) &keywordf, X "fs", PRO_FONT, 0, 0, (int *) &stringf, X "ip", PRO_BOOL, true, ON, &ps.indent_parameters, X "i", PRO_INT, 8, 0, &ps.ind_size, X "lc", PRO_INT, 0, 0, &bk_max_col, X "lp", PRO_BOOL, true, ON, &lineup_to_parens, X "l", PRO_INT, 78, 0, &max_col, X "nbacc", PRO_BOOL, false, OFF, &bl_around, X "nbadp", PRO_BOOL, false, OFF, &bl_at_proctop, X "nbad", PRO_BOOL, false, OFF, &bl_aft_decl, X "nbap", PRO_BOOL, false, OFF, &bl_a_procs, X "nbbb", PRO_BOOL, false, OFF, &bl_bef_bk, X "nbc", PRO_BOOL, true, ON, &ps.leave_comma, X "nbs", PRO_BOOL, false, OFF, &Bill_Shannon, X "ncdb", PRO_BOOL, true, OFF, &del_on_bl, X "nce", PRO_BOOL, true, OFF, &cuddle_else, X "ndj", PRO_BOOL, false, OFF, &ps.ljust_decl, X "neei", PRO_BOOL, false, OFF, &ex_expr_indent, X "nei", PRO_BOOL, true, OFF, &ps.else_if, X "nfc1", PRO_BOOL, true, OFF, &format_col1_comments, X "nip", PRO_BOOL, true, OFF, &ps.indent_parameters, X "nlp", PRO_BOOL, true, OFF, &lineup_to_parens, X "npcs", PRO_BOOL, false, OFF, &proc_calls_space, X "npro", PRO_SPECIAL, 0, IGN, 0, X "npsl", PRO_BOOL, true, OFF, &proc_str_line, X "nps", PRO_BOOL, false, OFF, &ptr_binop, X "nsc", PRO_BOOL, true, OFF, &star_comment_cont, X "nsob", PRO_BOOL, false, OFF, &swallow_opt_bl, X "nv", PRO_BOOL, false, OFF, &verbose, X "pcs", PRO_BOOL, false, ON, &proc_calls_space, X "psl", PRO_BOOL, true, ON, &proc_str_line, X "ps", PRO_BOOL, false, ON, &ptr_binop, X "sc", PRO_BOOL, true, ON, &star_comment_cont, X "sob", PRO_BOOL, false, ON, &swallow_opt_bl, X "st", PRO_SPECIAL, 0, STDIN, 0, X "troff", PRO_BOOL, false, ON, &troff, X "v", PRO_BOOL, false, ON, &verbose, X /* whew! */ X 0, 0, 0, 0, 0 X}; X X/* X * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments X * given in these files. X */ Xset_profile() X{ X register FILE *f; X char fname[BUFSIZ]; X static char prof[] = ".indent.pro"; X X sprintf(fname, "%s/%s", getenv("HOME"), prof); X if ((f = fopen(fname, "r")) != NULL) X { X scan_profile(f); X (void) fclose(f); X } X if ((f = fopen(prof, "r")) != NULL) X { X scan_profile(f); X (void) fclose(f); X } X} X Xscan_profile(f) X register FILE *f; X{ X register int i; X register char *p; X char buf[BUFSIZ]; X X while (1) X { X for (p = buf; (i = getc(f)) != EOF && (*p = i) > ' '; ++p); X if (p != buf) X { X *p++ = 0; X if (verbose) X printf("profile: %s\n", buf); X set_option(buf); X } else if (i == EOF) X return; X } X} X Xchar *param_start; X Xeqin(s1, s2) X register char *s1; X register char *s2; X{ X while (*s1) X { X if (*s1++ != *s2++) X return (false); X } X param_start = s2; X return (true); X} X X/* X * Set the defaults. X */ Xset_defaults() X{ X register struct pro *p; X X /* Because ps.case_indent is a float, we can't initialize it from X the table: */ X ps.case_indent = 0; /* -cli0.0 */ X for (p = pro; p->p_name; p++) X if (p->p_type != PRO_SPECIAL && p->p_type != PRO_FONT) X *p->p_obj = p->p_default; X} X Xset_option(arg) X register char *arg; X{ X register struct pro *p; X extern int atoi(); X X arg++; /* ignore leading "-" */ X for (p = pro; p->p_name; p++) X if (*p->p_name == *arg && eqin(p->p_name, arg)) X goto found; X fprintf(stderr, "indent: unknown parameter \"%s\"\n", arg - 1); X exit(1); Xfound: X switch (p->p_type) X { X X case PRO_SPECIAL: X switch (p->p_special) X { X X case IGN: X break; X X case CLI: X if (*param_start == 0) X goto need_param; X ps.case_indent = atoi(param_start); X break; X X case STDIN: X if (input == 0) X input = stdin; X if (output == 0) X output = stdout; X break; X X case KEY: X if (*param_start == 0) X goto need_param; X { X register char *str = (char *) malloc(strlen(param_start) + 1); X strcpy(str, param_start); X addkey(str, 4); X } X break; X X default: X fprintf(stderr, "\ Xindent: set_option: internal error: p_special %d\n", p->p_special); X exit(1); X } X break; X X case PRO_BOOL: X if (p->p_special == OFF) X *p->p_obj = false; X else X *p->p_obj = true; X break; X X case PRO_INT: X if (*param_start == 0) X { X need_param: X fprintf(stderr, "indent: ``%s'' requires a parameter\n", X arg - 1); X exit(1); X } X *p->p_obj = atoi(param_start); X break; X X case PRO_FONT: X parsefont((struct fstate *) p->p_obj, param_start); X break; X X default: X fprintf(stderr, "indent: set_option: internal error: p_type %d\n", X p->p_type); X exit(1); X } X} / echo x - comment.c sed '/^X/s///' > comment.c << '/' X/* X * Copyright (c) 1985 Sun Microsystems, Inc. X * Copyright (c) 1980 The Regents of the University of California. X * Copyright (c) 1976 Board of Trustees of the University of Illinois. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley, the University of Illinois, X * Urbana, and Sun Microsystems, Inc. The name of either University X * or Sun Microsystems may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)pr_comment.c 5.9 (Berkeley) 9/15/88"; X#endif /* not lint */ X X/* X * NAME: X * pr_comment X * X * FUNCTION: X * This routine takes care of scanning and printing comments. X * X * ALGORITHM: X * 1) Decide where the comment should be aligned, and if lines should X * be broken. X * 2) If lines should not be broken and filled, just copy up to end of X * comment. X * 3) If lines should be filled, then scan thru input_buffer copying X * characters to com_buf. Remember where the last blank, tab, or X * newline was. When line is filled, print up to last blank and X * continue copying. X * X * HISTORY: X * November 1976 D A Willcox of CAC Initial coding X * 12/6/76 D A Willcox of CAC Modification to handle X * UNIX-style comments X * X */ X X/* X * this routine processes comments. It makes an attempt to keep comments from X * going over the max line length. If a line is too long, it moves everything X * from the last blank to the next comment line. Blanks and tabs from the X * beginning of the input line are removed X */ X X X#define PUBLIC extern X#include "globs.h" X X Xpr_comment() X{ X int now_col; /* column we are in now */ X int adj_max_col; /* Adjusted max_col for when we X decide to spill comments X over the right margin */ X char *last_bl; /* points to the last blank in X the output buffer */ X char *t_ptr; /* used for moving string */ X int unix_comment; /* tri-state variable used to X decide if it is a unix-style X comment. 0 means only blanks X since /*, 1 means regular X style comment, 2 means unix X style comment */ X int break_delim = del_on_bl; X int l_just_saw_decl = ps.just_saw_decl; X /* int ps.last_nl = 0; /* true iff the last X significant thing weve seen is a newline */ X int one_liner = 1; /* true iff this comment is a X one-liner */ X adj_max_col = max_col; X ps.just_saw_decl = 0; X last_bl = 0; /* no blanks found so far */ X ps.box_com = false; /* at first, assume that we are X not in a boxed comment or X some other comment that X should not be touched */ X ++ps.out_coms; /* keep track of number of X comments */ X unix_comment = 1; /* set flag to let us figure X out if there is a unix-style X comment ** DISABLED: use 0 X to reenable this hack! */ X X /* Figure where to align and how to treat the comment */ X X if (ps.col_1 && !format_col1_comments) X { /* if comment starts in column X 1 it should not be touched */ X ps.box_com = true; X ps.com_col = 1; X } else X { X if (*buf_ptr == '-' || *buf_ptr == '*') X { X ps.box_com = true; /* a comment with a '-' or '*' X immediately after the /* is X assumed to be a boxed X comment */ X break_delim = 0; X } X if ( /* ps.bl_line && */ (s_lab == e_lab) && (s_code == e_code)) X { X /* klg: check only if this line is blank */ X /* If this (*and previous lines are*) blank, dont put comment X way out at left */ X ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1; X adj_max_col = bk_max_col; X if (ps.com_col <= 1) X ps.com_col = 1 + !format_col1_comments; X } else X { X register target_col; X break_delim = 0; X if (s_code != e_code) X target_col = count_spaces(code_target(), s_code); X else X { X target_col = 1; X if (s_lab != e_lab) X target_col = count_spaces(label_target(), s_lab); X } X ps.com_col = ps.decl_on_line || ps.ind_level == 0 ? ps.decl_com_ind : ps.com_ind; X if (ps.com_col < target_col) X ps.com_col = ((target_col + 7) & ~7) + 1; X if (ps.com_col + 24 > adj_max_col) X adj_max_col = ps.com_col + 24; X } X } X if (ps.box_com) X { X buf_ptr[-2] = 0; X ps.n_comment_delta = 1 - count_spaces(1, in_buffer); X buf_ptr[-2] = '/'; X } else X { X ps.n_comment_delta = 0; X while (*buf_ptr == ' ' || *buf_ptr == '\t') X buf_ptr++; X } X ps.comment_delta = 0; X *e_com++ = '/'; /* put '/*' into buffer */ X *e_com++ = '*'; X if (*buf_ptr != ' ' && !ps.box_com) X *e_com++ = ' '; X X *e_com = '\0'; X if (troff) X { X now_col = 1; X adj_max_col = 80; X } else X now_col = count_spaces(ps.com_col, s_com); /* figure what column we X would be in if we X printed the comment X now */ X X /* Start to copy the comment */ X X while (1) X { /* this loop will go until the X comment is copied */ X if (*buf_ptr > 040 && *buf_ptr != '*') X ps.last_nl = 0; X if (e_com >= l_com) X { X register nsize = l_com - s_com + 400; X combuf = (char *) realloc(combuf, nsize); X e_com = combuf + (e_com - s_com) + 1; X l_com = combuf + nsize - 5; X s_com = combuf + 1; X } X switch (*buf_ptr) X { /* this checks for various spcl X cases */ X case 014: /* check for a form feed */ X if (!ps.box_com) X { /* in a text comment, break the X line here */ X ps.use_ff = true; X /* fix so dump_line uses a form feed */ X dump_line(); X last_bl = 0; X *e_com++ = ' '; X *e_com++ = '*'; X *e_com++ = ' '; X while (*++buf_ptr == ' ' || *buf_ptr == '\t'); X } else X { X if (++buf_ptr >= buf_end) X fill_buffer(); X *e_com++ = 014; X } X break; X X case '\n': X if (had_eof) X { /* check for unexpected eof */ X printf("Unterminated comment\n"); X *e_com = '\0'; X dump_line(); X return; X } X one_liner = 0; X if (ps.box_com || ps.last_nl) X { /* if this is a boxed comment, X we dont ignore the newline */ X if (s_com == e_com) X { X *e_com++ = ' '; X *e_com++ = ' '; X } X *e_com = '\0'; X if (!ps.box_com && e_com - s_com > 3) X { X if (break_delim == 1 && s_com[0] == '/' X && s_com[1] == '*' && s_com[2] == ' ') X { X char *t = e_com; X break_delim = 2; X e_com = s_com + 2; X *e_com = 0; X if (bl_bef_bk) X prefix_blankline_requested = 1; X dump_line(); X e_com = t; X s_com[0] = s_com[1] = s_com[2] = ' '; X } X dump_line(); X if (e_com >= l_com) X { X register nsize = l_com - s_com + 400; X combuf = (char *) realloc(combuf, nsize); X e_com = combuf + (e_com - s_com) + 1; X l_com = combuf + nsize - 5; X s_com = combuf + 1; X } X *e_com++ = ' '; X *e_com++ = ' '; X } X dump_line(); X now_col = ps.com_col; X } else X { X ps.last_nl = 1; X if (unix_comment != 1) X { /* we not are in unix_style X comment */ X if (unix_comment == 0 && s_code == e_code) X { X /* if it is a UNIX-style comment, ignore the X requirement that previous line be blank for X unindention */ X ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1; X if (ps.com_col <= 1) X ps.com_col = 2; X } X unix_comment = 2; /* permanently remember that we X are in this type of comment */ X dump_line(); X ++line_no; X now_col = ps.com_col; X *e_com++ = ' '; X /* fix so that the star at the start of the line will X line up */ X do /* flush leading white space */ X if (++buf_ptr >= buf_end) X fill_buffer(); X while (*buf_ptr == ' ' || *buf_ptr == '\t'); X break; X } X if (*(e_com - 1) == ' ' || *(e_com - 1) == '\t') X last_bl = e_com - 1; X /* if there was a space at the end of the last line, X remember where it was */ X else X { /* otherwise, insert one */ X last_bl = e_com; X *e_com++ = ' '; X if (e_com >= l_com) X { X register nsize = l_com - s_com + 400; X combuf = (char *) realloc(combuf, nsize); X e_com = combuf + (e_com - s_com) + 1; X l_com = combuf + nsize - 5; X s_com = combuf + 1; X } X ++now_col; X } X } X ++line_no; /* keep track of input line X number */ X if (!ps.box_com) X { X int nstar = 1; X do X { /* flush any blanks and/or tabs X at start of next line */ X if (++buf_ptr >= buf_end) X fill_buffer(); X if (*buf_ptr == '*' && --nstar >= 0) X { X if (++buf_ptr >= buf_end) X fill_buffer(); X if (*buf_ptr == '/') X goto end_of_comment; X } X } while (*buf_ptr == ' ' || *buf_ptr == '\t'); X } else if (++buf_ptr >= buf_end) X fill_buffer(); X break; /* end of case for newline */ X X case '*': /* must check for possibility X of being at end of comment */ X if (++buf_ptr >= buf_end) /* get to next char after * */ X fill_buffer(); X X if (unix_comment == 0) /* set flag to show we are not X in unix-style comment */ X unix_comment = 1; X X if (*buf_ptr == '/') X { /* it is the end!!! */ X end_of_comment: X if (++buf_ptr >= buf_end) X fill_buffer(); X X if (*(e_com - 1) != ' ' && !ps.box_com) X { /* insure blank before end */ X *e_com++ = ' '; X ++now_col; X } X if (break_delim == 1 && !one_liner && s_com[0] == '/' X && s_com[1] == '*' && s_com[2] == ' ') X { X char *t = e_com; X break_delim = 2; X e_com = s_com + 2; X *e_com = 0; X if (bl_bef_bk) X prefix_blankline_requested = 1; X dump_line(); X e_com = t; X s_com[0] = s_com[1] = s_com[2] = ' '; X } X if (break_delim == 2 && e_com > s_com + 3 X /* now_col > adj_max_col - 2 && !ps.box_com */ ) X { X *e_com = '\0'; X dump_line(); X now_col = ps.com_col; X } X if (e_com >= l_com) X { X register nsize = l_com - s_com + 400; X combuf = (char *) realloc(combuf, nsize); X e_com = combuf + (e_com - s_com) + 1; X l_com = combuf + nsize - 5; X s_com = combuf + 1; X } X *e_com++ = '*'; X *e_com++ = '/'; X *e_com = '\0'; X ps.just_saw_decl = l_just_saw_decl; X return; X } else X { /* handle isolated '*' */ X *e_com++ = '*'; X ++now_col; X } X break; X default: /* we have a random char */ X if (unix_comment == 0 && *buf_ptr != ' ' && *buf_ptr != '\t') X unix_comment = 1; /* we are not in unix-style X comment */ X X *e_com = *buf_ptr++; X if (buf_ptr >= buf_end) X fill_buffer(); X X if (*e_com == '\t') /* keep track of column */ X now_col = ((now_col - 1) & tabmask) + tabsize + 1; X else if (*e_com == '\b') /* this is a backspace */ X --now_col; X else X ++now_col; X X if (*e_com == ' ' || *e_com == '\t') X last_bl = e_com; X /* remember we saw a blank */ X X ++e_com; X if (now_col > adj_max_col && !ps.box_com && unix_comment == 1 && e_com[-1] > ' ') X { X /* the comment is too long, it must be broken up */ X if (break_delim == 1 && s_com[0] == '/' X && s_com[1] == '*' && s_com[2] == ' ') X { X char *t = e_com; X break_delim = 2; X e_com = s_com + 2; X *e_com = 0; X if (bl_bef_bk) X prefix_blankline_requested = 1; X dump_line(); X e_com = t; X s_com[0] = s_com[1] = s_com[2] = ' '; X } X if (last_bl == 0) X { /* we have seen no blanks */ X last_bl = e_com; /* fake it */ X *e_com++ = ' '; X } X *e_com = '\0'; /* print what we have */ X *last_bl = '\0'; X while (last_bl > s_com && last_bl[-1] < 040) X *--last_bl = 0; X e_com = last_bl; X dump_line(); X X *e_com++ = ' '; /* add blanks for continuation */ X *e_com++ = ' '; X *e_com++ = ' '; X X t_ptr = last_bl + 1; X last_bl = 0; X if (t_ptr >= e_com) X { X while (*t_ptr == ' ' || *t_ptr == '\t') X t_ptr++; X while (*t_ptr != '\0') X { /* move unprinted part of X comment down in buffer */ X if (*t_ptr == ' ' || *t_ptr == '\t') X last_bl = e_com; X *e_com++ = *t_ptr++; X } X } X *e_com = '\0'; X now_col = count_spaces(ps.com_col, s_com); /* recompute current X position */ X } X break; X } X } X} / echo x - io.c sed '/^X/s///' > io.c << '/' X/* X * Copyright (c) 1985 Sun Microsystems, Inc. X * Copyright (c) 1980 The Regents of the University of California. X * Copyright (c) 1976 Board of Trustees of the University of Illinois. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley, the University of Illinois, X * Urbana, and Sun Microsystems, Inc. The name of either University X * or Sun Microsystems may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)io.c 5.10 (Berkeley) 9/15/88"; X#endif /* not lint */ X X#define PUBLIC extern X#include "globs.h" X#include X X Xint comment_open; Xstatic paren_target; X Xdump_line() X{ /* dump_line is the routine X that actually effects the X printing of the new source. X It prints the label section, X followed by the code section X with the appropriate nesting X level, followed by any X comments */ X register int cur_col, target_col; X static not_first_line; X X if (ps.procname[0]) X { X if (troff) X { X if (comment_open) X { X comment_open = 0; X fprintf(output, ".*/\n"); X } X fprintf(output, ".Pr \"%s\"\n", ps.procname); X } X ps.ind_level = 0; X ps.procname[0] = 0; X } X if (s_code == e_code && s_lab == e_lab && s_com == e_com) X { X if (suppress_blanklines > 0) X suppress_blanklines--; X else X { X ps.bl_line = true; X n_real_blanklines++; X } X } else if (!inhibit_formatting) X { X suppress_blanklines = 0; X ps.bl_line = false; X if (prefix_blankline_requested && not_first_line) X if (swallow_opt_bl) X { X if (n_real_blanklines == 1) X n_real_blanklines = 0; X } else X { X if (n_real_blanklines == 0) X n_real_blanklines = 1; X } X while (--n_real_blanklines >= 0) X putc('\n', output); X n_real_blanklines = 0; X if (ps.ind_level == 0) X ps.ind_stmt = 0; /* this is a class A kludge. X dont do additional statement X indentation if we are at X bracket level 0 */ X X if (e_lab != s_lab || e_code != s_code) X ++code_lines; /* keep count of lines with X code */ X X X if (e_lab != s_lab) X { /* print lab, if any */ X if (comment_open) X { X comment_open = 0; X fprintf(output, ".*/\n"); X } X while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) X e_lab--; X cur_col = pad_output(1, label_target()); X fprintf(output, "%.*s", e_lab - s_lab, s_lab); X cur_col = count_spaces(cur_col, s_lab); X } else X cur_col = 1; /* there is no label section */ X X ps.pcase = false; X X if (s_code != e_code) X { /* print code section, if any */ X register char *p; X X if (comment_open) X { X comment_open = 0; X fprintf(output, ".*/\n"); X } X target_col = code_target(); X { X register i; X X for (i = 0; i < ps.p_l_follow; i++) X if (ps.paren_indents[i] >= 0) X ps.paren_indents[i] = -(ps.paren_indents[i] + target_col); X } X cur_col = pad_output(cur_col, target_col); X for (p = s_code; p < e_code; p++) X if (*p == (char) 0200) X fprintf(output, "%d", target_col * 7); X else X putc(*p, output); X cur_col = count_spaces(cur_col, s_code); X } X if (s_com != e_com) X if (troff) X { X int all_here = 0; X register char *p; X X if (e_com[-1] == '/' && e_com[-2] == '*') X e_com -= 2, all_here++; X while (e_com > s_com && e_com[-1] == ' ') X e_com--; X *e_com = 0; X p = s_com; X while (*p == ' ') X p++; X if (p[0] == '/' && p[1] == '*') X p += 2, all_here++; X else if (p[0] == '*') X p += p[1] == '/' ? 2 : 1; X while (*p == ' ') X p++; X if (*p == 0) X goto inhibit_newline; X if (comment_open < 2 && ps.box_com) X { X comment_open = 0; X fprintf(output, ".*/\n"); X } X if (comment_open == 0) X { X if ('a' <= *p && *p <= 'z') X *p = *p + 'A' - 'a'; X if (e_com - p < 50 && all_here == 2) X { X register char *follow = p; X fprintf(output, "\n.nr C! \\w\1"); X while (follow < e_com) X { X switch (*follow) X { X case '\n': X putc(' ', output); X case 1: X break; X case '\\': X putc('\\', output); X default: X putc(*follow, output); X } X follow++; X } X putc(1, output); X } X fprintf(output, "\n./* %dp %d %dp\n", X ps.com_col * 7, X (s_code != e_code || s_lab != e_lab) - ps.box_com, X target_col * 7); X } X comment_open = 1 + ps.box_com; X while (*p) X { X if (*p == BACKSLASH) X putc(BACKSLASH, output); X putc(*p++, output); X } X } else X { /* print comment, if any */ X register target = ps.com_col; X register char *com_st = s_com; X X target += ps.comment_delta; X while (*com_st == '\t') X com_st++, target += 8; /* ? */ X while (target <= 0) X if (*com_st == ' ') X target++, com_st++; X else if (*com_st == '\t') X target = ((target - 1) & ~7) + 9, com_st++; X else X target = 1; X if (cur_col > target) X { /* if comment cant fit on this X line, put it on next line */ X putc('\n', output); X cur_col = 1; X ++ps.out_lines; X } X while (e_com > com_st && isspace(e_com[-1])) X e_com--; X cur_col = pad_output(cur_col, target); X if (!ps.box_com) X { X if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1)) X if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1) X com_st[1] = '*'; X else X fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output); X } X fwrite(com_st, e_com - com_st, 1, output); X ps.comment_delta = ps.n_comment_delta; X cur_col = count_spaces(cur_col, com_st); X ++ps.com_lines; /* count lines with comments */ X } X if (ps.use_ff) X putc('\014', output); X else X putc('\n', output); Xinhibit_newline: X ++ps.out_lines; X if (ps.just_saw_decl == 1 && bl_aft_decl) X { X prefix_blankline_requested = 1; X ps.just_saw_decl = 0; X } else X prefix_blankline_requested = postfix_blankline_requested; X postfix_blankline_requested = 0; X } X ps.decl_on_line = ps.in_decl; /* if we are in the middle of a X declaration, remember that X fact for proper comment X indentation */ X ps.ind_stmt = ps.in_stmt & ~ps.in_decl; /* next line should be X indented if we have X not completed this X stmt and if we are X not in the middle of X a declaration */ X ps.use_ff = false; X ps.dumped_decl_indent = 0; X *(e_lab = s_lab) = '\0'; /* reset buffers */ X *(e_code = s_code) = '\0'; X *(e_com = s_com) = '\0'; X ps.ind_level = ps.i_l_follow; X ps.paren_level = ps.p_l_follow; X paren_target = -ps.paren_indents[ps.paren_level - 1]; X not_first_line = 1; X return; X}; X Xcode_target() X{ X register target_col = ps.ind_size * ps.ind_level + 1; X X if (ps.paren_level) X if (!lineup_to_parens) X target_col += continuation_indent * ps.paren_level; X else X { X register w; X register t = paren_target; X X if ((w = count_spaces(t, s_code) - max_col) > 0 X && count_spaces(target_col, s_code) <= max_col) X { X t -= w + 1; X if (t > target_col) X target_col = t; X } else X target_col = t; X } X else if (ps.ind_stmt) X target_col += continuation_indent; X return target_col; X} X Xlabel_target() X{ X return X ps.pcase ? (int) (case_ind * ps.ind_size) + 1 X : *s_lab == '#' ? 1 X : ps.ind_size * (ps.ind_level - label_offset) + 1; X} X X X/* X * Copyright (C) 1976 by the Board of Trustees of the University of Illinois X * X * All rights reserved X * X * X * NAME: fill_buffer X * X * FUNCTION: Reads one block of input into input_buffer X * X * HISTORY: initial coding November 1976 D A Willcox of CAC 1/7/77 A X * Willcox of CAC Added check for switch back to partly full input X * buffer from temporary buffer X * X */ Xint Xfill_buffer() X{ /* this routine reads stuff X from the input */ X register char *p; X register int i; X register FILE *f = input; X X if (bp_save != 0) X { /* there is a partly filled X input buffer left */ X buf_ptr = bp_save; /* dont read anything, just X switch buffers */ X buf_end = be_save; X bp_save = be_save = 0; X if (buf_ptr < buf_end) X return; /* only return if there is X really something in this X buffer */ X } X for (p = buf_ptr = in_buffer;;) X { X if ((i = getc(f)) == EOF) X { X *p++ = ' '; X *p++ = '\n'; X had_eof = true; X break; X } X *p++ = i; X if (i == '\n') X break; X } X buf_end = p; X if (p[-2] == '/' && p[-3] == '*') X { X if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0) X fill_buffer(); /* flush indent error message */ X else X { X int com = 0; X X p = in_buffer; X while (*p == ' ' || *p == '\t') X p++; X if (*p == '/' && p[1] == '*') X { X p += 2; X while (*p == ' ' || *p == '\t') X p++; X if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E' X && p[4] == 'N' && p[5] == 'T') X { X p += 6; X while (*p == ' ' || *p == '\t') X p++; X if (*p == '*') X com = 1; X else if (*p == 'O') X if (*++p == 'N') X p++, com = 1; X else if (*p == 'F' && *++p == 'F') X p++, com = 2; X while (*p == ' ' || *p == '\t') X p++; X if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) X { X if (s_com != e_com || s_lab != e_lab || s_code != e_code) X dump_line(); X if (!(inhibit_formatting = com - 1)) X { X n_real_blanklines = 0; X postfix_blankline_requested = 0; X prefix_blankline_requested = 0; X suppress_blanklines = 1; X } X } X } X } X } X } X if (inhibit_formatting) X { X p = in_buffer; X do X putc(*p, output); X while (*p++ != '\n'); X } X return; X}; X X/* X * Copyright (C) 1976 by the Board of Trustees of the University of Illinois X * X * All rights reserved X * X * X * NAME: pad_output X * X * FUNCTION: Writes tabs and spaces to move the current column up to the desired X * position. X * X * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf. X * X * PARAMETERS: current integer The current column target X * nteger The desired column X * X * RETURNS: Integer value of the new column. (If current >= target, no action is X * taken, and current is returned. X * X * GLOBALS: None X * X * CALLS: write (sys) X * X * CALLED BY: dump_line X * X * HISTORY: initial coding November 1976 D A Willcox of CAC X * X */ Xpad_output(current, target) /* writes tabs and blanks (if X necessary) to get the X current output position up X to the target column */ X int current; /* the current column value */ X int target; /* position we want it at */ X{ X register int curr; /* internal column pointer */ X register int tcur; X X if (troff) X fprintf(output, "\\h'|%dp'", (target - 1) * 7); X else X { X if (current >= target) X return (current); /* line is already long enough */ X curr = current; X while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) X { X putc('\t', output); X curr = tcur; X } X while (curr++ < target) X putc(' ', output); /* pad with final blanks */ X } X return (target); X}; X X/* X * Copyright (C) 1976 by the Board of Trustees of the University of Illinois X * X * All rights reserved X * X * X * NAME: count_spaces X * X * FUNCTION: Find out where printing of a given string will leave the current X * character position on output. X * X * ALGORITHM: Run thru input string and add appropriate values to current X * position. X * X * RETURNS: Integer value of position after printing "buffer" starting in column X * "current". X * X * HISTORY: initial coding November 1976 D A Willcox of CAC X * X */ Xint Xcount_spaces(current, buffer) X/* X * this routine figures out where the character position will be after X * printing the text in buffer starting at column "current" X */ X int current; X char *buffer; X{ X register char *buf; /* used to look thru buffer */ X register int cur; /* current character counter */ X X cur = current; X X for (buf = buffer; *buf != '\0'; ++buf) X { X switch (*buf) X { X X case '\n': X case 014: /* form feed */ X cur = 1; X break; X X case '\t': X cur = ((cur - 1) & tabmask) + tabsize + 1; X break; X X case '': /* this is a backspace */ X --cur; X break; X X default: X ++cur; X break; X } /* end of switch */ X } /* end of for loop */ X return (cur); X}; X Xint found_err; Xdiag(level, msg, a, b) X{ X if (level) X found_err = 1; X if (output == stdout) X { X fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no); X fprintf(stdout, msg, a, b); X fprintf(stdout, " */\n"); X } else X { X fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no); X fprintf(stderr, msg, a, b); X fprintf(stderr, "\n"); X } X} X Xwritefdef(f, nm) X register struct fstate *f; X{ X fprintf(output, ".ds f%c %s\n.nr s%c %d\n", X nm, f->font, nm, f->size); X} X Xchar * Xchfont(of, nf, s) X register struct fstate *of, *nf; X char *s; X{ X if (of->font[0] != nf->font[0] X || of->font[1] != nf->font[1]) X { X *s++ = '\\'; X *s++ = 'f'; X if (nf->font[1]) X { X *s++ = '('; X *s++ = nf->font[0]; X *s++ = nf->font[1]; X } else X *s++ = nf->font[0]; X } X if (nf->size != of->size) X { X *s++ = '\\'; X *s++ = 's'; X if (nf->size < of->size) X { X *s++ = '-'; X *s++ = '0' + of->size - nf->size; X } else X { X *s++ = '+'; X *s++ = '0' + nf->size - of->size; X } X } X return s; X} X X Xparsefont(f, s0) X register struct fstate *f; X char *s0; X{ X register char *s = s0; X int sizedelta = 0; X bzero(f, sizeof *f); X while (*s) X { X if (isdigit(*s)) X f->size = f->size * 10 + *s - '0'; X else if (isupper(*s)) X if (f->font[0]) X f->font[1] = *s; X else X f->font[0] = *s; X else if (*s == 'c') X f->allcaps = 1; X else if (*s == '+') X sizedelta++; X else if (*s == '-') X sizedelta--; X else X { X fprintf(stderr, "indent: bad font specification: %s\n", s0); X exit(1); X } X s++; X } X if (f->font[0] == 0) X f->font[0] = 'R'; X if (bodyf.size == 0) X bodyf.size = 11; X if (f->size == 0) X f->size = bodyf.size + sizedelta; X else if (sizedelta > 0) X f->size += bodyf.size; X else X f->size = bodyf.size - f->size; X} / echo x - lexi.c sed '/^X/s///' > lexi.c << '/' X/* X * Copyright (c) 1985 Sun Microsystems, Inc. X * Copyright (c) 1980 The Regents of the University of California. X * Copyright (c) 1976 Board of Trustees of the University of Illinois. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley, the University of Illinois, X * Urbana, and Sun Microsystems, Inc. The name of either University X * or Sun Microsystems may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)lexi.c 5.11 (Berkeley) 9/15/88"; X#endif /* not lint */ X X/* X * Here we have the token scanner for indent. It scans off one token and puts X * it in the global variable "token". It returns a code, indicating the type X * of token scanned. X */ X X#define PUBLIC extern X#include "globs.h" X#include "codes.h" X#include "ctype.h" X X#define alphanum 1 X#define opchar 3 X Xstruct templ X{ X char *rwd; X int rwcode; X}; X Xstruct templ specials[100] = X{ X "switch", 1, X "case", 2, X "break", 0, X "struct", 3, X "union", 3, X "enum", 3, X "default", 2, X "int", 4, X "char", 4, X "float", 4, X "double", 4, X "long", 4, X "short", 4, X "typdef", 4, X "unsigned", 4, X "register", 4, X "static", 4, X "global", 4, X "extern", 4, X "void", 4, X "goto", 0, X "return", 0, X "if", 5, X "while", 5, X "for", 5, X "else", 6, X "do", 6, X "sizeof", 7, X 0, 0 X}; X Xchar chartype[128] = X{ /* this is used to facilitate X the decision of what type X (alphanumeric, operator) X each character is */ X 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, X 0, 3, 0, 0, 1, 3, 3, 0, X 0, 0, 3, 3, 0, 3, 0, 3, X 1, 1, 1, 1, 1, 1, 1, 1, X 1, 1, 0, 0, 3, 3, 3, 3, X 0, 1, 1, 1, 1, 1, 1, 1, X 1, 1, 1, 1, 1, 1, 1, 1, X 1, 1, 1, 1, 1, 1, 1, 1, X 1, 1, 1, 0, 0, 0, 3, 1, X 0, 1, 1, 1, 1, 1, 1, 1, X 1, 1, 1, 1, 1, 1, 1, 1, X 1, 1, 1, 1, 1, 1, 1, 1, X 1, 1, 1, 0, 3, 0, 3, 0 X}; X X X X Xint Xlexi() X{ X register char *tok; /* local pointer to next char X in token */ X int unary_delim; /* this is set to 1 if the X current token X X forces a following operator to X be unary */ X static int last_code; /* the last token type returned */ X static int l_struct; /* set to 1 if the last token X was 'struct' */ X int code; /* internal code to be returned */ X char qchar; /* the delimiter character for X a string */ X X tok = token; /* point to start of place to X save token */ X unary_delim = false; X ps.col_1 = ps.last_nl; /* tell world that this token X started in column 1 iff the X last thing scanned was nl */ X ps.last_nl = false; X X while (*buf_ptr == ' ' || *buf_ptr == '\t') X { /* get rid of blanks */ X ps.col_1 = false; /* leading blanks imply token X is not in column 1 */ X if (++buf_ptr >= buf_end) X fill_buffer(); X } X X /* Scan an alphanumeric token */ X if (chartype[*buf_ptr] == alphanum || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) X { X /* we have a character or number */ X register char *j; /* used for searching thru list X of X X reserved words */ X register struct templ *p; X X if (isdigit(*buf_ptr) || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) X { X int seendot = 0, seenexp = 0; X if (*buf_ptr == '0' && X (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) X { X *tok++ = *buf_ptr++; X *tok++ = *buf_ptr++; X while (isxdigit(*buf_ptr)) X *tok++ = *buf_ptr++; X } else X while (1) X { X if (*buf_ptr == '.') X if (seendot) X break; X else X seendot++; X *tok++ = *buf_ptr++; X if (!isdigit(*buf_ptr) && *buf_ptr != '.') X if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp) X break; X else X { X seenexp++; X seendot++; X *tok++ = *buf_ptr++; X if (*buf_ptr == '+' || *buf_ptr == '-') X *tok++ = *buf_ptr++; X } X } X if (*buf_ptr == 'L' || *buf_ptr == 'l') X *tok++ = *buf_ptr++; X } else X while (chartype[*buf_ptr] == alphanum) X { /* copy it over */ X *tok++ = *buf_ptr++; X if (buf_ptr >= buf_end) X fill_buffer(); X } X *tok++ = '\0'; X while (*buf_ptr == ' ' || *buf_ptr == '\t') X { /* get rid of blanks */ X if (++buf_ptr >= buf_end) X fill_buffer(); X } X ps.its_a_keyword = false; X ps.sizeof_keyword = false; X if (l_struct) X { /* if last token was 'struct', X then this token should be X treated as a declaration */ X l_struct = false; X last_code = ident; X ps.last_u_d = true; X return (decl); X } X ps.last_u_d = false; /* Operator after indentifier X is binary */ X last_code = ident; /* Remember that this is the X code we will return */ X X /* This loop will check if the token is a keyword. */ X for (p = specials; (j = p->rwd) != 0; p++) X { X tok = token; /* point at scanned token */ X if (*j++ != *tok++ || *j++ != *tok++) X continue; /* This test depends on the X fact that identifiers are X always at least 1 character X long (ie. the first two X bytes of the identifier are X always meaningful) */ X if (tok[-1] == 0) X break; /* If its a one-character X identifier */ X while (*tok++ == *j) X if (*j++ == 0) X goto found_keyword; /* I wish that C had a X multi-level break... */ X } X if (p->rwd) X { /* we have a keyword */ X found_keyword: X ps.its_a_keyword = true; X ps.last_u_d = true; X switch (p->rwcode) X { X case 1: /* it is a switch */ X return (swstmt); X case 2: /* a case or default */ X return (casestmt); X X case 3: /* a "struct" */ X if (ps.p_l_follow) X break; /* inside parens: cast */ X l_struct = true; X X /* Next time around, we will want to know that we have had X a 'struct' */ X case 4: /* one of the declaration X keywords */ X if (ps.p_l_follow) X { X ps.cast_mask |= 1 << ps.p_l_follow; X break; /* inside parens: cast */ X } X last_code = decl; X return (decl); X X case 5: /* if, while, for */ X return (sp_paren); X X case 6: /* do, else */ X return (sp_nparen); X X case 7: X ps.sizeof_keyword = true; X default: /* all others are treated like X any other identifier */ X return (ident); X } /* end of switch */ X } /* end of if (found_it) */ X if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0) X { X register char *tp = buf_ptr; X while (tp < buf_end) X if (*tp++ == ')' && *tp == ';') X goto not_proc; X strncpy(ps.procname, token, sizeof ps.procname - 1); X ps.in_par_decl = 1; X not_proc:; X } X /* The following hack attempts to guess whether or not the X current token is in fact a declaration keyword -- one that has X been typedefd */ X if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_') X && !ps.p_l_follow X && !ps.block_init X && (ps.last_token == rparen || ps.last_token == semicolon || X ps.last_token == decl || X ps.last_token == lbrace || ps.last_token == rbrace)) X { X ps.its_a_keyword = true; X ps.last_u_d = true; X last_code = decl; X return decl; X } X if (last_code == decl) /* if this is a declared X variable, then following X sign is unary */ X ps.last_u_d = true; /* will make "int a -1" work */ X last_code = ident; X return (ident); /* the ident is not in the list */ X } /* end of procesing for alpanum X character */ X /* l l l Scan a non-alphanumeric token */ X *tok++ = *buf_ptr; /* if it is only a X one-character token, it is X moved here */ X *tok = '\0'; X if (++buf_ptr >= buf_end) X fill_buffer(); X X switch (*token) X { X case '\n': X unary_delim = ps.last_u_d; X ps.last_nl = true; /* remember that we just had a X newline */ X code = (had_eof ? 0 : newline); X X /* if data has been exausted, the newline is a dummy, and we X should return code to stop */ X break; X X case '\'': /* start of quoted character */ X case '"': /* start of string */ X qchar = *token; X if (troff) X { X tok[-1] = '`'; X if (qchar == '"') X *tok++ = '`'; X tok = chfont(&bodyf, &stringf, tok); X } X do X { /* copy the string */ X while (1) X { /* move one character or X [/] */ X if (*buf_ptr == '\n') X { X printf("%d: Unterminated literal\n", line_no); X goto stop_lit; X } X *tok = *buf_ptr++; X if (buf_ptr >= buf_end) X fill_buffer(); X if (had_eof || ((tok - token) > (bufsize - 2))) X { X printf("Unterminated literal\n"); X ++tok; X goto stop_lit; X /* get outof literal copying loop */ X } X if (*tok == BACKSLASH) X { /* if escape, copy extra char */ X if (*buf_ptr == '\n') /* check for escaped newline */ X ++line_no; X if (troff) X { X *++tok = BACKSLASH; X if (*buf_ptr == BACKSLASH) X *++tok = BACKSLASH; X } X *++tok = *buf_ptr++; X ++tok; /* we must increment this again X because we copied two chars */ X if (buf_ptr >= buf_end) X fill_buffer(); X } else X break; /* we copied one character */ X } /* end of while (1) */ X } while (*tok++ != qchar); X if (troff) X { X tok = chfont(&stringf, &bodyf, tok - 1); X if (qchar == '"') X *tok++ = '\''; X } Xstop_lit: X code = ident; X break; X X case ('('): X case ('['): X unary_delim = true; X code = lparen; X break; X X case (')'): X case (']'): X code = rparen; X break; X X case '#': X unary_delim = ps.last_u_d; X code = preesc; X break; X X case '?': X unary_delim = true; X code = question; X break; X X case (':'): X code = colon; X unary_delim = true; X break; X X case (';'): X unary_delim = true; X code = semicolon; X break; X X case ('{'): X unary_delim = true; X X /* if (ps.in_or_st) ps.block_init = 1; */ X /* ? code = ps.block_init ? lparen : lbrace; */ X code = lbrace; X break; X X case ('}'): X unary_delim = true; X /* ? code = ps.block_init ? rparen : rbrace; */ X code = rbrace; X break; X X case 014: /* a form feed */ X unary_delim = ps.last_u_d; X ps.last_nl = true; /* remember this so we can set X 'ps.col_1' right */ X code = form_feed; X break; X X case (','): X unary_delim = true; X code = comma; X break; X X case '.': X unary_delim = false; X code = period; X break; X X case '-': X case '+': /* check for -, +, --, ++ */ X code = (ps.last_u_d ? unary_op : binary_op); X unary_delim = true; X X if (*buf_ptr == token[0]) X { X /* check for doubled character */ X *tok++ = *buf_ptr++; X /* buffer overflow will be checked at end of loop */ X if (last_code == ident || last_code == rparen) X { X code = (ps.last_u_d ? unary_op : postop); X /* check for following ++ or -- */ X unary_delim = false; X } X } else if (*buf_ptr == '=') X /* check for operator += */ X *tok++ = *buf_ptr++; X else if (*buf_ptr == '>') X { X /* check for operator -> */ X *tok++ = *buf_ptr++; X if (!ptr_binop) X { X unary_delim = false; X code = unary_op; X ps.want_blank = false; X } X } X break; /* buffer overflow will be X checked at end of switch */ X X case '=': X if (ps.in_or_st) X ps.block_init = 1; X#ifdef undef X if (chartype[*buf_ptr] == opchar) X { /* we have two char assignment */ X tok[-1] = *buf_ptr++; X if ((tok[-1] == '<' || tok[-1] == '>') && tok[-1] == *buf_ptr) X *tok++ = *buf_ptr++; X *tok++ = '='; /* Flip =+ to += */ X *tok = 0; X } X#else X if (*buf_ptr == '=') X { /* == */ X *tok++ = '='; /* Flip =+ to += */ X buf_ptr++; X *tok = 0; X } X#endif X code = binary_op; X unary_delim = true; X break; X /* can drop thru!!! */ X X case '>': X case '<': X case '!': /* ops like <, <<, <=, !=, etc */ X if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') X { X *tok++ = *buf_ptr; X if (++buf_ptr >= buf_end) X fill_buffer(); X } X if (*buf_ptr == '=') X *tok++ = *buf_ptr++; X code = (ps.last_u_d ? unary_op : binary_op); X unary_delim = true; X break; X X default: X if (token[0] == '/' && *buf_ptr == '*') X { X /* it is start of comment */ X *tok++ = '*'; X X if (++buf_ptr >= buf_end) X fill_buffer(); X X code = comment; X unary_delim = ps.last_u_d; X break; X } X while (*(tok - 1) == *buf_ptr || *buf_ptr == '=') X { X /* handle ||, &&, etc, and also things as in int *****i */ X *tok++ = *buf_ptr; X if (++buf_ptr >= buf_end) X fill_buffer(); X } X code = (ps.last_u_d ? unary_op : binary_op); X unary_delim = true; X X X } /* end of switch */ X if (code != newline) X { X l_struct = false; X last_code = code; X } X if (buf_ptr >= buf_end) /* check for input buffer empty */ X fill_buffer(); X ps.last_u_d = unary_delim; X *tok = '\0'; /* null terminate the token */ X return (code); X}; X X/* X * Add the given keyword to the keyword table, using val as the keyword type X */ Xaddkey(key, val) X char *key; X{ X register struct templ *p = specials; X while (p->rwd) X if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0) X return; X else X p++; X if (p >= specials + sizeof specials / sizeof specials[0]) X return; /* For now, table overflows are X silently ignored */ X p->rwd = key; X p->rwcode = val; X p[1].rwd = 0; X p[1].rwcode = 0; X return; X} / echo x - parse.c sed '/^X/s///' > parse.c << '/' X/* X * Copyright (c) 1985 Sun Microsystems, Inc. X * Copyright (c) 1980 The Regents of the University of California. X * Copyright (c) 1976 Board of Trustees of the University of Illinois. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley, the University of Illinois, X * Urbana, and Sun Microsystems, Inc. The name of either University X * or Sun Microsystems may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)parse.c 5.8 (Berkeley) 9/15/88"; X#endif /* not lint */ X X#define PUBLIC extern X#include "./globs.h" X#include "./codes.h" X X X X Xparse(tk) X int tk; /* the code for the construct X scanned */ X{ X int i; X X#ifdef debug X printf("%2d - %s\n", tk, token); X#endif X X while (ps.p_stack[ps.tos] == ifhead && tk != elselit) X { X /* true if we have an if without an else */ X ps.p_stack[ps.tos] = stmt; /* apply the if(..) stmt ::= X stmt reduction */ X reduce(); /* see if this allows any X reduction */ X } X X X switch (tk) X { /* go on and figure out what to X do with the input */ X X case decl: /* scanned a declaration word */ X ps.search_brace = btype_2; X /* indicate that following brace should be on same line */ X if (ps.p_stack[ps.tos] != decl) X { /* only put one declaration X onto stack */ X break_comma = true; /* while in declaration, X newline should be forced X after comma */ X ps.p_stack[++ps.tos] = decl; X ps.il[ps.tos] = ps.i_l_follow; X X if (ps.ljust_decl) X { /* only do if we want left X justified declarations */ X ps.ind_level = 0; X for (i = ps.tos - 1; i > 0; --i) X if (ps.p_stack[i] == decl) X ++ps.ind_level; /* indentation is number of X declaration levels deep we X are */ X ps.i_l_follow = ps.ind_level; X } X } X break; X X case ifstmt: /* scanned if (...) */ X if (ps.p_stack[ps.tos] == elsehead && ps.else_if) /* "else if ..." */ X ps.i_l_follow = ps.il[ps.tos]; X case dolit: /* 'do' */ X case forstmt: /* for (...) */ X ps.p_stack[++ps.tos] = tk; X ps.il[ps.tos] = ps.ind_level = ps.i_l_follow; X ++ps.i_l_follow; /* subsequent statements should X be indented 1 */ X ps.search_brace = btype_2; X break; X X case lbrace: /* scanned { */ X break_comma = false; /* don't break comma in an X initial list */ X if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl X || ps.p_stack[ps.tos] == stmtl) X ++ps.i_l_follow; /* it is a random, isolated X stmt group or a declaration */ X else X { X if (s_code == e_code) X { X /* only do this if there is nothing on the line */ X --ps.ind_level; X /* it is a group as part of a while, for, etc. */ X if (ps.p_stack[ps.tos] == swstmt && ps.case_indent >= 1) X --ps.ind_level; X /* for a switch, brace should be two levels out from the X code */ X } X } X X ps.p_stack[++ps.tos] = lbrace; X ps.il[ps.tos] = ps.ind_level; X ps.p_stack[++ps.tos] = stmt; X /* allow null stmt between braces */ X ps.il[ps.tos] = ps.i_l_follow; X break; X X case whilestmt: /* scanned while (...) */ X if (ps.p_stack[ps.tos] == dohead) X { X /* it is matched with do stmt */ X ps.ind_level = ps.i_l_follow = ps.il[ps.tos]; X ps.p_stack[++ps.tos] = whilestmt; X ps.il[ps.tos] = ps.ind_level = ps.i_l_follow; X } else X { /* it is a while loop */ X ps.p_stack[++ps.tos] = whilestmt; X ps.il[ps.tos] = ps.i_l_follow; X ++ps.i_l_follow; X ps.search_brace = btype_2; X } X X break; X X case elselit: /* scanned an else */ X X if (ps.p_stack[ps.tos] != ifhead) X diag(1, "Unmatched 'else'"); X else X { X ps.ind_level = ps.il[ps.tos]; /* indentation for else should X be same as for if */ X ps.i_l_follow = ps.ind_level + 1; /* everything following X should be in 1 level */ X ps.p_stack[ps.tos] = elsehead; X /* remember if with else */ X ps.search_brace = btype_2 | ps.else_if; X } X break; X X case rbrace: /* scanned a } */ X /* stack should have or */ X if (ps.p_stack[ps.tos - 1] == lbrace) X { X ps.ind_level = ps.i_l_follow = ps.il[--ps.tos]; X ps.p_stack[ps.tos] = stmt; X } else X diag(1, "Stmt nesting error."); X break; X X case swstmt: /* had switch (...) */ X ps.p_stack[++ps.tos] = swstmt; X ps.cstk[ps.tos] = case_ind; X /* save current case indent level */ X ps.il[ps.tos] = ps.i_l_follow; X case_ind = ps.i_l_follow + ps.case_indent; /* cases should be one X level down from X switch */ X ps.i_l_follow += ps.case_indent + 1; /* statements should be X two levels in */ X ps.search_brace = btype_2; X break; X X case semicolon: /* this indicates a simple stmt */ X break_comma = false; /* turn off flag to break after X commas in a declaration */ X ps.p_stack[++ps.tos] = stmt; X ps.il[ps.tos] = ps.ind_level; X break; X X default: /* this is an error */ X diag(1, "Unknown code to parser"); X return; X X X } /* end of switch */ X X reduce(); /* see if any reduction can be X done */ X X#ifdef debug X for (i = 1; i <= ps.tos; ++i) X printf("(%d %d)", ps.p_stack[i], ps.il[i]); X printf("\n"); X#endif X X return; X} X X/* X * Copyright (C) 1976 by the Board of Trustees of the University of Illinois X * X * All rights reserved X * X * X * NAME: reduce X * X * FUNCTION: Implements the reduce part of the parsing algorithm X * X * ALGORITHM: The following reductions are done. Reductions are repeated until X * no more are possible. X * X * Old TOS New TOS do X * "dostmt" if "ifstmt" switch decl X * "ifelse" for while X * "dostmt" while X * X * On each reduction, ps.i_l_follow (the indentation for the following line) is X * set to the indentation level associated with the old TOS. X * X * PARAMETERS: None X * X * RETURNS: Nothing X * X * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos = X * X * CALLS: None X * X * CALLED BY: parse X * X * HISTORY: initial coding November 1976 D A Willcox of CAC X * X */ X/*----------------------------------------------*\ X| REDUCTION PHASE | X\*----------------------------------------------*/ Xreduce() X{ X X register int i; X X for (;;) X { /* keep looping until there is X nothing left to reduce */ X X switch (ps.p_stack[ps.tos]) X { X X case stmt: X switch (ps.p_stack[ps.tos - 1]) X { X X case stmt: X case stmtl: X /* stmtl stmt or stmt stmt */ X ps.p_stack[--ps.tos] = stmtl; X break; X X case dolit: /* */ X ps.p_stack[--ps.tos] = dohead; X ps.i_l_follow = ps.il[ps.tos]; X break; X X case ifstmt: X /* */ X ps.p_stack[--ps.tos] = ifhead; X for (i = ps.tos - 1; X ( X ps.p_stack[i] != stmt X && X ps.p_stack[i] != stmtl X && X ps.p_stack[i] != lbrace X ); X --i); X ps.i_l_follow = ps.il[i]; X /* for the time being, we will assume that there is no else X on this if, and set the indentation level accordingly. X If an else is scanned, it will be fixed up later */ X break; X X case swstmt: X /* */ X case_ind = ps.cstk[ps.tos - 1]; X X case decl: /* finish of a declaration */ X case elsehead: X /* < else> */ X case forstmt: X /* */ X case whilestmt: X /* */ X ps.p_stack[--ps.tos] = stmt; X ps.i_l_follow = ps.il[ps.tos]; X break; X X default: /* */ X return; X X } /* end of section for on X top of stack */ X break; X X case whilestmt: /* while (...) on top */ X if (ps.p_stack[ps.tos - 1] == dohead) X { X /* it is termination of a do while */ X ps.p_stack[--ps.tos] = stmt; X break; X } else X return; X X default: /* anything else on top */ X return; X X } X } X} /