# # include "../unix.h" extern jmp_buf Env; /* ** DISPLAY.C -- display manipulation routines ** ** a display is a list of strings, the symbol ** space Symsp is impemented by means of displays. ** ** Defines: ** enter_display() ** addsym() ** free_display() ** symspfree() ** w_display() ** eat_display() ** ** Required By: ** Lexical analysis routines to add to the symbol space ** semantic productions to manipulate input ** ** Files: ** .../fileio.h ** constants.h ** globals.h ** ** History: ** 6/1/78 -- (marc) written ** */ # include "../fileio.h" # include "constants.h" # include "globals.h" /* this avoids having to specify &Cv_display in the semantic * routines, by making Cv_display a pointer to the pertinent * display structure. */ extern struct display *Cv_display &Displays [0]; /* ** ENTER_DISPLAY -- enter a new string into a display ** ** Parameters: ** disp -- display to be added to ** string -- string to add ** ** Returns: ** pointer to new disp_node structure. ** ** Side Effects: ** allocates a new disp_node structure. ** Expects a dynamic "string", i.e. one that it can ** dispose of as it wishes, so it is the users responsability ** to allocate space for this string. ** If the string passed is 0, the string ** "ERROR_TOKEN" is substituted, and a message is printed, ** so a caller may call enter_display with the return of an ** salloc() directly. ** If no space is available for the allocation of the ** new node, an error message is given, and a longjump(3) ** is performed (this should goto equel()[main.c]) ** ** Called By: ** add_sym() -- to add a token to the Symsp ** the semantic productions -- for manipulating usages ** of C variables. ** ** Diagnostics: ** "symbol space overflow" -- total reset to after ** current top level file (not #included) ** "alloc error in display" -- someone called enter_display ** with a string == 0 ** ** History: ** 6/1/78 -- (marc) written ** */ struct disp_node *enter_display(disp, string) struct display *disp; char *string; { register struct display *d; register struct disp_node *node; node = nalloc(sizeof *node); if (node == 0) { yysemerr("symbol space overflow", string); reset(Env, 1); } d = disp; if (!d->disp_first) d->disp_first = d->disp_last = node; else { d->disp_last->d_next = node; d->disp_last = node; } node->d_next = 0; if (!(node->d_elm = string)) { printf("alloc error in display\n"); node->d_elm = "ERROR_TOKEN"; } return (node); } /* ** ADDSYM -- add a token to the symbol space ** ** The node's .d_line field is set to the value of yyline, ** which, if this routine is called from a lexical routine ** taking lexemes that can't include newlines (and back them up), ** is the line the lexeme was read from. This fact is used ** be yyserror() [yyerror.c] to report accurate line numbers ** for errors. ** ** Parameters: ** s -- string to add ** ** Returns: ** pointer to node added ** ** Requires: ** enter_display() -- to enter the string ** Symsp -- display in which to enter it ** ** Called By: ** All lexical routines ** ** History: ** 6/1/78 -- (marc) written ** */ struct disp_node *addsym(s) char *s; { register struct disp_node *d; d = enter_display(&Symsp, s); d->d_line = yyline; return (d); } /* ** FREE_DISPLAY -- frees all elements of a display ** ** Parameters: ** disp -- the display to free ** ** Called By: ** The semantic produtions dealing with ** usage of C variables. ** ** History: ** 6/1/78 -- (marc) written ** */ free_display(disp) struct display *disp; { register struct display *d; register struct disp_node *f, *n; d = disp; for (f = d->disp_first; f; f = n) { n = f->d_next; xfree(f->d_elm); xfree(f); } d->disp_first = d->disp_last = 0; } /* ** SYSMSPFREE -- Frees symbol space ** Symspfree frees all the symbol table, EXCEPT ** for the last element in it, as this is the lookahead ** element. That is to say, the element which forced reduction ** to the non-terminal program, which called on symspfree() ** ** Requires: ** Symsp -- to free it ** ** Called By: ** argproc() ** semantic routines (nonterminal "program") ** ** History: ** 6/1/78 -- (marc) written ** */ symspfree() { register struct display *d; register struct disp_node *f, *n; d = &Symsp; for (f = d->disp_first; f && f->d_next; f = n) { n = f->d_next; xfree(f->d_elm); xfree(f); } d->disp_first = d->disp_last; } /* ** W_DISPLAY -- write out the contents of a display ** ** Parameters: ** disp -- display to take write out ** ** Side Effects: ** Writes onto Out_file ** the contents of the display, ** each string is comsidered a separate ** word to be written out(so w_raw may ** break a line between words). ** Calls are made to w_op() and w_key() so as ** to have the minimum number of spaces in the text. ** ** Requires: ** w_op() -- to write out operator terminated ** strings ** w_key() -- to write out KEYCHAR terminated ** strings ** ** Called By: ** semantic productions dealing with usage of ** C variables. ** ** History: ** 6/1/78 -- (marc) written ** */ w_display(disp) struct display *disp; { register struct disp_node *n; for (n = disp->disp_first; n; n = n->d_next) { switch (Cmap [n->d_elm [length(n->d_elm) - 1]]) { case OPATR : case PUNCT : w_op(n->d_elm); break; default : w_key(n->d_elm); break; } } } /* ** EAT_DISPLAY -- enter text from In_file into a display ** Enters all text gotten through getch() [getch.c] ** lying between one character delimiters, which may ** be nested, into a display or w_op()'s it. ** eat_display() assumes that when it is called a ** "left_ch" has just been seen. It will "eat" up to ** MAXSTRING characters. ** Newline is played with because : ** a) a newline may have been read by eat_display ** instead of yylex(), therefore if eat_display ** stops there, yylex() must know that a newline ** has just been seen and it must test for C_CODE. ** b) Newline may have to be set to 0 if an include() ** was done which sets it to 1, and no yylex() was ** done afterwards to reset it. ** ** NOTE : This playing with Newline is needed because ** yylex() and not getch() maintains Newline. If getch() ** maintained Newline then it would be automatically right. ** ** Parameters: ** disp -- display to add elements to if != 0 else ** characters are written out. ** left_ch -- left delimiter character ** right_ch -- right delimiter character ** ** Side Effects: ** advances input to after the close of the ** left_ch, right_ch pair. ** may back up 2 characters. ** ** Called By: ** semantic routines dealing with array subscription ** ** Diagnostics: ** "missing closing character" -- if end-of-file ** encountered in the stream. ** "display too long" -- if more than MAXSTRING ** chars between delimiters. ** ** History: ** 6/1/78 -- (marc) written ** ** Bugs: ** #include's encountered, are treated wrongly ** because the "#include ...c.h" is put out immediately, ** while the display is put out only later. ** ** */ eat_display(disp, left_ch, right_ch) struct display *disp; char left_ch; char right_ch; { char buf [MAXSTRING + 1]; register char *cp; register level; register i; char pk; char r_c [2]; cp = buf; level = i = 1; *cp = left_ch; do { i++; if (i >= sizeof buf) { yysemerr("display too long", 0); break; } if ((*++cp = getch()) == left_ch) level++; else if (*cp == right_ch) level =- 1; else if (*cp == EOF_TOK) { backup(*cp); missing : r_c [1] = '\0'; r_c [0] = right_ch; yysemerr("missing closing character", r_c); *cp = right_ch; /* make next line be read as possible * C_CODE by yylex() [yylex.c] */ Newline = 1; break; } else if (*cp == '\n') { /* test that next line is valid equel line, * and strip "##" */ if ((pk = getch()) != '#') { backup(pk); goto missing; } if ((pk = getch()) != '#') { backup(pk); backup('#'); goto missing; } } } while (*cp != right_ch || level > 0); if (level == 0) Newline = 0; *++cp = '\0'; if (disp) enter_display(disp, salloc(buf)); else w_op(buf); }