--- /dev/null
+Version.c
+Makefile
+Resolve
+nmclash.c
+LLlex.c
+LLlex.h
+LLmessage.c
+SmallPars
+BigPars
+LintPars
+align.h
+arith.c
+arith.h
+asm.c
+assert.h
+atw.h
+blocks.c
+cem.1
+cem.c
+cemcom.1
+ch7.c
+ch7bin.c
+ch7mon.c
+char.tab
+class.h
+code.c
+code.str
+conversion.c
+cstoper.c
+dataflow.c
+declar.g
+declar.str
+declarator.c
+decspecs.c
+decspecs.str
+def.str
+domacro.c
+dumpidf.c
+error.c
+estack.str
+eval.c
+expr.c
+expr.str
+expression.g
+field.c
+field.str
+file_info.h
+idf.c
+idf.str
+init.c
+input.c
+input.h
+interface.h
+ival.g
+l_brace.str
+l_class.h
+l_comment.c
+l_dummy.c
+l_ev_ord.c
+l_lint.c
+l_lint.h
+l_misc.c
+l_outdef.c
+l_outdef.str
+l_state.str
+l_states.c
+label.c
+label.h
+level.h
+macro.str
+main.c
+make.allocd
+make.hfiles
+make.next
+make.tokcase
+make.tokfile
+mcomm.c
+mes.h
+options
+options.c
+program.g
+replace.c
+scan.c
+sizes.h
+skip.c
+specials.h
+stack.c
+stack.str
+statement.g
+stb.c
+stmt.str
+struct.c
+struct.str
+switch.c
+switch.str
+tokenname.c
+tokenname.h
+type.c
+type.str
+util.str
+util.c
--- /dev/null
+!File: lint.h
+#undef LINT 1 /* if defined, 'lint' is produced */
+
+
+!File: pathlength.h
+#define PATHLENGTH 1024 /* max. length of path to file */
+
+
+!File: errout.h
+#define ERROUT STDERR /* file pointer for writing messages */
+#define MAXERR_LINE 5 /* maximum number of error messages given
+ on the same input line. */
+
+
+!File: idfsize.h
+#define IDFSIZE 64 /* maximum significant length of an identifier */
+
+
+!File: numsize.h
+#define NUMSIZE 256 /* maximum length of a numeric constant */
+
+
+!File: nparams.h
+#define NPARAMS 32 /* maximum number of parameters of macros */
+
+
+!File: ifdepth.h
+#define IFDEPTH 256 /* maximum number of nested if-constructions */
+
+
+!File: density.h
+#define DENSITY 2 /* see switch.[ch] for an explanation */
+
+
+!File: lapbuf.h
+#define LAPBUF 4096 /* size of macro actual parameter buffer */
+
+
+!File: strsize.h
+#define ISTRSIZE 32 /* minimum number of bytes allocated for
+ storing a string */
+#define RSTRSIZE 16 /* step size in enlarging the memory for
+ the storage of a string */
+
+
+!File: target_sizes.h
+#define MAXSIZE 8 /* the maximum of the SZ_* constants */
+
+/* target machine sizes */
+#define SZ_CHAR (arith)1
+#define SZ_SHORT (arith)2
+#define SZ_WORD (arith)4
+#define SZ_INT (arith)4
+#define SZ_LONG (arith)4
+#ifndef NOFLOAT
+#define SZ_FLOAT (arith)4
+#define SZ_DOUBLE (arith)8
+#endif NOFLOAT
+#define SZ_POINTER (arith)4
+
+/* target machine alignment requirements */
+#define AL_CHAR 1
+#define AL_SHORT SZ_SHORT
+#define AL_WORD SZ_WORD
+#define AL_INT SZ_WORD
+#define AL_LONG SZ_WORD
+#ifndef NOFLOAT
+#define AL_FLOAT SZ_WORD
+#define AL_DOUBLE SZ_WORD
+#endif NOFLOAT
+#define AL_POINTER SZ_WORD
+#define AL_STRUCT 1
+#define AL_UNION 1
+
+
+!File: botch_free.h
+#undef BOTCH_FREE 1 /* when defined, botch freed memory, as a check */
+
+
+!File: dataflow.h
+#define DATAFLOW 1 /* produce some compile-time xref */
+
+
+!File: debug.h
+#undef DEBUG 1 /* perform various self-tests */
+
+
+!File: use_tmp.h
+#define PREPEND_SCOPES 1 /* collect exa, exp, ina and inp commands
+ and if USE_TMP is defined let them
+ precede the rest of the generated
+ compact code */
+#define USE_TMP 1 /* use C_insertpart, C_endpart mechanism
+ to generate EM-code in the order needed
+ for the code-generators. If not defined,
+ the old-style peephole optimizer is
+ needed. */
+
+
+!File: parbufsize.h
+#define PARBUFSIZE 1024
+
+
+!File: textsize.h
+#define ITEXTSIZE 32 /* 1st piece of memory for repl. text */
+#define RTEXTSIZE 16 /* stepsize for enlarging repl.text */
+
+
+!File: inputtype.h
+#define INP_READ_IN_ONE 1 /* read input file in one */
+
+
+!File: nopp.h
+#undef NOPP 1 /* if NOT defined, use built-int preprocessor */
+
+
+!File: nobitfield.h
+#undef NOBITFIELD 1 /* if NOT defined, implement bitfields */
+
+
+!File: spec_arith.h
+/* describes internal compiler arithmetics */
+#undef SPECIAL_ARITHMETICS /* something different from native long */
+
+
+!File: static.h
+#define GSTATIC /* for large global "static" arrays */
+
+
+!File: nofloat.h
+#undef NOFLOAT 1 /* if NOT defined, floats are implemented */
+
+
+!File: noRoption.h
+#undef NOROPTION 1 /* if NOT defined, R option is implemented */
+
+
+!File: nocross.h
+#undef NOCROSS 1 /* if NOT defined, cross compiler */
+
+
+!File: regcount.h
+#undef REGCOUNT 1 /* count occurrences for register messages */
+
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* L E X I C A L A N A L Y Z E R */
+
+#include "lint.h"
+#include <alloc.h>
+#include "nofloat.h"
+#include "idfsize.h"
+#include "numsize.h"
+#include "debug.h"
+#include "strsize.h"
+#include "nopp.h"
+#include "input.h"
+#include "arith.h"
+#include "def.h"
+#include "macro.h"
+#include "idf.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "class.h"
+#include "assert.h"
+#include "sizes.h"
+
+/* Data about the token yielded */
+struct token dot, ahead, aside;
+
+#ifndef NOPP
+int ReplaceMacros = 1; /* replacing macros */
+int AccDefined = 0; /* accept "defined(...)" */
+int UnknownIdIsZero = 0; /* interpret unknown id as integer 0 */
+int Unstacked = 0; /* an unstack is done */
+#endif
+int AccFileSpecifier = 0; /* return filespecifier <...> */
+int EoiForNewline = 0; /* return EOI upon encountering newline */
+int File_Inserted = 0; /* a file has just been inserted */
+int LexSave = 0; /* last character read by GetChar */
+#define MAX_LL_DEPTH 2
+
+static struct token LexStack[MAX_LL_DEPTH];
+static LexSP = 0;
+
+/* In PushLex() the actions are taken in order to initialise or
+ re-initialise the lexical scanner.
+ E.g. at the invocation of a sub-parser that uses LLlex(), the
+ state of the current parser should be saved.
+*/
+PushLex()
+{
+ ASSERT(LexSP < 2);
+ ASSERT(ASIDE == 0); /* ASIDE = 0; */
+ GetToken(&ahead);
+ LexStack[LexSP++] = dot;
+}
+
+PopLex()
+{
+ ASSERT(LexSP > 0);
+ dot = LexStack[--LexSP];
+}
+
+int
+LLlex()
+{
+ /* LLlex() plays the role of Lexical Analyzer for the C parser.
+ The look-ahead and putting aside of tokens are taken into
+ account.
+ */
+ if (ASIDE) { /* a token is put aside */
+ dot = aside;
+ ASIDE = 0;
+ }
+ else { /* read ahead and return the old one */
+#ifdef LINT
+ lint_comment_ahead();
+#endif LINT
+ dot = ahead;
+ /* the following test is performed due to the dual
+ task of LLlex(): it is also called for parsing the
+ restricted constant expression following a #if or
+ #elif. The newline character causes EOF to be
+ returned in this case to stop the LLgen parsing task.
+ */
+ if (DOT != EOI)
+ GetToken(&ahead);
+ else
+ DOT = EOF;
+ }
+ return DOT;
+}
+
+
+char *string_token();
+arith char_constant();
+
+
+int
+GetToken(ptok)
+ register struct token *ptok;
+{
+ /* LexToken() is the actual token recognizer. It calls the
+ control line interpreter if it encounters a "\n{w}*#"
+ combination. Macro replacement is also performed if it is
+ needed.
+ */
+ char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
+ register int ch, nch;
+
+ if (File_Inserted) {
+ File_Inserted = 0;
+ goto firstline;
+ }
+
+again: /* rescan the input after an error or replacement */
+ ch = GetChar();
+go_on: /* rescan, the following character has been read */
+ if ((ch & 0200) && ch != EOI) /* stop on non-ascii character */
+ fatal("non-ascii '\\%03o' read", ch & 0377);
+ /* keep track of the place of the token in the file */
+ ptok->tk_file = FileName;
+ ptok->tk_line = LineNumber;
+
+ switch (class(ch)) { /* detect character class */
+ case STNL: /* newline, vertical space or formfeed */
+firstline:
+ LineNumber++; /* also at vs and ff */
+ ptok->tk_file = FileName;
+ ptok->tk_line = LineNumber;
+ if (EoiForNewline) /* called in control line */
+ /* a newline in a control line indicates the
+ end-of-information of the line.
+ */
+ return ptok->tk_symb = EOI;
+ while ((ch = GetChar()), (ch == '#' || class(ch) == STSKIP)) {
+ /* blanks are allowed before hashes */
+ if (ch == '#') {
+ /* a control line follows */
+ domacro();
+ if (File_Inserted) {
+ File_Inserted = 0;
+ goto firstline;
+ }
+ }
+ }
+ /* We have to loop here, because in
+ `domacro' the nl, vt or ff is read. The
+ character following it may again be a `#'.
+ */
+ goto go_on;
+ case STSKIP: /* just skip the skip characters */
+ goto again;
+ case STGARB: /* garbage character */
+ if (040 < ch && ch < 0177)
+ lexerror("garbage char %c", ch);
+ else
+ lexerror("garbage char \\%03o", ch);
+ goto again;
+ case STSIMP: /* a simple character, no part of compound token*/
+ if (ch == '/') { /* probably the start of comment */
+ ch = GetChar();
+ if (ch == '*') { /* start of comment */
+ skipcomment();
+ goto again;
+ }
+ else {
+ UnGetChar();
+ ch = '/'; /* restore ch */
+ }
+ }
+ return ptok->tk_symb = ch;
+ case STCOMP: /* maybe the start of a compound token */
+ nch = GetChar(); /* character lookahead */
+ switch (ch) {
+ case '!':
+ if (nch == '=')
+ return ptok->tk_symb = NOTEQUAL;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '&':
+ if (nch == '&')
+ return ptok->tk_symb = AND;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '+':
+ if (nch == '+')
+ return ptok->tk_symb = PLUSPLUS;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '-':
+ if (nch == '-')
+ return ptok->tk_symb = MINMIN;
+ if (nch == '>')
+ return ptok->tk_symb = ARROW;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '<':
+ if (AccFileSpecifier) {
+ UnGetChar(); /* pushback nch */
+ ptok->tk_bts = string_token("file specifier",
+ '>', &(ptok->tk_len));
+ return ptok->tk_symb = FILESPECIFIER;
+ }
+ if (nch == '<')
+ return ptok->tk_symb = LEFT;
+ if (nch == '=')
+ return ptok->tk_symb = LESSEQ;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '=':
+ if (nch == '=')
+ return ptok->tk_symb = EQUAL;
+
+ /* The following piece of code tries to recognise
+ old-fashioned assignment operators `=op'
+ Note however, that these are removed from the
+ ANSI C standard.
+ */
+ switch (nch) {
+ case '+':
+ ptok->tk_symb = PLUSAB;
+ goto warn;
+ case '-':
+ ptok->tk_symb = MINAB;
+ goto warn;
+ case '*':
+ ptok->tk_symb = TIMESAB;
+ goto warn;
+ case '/':
+ ptok->tk_symb = DIVAB;
+ goto warn;
+ case '%':
+ ptok->tk_symb = MODAB;
+ goto warn;
+ case '>':
+ case '<':
+ GetChar(ch);
+ if (ch != nch) {
+ UnGetChar();
+ lexerror("illegal combination '=%c'",
+ nch);
+ }
+ ptok->tk_symb = nch == '<' ? LEFTAB : RIGHTAB;
+ goto warn;
+ case '&':
+ ptok->tk_symb = ANDAB;
+ goto warn;
+ case '^':
+ ptok->tk_symb = XORAB;
+ goto warn;
+ case '|':
+ ptok->tk_symb = ORAB;
+ warn:
+ warning("Old-fashioned assignment operator");
+ return ptok->tk_symb;
+ }
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '>':
+ if (nch == '=')
+ return ptok->tk_symb = GREATEREQ;
+ if (nch == '>')
+ return ptok->tk_symb = RIGHT;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ case '|':
+ if (nch == '|')
+ return ptok->tk_symb = OR;
+ UnGetChar();
+ return ptok->tk_symb = ch;
+ }
+ case STCHAR: /* character constant */
+ ptok->tk_ival = char_constant("character");
+ ptok->tk_fund = INT;
+ return ptok->tk_symb = INTEGER;
+ case STSTR: /* string */
+ ptok->tk_bts = string_token("string", '"', &(ptok->tk_len));
+ ptok->tk_fund = CHAR; /* string of characters */
+ return ptok->tk_symb = STRING;
+ case STELL: /* wide character constant/string prefix */
+ nch = GetChar();
+ if (nch == '"') {
+ ptok->tk_bts = string_token("wide character string",
+ '"', &(ptok->tk_len));
+ ptok->tk_fund = WCHAR; /* string of wide characters */
+ return ptok->tk_symb = STRING;
+ } else if (nch == '\'') {
+ ptok->tk_ival = char_constant("wide character");
+ ptok->tk_fund = INT;
+ return ptok->tk_symb = INTEGER;
+ }
+ UnGetChar();
+ case STIDF:
+ {
+ register char *tg = &buf[0];
+ register int pos = -1;
+ register int hash;
+ register struct idf *idef;
+ extern int idfsize; /* ??? */
+
+ hash = STARTHASH();
+ do { /* read the identifier */
+ if (++pos < idfsize) {
+ *tg++ = ch;
+ hash = ENHASH(hash, ch, pos);
+ }
+ ch = GetChar();
+ } while (in_idf(ch));
+
+ hash = STOPHASH(hash);
+ if (ch != EOI)
+ UnGetChar();
+ *tg++ = '\0'; /* mark the end of the identifier */
+ idef = ptok->tk_idf = idf_hashed(buf, tg - buf, hash);
+ idef->id_file = ptok->tk_file;
+ idef->id_line = ptok->tk_line;
+#ifndef NOPP
+ if (idef->id_macro && ReplaceMacros) {
+ if (idef->id_macro->mc_count > 0)
+ idef->id_macro->mc_count--;
+ else if (replace(idef))
+ goto again;
+ }
+ if (UnknownIdIsZero && idef->id_reserved != SIZEOF) {
+ ptok->tk_ival = (arith)0;
+ ptok->tk_fund = INT;
+ return ptok->tk_symb = INTEGER;
+ }
+#endif NOPP
+ ptok->tk_symb = (
+ idef->id_reserved ? idef->id_reserved
+ : idef->id_def && idef->id_def->df_sc == TYPEDEF ?
+ TYPE_IDENTIFIER
+ : IDENTIFIER
+ );
+ return IDENTIFIER;
+ }
+ case STNUM: /* a numeric constant */
+ {
+ register char *np = &buf[1];
+ register int base = 10;
+ register int vch;
+ register arith val = 0;
+
+ if (ch == '.') {
+#ifndef NOFLOAT
+ /* A very embarrasing ambiguity. We have either a
+ floating point number or field operator or
+ ELLIPSIS.
+ */
+ ch = GetChar();
+ if (!is_dig(ch)) { /* . or ... */
+ if (ch == '.') {
+ if ((ch = GetChar()) == '.')
+ return ptok->tk_symb = ELLIPSIS;
+ /* This is funny: we can't push the
+ second dot back. But then again
+ ..<ch> is already an error in C,
+ so why bother ?
+ */
+ UnGetChar();
+ lexerror("illegal combination '..'");
+ }
+ UnGetChar();
+ return ptok->tk_symb = '.';
+ } else
+ *np++ = '0';
+ UnGetChar();
+#else
+ if ((ch = GetChar()) == '.') {
+ if ((ch = GetChar()) == '.')
+ return ptok->tk_symb = ELLIPSIS;
+ UnGetChar();
+ lexerror("illegal combination '..'");
+ }
+ UnGetChar();
+ return ptok->tk_symb = '.';
+#endif
+ }
+ if (ch == '0') {
+ *np++ = ch;
+ ch = GetChar();
+ if (ch == 'x' || ch == 'X') {
+ base = 16;
+ ch = GetChar();
+ }
+ else
+ base = 8;
+ }
+ while (vch = val_in_base(ch, base), vch >= 0) {
+ val = val*base + vch;
+ if (np < &buf[NUMSIZE])
+ *np++ = ch;
+ ch = GetChar();
+ }
+ if (is_suf(ch)) {
+ register int suf_long = 0;
+ register int suf_unsigned = 0;
+
+ /* The type of the integal constant is
+ based on its suffix.
+ */
+ do {
+ switch (ch) {
+ case 'l':
+ case 'L':
+ suf_long++;
+ break;
+ case 'u':
+ case 'U':
+ suf_unsigned++;
+ break;
+ }
+ ch = GetChar();
+ } while (is_suf(ch));
+ UnGetChar();
+
+ if (suf_long > 1)
+ lexerror("only one long suffix allowed");
+ if (suf_unsigned > 1)
+ lexerror("only one unsigned suffix allowed");
+
+ ptok->tk_fund = (suf_long && suf_unsigned) ? ULONG :
+ (suf_long) ? LONG : UNSIGNED;
+ ptok->tk_ival = val;
+ return ptok->tk_symb = INTEGER;
+ }
+#ifndef NOFLOAT
+ if (base == 16 || !(ch == '.' || ch == 'e' || ch == 'E'))
+#endif NOFLOAT
+ {
+ UnGetChar();
+ ptok->tk_ival = val;
+ /* The semantic analyser must know if the
+ integral constant is given in octal/hexa-
+ decimal form, in which case its type is
+ UNSIGNED, or in decimal form, in which case
+ its type is signed, indicated by
+ the fund INTEGER.
+ */
+ ptok->tk_fund =
+ (base == 10 || (base == 8 && val == (arith)0))
+ ? INTEGER : UNSIGNED;
+ return ptok->tk_symb = INTEGER;
+ }
+ /* where's the test for the length of the integral ??? */
+#ifndef NOFLOAT
+ if (ch == '.'){
+ if (np < &buf[NUMSIZE])
+ *np++ = ch;
+ ch = GetChar();
+ }
+ while (is_dig(ch)){
+ if (np < &buf[NUMSIZE])
+ *np++ = ch;
+ ch = GetChar();
+ }
+ if (ch == 'e' || ch == 'E') {
+ if (np < &buf[NUMSIZE])
+ *np++ = ch;
+ ch = GetChar();
+ if (ch == '+' || ch == '-') {
+ if (np < &buf[NUMSIZE])
+ *np++ = ch;
+ ch = GetChar();
+ }
+ if (!is_dig(ch)) {
+ lexerror("malformed floating constant");
+ if (np < &buf[NUMSIZE])
+ *np++ = ch;
+ }
+ while (is_dig(ch)) {
+ if (np < &buf[NUMSIZE])
+ *np++ = ch;
+ ch = GetChar();
+ }
+ }
+
+ /* The type of an integral floating point
+ constant may be given by the float (f)
+ or long double (l) suffix.
+ */
+ if (ch == 'f' || ch == 'F')
+ ptok->tk_fund = FLOAT;
+ else if (ch == 'l' || ch == 'L')
+ ptok->tk_fund = LNGDBL;
+ else {
+ ptok->tk_fund = DOUBLE;
+ UnGetChar();
+ }
+
+ *np++ = '\0';
+ buf[0] = '-'; /* good heavens... */
+ if (np == &buf[NUMSIZE+1]) {
+ lexerror("floating constant too long");
+ ptok->tk_fval = Salloc("0.0",(unsigned) 5) + 1;
+ }
+ else
+ ptok->tk_fval = Salloc(buf,(unsigned) (np - buf)) + 1;
+ return ptok->tk_symb = FLOATING;
+#endif NOFLOAT
+ }
+ case STEOI: /* end of text on source file */
+ return ptok->tk_symb = EOI;
+ default: /* this cannot happen */
+ crash("bad class for char 0%o", ch);
+ }
+ /*NOTREACHED*/
+}
+
+skipcomment()
+{
+ /* The last character read has been the '*' of '/_*'. The
+ characters, except NL and EOI, between '/_*' and the first
+ occurring '*_/' are not interpreted.
+ NL only affects the LineNumber. EOI is not legal.
+
+ Important note: it is not possible to stop skipping comment
+ beyond the end-of-file of an included file.
+ EOI is returned by LoadChar only on encountering EOF of the
+ top-level file...
+ */
+ register int c;
+
+ NoUnstack++;
+ c = GetChar();
+#ifdef LINT
+ lint_start_comment();
+ lint_comment_char(c);
+#endif LINT
+ do {
+ while (c != '*') {
+ if (class(c) == STNL) {
+ ++LineNumber;
+ } else
+ if (c == EOI) {
+ NoUnstack--;
+#ifdef LINT
+ lint_end_comment();
+#endif LINT
+ return;
+ }
+ if (c == '/' && (c = GetChar()) == '*')
+ strict("extra comment delimiter found");
+ c = GetChar();
+#ifdef LINT
+ lint_comment_char(c);
+#endif LINT
+ } /* last Character seen was '*' */
+ c = GetChar();
+#ifdef LINT
+ lint_comment_char(c);
+#endif LINT
+ } while (c != '/');
+#ifdef LINT
+ lint_end_comment();
+#endif LINT
+ NoUnstack--;
+}
+
+arith
+char_constant(nm)
+ char *nm;
+{
+ register arith val = 0;
+ register int ch;
+ int size = 0;
+
+ ch = GetChar();
+ if (ch == '\'')
+ lexerror("%s constant too short", nm);
+ else
+ while (ch != '\'') {
+ if (ch == '\n') {
+ lexerror("newline in %s constant", nm);
+ LineNumber++;
+ break;
+ }
+ if (ch == '\\')
+ ch = quoted(GetChar());
+ if (ch >= 128) ch -= 256;
+ val = val*256 + ch;
+ size++;
+ ch = GetChar();
+ }
+ if (size > 1)
+ strict("%s constant includes more than one character", nm);
+ if (size > (int)int_size)
+ lexerror("%s constant too long", nm);
+ return val;
+}
+
+char *
+string_token(nm, stop_char, plen)
+ char *nm;
+ int *plen;
+{
+ register int ch;
+ register int str_size;
+ register char *str = Malloc((unsigned) (str_size = ISTRSIZE));
+ register int pos = 0;
+
+ ch = GetChar();
+ while (ch != stop_char) {
+ if (ch == '\n') {
+ lexerror("newline in %s", nm);
+ LineNumber++;
+ break;
+ }
+ if (ch == EOI) {
+ lexerror("end-of-file inside %s", nm);
+ break;
+ }
+ if (ch == '\\')
+ ch = quoted(GetChar());
+ str[pos++] = ch;
+ if (pos == str_size)
+ str = Srealloc(str, (unsigned) (str_size += RSTRSIZE));
+ ch = GetChar();
+ }
+ str[pos++] = '\0'; /* for filenames etc. */
+ *plen = pos;
+ return str;
+}
+
+int
+quoted(ch)
+ register int ch;
+{
+ /* quoted() replaces an escaped character sequence by the
+ character meant.
+ */
+ /* first char after backslash already in ch */
+ if (!is_oct(ch)) { /* a quoted char */
+ switch (ch) {
+ case 'n':
+ ch = '\n';
+ break;
+ case 't':
+ ch = '\t';
+ break;
+ case 'b':
+ ch = '\b';
+ break;
+ case 'r':
+ ch = '\r';
+ break;
+ case 'f':
+ ch = '\f';
+ break;
+ case 'a': /* alert */
+ ch = '\007';
+ break;
+ case 'v': /* vertical tab */
+ ch = '\013';
+ break;
+ case 'x': /* quoted hex */
+ {
+ register int hex = 0;
+ register int vch;
+
+ for (;;) {
+ ch = GetChar();
+ if (vch = val_in_base(ch, 16), vch == -1)
+ break;
+ hex = hex * 16 + vch;
+ }
+ UnGetChar();
+ ch = hex;
+ }
+ }
+ }
+ else { /* a quoted octal */
+ register int oct = 0, cnt = 0;
+
+ do {
+ oct = oct*8 + (ch-'0');
+ ch = GetChar();
+ } while (is_oct(ch) && ++cnt < 3);
+ UnGetChar();
+ ch = oct;
+ }
+ return ch&0377;
+}
+
+
+int
+val_in_base(ch, base)
+ register int ch;
+{
+ switch (base) {
+ case 8:
+ return (is_dig(ch) && ch < '9') ? ch - '0' : -1;
+ case 10:
+ case 16:
+ return is_dig(ch) ? ch - '0'
+ : is_hex(ch) ? (ch - 'a' + 10) & 017
+ : -1;
+ default:
+ fatal("(val_in_base) illegal base value %d", base);
+ /* NOTREACHED */
+ }
+}
+
+
+int
+GetChar()
+{
+ /* The routines GetChar and trigraph parses the trigraph
+ sequences and removes occurences of \\\n.
+ */
+ register int ch;
+
+again:
+ LoadChar(ch);
+
+ /* possible trigraph sequence */
+ if (ch == '?')
+ ch = trigraph();
+
+ /* \\\n are removed from the input stream */
+ if (ch == '\\') {
+ LoadChar(ch);
+ if (ch == '\n') {
+ ++LineNumber;
+ goto again;
+ }
+ PushBack();
+ ch = '\\';
+ }
+ return(LexSave = ch);
+}
+
+
+int
+trigraph()
+{
+ register int ch;
+
+ LoadChar(ch);
+ if (ch == '?') {
+ LoadChar(ch);
+ switch (ch) { /* its a trigraph */
+ case '=':
+ ch = '#';
+ return(ch);
+ case '(':
+ ch = '[';
+ return(ch);
+ case '/':
+ ch = '\\';
+ return(ch);
+ case ')':
+ ch = ']';
+ return(ch);
+ case '\'':
+ ch = '^';
+ return(ch);
+ case '<':
+ ch = '{';
+ return(ch);
+ case '!':
+ ch = '|';
+ return(ch);
+ case '>':
+ ch = '}';
+ return(ch);
+ case '-':
+ ch = '~';
+ return(ch);
+ }
+ PushBack();
+ }
+ PushBack();
+ return('?');
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* D E F I N I T I O N S F O R T H E L E X I C A L A N A L Y Z E R */
+
+/* A token from the input stream is represented by an integer,
+ called a "symbol", but it may have other information associated
+ to it.
+*/
+
+#include "nofloat.h"
+#include "file_info.h"
+#include "nopp.h"
+
+/* the structure of a token: */
+struct token {
+ int tok_symb; /* the token itself */
+ char *tok_file; /* the file it (probably) comes from */
+ unsigned int tok_line; /* the line it (probably) comes from */
+ int tok_fund;
+ union {
+ struct idf *tok_idf; /* for IDENTIFIER & TYPE_IDENTIFIER */
+ struct { /* for STRING */
+ char *tok_bts; /* row of bytes */
+ int tok_len; /* length of row of bytes */
+ } tok_string;
+ arith tok_ival; /* for INTEGER */
+#ifndef NOFLOAT
+ char *tok_fval; /* for FLOATING */
+#endif NOFLOAT
+ } tok_data;
+};
+
+#define tk_symb tok_symb
+#define tk_file tok_file
+#define tk_line tok_line
+#define tk_fund tok_fund
+#define tk_idf tok_data.tok_idf
+#define tk_bts tok_data.tok_string.tok_bts
+#define tk_len tok_data.tok_string.tok_len
+#define tk_ival tok_data.tok_ival
+#ifndef NOFLOAT
+#define tk_fval tok_data.tok_fval
+#endif NOFLOAT
+
+extern struct token dot, ahead, aside;
+
+#ifndef NOPP
+extern int ReplaceMacros; /* "LLlex.c" */
+extern int AccDefined; /* "LLlex.c" */
+extern int Unstacked; /* "LLlex.c" */
+extern int UnknownIdIsZero; /* "LLlex.c" */
+#endif NOPP
+extern int EoiForNewline; /* "LLlex.c" */
+extern int AccFileSpecifier; /* "LLlex.c" */
+extern int SkipEscNewline; /* "LLlex.c" */
+extern int File_Inserted; /* "LLlex.c" */
+
+extern int NoUnstack; /* buffer.c */
+
+extern int err_occurred; /* "error.c" */
+
+#define DOT dot.tk_symb
+#define AHEAD ahead.tk_symb
+#define ASIDE aside.tk_symb
+
+#define EOF (-1)
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PARSER ERROR ADMINISTRATION */
+
+#include <alloc.h>
+#include "nofloat.h"
+#include "idf.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "Lpars.h"
+
+extern char *symbol2str();
+
+LLmessage(tk) {
+ err_occurred = 1;
+ if (tk < 0) {
+ error("end of file expected");
+ }
+ else if (tk) {
+ error("%s missing", symbol2str(tk));
+ insert_token(tk);
+ }
+ else
+ error("%s deleted", symbol2str(DOT));
+}
+
+insert_token(tk)
+ int tk;
+{
+ aside = dot;
+
+ DOT = tk;
+
+ switch (tk) {
+ /* The operands need some body */
+ case IDENTIFIER:
+ dot.tk_idf = gen_idf();
+ break;
+ case TYPE_IDENTIFIER:
+ dot.tk_idf = str2idf("int");
+ break;
+ case STRING:
+ dot.tk_bts = Salloc("", 1);
+ dot.tk_len = 1;
+ break;
+ case INTEGER:
+ dot.tk_fund = INT;
+ dot.tk_ival = 1;
+ break;
+#ifndef NOFLOAT
+ case FLOATING:
+ dot.tk_fval = Salloc("0.0", 4);
+ break;
+#endif NOFLOAT
+ }
+}
--- /dev/null
+!File: lint.h
+#define LINT 1 /* if defined, 'lint' is produced */
+
+
+!File: pathlength.h
+#define PATHLENGTH 1024 /* max. length of path to file */
+
+
+!File: errout.h
+#define ERROUT STDERR /* file pointer for writing messages */
+#define MAXERR_LINE 5 /* maximum number of error messages given
+ on the same input line. */
+
+
+!File: idfsize.h
+#define IDFSIZE 64 /* maximum significant length of an identifier */
+
+
+!File: numsize.h
+#define NUMSIZE 256 /* maximum length of a numeric constant */
+
+
+!File: nparams.h
+#define NPARAMS 32 /* maximum number of parameters of macros */
+
+
+!File: ifdepth.h
+#define IFDEPTH 256 /* maximum number of nested if-constructions */
+
+
+!File: density.h
+#define DENSITY 2 /* see switch.[ch] for an explanation */
+
+
+!File: lapbuf.h
+#define LAPBUF 4096 /* size of macro actual parameter buffer */
+
+
+!File: strsize.h
+#define ISTRSIZE 32 /* minimum number of bytes allocated for
+ storing a string */
+#define RSTRSIZE 8 /* step size in enlarging the memory for
+ the storage of a string */
+
+
+!File: target_sizes.h
+#define MAXSIZE 8 /* the maximum of the SZ_* constants */
+
+/* target machine sizes */
+#define SZ_CHAR (arith)1
+#define SZ_SHORT (arith)2
+#define SZ_WORD (arith)4
+#define SZ_INT (arith)4
+#define SZ_LONG (arith)4
+#ifndef NOFLOAT
+#define SZ_FLOAT (arith)4
+#define SZ_DOUBLE (arith)8
+#endif NOFLOAT
+#define SZ_POINTER (arith)4
+
+/* target machine alignment requirements */
+#define AL_CHAR 1
+#define AL_SHORT SZ_SHORT
+#define AL_WORD SZ_WORD
+#define AL_INT SZ_WORD
+#define AL_LONG SZ_WORD
+#ifndef NOFLOAT
+#define AL_FLOAT SZ_WORD
+#define AL_DOUBLE SZ_WORD
+#endif NOFLOAT
+#define AL_POINTER SZ_WORD
+#define AL_STRUCT 1
+#define AL_UNION 1
+
+
+!File: botch_free.h
+#undef BOTCH_FREE 1 /* when defined, botch freed memory, as a check */
+
+
+!File: dataflow.h
+#undef DATAFLOW 1 /* produce some compile-time xref */
+
+
+!File: debug.h
+#undef DEBUG 1 /* perform various self-tests */
+
+
+!File: use_tmp.h
+#undef PREPEND_SCOPES 1 /* collect exa, exp, ina and inp commands
+ and if USE_TMP is defined let them
+ precede the rest of the generated
+ compact code */
+#undef USE_TMP 1 /* use C_insertpart, C_endpart mechanism
+ to generate EM-code in the order needed
+ for the code-generators. If not defined,
+ the old-style peephole optimizer is
+ needed. */
+
+
+!File: parbufsize.h
+#define PARBUFSIZE 1024
+
+
+!File: textsize.h
+#define ITEXTSIZE 8 /* 1st piece of memory for repl. text */
+#define RTEXTSIZE 8 /* stepsize for enlarging repl.text */
+
+
+!File: inputtype.h
+#define INP_READ_IN_ONE 1 /* read input file in one */
+
+
+!File: nopp.h
+#undef NOPP 1 /* if NOT defined, use built-int preprocessor */
+
+
+!File: nobitfield.h
+#undef NOBITFIELD 1 /* if NOT defined, implement bitfields */
+
+
+!File: spec_arith.h
+/* describes internal compiler arithmetics */
+#undef SPECIAL_ARITHMETICS /* something different from native long */
+
+
+!File: static.h
+#define GSTATIC /* for large global "static" arrays */
+
+
+!File: nofloat.h
+#undef NOFLOAT 1 /* if NOT defined, floats are implemented */
+
+
+!File: noRoption.h
+#undef NOROPTION 1 /* if NOT defined, R option is implemented */
+
+
+!File: nocross.h
+#undef NOCROSS 1 /* if NOT defined, cross compiler */
+
+
+!File: regcount.h
+#undef REGCOUNT 1 /* count occurrences for register messages */
+
+
--- /dev/null
+# $Header$
+# M A K E F I L E F O R A C K C - C O M P I L E R
+
+# Machine and environ dependent definitions
+EMHOME = ../../..
+CC = /proj/em/Work/bin/fcc.cc
+CFLOW = cflow
+MAKE = make
+MKDEP = $(EMHOME)/bin/mkdep
+PRID = $(EMHOME)/bin/prid
+CID = $(EMHOME)/bin/cid
+
+# Libraries and EM interface definitions
+SYSLIB = $(EMHOME)/modules/lib/libsystem.a
+EMKLIB = $(EMHOME)/modules/lib/libemk.a $(EMHOME)/lib/em_data.a
+EMOLIB = $(EMHOME)/modules/lib/libemopt.a
+EMELIB = $(EMHOME)/modules/lib/libeme.a $(EMHOME)/lib/em_data.a
+STRLIB = $(EMHOME)/modules/lib/libstring.a
+PRTLIB = $(EMHOME)/modules/lib/libprint.a
+EMMESLIB = $(EMHOME)/modules/lib/libem_mes.a
+EMMESOLIB = $(EMHOME)/modules/lib/libem_mesO.a
+EMMESCELIB = $(EMHOME)/modules/lib/libem_mesCE.a
+MACH = sun3
+EMCELIB = $(EMHOME)/lib/$(MACH)/ce.a \
+ $(EMHOME)/lib/$(MACH)/back.a \
+ $(EMHOME)/modules/lib/libobject.a $(EMHOME)/lib/em_data.a
+INPLIB = $(EMHOME)/modules/lib/libinput.a
+ALLOCLIB = $(EMHOME)/modules/lib/liballoc.a
+MALLOC = $(EMHOME)/modules/lib/malloc.o
+LIBS = $(INPLIB) $(EMMESLIB) $(EMKLIB) $(PRTLIB) $(STRLIB) \
+ $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+ELIBS = $(INPLIB) $(EMMESLIB) $(EMELIB) $(PRTLIB) $(STRLIB) \
+ $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+OLIBS = $(INPLIB) $(EMMESOLIB) $(EMOLIB) $(EMKLIB) $(PRTLIB) $(STRLIB) \
+ $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+CELIBS = $(INPLIB) $(EMMESCELIB) $(EMCELIB) $(PRTLIB) $(STRLIB) \
+ $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+LLIBS = $(INPLIB) $(EMMESLIB) $(PRTLIB) $(STRLIB) \
+ $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+LIB_INCLUDES = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg
+EM_INCLUDES = -I$(EMHOME)/h
+SYSLLIB = $(EMHOME)/modules/lib/llib-lsystem.ln
+EMKLLIB = $(EMHOME)/modules/lib/llib-lemk.ln
+EMELLIB = $(EMHOME)/modules/lib/llib-leme.ln
+STRLLIB = $(EMHOME)/modules/lib/llib-lstring.ln
+PRTLLIB = $(EMHOME)/modules/lib/llib-lprint.ln
+EMMESLLIB = $(EMHOME)/modules/lib/llib-lem_mes.ln
+INPLLIB = $(EMHOME)/modules/lib/llib-linput.ln
+ALLOCLLIB = $(EMHOME)/modules/lib/llib-lalloc.ln
+#LINTLIBS =
+LINTLIBS = $(EMMESLLIB) $(EMKLLIB) $(PRTLLIB) $(STRLLIB) $(ALLOCLLIB) $(SYSLLIB)
+CURRDIR =
+
+COPTIONS =
+
+# What parser generator to use and how
+GEN = $(EMHOME)/bin/LLgen
+GENOPTIONS = -v
+
+# Special #defines during compilation
+PROF = #-pg
+CDEFS = $(EM_INCLUDES) $(LIB_INCLUDES)
+CFLAGS = $(CDEFS) $(COPTIONS) $(PROF) #-O
+LDFLAGS = -i $(PROF)
+
+# Grammar files and their objects
+LSRC = tokenfile.g declar.g statement.g expression.g program.g ival.g
+LCSRC = tokenfile.c declar.c statement.c expression.c program.c Lpars.c ival.c
+LOBJ = tokenfile.o declar.o statement.o expression.o program.o Lpars.o ival.o
+
+# Objects of hand-written C files
+CSRC = main.c idf.c declarator.c decspecs.c struct.c \
+ expr.c ch7.c ch7bin.c cstoper.c arith.c \
+ code.c dumpidf.c error.c field.c\
+ tokenname.c LLlex.c LLmessage.c \
+ input.c domacro.c replace.c init.c options.c \
+ skip.c stack.c type.c ch7mon.c label.c eval.c \
+ switch.c conversion.c util.c proto.c \
+ pragma.c blocks.c dataflow.c Version.c \
+ l_lint.c l_states.c l_misc.c l_ev_ord.c l_outdef.c l_comment.c l_dummy.c
+COBJ = main.o idf.o declarator.o decspecs.o struct.o \
+ expr.o ch7.o ch7bin.o cstoper.o arith.o \
+ code.o dumpidf.o error.o field.o\
+ tokenname.o LLlex.o LLmessage.o \
+ input.o domacro.o replace.o init.o options.o \
+ skip.o stack.o type.o ch7mon.o label.o eval.o \
+ switch.o conversion.o util.o proto.o \
+ pragma.o blocks.o dataflow.o Version.o \
+ l_lint.o l_states.o l_misc.o l_ev_ord.o l_outdef.o l_comment.o l_dummy.o
+
+# Objects of other generated C files
+GCSRC = char.c symbol2str.c next.c
+GOBJ = char.o symbol2str.o next.o
+
+STRSRC = code.str declar.str decspecs.str def.str expr.str field.str \
+ estack.str util.str proto.str replace.str \
+ idf.str macro.str stack.str stmt.str struct.str switch.str type.str \
+ l_brace.str l_state.str l_outdef.str
+# generated source files
+GHSTRSRC = code.h declar.h decspecs.h def.h expr.h field.h \
+ estack.h util.h proto.h replace.h \
+ idf.h macro.h stack.h stmt.h struct.h switch.h type.h \
+ l_brace.h l_state.h l_outdef.h
+GSRC = $(GCSRC) $(GHSTRSRC)
+
+# .h files generated by `make hfiles LLfiles'; PLEASE KEEP THIS UP-TO-DATE!
+GHSRC = botch_free.h dataflow.h debug.h density.h errout.h \
+ idfsize.h ifdepth.h inputtype.h lapbuf.h argbuf.h lint.h \
+ nobitfield.h nofloat.h nopp.h noRoption.h nocross.h \
+ nparams.h numsize.h parbufsize.h pathlength.h Lpars.h \
+ strsize.h target_sizes.h textsize.h use_tmp.h spec_arith.h static.h \
+ regcount.h
+
+HSRC = LLlex.h align.h arith.h assert.h atw.h class.h \
+ input.h label.h level.h mes.h sizes.h specials.h \
+ file_info.h tokenname.h l_lint.h
+
+HFILES = $(HSRC) $(GHSRC) $(GHSTRSRC)
+
+# generated files, for 'make clean' only
+GENERATED = tokenfile.g Lpars.h LLfiles LL.output lint.out \
+ print hfiles Cfiles $(GHSRC) $(GSRC) longnames $(LCSRC)
+
+# include files containing ALLOCDEF specifications
+OBJ = $(COBJ) $(LOBJ) $(GOBJ)
+SRC = $(CSRC) $(LCSRC) $(GCSRC)
+
+LINT = /usr/bin/lint
+LINTFLAGS =
+
+MYLINT = /usr/star/dick/bin/lint #../lint
+MYLINTFLAGS = #-xh
+
+#EXCLEXCLEXCLEXCL
+
+.SUFFIXES: .str .h
+.str.h:
+ ./make.allocd <$*.str >$*.h
+
+Main: Cfiles
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) $(CURRDIR)main ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve main ; fi'
+ @rm -f nmclash.o a.out
+
+Emain: Cfiles
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) $(CURRDIR)emain ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve emain ; fi'
+ @rm -f nmclash.o a.out
+
+Omain: Cfiles
+ rm -f *.o
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) "COPTIONS="-DPEEPHOLE $(CURRDIR)omain ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve omain ; fi'
+ @rm -f nmclash.o a.out
+ mv *.o PEEPHOLE
+
+CEmain: Cfiles
+ rm -f *.o
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) "COPTIONS="-DCODE_EXPANDER $(CURRDIR)cemain ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve cemain ; fi'
+ @rm -f nmclash.o a.out
+ mv *.o CODE_EXPANDER
+
+Lnt: Cfiles
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) $(CURRDIR)lnt ; else EMHOME=$(EMHOME); export EMHOME; ./Resolve lnt ; fi'
+ make "EMHOME="$(EMHOME) $(CURRDIR)lnt
+ @rm -f nmclash.o a.out
+
+install: Main
+ rm -f $(EMHOME)/lib/em_cemcom $(EMHOME)/man/em_cemcom.6
+ cp $(CURRDIR)main $(EMHOME)/lib/em_cemcom
+ cp $(CURRDIR)cemcom.1 $(EMHOME)/man/em_cemcom.6
+
+Oinstall: Omain
+ cp $(CURRDIR)omain $(EMHOME)/lib/em_cemcomO
+
+cmp: Main
+ -cmp $(CURRDIR)main $(EMHOME)/lib/em_cemcom
+ -cmp $(CURRDIR)cemcom.1 $(EMHOME)/man/em_cemcom.6
+
+pr:
+ @pr Makefile make.* char.tab Parameters $(HSRC) $(STRSRC) $(LSRC) $(CSRC)
+
+opr:
+ $(MAKE) pr | opr
+
+clean:
+ rm -f $(OBJ)
+ rm -f $(GENERATED) main
+ (cd .. ; rm -rf Xsrc)
+
+cflow: Cfiles
+ $(CFLOW) $(CDEFS) $(SRC)
+
+lint: Cfiles
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then $(MAKE) "EMHOME="$(EMHOME) Xlint ; else sh Resolve Xlint ; fi'
+ @rm -f nmclash.o a.out
+
+mylint: Cfiles
+ sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then $(MAKE) "EMHOME="$(EMHOME) Xmylint ; else sh Resolve Xmylint ; fi'
+ @rm -f nmclash.o a.out
+
+longnames: $(SRC) $(HFILES)
+ sh -c 'if test -f longnames ; then : ; else touch longnames ; fi ; $(PRID) -l7 longnames $? > Xlongnames ; mv Xlongnames longnames'
+
+# entry points not to be used directly
+
+Cfiles: hfiles LLfiles $(GENCFILES) $(GSRC) $(GHSRC) Makefile
+ echo $(SRC) $(HFILES) > Cfiles
+
+hfiles: ./make.hfiles Parameters
+ ./make.hfiles Parameters
+ @touch hfiles
+
+LLfiles: $(LSRC)
+ $(GEN) $(GENOPTIONS) $(LSRC)
+ @touch LLfiles
+
+tokenfile.g: tokenname.c make.tokfile
+ <tokenname.c ./make.tokfile >tokenfile.g
+
+symbol2str.c: tokenname.c make.tokcase
+ <tokenname.c ./make.tokcase >symbol2str.c
+
+char.c: char.tab
+ $(EMHOME)/bin/tabgen -fchar.tab >char.c
+
+next.c: make.next $(STRSRC)
+ ./make.next $(STRSRC) >next.c
+
+code.h: make.allocd
+declar.h: make.allocd
+decspecs.h: make.allocd
+def.h: make.allocd
+expr.h: make.allocd
+field.h: make.allocd
+idf.h: make.allocd
+macro.h: make.allocd
+stack.h: make.allocd
+stmt.h: make.allocd
+struct.h: make.allocd
+switch.h: make.allocd
+type.h: make.allocd
+estack.h: make.allocd
+util.h: make.allocd
+l_brace.h: make.allocd
+l_state.h: make.allocd
+l_outdef.h: make.allocd
+
+depend: Cfiles
+ sed '/^#AUTOAUTO/,$$d' Makefile >Makefile.new
+ echo '#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO' >>Makefile.new
+ $(MKDEP) $(SRC) | sed 's/\.c:/.o:/' >>Makefile.new
+ mv Makefile Makefile.old
+ mv Makefile.new Makefile
+
+#INCLINCLINCLINCL
+
+$(CURRDIR)main: $(OBJ) $(CURRDIR)Makefile
+ $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(LIBS) -o $(CURRDIR)main
+ size $(CURRDIR)main
+
+$(CURRDIR)emain: $(OBJ) $(CURRDIR)Makefile
+ $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(ELIBS) -o $(CURRDIR)emain
+ size $(CURRDIR)emain
+
+$(CURRDIR)omain: $(OBJ) $(CURRDIR)Makefile
+ $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(OLIBS) -o $(CURRDIR)omain
+ size $(CURRDIR)omain
+
+$(CURRDIR)cemain: $(OBJ) $(CURRDIR)Makefile
+ $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(CELIBS) -o $(CURRDIR)cemain
+ size $(CURRDIR)cemain
+
+$(CURRDIR)lnt: $(OBJ) $(CURRDIR)Makefile
+ $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(LLIBS) -o $(CURRDIR)lnt
+ size $(CURRDIR)lnt
+
+Xlint: $(SRC)
+ $(LINT) $(CDEFS) $(LINTFLAGS) $(SRC)
+
+Xmylint: $(SRC)
+ $(MYLINT) $(CDEFS) $(MYLINTFLAGS) $(SRC)
+
+#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
+main.o: LLlex.h
+main.o: Lpars.h
+main.o: align.h
+main.o: arith.h
+main.o: debug.h
+main.o: declar.h
+main.o: file_info.h
+main.o: idf.h
+main.o: input.h
+main.o: inputtype.h
+main.o: level.h
+main.o: lint.h
+main.o: noRoption.h
+main.o: nobitfield.h
+main.o: nocross.h
+main.o: nofloat.h
+main.o: nopp.h
+main.o: proto.h
+main.o: sizes.h
+main.o: spec_arith.h
+main.o: specials.h
+main.o: target_sizes.h
+main.o: tokenname.h
+main.o: type.h
+main.o: use_tmp.h
+idf.o: LLlex.h
+idf.o: Lpars.h
+idf.o: align.h
+idf.o: arith.h
+idf.o: assert.h
+idf.o: botch_free.h
+idf.o: debug.h
+idf.o: declar.h
+idf.o: decspecs.h
+idf.o: def.h
+idf.o: file_info.h
+idf.o: idf.h
+idf.o: idfsize.h
+idf.o: label.h
+idf.o: level.h
+idf.o: lint.h
+idf.o: noRoption.h
+idf.o: nobitfield.h
+idf.o: nocross.h
+idf.o: nofloat.h
+idf.o: nopp.h
+idf.o: nparams.h
+idf.o: proto.h
+idf.o: sizes.h
+idf.o: spec_arith.h
+idf.o: specials.h
+idf.o: stack.h
+idf.o: struct.h
+idf.o: target_sizes.h
+idf.o: type.h
+declarator.o: Lpars.h
+declarator.o: arith.h
+declarator.o: botch_free.h
+declarator.o: debug.h
+declarator.o: declar.h
+declarator.o: def.h
+declarator.o: expr.h
+declarator.o: idf.h
+declarator.o: label.h
+declarator.o: level.h
+declarator.o: lint.h
+declarator.o: nobitfield.h
+declarator.o: nocross.h
+declarator.o: nofloat.h
+declarator.o: nopp.h
+declarator.o: proto.h
+declarator.o: sizes.h
+declarator.o: spec_arith.h
+declarator.o: target_sizes.h
+declarator.o: type.h
+decspecs.o: Lpars.h
+decspecs.o: arith.h
+decspecs.o: assert.h
+decspecs.o: debug.h
+decspecs.o: decspecs.h
+decspecs.o: def.h
+decspecs.o: level.h
+decspecs.o: lint.h
+decspecs.o: noRoption.h
+decspecs.o: nobitfield.h
+decspecs.o: nofloat.h
+decspecs.o: spec_arith.h
+decspecs.o: type.h
+struct.o: LLlex.h
+struct.o: Lpars.h
+struct.o: align.h
+struct.o: arith.h
+struct.o: assert.h
+struct.o: botch_free.h
+struct.o: debug.h
+struct.o: def.h
+struct.o: field.h
+struct.o: file_info.h
+struct.o: idf.h
+struct.o: level.h
+struct.o: lint.h
+struct.o: noRoption.h
+struct.o: nobitfield.h
+struct.o: nocross.h
+struct.o: nofloat.h
+struct.o: nopp.h
+struct.o: proto.h
+struct.o: sizes.h
+struct.o: spec_arith.h
+struct.o: stack.h
+struct.o: struct.h
+struct.o: target_sizes.h
+struct.o: type.h
+expr.o: LLlex.h
+expr.o: Lpars.h
+expr.o: arith.h
+expr.o: botch_free.h
+expr.o: declar.h
+expr.o: decspecs.h
+expr.o: def.h
+expr.o: expr.h
+expr.o: file_info.h
+expr.o: idf.h
+expr.o: label.h
+expr.o: level.h
+expr.o: lint.h
+expr.o: noRoption.h
+expr.o: nobitfield.h
+expr.o: nocross.h
+expr.o: nofloat.h
+expr.o: nopp.h
+expr.o: sizes.h
+expr.o: spec_arith.h
+expr.o: target_sizes.h
+expr.o: type.h
+ch7.o: Lpars.h
+ch7.o: arith.h
+ch7.o: assert.h
+ch7.o: debug.h
+ch7.o: def.h
+ch7.o: expr.h
+ch7.o: file_info.h
+ch7.o: idf.h
+ch7.o: label.h
+ch7.o: lint.h
+ch7.o: nobitfield.h
+ch7.o: nofloat.h
+ch7.o: nopp.h
+ch7.o: proto.h
+ch7.o: spec_arith.h
+ch7.o: struct.h
+ch7.o: type.h
+ch7bin.o: Lpars.h
+ch7bin.o: arith.h
+ch7bin.o: botch_free.h
+ch7bin.o: expr.h
+ch7bin.o: idf.h
+ch7bin.o: label.h
+ch7bin.o: lint.h
+ch7bin.o: noRoption.h
+ch7bin.o: nobitfield.h
+ch7bin.o: nofloat.h
+ch7bin.o: nopp.h
+ch7bin.o: spec_arith.h
+ch7bin.o: struct.h
+ch7bin.o: type.h
+cstoper.o: Lpars.h
+cstoper.o: arith.h
+cstoper.o: assert.h
+cstoper.o: debug.h
+cstoper.o: expr.h
+cstoper.o: idf.h
+cstoper.o: label.h
+cstoper.o: nobitfield.h
+cstoper.o: nocross.h
+cstoper.o: nofloat.h
+cstoper.o: nopp.h
+cstoper.o: sizes.h
+cstoper.o: spec_arith.h
+cstoper.o: target_sizes.h
+cstoper.o: type.h
+arith.o: Lpars.h
+arith.o: arith.h
+arith.o: expr.h
+arith.o: field.h
+arith.o: idf.h
+arith.o: label.h
+arith.o: lint.h
+arith.o: mes.h
+arith.o: noRoption.h
+arith.o: nobitfield.h
+arith.o: nocross.h
+arith.o: nofloat.h
+arith.o: nopp.h
+arith.o: proto.h
+arith.o: sizes.h
+arith.o: spec_arith.h
+arith.o: target_sizes.h
+arith.o: type.h
+code.o: Lpars.h
+code.o: arith.h
+code.o: assert.h
+code.o: atw.h
+code.o: botch_free.h
+code.o: code.h
+code.o: dataflow.h
+code.o: debug.h
+code.o: declar.h
+code.o: decspecs.h
+code.o: def.h
+code.o: expr.h
+code.o: file_info.h
+code.o: idf.h
+code.o: l_lint.h
+code.o: label.h
+code.o: level.h
+code.o: lint.h
+code.o: noRoption.h
+code.o: nobitfield.h
+code.o: nocross.h
+code.o: nofloat.h
+code.o: nopp.h
+code.o: sizes.h
+code.o: spec_arith.h
+code.o: specials.h
+code.o: stack.h
+code.o: stmt.h
+code.o: target_sizes.h
+code.o: type.h
+code.o: use_tmp.h
+dumpidf.o: Lpars.h
+dumpidf.o: arith.h
+dumpidf.o: debug.h
+dumpidf.o: declar.h
+dumpidf.o: def.h
+dumpidf.o: expr.h
+dumpidf.o: field.h
+dumpidf.o: idf.h
+dumpidf.o: label.h
+dumpidf.o: lint.h
+dumpidf.o: nobitfield.h
+dumpidf.o: nofloat.h
+dumpidf.o: nopp.h
+dumpidf.o: proto.h
+dumpidf.o: spec_arith.h
+dumpidf.o: stack.h
+dumpidf.o: static.h
+dumpidf.o: struct.h
+dumpidf.o: type.h
+error.o: LLlex.h
+error.o: arith.h
+error.o: debug.h
+error.o: def.h
+error.o: errout.h
+error.o: expr.h
+error.o: file_info.h
+error.o: label.h
+error.o: lint.h
+error.o: nofloat.h
+error.o: nopp.h
+error.o: spec_arith.h
+error.o: tokenname.h
+field.o: Lpars.h
+field.o: align.h
+field.o: arith.h
+field.o: assert.h
+field.o: code.h
+field.o: debug.h
+field.o: expr.h
+field.o: field.h
+field.o: idf.h
+field.o: label.h
+field.o: lint.h
+field.o: nobitfield.h
+field.o: nocross.h
+field.o: nofloat.h
+field.o: nopp.h
+field.o: sizes.h
+field.o: spec_arith.h
+field.o: target_sizes.h
+field.o: type.h
+tokenname.o: LLlex.h
+tokenname.o: Lpars.h
+tokenname.o: arith.h
+tokenname.o: file_info.h
+tokenname.o: idf.h
+tokenname.o: nofloat.h
+tokenname.o: nopp.h
+tokenname.o: spec_arith.h
+tokenname.o: tokenname.h
+LLlex.o: LLlex.h
+LLlex.o: Lpars.h
+LLlex.o: arith.h
+LLlex.o: assert.h
+LLlex.o: class.h
+LLlex.o: debug.h
+LLlex.o: def.h
+LLlex.o: file_info.h
+LLlex.o: idf.h
+LLlex.o: idfsize.h
+LLlex.o: input.h
+LLlex.o: lint.h
+LLlex.o: macro.h
+LLlex.o: nocross.h
+LLlex.o: nofloat.h
+LLlex.o: nopp.h
+LLlex.o: numsize.h
+LLlex.o: sizes.h
+LLlex.o: spec_arith.h
+LLlex.o: strsize.h
+LLlex.o: target_sizes.h
+LLmessage.o: LLlex.h
+LLmessage.o: Lpars.h
+LLmessage.o: arith.h
+LLmessage.o: file_info.h
+LLmessage.o: idf.h
+LLmessage.o: nofloat.h
+LLmessage.o: nopp.h
+LLmessage.o: spec_arith.h
+input.o: file_info.h
+input.o: input.h
+input.o: inputtype.h
+input.o: nopp.h
+domacro.o: LLlex.h
+domacro.o: Lpars.h
+domacro.o: arith.h
+domacro.o: assert.h
+domacro.o: botch_free.h
+domacro.o: class.h
+domacro.o: debug.h
+domacro.o: file_info.h
+domacro.o: idf.h
+domacro.o: idfsize.h
+domacro.o: ifdepth.h
+domacro.o: input.h
+domacro.o: macro.h
+domacro.o: nofloat.h
+domacro.o: nopp.h
+domacro.o: nparams.h
+domacro.o: parbufsize.h
+domacro.o: spec_arith.h
+domacro.o: textsize.h
+replace.o: LLlex.h
+replace.o: argbuf.h
+replace.o: arith.h
+replace.o: assert.h
+replace.o: class.h
+replace.o: debug.h
+replace.o: file_info.h
+replace.o: idf.h
+replace.o: idfsize.h
+replace.o: input.h
+replace.o: lapbuf.h
+replace.o: macro.h
+replace.o: nofloat.h
+replace.o: nopp.h
+replace.o: nparams.h
+replace.o: numsize.h
+replace.o: pathlength.h
+replace.o: replace.h
+replace.o: spec_arith.h
+replace.o: static.h
+replace.o: strsize.h
+init.o: class.h
+init.o: idf.h
+init.o: macro.h
+init.o: nopp.h
+options.o: align.h
+options.o: arith.h
+options.o: botch_free.h
+options.o: class.h
+options.o: dataflow.h
+options.o: idf.h
+options.o: idfsize.h
+options.o: lint.h
+options.o: macro.h
+options.o: noRoption.h
+options.o: nobitfield.h
+options.o: nocross.h
+options.o: nofloat.h
+options.o: nopp.h
+options.o: sizes.h
+options.o: spec_arith.h
+options.o: target_sizes.h
+options.o: use_tmp.h
+skip.o: LLlex.h
+skip.o: arith.h
+skip.o: class.h
+skip.o: file_info.h
+skip.o: input.h
+skip.o: nofloat.h
+skip.o: nopp.h
+skip.o: spec_arith.h
+stack.o: Lpars.h
+stack.o: arith.h
+stack.o: botch_free.h
+stack.o: debug.h
+stack.o: def.h
+stack.o: idf.h
+stack.o: level.h
+stack.o: lint.h
+stack.o: mes.h
+stack.o: noRoption.h
+stack.o: nobitfield.h
+stack.o: nofloat.h
+stack.o: nopp.h
+stack.o: spec_arith.h
+stack.o: stack.h
+stack.o: struct.h
+stack.o: type.h
+type.o: Lpars.h
+type.o: align.h
+type.o: arith.h
+type.o: botch_free.h
+type.o: decspecs.h
+type.o: def.h
+type.o: idf.h
+type.o: lint.h
+type.o: nobitfield.h
+type.o: nocross.h
+type.o: nofloat.h
+type.o: nopp.h
+type.o: proto.h
+type.o: sizes.h
+type.o: spec_arith.h
+type.o: target_sizes.h
+type.o: type.h
+ch7mon.o: Lpars.h
+ch7mon.o: arith.h
+ch7mon.o: botch_free.h
+ch7mon.o: def.h
+ch7mon.o: expr.h
+ch7mon.o: idf.h
+ch7mon.o: label.h
+ch7mon.o: lint.h
+ch7mon.o: nobitfield.h
+ch7mon.o: nofloat.h
+ch7mon.o: nopp.h
+ch7mon.o: spec_arith.h
+ch7mon.o: type.h
+label.o: Lpars.h
+label.o: arith.h
+label.o: def.h
+label.o: idf.h
+label.o: label.h
+label.o: level.h
+label.o: lint.h
+label.o: noRoption.h
+label.o: nobitfield.h
+label.o: nofloat.h
+label.o: nopp.h
+label.o: spec_arith.h
+label.o: type.h
+eval.o: Lpars.h
+eval.o: align.h
+eval.o: arith.h
+eval.o: assert.h
+eval.o: atw.h
+eval.o: code.h
+eval.o: dataflow.h
+eval.o: debug.h
+eval.o: def.h
+eval.o: expr.h
+eval.o: idf.h
+eval.o: label.h
+eval.o: level.h
+eval.o: lint.h
+eval.o: mes.h
+eval.o: nobitfield.h
+eval.o: nocross.h
+eval.o: nofloat.h
+eval.o: nopp.h
+eval.o: sizes.h
+eval.o: spec_arith.h
+eval.o: specials.h
+eval.o: stack.h
+eval.o: target_sizes.h
+eval.o: type.h
+switch.o: Lpars.h
+switch.o: arith.h
+switch.o: assert.h
+switch.o: botch_free.h
+switch.o: code.h
+switch.o: debug.h
+switch.o: density.h
+switch.o: expr.h
+switch.o: idf.h
+switch.o: label.h
+switch.o: noRoption.h
+switch.o: nobitfield.h
+switch.o: nofloat.h
+switch.o: nopp.h
+switch.o: spec_arith.h
+switch.o: switch.h
+switch.o: type.h
+conversion.o: Lpars.h
+conversion.o: arith.h
+conversion.o: lint.h
+conversion.o: nobitfield.h
+conversion.o: nocross.h
+conversion.o: nofloat.h
+conversion.o: sizes.h
+conversion.o: spec_arith.h
+conversion.o: target_sizes.h
+conversion.o: type.h
+util.o: Lpars.h
+util.o: align.h
+util.o: def.h
+util.o: lint.h
+util.o: nocross.h
+util.o: nofloat.h
+util.o: regcount.h
+util.o: sizes.h
+util.o: stack.h
+util.o: target_sizes.h
+util.o: use_tmp.h
+util.o: util.h
+proto.o: Lpars.h
+proto.o: align.h
+proto.o: arith.h
+proto.o: assert.h
+proto.o: botch_free.h
+proto.o: debug.h
+proto.o: declar.h
+proto.o: decspecs.h
+proto.o: def.h
+proto.o: expr.h
+proto.o: idf.h
+proto.o: idfsize.h
+proto.o: label.h
+proto.o: level.h
+proto.o: lint.h
+proto.o: nobitfield.h
+proto.o: nocross.h
+proto.o: nofloat.h
+proto.o: nopp.h
+proto.o: nparams.h
+proto.o: proto.h
+proto.o: spec_arith.h
+proto.o: stack.h
+proto.o: struct.h
+proto.o: target_sizes.h
+proto.o: type.h
+pragma.o: LLlex.h
+pragma.o: Lpars.h
+pragma.o: arith.h
+pragma.o: assert.h
+pragma.o: botch_free.h
+pragma.o: class.h
+pragma.o: debug.h
+pragma.o: file_info.h
+pragma.o: idf.h
+pragma.o: idfsize.h
+pragma.o: ifdepth.h
+pragma.o: input.h
+pragma.o: macro.h
+pragma.o: nofloat.h
+pragma.o: nopp.h
+pragma.o: nparams.h
+pragma.o: parbufsize.h
+pragma.o: spec_arith.h
+pragma.o: textsize.h
+blocks.o: Lpars.h
+blocks.o: align.h
+blocks.o: arith.h
+blocks.o: atw.h
+blocks.o: label.h
+blocks.o: lint.h
+blocks.o: nocross.h
+blocks.o: nofloat.h
+blocks.o: sizes.h
+blocks.o: spec_arith.h
+blocks.o: stack.h
+blocks.o: target_sizes.h
+dataflow.o: dataflow.h
+l_lint.o: LLlex.h
+l_lint.o: Lpars.h
+l_lint.o: arith.h
+l_lint.o: assert.h
+l_lint.o: code.h
+l_lint.o: debug.h
+l_lint.o: def.h
+l_lint.o: expr.h
+l_lint.o: file_info.h
+l_lint.o: idf.h
+l_lint.o: interface.h
+l_lint.o: l_lint.h
+l_lint.o: l_outdef.h
+l_lint.o: l_state.h
+l_lint.o: label.h
+l_lint.o: level.h
+l_lint.o: lint.h
+l_lint.o: nobitfield.h
+l_lint.o: nofloat.h
+l_lint.o: nopp.h
+l_lint.o: spec_arith.h
+l_lint.o: stack.h
+l_lint.o: type.h
+l_states.o: LLlex.h
+l_states.o: Lpars.h
+l_states.o: arith.h
+l_states.o: assert.h
+l_states.o: code.h
+l_states.o: debug.h
+l_states.o: def.h
+l_states.o: expr.h
+l_states.o: file_info.h
+l_states.o: idf.h
+l_states.o: interface.h
+l_states.o: l_brace.h
+l_states.o: l_comment.h
+l_states.o: l_lint.h
+l_states.o: l_outdef.h
+l_states.o: l_state.h
+l_states.o: label.h
+l_states.o: level.h
+l_states.o: lint.h
+l_states.o: nobitfield.h
+l_states.o: nofloat.h
+l_states.o: nopp.h
+l_states.o: spec_arith.h
+l_states.o: stack.h
+l_states.o: type.h
+l_misc.o: LLlex.h
+l_misc.o: Lpars.h
+l_misc.o: arith.h
+l_misc.o: code.h
+l_misc.o: def.h
+l_misc.o: expr.h
+l_misc.o: file_info.h
+l_misc.o: idf.h
+l_misc.o: interface.h
+l_misc.o: l_state.h
+l_misc.o: label.h
+l_misc.o: level.h
+l_misc.o: lint.h
+l_misc.o: nobitfield.h
+l_misc.o: nofloat.h
+l_misc.o: nopp.h
+l_misc.o: spec_arith.h
+l_misc.o: stack.h
+l_misc.o: type.h
+l_ev_ord.o: LLlex.h
+l_ev_ord.o: Lpars.h
+l_ev_ord.o: arith.h
+l_ev_ord.o: assert.h
+l_ev_ord.o: code.h
+l_ev_ord.o: debug.h
+l_ev_ord.o: def.h
+l_ev_ord.o: expr.h
+l_ev_ord.o: file_info.h
+l_ev_ord.o: idf.h
+l_ev_ord.o: interface.h
+l_ev_ord.o: l_lint.h
+l_ev_ord.o: l_state.h
+l_ev_ord.o: label.h
+l_ev_ord.o: level.h
+l_ev_ord.o: lint.h
+l_ev_ord.o: nobitfield.h
+l_ev_ord.o: nofloat.h
+l_ev_ord.o: nopp.h
+l_ev_ord.o: spec_arith.h
+l_ev_ord.o: stack.h
+l_ev_ord.o: type.h
+l_outdef.o: LLlex.h
+l_outdef.o: Lpars.h
+l_outdef.o: arith.h
+l_outdef.o: assert.h
+l_outdef.o: code.h
+l_outdef.o: debug.h
+l_outdef.o: def.h
+l_outdef.o: expr.h
+l_outdef.o: field.h
+l_outdef.o: file_info.h
+l_outdef.o: idf.h
+l_outdef.o: interface.h
+l_outdef.o: l_class.h
+l_outdef.o: l_comment.h
+l_outdef.o: l_lint.h
+l_outdef.o: l_outdef.h
+l_outdef.o: label.h
+l_outdef.o: level.h
+l_outdef.o: lint.h
+l_outdef.o: nobitfield.h
+l_outdef.o: nofloat.h
+l_outdef.o: nopp.h
+l_outdef.o: spec_arith.h
+l_outdef.o: stack.h
+l_outdef.o: struct.h
+l_outdef.o: type.h
+l_comment.o: arith.h
+l_comment.o: interface.h
+l_comment.o: l_comment.h
+l_comment.o: l_state.h
+l_comment.o: lint.h
+l_comment.o: spec_arith.h
+l_dummy.o: arith.h
+l_dummy.o: label.h
+l_dummy.o: lint.h
+l_dummy.o: spec_arith.h
+tokenfile.o: Lpars.h
+declar.o: LLlex.h
+declar.o: Lpars.h
+declar.o: arith.h
+declar.o: code.h
+declar.o: debug.h
+declar.o: declar.h
+declar.o: decspecs.h
+declar.o: def.h
+declar.o: expr.h
+declar.o: field.h
+declar.o: file_info.h
+declar.o: idf.h
+declar.o: l_lint.h
+declar.o: l_state.h
+declar.o: label.h
+declar.o: level.h
+declar.o: lint.h
+declar.o: nobitfield.h
+declar.o: nocross.h
+declar.o: nofloat.h
+declar.o: nopp.h
+declar.o: proto.h
+declar.o: sizes.h
+declar.o: spec_arith.h
+declar.o: struct.h
+declar.o: target_sizes.h
+declar.o: type.h
+statement.o: LLlex.h
+statement.o: Lpars.h
+statement.o: arith.h
+statement.o: botch_free.h
+statement.o: code.h
+statement.o: debug.h
+statement.o: def.h
+statement.o: expr.h
+statement.o: file_info.h
+statement.o: idf.h
+statement.o: l_lint.h
+statement.o: l_state.h
+statement.o: label.h
+statement.o: lint.h
+statement.o: nobitfield.h
+statement.o: nofloat.h
+statement.o: nopp.h
+statement.o: spec_arith.h
+statement.o: stack.h
+statement.o: type.h
+expression.o: LLlex.h
+expression.o: Lpars.h
+expression.o: arith.h
+expression.o: code.h
+expression.o: expr.h
+expression.o: file_info.h
+expression.o: idf.h
+expression.o: label.h
+expression.o: lint.h
+expression.o: noRoption.h
+expression.o: nobitfield.h
+expression.o: nofloat.h
+expression.o: nopp.h
+expression.o: spec_arith.h
+expression.o: type.h
+program.o: LLlex.h
+program.o: Lpars.h
+program.o: arith.h
+program.o: code.h
+program.o: declar.h
+program.o: decspecs.h
+program.o: def.h
+program.o: expr.h
+program.o: file_info.h
+program.o: idf.h
+program.o: l_state.h
+program.o: label.h
+program.o: lint.h
+program.o: nobitfield.h
+program.o: nofloat.h
+program.o: nopp.h
+program.o: spec_arith.h
+program.o: type.h
+Lpars.o: Lpars.h
+ival.o: LLlex.h
+ival.o: Lpars.h
+ival.o: arith.h
+ival.o: assert.h
+ival.o: debug.h
+ival.o: def.h
+ival.o: estack.h
+ival.o: expr.h
+ival.o: field.h
+ival.o: file_info.h
+ival.o: idf.h
+ival.o: l_lint.h
+ival.o: label.h
+ival.o: level.h
+ival.o: lint.h
+ival.o: noRoption.h
+ival.o: nobitfield.h
+ival.o: nocross.h
+ival.o: nofloat.h
+ival.o: nopp.h
+ival.o: proto.h
+ival.o: sizes.h
+ival.o: spec_arith.h
+ival.o: struct.h
+ival.o: target_sizes.h
+ival.o: type.h
+char.o: class.h
+symbol2str.o: Lpars.h
--- /dev/null
+# $Header$
+# M A K E F I L E F O R A C K C - C O M P I L E R
+
+# Machine and environ dependent definitions
+EMHOME = /usr/em# # ACK tree on this machine
+DESTINATION = /user1/$$USER/bin# # where to put the stuff
+MKDEP = $(EMHOME)/bin/mkdep# # dependency generator
+MAP =
+#MAP = -DInsertFile=ins_file -DInsertText=ins_text# bug in m68k2 back end
+SIM = /user1/dick/bin/sim# # Dicks sim program
+LINT = /usr/new/lint
+
+# Libraries and EM interface definitions
+SYSLIB = $(EMHOME)/modules/lib/libsystem.a
+EMKLIB = $(EMHOME)/modules/lib/libemk.a
+EMELIB = $(EMHOME)/modules/lib/libeme.a $(EMHOME)/lib/em_data.a
+STRLIB = $(EMHOME)/modules/lib/libstring.a
+PRTLIB = $(EMHOME)/modules/lib/libprint.a
+EMMESLIB = $(EMHOME)/modules/lib/libem_mes.a
+INPLIB = $(EMHOME)/modules/lib/libinput.a
+ALLOCLIB = $(EMHOME)/modules/lib/liballoc.a
+MALLOC = $(EMHOME)/modules/lib/malloc.o
+#CH3LIB = $(EMHOME)/modules/lib/libch3.a
+CH3LIB =
+LIBS = $(INPLIB) $(CH3LIB) $(EMMESLIB) $(EMKLIB) \
+ $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+ELIBS = $(INPLIB) $(CH3LIB) $(EMMESLIB) $(EMELIB) \
+ $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+LIB_INCLUDES = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg
+EM_INCLUDES = -I$(EMHOME)/h
+SYSLLIB = $(EMHOME)/modules/lib/llib-lsys.ln
+EMKLLIB = $(EMHOME)/modules/lib/llib-lemk.ln
+EMELLIB = $(EMHOME)/modules/lib/llib-leme.ln
+STRLLIB = $(EMHOME)/modules/lib/llib-lstr.ln
+PRTLLIB = $(EMHOME)/modules/lib/llib-lprint.ln
+EMMESLLIB = $(EMHOME)/modules/lib/llib-lmes.ln
+INPLLIB = $(EMHOME)/modules/lib/llib-linput.ln
+CH3LLIB = $(EMHOME)/modules/lib/llib-lch3.ln
+ALLOCLLIB = $(EMHOME)/modules/lib/llib-alloc.ln
+LINTLIBS =
+#LINTLIBS = $(CH3LLIB) $(INPLLIB) $(EMMESLLIB) $(EMKLLIB) \
+# $(PRTLLIB) $(STRLLIB) $(SYSLLIB) $(ALLOCLLIB)
+
+# Where to install the compiler and its driver
+CEMCOM = $(DESTINATION)/cemcom
+DRIVER = $(DESTINATION)/cem
+
+# What C compiler to use and how
+# CC = $(ACK) -.c
+# CC = CC
+# CC = /bin/cc
+COPTIONS =
+
+# What parser generator to use and how
+GEN = $(EMHOME)/bin/LLgen
+GENOPTIONS = -vv
+
+# Special #defines during compilation
+CDEFS = $(MAP) $(EM_INCLUDES) $(LIB_INCLUDES)
+CFLAGS = $(CDEFS) $(COPTIONS) -O# we cannot pass the COPTIONS to lint!
+
+# Grammar files and their objects
+LSRC = tokenfile.g declar.g statement.g expression.g program.g ival.g
+GLCSRC = tokenfile.c declar.c statement.c expression.c program.c Lpars.c ival.c
+LOBJ = tokenfile.o declar.o statement.o expression.o program.o Lpars.o ival.o
+
+CSRC = main.c idf.c declarator.c decspecs.c struct.c \
+ expr.c ch7.c ch7bin.c cstoper.c arith.c \
+ asm.c code.c dumpidf.c error.c field.c\
+ tokenname.c LLlex.c LLmessage.c \
+ input.c domacro.c replace.c init.c options.c \
+ scan.c skip.c stack.c type.c ch7mon.c label.c eval.c \
+ switch.c conversion.c util.c \
+ blocks.c dataflow.c Version.c
+# Objects of hand-written C files
+COBJ = main.o idf.o declarator.o decspecs.o struct.o \
+ expr.o ch7.o ch7bin.o cstoper.o arith.o \
+ asm.o code.o dumpidf.o error.o field.o\
+ tokenname.o LLlex.o LLmessage.o \
+ input.o domacro.o replace.o init.o options.o \
+ scan.o skip.o stack.o type.o ch7mon.o label.o eval.o \
+ switch.o conversion.o util.o \
+ blocks.o dataflow.o Version.o
+
+# Objects of other generated C files
+GCSRC = char.c symbol2str.c next.c
+GOBJ = char.o symbol2str.o next.o
+
+# generated source files
+GSRC = char.c symbol2str.c next.c \
+ code.h declar.h decspecs.h def.h expr.h field.h estack.h \
+ idf.h macro.h stack.h stmt.h struct.h switch.h type.h util.h
+
+# .h files generated by `make hfiles'; PLEASE KEEP THIS UP-TO-DATE!
+GHSRC = botch_free.h dataflow.h debug.h density.h errout.h \
+ idfsize.h ifdepth.h inputtype.h inumlength.h lapbuf.h \
+ nobitfield.h nofloat.h nopp.h noRoption.h nocross.h \
+ nparams.h numsize.h parbufsize.h pathlength.h \
+ strsize.h target_sizes.h textsize.h use_tmp.h spec_arith.h static.h \
+ reg_count.h
+
+# Other generated files, for 'make clean' only
+GENERATED = tokenfile.g Lpars.h LLfiles LL.output lint.out \
+ print Xref lxref hfiles cfiles $(GLCSRC)
+
+# include files containing ALLOCDEF specifications
+NEXTFILES = code.str declar.str decspecs.str def.str expr.str field.str \
+ estack.str util.str \
+ idf.str macro.str stack.str stmt.str struct.str switch.str type.str
+
+.SUFFIXES: .str .h
+.str.h:
+ ./make.allocd <$*.str >$*.h
+
+all: cc
+
+cc:
+ make "EMHOME="$(EMHOME) "CC=$(CC)" hfiles
+ make "EMHOME="$(EMHOME) "CC=$(CC)" LLfiles
+ make "EMHOME="$(EMHOME) "CC=$(CC)" main
+
+cem: cem.c
+ $(CC) -O cem.c $(SYSLIB) -o cem
+
+lint.cem: cem.c
+ $(LINT) -bx cem.c
+
+hfiles: ./make.hfiles Parameters
+ ./make.hfiles Parameters
+ @touch hfiles
+
+LLfiles: $(LSRC)
+ $(GEN) $(GENOPTIONS) $(LSRC)
+ @touch LLfiles
+
+tokenfile.g: tokenname.c make.tokfile
+ <tokenname.c ./make.tokfile >tokenfile.g
+
+symbol2str.c: tokenname.c make.tokcase
+ <tokenname.c ./make.tokcase >symbol2str.c
+
+char.c: char.tab
+ $(EMHOME)/bin/tabgen -fchar.tab >char.c
+
+next.c: make.next $(NEXTFILES)
+ ./make.next $(NEXTFILES) >next.c
+
+code.h: make.allocd
+declar.h: make.allocd
+decspecs.h: make.allocd
+def.h: make.allocd
+estack.h: make.allocd
+expr.h: make.allocd
+field.h: make.allocd
+idf.h: make.allocd
+macro.h: make.allocd
+stack.h: make.allocd
+stmt.h: make.allocd
+struct.h: make.allocd
+switch.h: make.allocd
+type.h: make.allocd
+util.h: make.allocd
+
+# Objects needed for 'main'
+OBJ = $(COBJ) $(LOBJ) $(GOBJ)
+SRC = $(CSRC) $(LCSRC) $(GCSRC)
+
+main: $(OBJ) Makefile.erik
+ $(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(LIBS) -o main
+ size main
+
+emain: $(OBJ) Makefile.erik
+ $(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(ELIBS) -o emain
+ size emain
+
+cfiles: hfiles LLfiles $(GSRC)
+ @touch cfiles
+
+install: main cem
+ cp main $(CEMCOM)
+ cp cem $(DRIVER)
+
+print: files
+ pr `cat files` > print
+
+tags: cfiles
+ ctags $(SRC)
+
+shar: files
+ shar `cat files`
+
+listcfiles:
+ @echo $(SRC)
+
+listobjects:
+ @echo $(OBJ)
+
+depend: cfiles
+ sed '/^#AUTOAUTO/,$$d' Makefile.erik >Makefile.erik.new
+ echo '#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO' >>Makefile.erik.new
+ $(MKDEP) $(SRC) | sed 's/\.c:/.o:/' >>Makefile.erik.new
+ mv Makefile.erik Makefile.erik.old
+ mv Makefile.erik.new Makefile.erik
+
+xref:
+ ctags -x `grep "\.[ch]" files`|sed "s/).*/)/">Xref
+
+lxref:
+ lxref $(OBJ) -lc >lxref
+
+lint: lint.main lint.cem
+
+lint.main: cfiles
+ $(LINT) -bx $(CDEFS) $(SRC) $(LINTLIBS) >lint.out
+
+cchk:
+ cchk $(SRC)
+
+clean:
+ rm -f $(LCSRC) $(OBJ) $(GENERATED) $(GSRC) $(GHSRC)
+
+sim: cfiles
+ $(SIM) $(SIMFLAGS) $(CSRC) $(GSRC) $(LSRC)
+
+#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
+main.o: LLlex.h
+main.o: Lpars.h
+main.o: align.h
+main.o: arith.h
+main.o: debug.h
+main.o: declar.h
+main.o: file_info.h
+main.o: idf.h
+main.o: input.h
+main.o: inputtype.h
+main.o: level.h
+main.o: noRoption.h
+main.o: nobitfield.h
+main.o: nocross.h
+main.o: nofloat.h
+main.o: nopp.h
+main.o: sizes.h
+main.o: spec_arith.h
+main.o: specials.h
+main.o: target_sizes.h
+main.o: tokenname.h
+main.o: type.h
+main.o: use_tmp.h
+idf.o: LLlex.h
+idf.o: Lpars.h
+idf.o: align.h
+idf.o: arith.h
+idf.o: assert.h
+idf.o: botch_free.h
+idf.o: debug.h
+idf.o: declar.h
+idf.o: decspecs.h
+idf.o: def.h
+idf.o: file_info.h
+idf.o: idf.h
+idf.o: idfsize.h
+idf.o: label.h
+idf.o: level.h
+idf.o: noRoption.h
+idf.o: nobitfield.h
+idf.o: nocross.h
+idf.o: nofloat.h
+idf.o: nopp.h
+idf.o: sizes.h
+idf.o: spec_arith.h
+idf.o: specials.h
+idf.o: stack.h
+idf.o: struct.h
+idf.o: target_sizes.h
+idf.o: type.h
+declarator.o: Lpars.h
+declarator.o: arith.h
+declarator.o: botch_free.h
+declarator.o: declar.h
+declarator.o: expr.h
+declarator.o: idf.h
+declarator.o: label.h
+declarator.o: nobitfield.h
+declarator.o: nocross.h
+declarator.o: nofloat.h
+declarator.o: nopp.h
+declarator.o: sizes.h
+declarator.o: spec_arith.h
+declarator.o: target_sizes.h
+declarator.o: type.h
+decspecs.o: Lpars.h
+decspecs.o: arith.h
+decspecs.o: decspecs.h
+decspecs.o: def.h
+decspecs.o: level.h
+decspecs.o: noRoption.h
+decspecs.o: nobitfield.h
+decspecs.o: nofloat.h
+decspecs.o: spec_arith.h
+decspecs.o: type.h
+struct.o: LLlex.h
+struct.o: Lpars.h
+struct.o: align.h
+struct.o: arith.h
+struct.o: assert.h
+struct.o: botch_free.h
+struct.o: debug.h
+struct.o: def.h
+struct.o: field.h
+struct.o: file_info.h
+struct.o: idf.h
+struct.o: level.h
+struct.o: noRoption.h
+struct.o: nobitfield.h
+struct.o: nocross.h
+struct.o: nofloat.h
+struct.o: nopp.h
+struct.o: sizes.h
+struct.o: spec_arith.h
+struct.o: stack.h
+struct.o: struct.h
+struct.o: target_sizes.h
+struct.o: type.h
+expr.o: LLlex.h
+expr.o: Lpars.h
+expr.o: arith.h
+expr.o: botch_free.h
+expr.o: declar.h
+expr.o: decspecs.h
+expr.o: def.h
+expr.o: expr.h
+expr.o: file_info.h
+expr.o: idf.h
+expr.o: label.h
+expr.o: level.h
+expr.o: noRoption.h
+expr.o: nobitfield.h
+expr.o: nocross.h
+expr.o: nofloat.h
+expr.o: nopp.h
+expr.o: sizes.h
+expr.o: spec_arith.h
+expr.o: target_sizes.h
+expr.o: type.h
+ch7.o: Lpars.h
+ch7.o: arith.h
+ch7.o: assert.h
+ch7.o: debug.h
+ch7.o: def.h
+ch7.o: expr.h
+ch7.o: idf.h
+ch7.o: label.h
+ch7.o: nobitfield.h
+ch7.o: nofloat.h
+ch7.o: nopp.h
+ch7.o: spec_arith.h
+ch7.o: struct.h
+ch7.o: type.h
+ch7bin.o: Lpars.h
+ch7bin.o: arith.h
+ch7bin.o: botch_free.h
+ch7bin.o: expr.h
+ch7bin.o: idf.h
+ch7bin.o: label.h
+ch7bin.o: noRoption.h
+ch7bin.o: nobitfield.h
+ch7bin.o: nofloat.h
+ch7bin.o: nopp.h
+ch7bin.o: spec_arith.h
+ch7bin.o: struct.h
+ch7bin.o: type.h
+cstoper.o: Lpars.h
+cstoper.o: arith.h
+cstoper.o: assert.h
+cstoper.o: debug.h
+cstoper.o: expr.h
+cstoper.o: idf.h
+cstoper.o: label.h
+cstoper.o: nobitfield.h
+cstoper.o: nocross.h
+cstoper.o: nofloat.h
+cstoper.o: nopp.h
+cstoper.o: sizes.h
+cstoper.o: spec_arith.h
+cstoper.o: target_sizes.h
+cstoper.o: type.h
+arith.o: Lpars.h
+arith.o: arith.h
+arith.o: botch_free.h
+arith.o: expr.h
+arith.o: field.h
+arith.o: idf.h
+arith.o: label.h
+arith.o: mes.h
+arith.o: noRoption.h
+arith.o: nobitfield.h
+arith.o: nofloat.h
+arith.o: nopp.h
+arith.o: spec_arith.h
+arith.o: type.h
+code.o: Lpars.h
+code.o: arith.h
+code.o: assert.h
+code.o: atw.h
+code.o: botch_free.h
+code.o: code.h
+code.o: dataflow.h
+code.o: debug.h
+code.o: declar.h
+code.o: decspecs.h
+code.o: def.h
+code.o: expr.h
+code.o: file_info.h
+code.o: idf.h
+code.o: label.h
+code.o: level.h
+code.o: noRoption.h
+code.o: nobitfield.h
+code.o: nocross.h
+code.o: nofloat.h
+code.o: nopp.h
+code.o: sizes.h
+code.o: spec_arith.h
+code.o: specials.h
+code.o: stack.h
+code.o: stmt.h
+code.o: target_sizes.h
+code.o: type.h
+code.o: use_tmp.h
+dumpidf.o: Lpars.h
+dumpidf.o: arith.h
+dumpidf.o: debug.h
+dumpidf.o: def.h
+dumpidf.o: expr.h
+dumpidf.o: field.h
+dumpidf.o: idf.h
+dumpidf.o: label.h
+dumpidf.o: nobitfield.h
+dumpidf.o: nofloat.h
+dumpidf.o: nopp.h
+dumpidf.o: spec_arith.h
+dumpidf.o: stack.h
+dumpidf.o: static.h
+dumpidf.o: struct.h
+dumpidf.o: type.h
+error.o: LLlex.h
+error.o: arith.h
+error.o: debug.h
+error.o: errout.h
+error.o: expr.h
+error.o: file_info.h
+error.o: label.h
+error.o: nofloat.h
+error.o: nopp.h
+error.o: spec_arith.h
+error.o: tokenname.h
+field.o: Lpars.h
+field.o: align.h
+field.o: arith.h
+field.o: assert.h
+field.o: code.h
+field.o: debug.h
+field.o: expr.h
+field.o: field.h
+field.o: idf.h
+field.o: label.h
+field.o: nobitfield.h
+field.o: nocross.h
+field.o: nofloat.h
+field.o: nopp.h
+field.o: sizes.h
+field.o: spec_arith.h
+field.o: target_sizes.h
+field.o: type.h
+tokenname.o: LLlex.h
+tokenname.o: Lpars.h
+tokenname.o: arith.h
+tokenname.o: file_info.h
+tokenname.o: idf.h
+tokenname.o: nofloat.h
+tokenname.o: nopp.h
+tokenname.o: spec_arith.h
+tokenname.o: tokenname.h
+LLlex.o: LLlex.h
+LLlex.o: Lpars.h
+LLlex.o: arith.h
+LLlex.o: assert.h
+LLlex.o: class.h
+LLlex.o: debug.h
+LLlex.o: def.h
+LLlex.o: file_info.h
+LLlex.o: idf.h
+LLlex.o: idfsize.h
+LLlex.o: input.h
+LLlex.o: nocross.h
+LLlex.o: nofloat.h
+LLlex.o: nopp.h
+LLlex.o: numsize.h
+LLlex.o: sizes.h
+LLlex.o: spec_arith.h
+LLlex.o: strsize.h
+LLlex.o: target_sizes.h
+LLmessage.o: LLlex.h
+LLmessage.o: Lpars.h
+LLmessage.o: arith.h
+LLmessage.o: file_info.h
+LLmessage.o: idf.h
+LLmessage.o: nofloat.h
+LLmessage.o: nopp.h
+LLmessage.o: spec_arith.h
+input.o: file_info.h
+input.o: input.h
+input.o: inputtype.h
+input.o: nopp.h
+domacro.o: LLlex.h
+domacro.o: Lpars.h
+domacro.o: arith.h
+domacro.o: assert.h
+domacro.o: botch_free.h
+domacro.o: class.h
+domacro.o: debug.h
+domacro.o: file_info.h
+domacro.o: idf.h
+domacro.o: idfsize.h
+domacro.o: ifdepth.h
+domacro.o: input.h
+domacro.o: interface.h
+domacro.o: macro.h
+domacro.o: nofloat.h
+domacro.o: nopp.h
+domacro.o: nparams.h
+domacro.o: parbufsize.h
+domacro.o: spec_arith.h
+domacro.o: textsize.h
+replace.o: LLlex.h
+replace.o: arith.h
+replace.o: assert.h
+replace.o: class.h
+replace.o: debug.h
+replace.o: file_info.h
+replace.o: idf.h
+replace.o: input.h
+replace.o: interface.h
+replace.o: macro.h
+replace.o: nofloat.h
+replace.o: nopp.h
+replace.o: pathlength.h
+replace.o: spec_arith.h
+replace.o: static.h
+replace.o: strsize.h
+init.o: class.h
+init.o: idf.h
+init.o: interface.h
+init.o: macro.h
+init.o: nopp.h
+options.o: align.h
+options.o: arith.h
+options.o: botch_free.h
+options.o: class.h
+options.o: dataflow.h
+options.o: idf.h
+options.o: idfsize.h
+options.o: macro.h
+options.o: noRoption.h
+options.o: nobitfield.h
+options.o: nocross.h
+options.o: nofloat.h
+options.o: nopp.h
+options.o: sizes.h
+options.o: spec_arith.h
+options.o: target_sizes.h
+options.o: use_tmp.h
+scan.o: class.h
+scan.o: idf.h
+scan.o: input.h
+scan.o: interface.h
+scan.o: lapbuf.h
+scan.o: macro.h
+scan.o: nopp.h
+scan.o: nparams.h
+skip.o: LLlex.h
+skip.o: arith.h
+skip.o: class.h
+skip.o: file_info.h
+skip.o: input.h
+skip.o: interface.h
+skip.o: nofloat.h
+skip.o: nopp.h
+skip.o: spec_arith.h
+stack.o: Lpars.h
+stack.o: arith.h
+stack.o: botch_free.h
+stack.o: debug.h
+stack.o: def.h
+stack.o: idf.h
+stack.o: level.h
+stack.o: mes.h
+stack.o: noRoption.h
+stack.o: nobitfield.h
+stack.o: nofloat.h
+stack.o: nopp.h
+stack.o: spec_arith.h
+stack.o: stack.h
+stack.o: struct.h
+stack.o: type.h
+type.o: Lpars.h
+type.o: align.h
+type.o: arith.h
+type.o: botch_free.h
+type.o: def.h
+type.o: idf.h
+type.o: nobitfield.h
+type.o: nocross.h
+type.o: nofloat.h
+type.o: nopp.h
+type.o: sizes.h
+type.o: spec_arith.h
+type.o: target_sizes.h
+type.o: type.h
+ch7mon.o: Lpars.h
+ch7mon.o: arith.h
+ch7mon.o: botch_free.h
+ch7mon.o: def.h
+ch7mon.o: expr.h
+ch7mon.o: idf.h
+ch7mon.o: label.h
+ch7mon.o: nobitfield.h
+ch7mon.o: nofloat.h
+ch7mon.o: nopp.h
+ch7mon.o: spec_arith.h
+ch7mon.o: type.h
+label.o: Lpars.h
+label.o: arith.h
+label.o: def.h
+label.o: idf.h
+label.o: label.h
+label.o: level.h
+label.o: noRoption.h
+label.o: nobitfield.h
+label.o: nofloat.h
+label.o: nopp.h
+label.o: spec_arith.h
+label.o: type.h
+eval.o: Lpars.h
+eval.o: align.h
+eval.o: arith.h
+eval.o: assert.h
+eval.o: atw.h
+eval.o: code.h
+eval.o: dataflow.h
+eval.o: debug.h
+eval.o: def.h
+eval.o: expr.h
+eval.o: idf.h
+eval.o: label.h
+eval.o: level.h
+eval.o: mes.h
+eval.o: nobitfield.h
+eval.o: nocross.h
+eval.o: nofloat.h
+eval.o: nopp.h
+eval.o: sizes.h
+eval.o: spec_arith.h
+eval.o: specials.h
+eval.o: stack.h
+eval.o: target_sizes.h
+eval.o: type.h
+switch.o: Lpars.h
+switch.o: arith.h
+switch.o: assert.h
+switch.o: botch_free.h
+switch.o: code.h
+switch.o: debug.h
+switch.o: density.h
+switch.o: expr.h
+switch.o: idf.h
+switch.o: label.h
+switch.o: noRoption.h
+switch.o: nobitfield.h
+switch.o: nofloat.h
+switch.o: nopp.h
+switch.o: spec_arith.h
+switch.o: switch.h
+switch.o: type.h
+conversion.o: Lpars.h
+conversion.o: arith.h
+conversion.o: nobitfield.h
+conversion.o: nocross.h
+conversion.o: nofloat.h
+conversion.o: sizes.h
+conversion.o: spec_arith.h
+conversion.o: target_sizes.h
+conversion.o: type.h
+util.o: Lpars.h
+util.o: align.h
+util.o: def.h
+util.o: nocross.h
+util.o: nofloat.h
+util.o: regcount.h
+util.o: sizes.h
+util.o: stack.h
+util.o: target_sizes.h
+util.o: use_tmp.h
+util.o: util.h
+blocks.o: Lpars.h
+blocks.o: align.h
+blocks.o: arith.h
+blocks.o: atw.h
+blocks.o: label.h
+blocks.o: nocross.h
+blocks.o: nofloat.h
+blocks.o: sizes.h
+blocks.o: spec_arith.h
+blocks.o: stack.h
+blocks.o: target_sizes.h
+dataflow.o: dataflow.h
+char.o: class.h
+symbol2str.o: Lpars.h
--- /dev/null
+: create a directory Xsrc with name clashes resolved
+: and run make in that directory
+: '$Header$'
+
+case $# in
+1)
+ ;;
+*) echo "$0: one argument expected" 1>&2
+ exit 1
+ ;;
+esac
+PW=`pwd`
+options=
+case $1 in
+main|emain|lnt)
+ target=$PW/$1
+ ;;
+omain)
+ target=$PW/$1
+ options=-DPEEPHOLE
+ ;;
+cemain)
+ target=$PW/$1
+ options=-DCODE_EXPANDER
+ ;;
+Xlint)
+ target=$1
+ ;;
+*) echo "$0: $1: Illegal argument" 1>&2
+ exit 1
+ ;;
+esac
+if test -d ../Xsrc
+then
+ :
+else mkdir ../Xsrc
+fi
+make EMHOME=$EMHOME longnames
+: remove code generating routines from the clashes list as they are defines.
+: code generating routine names start with C_
+sed '/^C_/d' < longnames > tmp$$
+cclash -c -l7 tmp$$ > ../Xsrc/Xclashes
+rm -f tmp$$
+cd ../Xsrc
+if cmp -s Xclashes clashes
+then
+ :
+else
+ mv Xclashes clashes
+fi
+rm -f Makefile
+for i in `cat $PW/Cfiles`
+do
+ cat >> Makefile <<EOF
+
+$i: clashes $PW/$i
+ cid -Fclashes < $PW/$i > $i
+EOF
+done
+make EMHOME=$EMHOME `cat $PW/Cfiles`
+rm -f Makefile
+ed - $PW/Makefile <<'EOF'
+/^#EXCLEXCL/,/^#INCLINCL/d
+w Makefile
+q
+EOF
+make EMHOME=$EMHOME COPTIONS=$options CURRDIR=$PW/ $target
--- /dev/null
+!File: lint.h
+#undef LINT 1 /* if defined, 'lint' is produced */
+
+
+!File: pathlength.h
+#define PATHLENGTH 1024 /* max. length of path to file */
+
+
+!File: errout.h
+#define ERROUT STDERR /* file pointer for writing messages */
+#define MAXERR_LINE 5 /* maximum number of error messages given
+ on the same input line. */
+
+
+!File: idfsize.h
+#define IDFSIZE 64 /* maximum significant length of an identifier */
+
+
+!File: numsize.h
+#define NUMSIZE 256 /* maximum length of a numeric constant */
+
+
+!File: nparams.h
+#define NPARAMS 32 /* maximum number of parameters of macros */
+
+
+!File: ifdepth.h
+#define IFDEPTH 256 /* maximum number of nested if-constructions */
+
+
+!File: density.h
+#define DENSITY 2 /* see switch.[ch] for an explanation */
+
+
+!File: lapbuf.h
+#define LAPBUF 4096 /* size of macro actual parameter buffer */
+
+
+!File: strsize.h
+#define ISTRSIZE 32 /* minimum number of bytes allocated for
+ storing a string */
+#define RSTRSIZE 8 /* step size in enlarging the memory for
+ the storage of a string */
+
+
+!File: target_sizes.h
+#define MAXSIZE 8 /* the maximum of the SZ_* constants */
+
+/* target machine sizes */
+#define SZ_CHAR (arith)1
+#define SZ_SHORT (arith)2
+#define SZ_WORD (arith)4
+#define SZ_INT (arith)4
+#define SZ_LONG (arith)4
+#ifndef NOFLOAT
+#define SZ_FLOAT (arith)4
+#define SZ_DOUBLE (arith)8
+#endif NOFLOAT
+#define SZ_POINTER (arith)4
+
+/* target machine alignment requirements */
+#define AL_CHAR 1
+#define AL_SHORT SZ_SHORT
+#define AL_WORD SZ_WORD
+#define AL_INT SZ_WORD
+#define AL_LONG SZ_WORD
+#ifndef NOFLOAT
+#define AL_FLOAT SZ_WORD
+#define AL_DOUBLE SZ_WORD
+#endif NOFLOAT
+#define AL_POINTER SZ_WORD
+#define AL_STRUCT 1
+#define AL_UNION 1
+
+
+!File: botch_free.h
+#undef BOTCH_FREE 1 /* when defined, botch freed memory, as a check */
+
+
+!File: dataflow.h
+#undef DATAFLOW 1 /* produce some compile-time xref */
+
+
+!File: debug.h
+#undef DEBUG 1 /* perform various self-tests */
+
+
+!File: use_tmp.h
+#undef PREPEND_SCOPES 1 /* collect exa, exp, ina and inp commands
+ and if USE_TMP is defined let them
+ precede the rest of the generated
+ compact code */
+#undef USE_TMP 1 /* use C_insertpart, C_endpart mechanism
+ to generate EM-code in the order needed
+ for the code-generators. If not defined,
+ the old-style peephole optimizer is
+ needed. */
+
+
+!File: parbufsize.h
+#define PARBUFSIZE 1024
+
+
+!File: textsize.h
+#define ITEXTSIZE 8 /* 1st piece of memory for repl. text */
+#define RTEXTSIZE 8 /* stepsize for enlarging repl.text */
+
+
+!File: inputtype.h
+#undef INP_READ_IN_ONE 1 /* read input file in one */
+
+
+!File: nopp.h
+#define NOPP 1 /* if NOT defined, use built-int preprocessor */
+
+
+!File: nobitfield.h
+#undef NOBITFIELD 1 /* if NOT defined, implement bitfields */
+
+
+!File: spec_arith.h
+/* describes internal compiler arithmetics */
+#undef SPECIAL_ARITHMETICS /* something different from native long */
+
+
+!File: static.h
+#define GSTATIC /* for large global "static" arrays */
+
+
+!File: nofloat.h
+#undef NOFLOAT 1 /* if NOT defined, floats are implemented */
+
+
+!File: noRoption.h
+#define NOROPTION 1 /* if NOT defined, R option is implemented */
+
+
+!File: nocross.h
+#undef NOCROSS 1 /* if NOT defined, cross compiler */
+
+
+!File: regcount.h
+#undef REGCOUNT 1 /* count occurrences for register messages */
+
+
--- /dev/null
+/* $Header$ */
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#ifndef lint
+static char Version[] = "ACK CEM compiler Version 3.1";
+#endif lint
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* A L I G N M E N T D E F I N I T I O N S */
+
+#include "nofloat.h"
+#include "nocross.h"
+#include "target_sizes.h"
+
+#ifndef NOCROSS
+extern int
+ short_align, word_align, int_align, long_align,
+#ifndef NOFLOAT
+ float_align, double_align, lngdbl_align,
+#endif NOFLOAT
+ pointer_align,
+ struct_align, union_align;
+#else NOCROSS
+#define short_align ((int)AL_SHORT)
+#define word_align ((int)AL_WORD)
+#define int_align ((int)AL_INT)
+#define long_align ((int)AL_LONG)
+#ifndef NOFLOAT
+#define float_align ((int)AL_FLOAT)
+#define double_align ((int)AL_DOUBLE)
+#define lngdbl_align ((int)AL_LNGDBL)
+#endif NOFLOAT
+#define pointer_align ((int)AL_POINTER)
+#define struct_align ((int)AL_STRUCT)
+#define union_align ((int)AL_UNION)
+#endif NOCROSS
+
+extern arith align();
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* A R I T H M E T I C C O N V E R S I O N S */
+
+/* This file contains the routines for the various conversions that
+ may befall operands in C. It is structurally a mess, but I haven't
+ decided yet whether I can't find the right structure or the
+ semantics of C is a mess.
+*/
+
+#include <alloc.h>
+#include "lint.h"
+#include "nofloat.h"
+#include "nobitfield.h"
+#include "idf.h"
+#include "arith.h"
+#include "sizes.h"
+#include "type.h"
+#include "proto.h"
+#include "label.h"
+#include "expr.h"
+#include "Lpars.h"
+#include "field.h"
+#include "mes.h"
+#include "noRoption.h"
+
+extern char *symbol2str();
+extern char options[];
+
+arithbalance(e1p, oper, e2p) /* RM 6.6 */
+ register struct expr **e1p, **e2p;
+ int oper;
+{
+ /* The expressions *e1p and *e2p are balanced to be operands
+ of the arithmetic operator oper.
+ */
+ register int t1, t2, u1, u2;
+
+ t1 = any2arith(e1p, oper);
+ t2 = any2arith(e2p, oper);
+ /* Now t1 and t2 are either INT, LONG, FLOAT, DOUBLE, or LNGDBL */
+
+#ifndef NOFLOAT
+ /* If any operand has the type long double, the other operand
+ is converted to long double.
+ */
+ if (t1 == LNGDBL) {
+ if (t2 != LNGDBL)
+ int2float(e2p, lngdbl_type);
+ return;
+ } else if (t2 == LNGDBL) {
+ if (t1 != LNGDBL)
+ int2float(e1p, lngdbl_type);
+ return;
+ }
+
+ /* If any operand has the type double, the other operand
+ is converted to double.
+ */
+ if (t1 == DOUBLE) {
+ if (t2 != DOUBLE)
+ int2float(e2p, double_type);
+ return;
+ } else if (t2 == DOUBLE) {
+ if (t1 != DOUBLE)
+ int2float(e1p, double_type);
+ return;
+ }
+
+ /* If any operand has the type float, the other operand
+ is converted to float.
+ */
+ if (t1 == FLOAT) {
+ if (t2 != FLOAT)
+ int2float(e2p, float_type);
+ return;
+ } else if (t2 == FLOAT) {
+ if (t1 != FLOAT)
+ int2float(e1p, float_type);
+ return;
+ }
+#endif NOFLOAT
+
+ /* Now they are INT or LONG */
+ u1 = (*e1p)->ex_type->tp_unsigned;
+ u2 = (*e2p)->ex_type->tp_unsigned;
+
+ /* If either operand has type unsigned long int, the other
+ operand is converted to unsigned long int.
+ */
+ if (t1 == LONG && u1 && (t2 != LONG || !u2))
+ t2 = int2int(e2p, ulong_type);
+ else if (t2 == LONG && u2 && (t1 != LONG || !u1))
+ t1 = int2int(e1p, ulong_type);
+
+ /* If one operand has type long int and the other has type unsigned
+ int, if a long int can represent all values of an unsigned int,
+ the operand of type unsigned int is converted to long int; if
+ a long int cannot represent all values of an unsigned int,
+ both operands are converted to unsigned long int.
+ */
+ if (t1 == LONG && t2 == INT && u2)
+ t2 = int2int(e2p, (int_size<long_size)? long_type : ulong_type);
+ else if (t2 == LONG && t1 == INT && u1)
+ t1 = int2int(e1p, (int_size<long_size)? long_type : ulong_type);
+ if (int_size > long_size) /* sanity check */
+ crash("size of int exceeds size of long");
+
+ /* If either operand has type long int, the other operand is con-
+ verted to long int.
+ */
+ if (t1 == LONG && t2 != LONG)
+ t2 = int2int(e2p, long_type);
+ else
+ if (t2 == LONG && t1 != LONG)
+ t1 = int2int(e1p, long_type);
+
+ /* If either operand has type unsigned int, the other operand
+ is converted to unsigned int.
+ Otherwise, both operands have type int.
+ */
+ if (u1 && !u2)
+ t2 = int2int(e2p, (t1 == LONG) ? ulong_type : uint_type);
+ else
+ if (!u1 && u2)
+ t1 = int2int(e1p, (t2 == LONG) ? ulong_type : uint_type);
+}
+
+relbalance(e1p, oper, e2p)
+ register struct expr **e1p, **e2p;
+{
+ /* The expressions *e1p and *e2p are balanced to be operands
+ of the relational operator oper.
+ */
+ if ((*e1p)->ex_type->tp_fund == FUNCTION)
+ function2pointer(*e1p);
+ if ((*e2p)->ex_type->tp_fund == FUNCTION)
+ function2pointer(*e2p);
+ if ((*e1p)->ex_type->tp_fund == POINTER)
+ ch76pointer(e2p, oper, (*e1p)->ex_type);
+ else
+ if ((*e2p)->ex_type->tp_fund == POINTER)
+ ch76pointer(e1p, oper, (*e2p)->ex_type);
+ else
+ if ( (*e1p)->ex_type == (*e2p)->ex_type &&
+ (*e1p)->ex_type->tp_fund == ENUM
+ )
+ {}
+ else
+ arithbalance(e1p, oper, e2p);
+}
+
+ch76pointer(expp, oper, tp)
+ struct expr **expp;
+ register struct type *tp;
+{
+ /* Checks whether *expp may be compared to tp using oper,
+ as described in chapter 7.6 and 7.7.
+ tp is known to be a pointer.
+ */
+ register struct expr *exp = *expp;
+
+ if (exp->ex_type->tp_fund == POINTER) {
+ if (exp->ex_type != tp)
+ ch7cast(expp, oper, tp);
+ }
+ else
+ if ( is_integral_type(exp->ex_type)
+#ifndef NOROPTION
+ &&
+ ( !options['R'] /* we don't care */ ||
+ (oper == EQUAL || oper == NOTEQUAL || oper == ':')
+ )
+#endif NOROPTION
+ ) /* ch 7.7 */
+ ch7cast(expp, CAST, tp);
+ else {
+ expr_error(exp, "%s on %s and pointer",
+ symbol2str(oper),
+ symbol2str(exp->ex_type->tp_fund)
+ );
+ ch7cast(expp, oper, tp);
+ }
+}
+
+int
+any2arith(expp, oper)
+ register struct expr **expp;
+ register int oper;
+{
+ /* Turns any expression into int_type, long_type or
+ double_type.
+ */
+ int fund;
+
+ switch (fund = (*expp)->ex_type->tp_fund) {
+ case CHAR:
+ case SHORT:
+ case GENERIC:
+ int2int(expp,
+ (*expp)->ex_type->tp_unsigned ? uint_type : int_type);
+ break;
+ case INT:
+ case LONG:
+ break;
+ case ENUM:
+ /* test the admissibility of the operator */
+ if ( is_test_op(oper) || oper == '=' || oper == PARCOMMA ||
+ oper == ',' || oper == ':'
+ ) {
+ /* allowed by K & R */
+ }
+ else
+#ifndef NOROPTION
+ if (!options['R']) {
+ /* allowed by us */
+ }
+ else
+ expr_warning(*expp, "%s on enum", symbol2str(oper));
+#endif NOROPTION
+#ifndef LINT
+ int2int(expp, int_type);
+#endif LINT
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+/*
+ float2float(expp, double_type);
+ break;
+*/
+ case DOUBLE:
+ case LNGDBL:
+ break;
+#endif NOFLOAT
+#ifndef NOBITFIELD
+ case FIELD:
+ field2arith(expp);
+ break;
+#endif NOBITFIELD
+ default:
+ expr_error(*expp, "operator %s on non-numerical operand (%s)",
+ symbol2str(oper), symbol2str(fund));
+ case ERRONEOUS:
+ erroneous2int(expp);
+ break;
+ }
+
+ return (*expp)->ex_type->tp_fund;
+}
+
+erroneous2int(expp)
+ struct expr **expp;
+{
+ /* the (erroneous) expression *expp is replaced by an
+ int expression
+ */
+ register struct expr *exp = *expp;
+ int flags = exp->ex_flags;
+
+ free_expression(exp);
+ exp = intexpr((arith)0, INT);
+ exp->ex_flags = (flags | EX_ERROR);
+ *expp = exp;
+}
+
+struct expr *
+arith2arith(tp, oper, expr)
+ struct type *tp;
+ int oper;
+ register struct expr *expr;
+{
+ /* arith2arith constructs a new expression containing a
+ run-time conversion between some arithmetic types.
+ */
+ register struct expr *new = new_expr();
+
+ new->ex_file = expr->ex_file;
+ new->ex_line = expr->ex_line;
+ new->ex_type = tp;
+ new->ex_class = Type;
+ return new_oper(tp, new, oper, expr);
+}
+
+int
+int2int(expp, tp)
+ struct expr **expp;
+ register struct type *tp;
+{
+ /* The expression *expp, which is of some integral type, is
+ converted to the integral type tp.
+ */
+ register struct expr *exp = *expp;
+
+ if (is_cp_cst(exp)) {
+ register struct type *tp1 = exp->ex_type;
+
+ exp->ex_type = tp;
+ if (! tp1->tp_unsigned && tp->tp_unsigned) {
+ /* Avoid "unreal" overflow warnings, such as
+ caused by f.i.:
+ unsigned int x = ~0;
+ unsigned int y = -1;
+ */
+ extern long full_mask[];
+ long remainder = exp->VL_VALUE &
+ ~full_mask[(int)(tp->tp_size)];
+
+ if (remainder == 0 ||
+ remainder == ~full_mask[(int)(tp->tp_size)]) {
+ exp->VL_VALUE &= ~remainder;
+ }
+ }
+ cut_size(exp);
+ }
+ else {
+ exp = arith2arith(tp, INT2INT, exp);
+ }
+ *expp = exp;
+ return exp->ex_type->tp_fund;
+}
+
+#ifndef NOFLOAT
+int2float(expp, tp)
+ register struct expr **expp;
+ struct type *tp;
+{
+ /* The expression *expp, which is of some integral type, is
+ converted to the floating type tp.
+ */
+ register struct expr *exp = *expp;
+ char buf[32];
+
+ fp_used = 1;
+ if (is_cp_cst(exp)) {
+ *expp = new_expr();
+ **expp = *exp;
+ sprint(buf+1, "%ld", (long)(exp->VL_VALUE));
+ buf[0] = '-';
+ exp = *expp;
+ exp->ex_type = tp;
+ exp->ex_class = Float;
+ exp->FL_VALUE = Salloc(buf, (unsigned)strlen(buf)+2) + 1;
+ exp->FL_DATLAB = 0;
+ }
+ else *expp = arith2arith(tp, INT2FLOAT, *expp);
+}
+
+float2int(expp, tp)
+ struct expr **expp;
+ struct type *tp;
+{
+ /* The expression *expp, which is of some floating type, is
+ converted to the integral type tp.
+ */
+
+ fp_used = 1;
+ *expp = arith2arith(tp, FLOAT2INT, *expp);
+}
+
+float2float(expp, tp)
+ register struct expr **expp;
+ struct type *tp;
+{
+ /* The expression *expp, which is of some floating type, is
+ converted to the floating type tp.
+ There is no need for an explicit conversion operator
+ if the expression is a constant.
+ */
+
+ fp_used = 1;
+ if (is_fp_cst(*expp))
+ (*expp)->ex_type = tp;
+ else
+ *expp = arith2arith(tp, FLOAT2FLOAT, *expp);
+}
+#endif NOFLOAT
+
+array2pointer(exp)
+ register struct expr *exp;
+{
+ /* The expression, which must be an array, is converted
+ to a pointer.
+ */
+ exp->ex_type = construct_type(POINTER, exp->ex_type->tp_up, 0,
+ (arith)0, NO_PROTO);
+}
+
+function2pointer(exp)
+ register struct expr *exp;
+{
+ /* The expression, which must be a function, is converted
+ to a pointer to the function.
+ */
+ exp->ex_type = construct_type(POINTER, exp->ex_type, 0,
+ (arith)0, NO_PROTO);
+}
+
+string2pointer(ex)
+ register struct expr *ex;
+{
+ /* The expression, which must be a string constant, is converted
+ to a pointer to the string-containing area.
+ */
+ label lbl = data_label();
+
+ code_string(ex->SG_VALUE, ex->SG_LEN, lbl);
+ ex->ex_class = Value;
+ ex->VL_CLASS = Label;
+ ex->VL_LBL = lbl;
+ ex->VL_VALUE = (arith)0;
+}
+
+opnd2integral(expp, oper)
+ register struct expr **expp;
+ int oper;
+{
+ register int fund = (*expp)->ex_type->tp_fund;
+
+ if (fund != INT && fund != LONG) {
+ expr_error(*expp, "%s operand to %s",
+ symbol2str(fund), symbol2str(oper));
+ erroneous2int(expp);
+ /* fund = INT; */
+ }
+}
+
+opnd2logical(expp, oper)
+ register struct expr **expp;
+ int oper;
+{
+ int fund = (*expp)->ex_type->tp_fund;
+
+ if (fund == FUNCTION || fund == ARRAY) {
+ expr_warning(*expp, "%s operand to %s",
+ symbol2str(fund),
+ symbol2str(oper));
+ if (fund == FUNCTION) {
+ function2pointer(*expp);
+ }
+ else array2pointer(*expp);
+ }
+#ifndef NOBITFIELD
+ else
+ if (fund == FIELD)
+ field2arith(expp);
+#endif NOBITFIELD
+ switch (fund = (*expp)->ex_type->tp_fund) {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case LONG:
+ case ENUM:
+ case POINTER:
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+#endif NOFLOAT
+ break;
+ default:
+ expr_error(*expp, "%s operand to %s",
+ symbol2str(fund), symbol2str(oper));
+ case ERRONEOUS:
+ erroneous2int(expp);
+ break;
+ }
+}
+
+opnd2test(expp, oper)
+ register struct expr **expp;
+{
+ opnd2logical(expp, oper);
+ if ((*expp)->ex_class == Oper && is_test_op((*expp)->OP_OPER))
+ { /* It is already a test */ }
+ else
+ ch7bin(expp, NOTEQUAL, intexpr((arith)0, INT));
+}
+
+int
+is_test_op(oper)
+{
+ switch (oper) {
+ case '<':
+ case '>':
+ case LESSEQ:
+ case GREATEREQ:
+ case EQUAL:
+ case NOTEQUAL:
+ case '!':
+ case AND:
+ case OR: /* && and || also impose a test */
+ return 1;
+ default:
+ return 0;
+ }
+ /*NOTREACHED*/
+}
+
+any2opnd(expp, oper)
+ register struct expr **expp;
+{
+ if (!*expp)
+ return;
+ switch ((*expp)->ex_type->tp_fund) { /* RM 7.1 */
+ case CHAR:
+ case SHORT:
+ case ENUM:
+#ifndef NOFLOAT
+ case FLOAT:
+#endif NOFLOAT
+ any2arith(expp, oper);
+ break;
+ case ARRAY:
+ array2pointer(*expp);
+ break;
+ case POINTER:
+ if ((*expp)->ex_class == String)
+ string2pointer(*expp);
+ break;
+#ifndef NOBITFIELD
+ case FIELD:
+ field2arith(expp);
+ break;
+#endif NOBITFIELD
+ }
+}
+
+#ifndef NOBITFIELD
+field2arith(expp)
+ register struct expr **expp;
+{
+ /* The expression to extract the bitfield value from the
+ memory word is put in the tree.
+ */
+ register struct type *tp = (*expp)->ex_type->tp_up;
+ register struct field *fd = (*expp)->ex_type->tp_field;
+ register struct type *atype = tp->tp_unsigned ? uword_type : word_type;
+
+ (*expp)->ex_type = atype;
+
+ if (atype->tp_unsigned) { /* don't worry about the sign bit */
+ ch7bin(expp, RIGHT, intexpr((arith)fd->fd_shift, INT));
+ ch7bin(expp, '&', intexpr(fd->fd_mask, INT));
+ }
+ else { /* take care of the sign bit: sign extend if needed */
+ arith bits_in_type = atype->tp_size * 8;
+
+ ch7bin(expp, LEFT,
+ intexpr(bits_in_type - fd->fd_width - fd->fd_shift,
+ INT)
+ );
+ ch7bin(expp, RIGHT, intexpr(bits_in_type - fd->fd_width, INT));
+ }
+ ch7cast(expp, CAST, tp); /* restore its original type */
+}
+#endif NOBITFIELD
+
+#ifndef NOFLOAT
+/* switch_sign_fp() negates the given floating constant expression
+ The lexical analyser has reserved an extra byte of space in front
+ of the string containing the representation of the floating
+ constant. This byte contains the '-' character and we have to
+ take care of the first byte the fl_value pointer points to.
+*/
+switch_sign_fp(expr)
+ register struct expr *expr;
+{
+ if (*(expr->FL_VALUE) == '-')
+ ++(expr->FL_VALUE);
+ else
+ --(expr->FL_VALUE);
+}
+#endif NOFLOAT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* COMPILER ARITHMETIC */
+
+/* Normally the compiler does its internal arithmetics in longs
+ native to the source machine, which is always good for local
+ compilations, and generally OK too for cross compilations
+ downwards and sidewards. For upwards cross compilation and
+ to save storage on small machines, SPECIAL_ARITHMETICS will
+ be handy.
+*/
+
+#include "spec_arith.h"
+
+#ifndef SPECIAL_ARITHMETICS
+
+#include <em_arith.h> /* obtain definition of "arith" */
+
+#else SPECIAL_ARITHMETICS
+
+/* All preprocessor arithmetic should be done in longs.
+*/
+#define arith long /* dummy */
+
+#endif SPECIAL_ARITHMETICS
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* A S M */
+
+/*ARGSUSED*/
+code_asm(s, l)
+ char *s;
+ int l;
+{
+ /* 'asm' '(' string ')' ';'
+ */
+ error("\"asm\" instruction not implemented");
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* A S S E R T I O N M A C R O D E F I N I T I O N */
+
+/* At some points in the program, it must be sure that some condition
+ holds true, due to further, successful, processing. As long as
+ there is no reasonable method to prove that a program is 100%
+ correct, these assertions are needed in some places.
+*/
+#include "debug.h" /* UF */
+
+#ifdef DEBUG
+/* Note: this macro uses parameter substitution inside strings */
+#define ASSERT(exp) (exp || crash("in %s, %u: assertion %s failed", \
+ __FILE__, __LINE__, "exp"))
+#define NOTREACHED() crash("in %s, %u: unreachable statement reached", \
+ __FILE__, __LINE__)
+#else
+#define ASSERT(exp)
+#define NOTREACHED()
+#endif DEBUG
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Align To Word boundary Definition */
+
+#include "sizes.h"
+
+#define ATW(arg) ((((arg) + word_size - 1) / word_size) * word_size)
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* B L O C K S T O R I N G A N D L O A D I N G */
+
+#include "lint.h"
+#ifndef LINT
+
+#include <em.h>
+#include <em_reg.h>
+#include "arith.h"
+#include "sizes.h"
+#include "atw.h"
+#include "align.h"
+#ifndef STB
+#include "label.h"
+#include "stack.h"
+#include "Lpars.h"
+extern arith NewLocal();
+#define LocalPtrVar() NewLocal(pointer_size, pointer_align, reg_pointer, REGISTER)
+#endif STB
+
+/* Because EM does not support the loading and storing of
+ objects having other sizes than word fragment and multiple,
+ we need to have a way of transferring these objects, whereby
+ we simulate "loi" and "sti": the address of the source resp.
+ destination is located on top of stack and a call is done
+ to load_block() resp. store_block().
+ ===============================================================
+ # Loadblock() works on the stack as follows: ([ ] indicates the
+ # position of the stackpointer)
+ # lower address--->
+ # 1) | &object
+ # 2) | ... ATW(sz) bytes ... | sz | &stack_block | &object
+ # 3) | ... ATW(sz) bytes ...
+ ===============================================================
+ Loadblock() pushes ATW(sz) bytes directly onto the stack!
+
+ Store_block() works on the stack as follows:
+ lower address--->
+ 1) | ... ATW(sz) bytes ... | &object
+ 2) | ... ATW(sz) bytes ... | &object | &stack_block | sz
+ 3) <empty>
+
+ If sz is a legal argument for "loi" or "sti", just one EM
+ instruction is generated.
+ In the other cases, the notion of alignment is taken into account:
+ we only push an object of the size accepted by EM onto the stack,
+ while we need a loop to store the stack block into a memory object.
+*/
+store_block(sz, al)
+ arith sz;
+ int al;
+{
+ if (
+ ((sz == al) && (word_align % al == 0)) ||
+ (
+ (sz % word_size == 0 || word_size % sz == 0) &&
+ (al % word_align == 0)
+ )
+ ) /* Lots of Irritating Stupid Parentheses */
+ C_sti(sz);
+ else {
+#ifndef STB
+ arith src, dst;
+
+ /* allocate two pointer temporaries */
+ src = LocalPtrVar();
+ dst = LocalPtrVar();
+
+ /* load the addresses */
+ StoreLocal(dst, pointer_size);
+ C_lor((arith)1); /* push current sp */
+ StoreLocal(src, pointer_size);
+ copy_loop(sz, src, dst);
+ C_asp(ATW(sz));
+ FreeLocal(dst);
+ FreeLocal(src);
+#else STB
+ /* address of destination lies on the stack */
+
+ /* push address of first byte of block on stack onto
+ the stack by computing it from the current stack
+ pointer position
+ */
+ C_lor((arith)1); /* push current sp */
+ C_adp(pointer_size); /* set & to 1st byte of block */
+ C_loc(sz); /* number of bytes to transfer */
+ C_cal("__stb"); /* call transfer routine */
+ C_asp(pointer_size + pointer_size + int_size + ATW(sz));
+#endif STB
+ }
+}
+
+load_block(sz, al)
+ arith sz;
+ int al;
+{
+ arith esz = ATW(sz); /* effective size == actual # pushed bytes */
+
+ if (
+ ((sz == al) && (word_align % al == 0)) ||
+ (
+ (sz % word_size == 0 || word_size % sz == 0) &&
+ (al % word_align == 0)
+ )
+ ) /* Lots of Irritating Stupid Parentheses */
+ C_loi(sz);
+ else {
+#ifndef STB
+ arith src, dst;
+
+ /* allocate two pointer temporaries */
+ src = LocalPtrVar();
+ dst = LocalPtrVar();
+
+ StoreLocal(src, pointer_size);
+ C_asp(-esz); /* allocate stack block */
+ C_lor((arith)1); /* push & of stack block as dst */
+ StoreLocal(dst, pointer_size);
+ copy_loop(sz, src, dst);
+ FreeLocal(dst);
+ FreeLocal(src);
+#else STB
+ C_asp(-(esz - pointer_size)); /* allocate stack block */
+ C_lor((arith)1); /* push & of stack block as dst */
+ C_dup(pointer_size); /* fetch source address */
+ C_adp(esz - pointer_size);
+ C_loi(pointer_size);
+ C_loc(sz); /* # bytes to copy */
+ C_cal("__stb"); /* library copy routine */
+ C_asp(int_size + pointer_size + pointer_size);
+#endif STB
+ }
+}
+
+#ifndef STB
+copy_loop(sz, src, dst)
+ arith sz, src, dst;
+{
+ /* generate inline byte-copy loop */
+ label l_cont = text_label(), l_stop = text_label();
+
+ C_loc(sz); /* amount of bytes */
+ C_df_ilb(l_cont);
+ C_dup(word_size);
+ C_zle(l_stop);
+ C_dec();
+ LoadLocal(src, pointer_size);
+ C_dup(pointer_size);
+ C_adp((arith)1);
+ StoreLocal(src, pointer_size);
+ C_loi((arith)1);
+ LoadLocal(dst, pointer_size);
+ C_dup(pointer_size);
+ C_adp((arith)1);
+ StoreLocal(dst, pointer_size);
+ C_sti((arith)1);
+ C_bra(l_cont);
+ C_df_ilb(l_stop);
+ C_asp(word_size);
+}
+#endif STB
+
+#endif LINT
+
--- /dev/null
+.TH CEM 1L 86/11/12
+.SH NAME
+cem \- ACK C compiler
+.SH SYNOPSIS
+.B cem
+[ option ] ... file ...
+.SH DESCRIPTION
+.I Cem
+is a
+.I cc (1)-like
+C compiler that uses the C front-end compiler
+.I cemcom (1)
+of the Amsterdam Compiler Kit.
+.I Cem
+interprets its arguments not starting with a '\-' as
+source files, to be compiled by the various parts of the compilation process,
+which are listed below.
+File arguments whose names end with \fB.\fP\fIcharacter\fP are interpreted as
+follows:
+.IP .[ao]
+object file.
+.IP .[ci]
+C source code
+.IP .e
+EM assembler source file.
+.IP .k
+compact EM file, not yet optimized by the EM peephole optimizer.
+.IP .m
+compact EM file, already optimized by the peephole optimizer.
+.IP .s
+assembler file.
+.LP
+The actions to be taken by
+.I cem
+are directed by the type of file argument and the various options that are
+presented to it.
+.PP
+The following set of options, which is a mixture of options interpreted by
+.I cc (1)
+and
+.I ack (?)
+are interpreted by
+.I cem .
+(The options not specified here are passed to the loader.)
+.IP \fB\-B\fP\fIname\fP
+Use
+.I name
+as front-end compiler instead of the default
+.I cemcom (1).
+.br
+Same as "\fB\-Rcem=\fP\fIname\fP".
+.IP \fB\-C\fP
+Run C preprocessor
+.I /lib/cpp
+only and prevent it from eliding comments.
+.IP \fB\-D\fP\fIname\fP\fB=\fP\fIdef\fP
+Define the
+.I name
+to the preprocessor, as if by "#define".
+.IP \fB\-D\fP\fIname\fP
+.br
+Same as "\fB\-D\fP\fIname\fP\fB=1\fP".
+.IP \fB\-E\fP
+Run only the macro preprocessor on the named files and send the
+result to standard output.
+.IP \fB\-I\fP\fIdir\fP
+\&"#include" files whose names do not begin with '/' are always
+sought first in the directory of the \fIfile\fP argument, then in directories
+in \fB\-I\fP options, then in directories on a standard list (which in fact
+consists of "/usr/include").
+.IP \fB\-L\fP\fIdir\fP
+Use \fIdir\fP as library-containing directory instead of the default.
+.IP \fB\-N\fP\fIc\fP
+Only effective if ACK pipeline is used.
+This option causes some default actions and options to be suppressed, according
+to
+.I c :
+.RS
+.IP \fBc\fP
+do not convert from EM a.out to local a.out format (i.e., skip the
+.B cv
+pass.)
+.IP \fBl\fP
+do not pass the default loader flags to the
+.B ld
+pass.
+.RE
+.IP \fB\-P\fP
+Same as \fB\-E\fP, but sending the result of input file \fIfile\fP\fB.[ceis]\fP
+to \fIfile\fP\fB.i\fP.
+.IP \fB\-R\fP
+Passed to \fIcemcom\fP(1) in order to parse the named C programs according
+to the C language as described in [K&R] (also called \fIRestricted\fP C).
+.IP \fB\-R\fP\fIprog\fP\fB=\fP\fIname\fP
+.br
+Use \fIname\fP as program for phase \fIprog\fP of the compilation instead of
+the default.
+\&\fIProg\fP is one of the following names:
+.RS
+.IP \fBcpp\fP
+macro preprocessor
+.IP \fBcem\fP
+front\-end compiler
+.IP \fBopt\fP
+EM peephole optimizer
+.IP \fBdecode\fP
+EM compact to EM assembler translator
+.IP \fBencode\fP
+EM assembler to EM compact translator
+.IP \fBbe\fP
+EM compact code to target\-machine assembly code compiler
+.IP \fBcg\fP
+same as \fBbe\fP
+.IP \fBas\fP
+assembler
+.IP \fBld\fP
+linker/loader
+.IP \fBcv\fP
+a.out format converting program (only if ACK pipeline is used)
+.RE
+.IP \fB\-R\fP\fIprog\fP\fB\-\fP\fIoption\fP
+.br
+Pass \fB\-\fP\fIoption\fP to the compilation phase indicated by \fIprog\fP.
+.IP \fB\-S\fP
+Same as \fB\-c.s\fP.
+.IP \fB\-U\fP\fIname\fP
+.br
+Remove any initial definition of \fIname\fP.
+.IP \fB\-V\fP\fIcm\fP.\fIn\fP,\ \fB\-V\fIcm\fP.\fIncm\fP.\fIn\fP\ ...
+.br
+Set the size and alignment requirements of the C constructs of the named
+C input files.
+The letter \fIc\fP indicates the simple type, which is one of
+\fBs\fP(short), \fBi\fP(int), \fBl\fP(long), \fBf\fP(float), \fBd\fP(double) or
+\fBp\fP(pointer).
+The \fIm\fP parameter can be used to specify the length of the type (in bytes)
+and the \fIn\fP parameter for the alignment of that type.
+Absence of \fIm\fP or \fIn\fP causes the default value to be retained.
+To specify that the bitfields should be right adjusted instead of the
+default left adjustment, specify \fBr\fP as \fIc\fP parameter
+without parameters.
+.br
+This option is passed directly to \fIcemcom\fP(1).
+.IP \fB\-c\fP
+Same as \fB\-c.o\fP.
+.IP \fB\-c.e\fP
+Produce human-readable EM assembly code on \fIfile\fP\fB.e\fP for the
+named files \fIfile\fP\fB.[cikm]\fP
+.IP \fB\-c.k\fP
+Compile C source \fIfile\fP\fB.[ci]\fP or
+encode human-readable EM assembly code from \fIfile\fP\fB.e\fP
+into non-optimized compact EM code and write the result on \fIfile\fP\fB.k\fP
+.IP \fB\-c.m\fP
+Compile C source \fIfile\fP\fB.[ci]\fP,
+translate non-optimized EM code from \fIfile\fP\fB.k\fP or
+encode EM assembly code from \fIfile\fP\fB.e\fP
+into optimized compact EM code and write the result on \fIfile\fP\fB.m\fP
+.IP \fB\-c.o\fP
+Suppress the loading phase of the compilation, and force an object file to
+be produced even if only one program is compiled
+.IP \fB\-c.s\fP
+Compile the named \fIfile\fP\fB.[ceikm]\fP input files, and leave the
+assembly language output on corresponding files suffixed ".s".
+.IP \fB\-k\fP
+Same as \fB\-c.k\fP.
+.IP \fB\-l\fP\fIname\fP
+.br
+Append the library \fBlib\fP\fIname\fP\fB.a\fP to the list of files that
+should be loaded and linked into the final output file.
+The library is searched for in the library directory.
+.IP \fB\-m\fP
+Same as \fB\-c.m\fP.
+.IP \fB\-o\fP\ \fIoutput\fP
+.br
+Name the final output file \fIoutput\fP.
+If this option is used, the default "a.out" will be left undisturbed.
+.IP \fB\-p\fP
+Produce EM profiling code (\fBfil\fP and \fBlin\fP instructions to
+enable an interpreter to keep track of the current location in the
+source code)
+.IP \fB\-t\fP
+Keep the intermediate files, produced during the various phases of the
+compilation.
+The produced files are named \fIfile\fP\fB.\fP\fIcharacter\fP where
+\&\fIcharacter\fP indicates the type of the file as listed before.
+.IP \fB\-v\fP
+Verbose.
+Print the commands before they are executed.
+.IP \fB\-vn\fP
+Do not really execute (for debugging purposes only).
+.IP \fB\-vd\fP
+Print some additional information (for debugging purposes only).
+.IP \fB\-\-\fP\fIanything\fP
+.br
+Equivalent to \fB\-Rcem\-\-\fP\fIanything\fP.
+The options
+.B \-\-C ,
+.B \-\-E
+and
+.B \-\-P
+all have the same effect as respectively
+.B \-C ,
+.B \-E
+and
+.B \-P
+except for the fact that the macro preprocessor is taken to be the
+built\-in preprocessor of the \fBcem\fP phase.
+Most "\-\-" options are used by
+.I cemcom (1)
+to set some internal debug switches.
+.LP
+.SH SEE ALSO
+cemcom(1), cc(1), ack(?), as(1), ld(1)
+.br
+.IP [K&R]
+B.W. Kernighan and D.M. Ritchie, \fIThe C Programming Language\fP,
+Prentice-Hall, 1978.
+.SH DIAGNOSTICS
+.I Cem
+reports any failure of its components.
+.SH BUGS
+.IP \(bu
+All intermediate files are placed in the current working directory which
+causes files with the same name as the intermediate files to be overwritten.
+.IP \(bu
+.B Cem
+only accepts a limited number of arguments to be passed to the components.
+(e.g., 256).
+.IP \(bu
+Please report suggestions and other bugs to erikb@vu44.uucp
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/*
+ Driver for the CEMCOM compiler: works like /bin/cc and accepts
+ most of the options accepted by /bin/cc and /usr/em/bin/ack.
+ Date written: dec 4, 1985
+ Adapted for 68000 (Aug 19, 1986)
+ Merged the vax and mantra versions (Nov 10, 1986)
+ Author: Erik Baalbergen
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <signal.h>
+
+#define MAXARGC 256 /* maximum number of arguments allowed in a list */
+#define USTR_SIZE 1024 /* maximum length of string variable */
+
+struct arglist {
+ int al_argc;
+ char *al_argv[MAXARGC];
+};
+
+/* some system-dependent variables */
+char *PP = "/lib/cpp";
+char *CEM = "/usr/em/lib/em_cemcom";
+char *ENCODE = "/usr/em/lib/em_encode";
+char *DECODE = "/usr/em/lib/em_decode";
+char *OPT = "/usr/em/lib/em_opt";
+char *SHELL = "/bin/sh";
+
+#ifndef MANTRA
+char *CG = "/usr/em/lib/vax4/cg";
+char *AS = "/bin/as";
+char *AS_FIX = "/user1/erikb/bin/mcomm";
+char *LD = "/bin/ld";
+char *LIBDIR = "/user1/cem/lib";
+char *V_FLAG = "-Vs2.2w4.4i4.4l4.4f4.4d8.4p4.4";
+#else MANTRA
+char *CG = "/usr/em/lib/m68k2/cg";
+char *AS = "/usr/em/lib/m68k2/as";
+char *LD = "/usr/em/lib/em_led";
+char *CV = "/usr/em/lib/m68k2/cv";
+char *LIBDIR = "/usr/em/lib/m68k2";
+char *V_FLAG = "-Vs2.2w2.2i2.2l4.2f4.2d8.2p4.2";
+#endif MANTRA
+
+struct arglist LD_HEAD = {
+ 2,
+ {
+#ifndef MANTRA
+ "/usr/em/lib/vax4/head_em",
+ "/usr/em/lib/vax4/head_cc"
+#else MANTRA
+ "/usr/em/lib/m68k2/head_em",
+ "/usr/em/lib/m68k2/head_cc"
+#endif MANTRA
+ }
+};
+
+struct arglist LD_TAIL = {
+#ifndef MANTRA
+ 4,
+ {
+ "/user1/cem/lib/libc.a",
+ "/user1/cem/lib/stb.o",
+ "/usr/em/lib/vax4/tail_mon",
+ "/usr/em/lib/vax4/tail_em"
+ }
+#else MANTRA
+ 7,
+ {
+ "/usr/em/lib/m68k2/tail_cc.1s",
+ "/usr/em/lib/m68k2/tail_cc.2g",
+ "/usr/em/lib/m68k2/tail_cem",
+ "/usr/em/lib/m68k2/tail_fp.a",
+ "/usr/em/lib/m68k2/tail_em.rt",
+ "/usr/em/lib/m68k2/tail_mon",
+ "/usr/em/lib/m68k2/end_em"
+ }
+#endif MANTRA
+};
+
+char *o_FILE = "a.out";
+#ifdef MANTRA
+char *cv_FILE = "cv.out";
+#endif MANTRA
+
+#define remove(str) (((FLAG(t) == 0) && unlink(str)), (str)[0] = '\0')
+#define cleanup(str) (str && remove(str))
+#define mkname(dst, s1, s2) mkstr(dst, (s1), (s2), 0)
+#define init(al) (al)->al_argc = 1
+#define library(nm) \
+ mkstr(alloc((unsigned int)strlen(nm) + strlen(LIBDIR) + 7), \
+ LIBDIR, "/lib", nm, ".a", 0)
+
+struct arglist SRCFILES, LDFILES, GEN_LDFILES, PP_FLAGS, CEM_FLAGS,
+ OPT_FLAGS, DECODE_FLAGS, ENCODE_FLAGS, CG_FLAGS, AS_FLAGS,
+ O_FLAGS, DEBUG_FLAGS, CALL_VEC;
+
+#ifndef MANTRA
+struct arglist LD_FLAGS;
+#else MANTRA
+struct arglist LD_FLAGS = {
+ 5,
+ {
+ "-b0:0x80000",
+ "-a0:2",
+ "-a1:2",
+ "-a2:2",
+ "-a3:2"
+ }
+};
+struct arglist CV_FLAGS;
+int Nc_flag = 0;
+#endif MANTRA
+
+/* option naming */
+#define NAME(chr) chr
+#define FLAG(chr) NAME(chr)_flag
+int E_flag, P_flag, S_flag, c_flag, e_flag, k_flag,
+ m_flag, o_flag, t_flag, v_flag;
+
+/* various passes */
+struct prog {
+ char *p_name;
+ char **p_task;
+ struct arglist *p_flags;
+} ProgParts[] = {
+ { "cpp", &PP, &PP_FLAGS },
+ { "cem", &CEM, &CEM_FLAGS },
+ { "opt", &OPT, &OPT_FLAGS },
+ { "decode", &DECODE, &DECODE_FLAGS },
+ { "encode", &ENCODE, &ENCODE_FLAGS },
+ { "be", &CG, &CG_FLAGS },
+ { "cg", &CG, &CG_FLAGS },
+ { "as", &AS, &AS_FLAGS },
+ { "ld", &LD, &LD_FLAGS },
+#ifdef MANTRA
+ { "cv", &CV, &CV_FLAGS },
+#endif MANTRA
+ { 0, 0, 0 }
+};
+
+/* various forward declarations */
+int trap();
+char *mkstr();
+char *alloc();
+long sizeof_file();
+
+/* various globals */
+char *ProgCall = 0;
+int debug = 0;
+int exec = 1;
+int RET_CODE = 0;
+
+main(argc, argv)
+ char *argv[];
+{
+ char *str, **argvec, *file, *ldfile = 0;
+ int count, ext;
+ char Nfile[USTR_SIZE], kfile[USTR_SIZE], sfile[USTR_SIZE],
+ mfile[USTR_SIZE], ofile[USTR_SIZE], BASE[USTR_SIZE];
+ register struct arglist *call = &CALL_VEC;
+
+ set_traps(trap);
+ ProgCall = *argv++;
+ append(&CEM_FLAGS, "-L");
+ while (--argc > 0) {
+ if (*(str = *argv++) != '-') {
+ append(&SRCFILES, str);
+ continue;
+ }
+ switch (str[1]) {
+ case '-':
+ switch (str[2]) {
+ case 'C':
+ case 'E':
+ case 'P':
+ FLAG(E) = 1;
+ append(&PP_FLAGS, str);
+ PP = CEM;
+ FLAG(P) = (str[2] == 'P');
+ break;
+ default:
+ append(&DEBUG_FLAGS, str);
+ break;
+ }
+ break;
+ case 'B':
+ PP = CEM = &str[2];
+ break;
+ case 'C':
+ case 'E':
+ case 'P':
+ FLAG(E) = 1;
+ append(&PP_FLAGS, str);
+ FLAG(P) = (str[1] == 'P');
+ break;
+ case 'c':
+ if (str[2] == '.') {
+ switch (str[3]) {
+ case 's':
+ FLAG(S) = 1;
+ break;
+ case 'k':
+ FLAG(k) = 1;
+ break;
+ case 'o':
+ FLAG(c) = 1;
+ break;
+ case 'm':
+ FLAG(m) = 1;
+ break;
+ case 'e':
+ FLAG(e) = 1;
+ break;
+ default:
+ bad_option(str);
+ }
+ }
+ else
+ if (str[2] == '\0')
+ FLAG(c) = 1;
+ else
+ bad_option(str);
+ break;
+ case 'D':
+ case 'I':
+ case 'U':
+ append(&PP_FLAGS, str);
+ break;
+ case 'k':
+ FLAG(k) = 1;
+ break;
+ case 'l':
+ if (str[2] == '\0') /* no standard libraries */
+ LD_HEAD.al_argc = LD_TAIL.al_argc = 0;
+ else /* use library from library directory */
+ append(&SRCFILES, library(&str[2]));
+ break;
+ case 'L': /* change default library directory */
+ LIBDIR = &str[2];
+ break;
+ case 'm':
+ FLAG(m) = 1;
+ break;
+#ifdef MANTRA
+ case 'N':
+ switch (str[2]) {
+ case 'c': /* no a.out conversion */
+ Nc_flag = 1;
+ break;
+ case 'l': /* no default options to led */
+ LD_FLAGS.al_argc = 0;
+ break;
+ default:
+ bad_option(str);
+ }
+ break;
+#endif MANTRA
+ case 'o':
+ FLAG(o) = 1;
+ if (argc-- < 0)
+ bad_option(str);
+ else
+ o_FILE = *argv++;
+ break;
+ case 'O':
+ append(&O_FLAGS, "-O");
+ break;
+ case 'R':
+ if (str[2] == '\0')
+ append(&CEM_FLAGS, str);
+ else
+ Roption(str);
+ break;
+ case 'S':
+ FLAG(S) = 1;
+ break;
+ case 't':
+ FLAG(t) = 1;
+ break;
+ case 'v': /* set debug switches */
+ FLAG(v) = 1;
+ switch (str[2]) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'n': /* no execute */
+ exec = 0;
+ break;
+ case '\0':
+ break;
+ default:
+ bad_option(str);
+ }
+ break;
+ case 'V':
+ V_FLAG = str;
+ break;
+ default:
+ append(&LD_FLAGS, str);
+ }
+ }
+ if (debug) report("Note: debug output");
+ if (exec == 0)
+ report("Note: no execution");
+ count = SRCFILES.al_argc;
+ argvec = &(SRCFILES.al_argv[0]);
+ Nfile[0] = '\0';
+ while (count-- > 0) {
+ basename(file = *argvec++, BASE);
+ if (FLAG(E)) {
+ char ifile[USTR_SIZE];
+
+ init(call);
+ append(call, PP);
+ concat(call, &DEBUG_FLAGS);
+ concat(call, &PP_FLAGS);
+ append(call, file);
+ runvec(call, FLAG(P) ? mkname(ifile, BASE, ".i") : 0);
+ continue;
+ }
+ ext = extension(file);
+ /* .c to .k and .N */
+ if (ext == 'c' || ext == 'i') {
+ init(call);
+ append(call, CEM);
+ concat(call, &DEBUG_FLAGS);
+ append(call, V_FLAG);
+ concat(call, &CEM_FLAGS);
+ concat(call, &PP_FLAGS);
+ append(call, file);
+ append(call, mkname(kfile, BASE, ".k"));
+ append(call, mkname(Nfile, BASE, ".N"));
+ if (runvec(call, (char *)0)) {
+ file = kfile;
+ ext = 'k';
+ if (sizeof_file(Nfile) <= 0L)
+ remove(Nfile);
+ }
+ else {
+ remove(kfile);
+ remove(Nfile);
+ continue;
+ }
+ }
+ /* .e to .k */
+ if (ext == 'e') {
+ init(call);
+ append(call, ENCODE);
+ concat(call, &ENCODE_FLAGS);
+ append(call, file);
+ append(call, mkname(kfile, BASE, ".k"));
+ if (runvec(call, (char *)0) == 0)
+ continue;
+ file = kfile;
+ ext = 'k';
+ }
+ if (FLAG(k))
+ continue;
+ /* decode .k or .m */
+ if (FLAG(e) && (ext == 'k' || ext == 'm')) {
+ char efile[USTR_SIZE];
+ init(call);
+ append(call, DECODE);
+ concat(call, &DECODE_FLAGS);
+ append(call, file);
+ append(call, mkname(efile, BASE, ".e"));
+ runvec(call, (char *)0);
+ cleanup(kfile);
+ continue;
+ }
+ /* .k to .m */
+ if (ext == 'k') {
+ init(call);
+ append(call, OPT);
+ concat(call, &OPT_FLAGS);
+ append(call, file);
+ if (runvec(call, mkname(mfile, BASE, ".m")) == 0)
+ continue;
+ file = mfile;
+ ext = 'm';
+ cleanup(kfile);
+ }
+ if (FLAG(m))
+ continue;
+ /* .m to .s */
+ if (ext == 'm') {
+ init(call);
+ append(call, CG);
+ concat(call, &CG_FLAGS);
+ append(call, file);
+ append(call, mkname(sfile, BASE, ".s"));
+ if (runvec(call, (char *)0) == 0)
+ continue;
+ if (Nfile[0] != '\0') {
+#ifndef MANTRA
+ init(call);
+ append(call, AS_FIX);
+ append(call, Nfile);
+ append(call, sfile);
+ runvec(call, (char *)0);
+#endif MANTRA
+ remove(Nfile);
+ }
+ cleanup(mfile);
+ file = sfile;
+ ext = 's';
+ }
+ if (FLAG(S))
+ continue;
+ /* .s to .o */
+ if (ext == 's') {
+ ldfile = FLAG(c) ?
+ ofile :
+ alloc((unsigned)strlen(BASE) + 3);
+ init(call);
+ append(call, AS);
+ concat(call, &AS_FLAGS);
+#ifdef MANTRA
+ append(call, "-");
+#endif MANTRA
+ append(call, "-o");
+ append(call, mkname(ldfile, BASE, ".o"));
+ append(call, file);
+ if (runvec(call, (char *)0) == 0)
+ continue;
+ file = ldfile;
+ ext = 'o';
+ cleanup(sfile);
+ }
+ if (FLAG(c))
+ continue;
+ append(&LDFILES, file);
+ if (ldfile) {
+ append(&GEN_LDFILES, ldfile);
+ ldfile = 0;
+ }
+ }
+ /* *.o to a.out */
+ if (RET_CODE == 0 && LDFILES.al_argc > 0) {
+ init(call);
+ append(call, LD);
+ concat(call, &LD_FLAGS);
+ append(call, "-o");
+#ifndef MANTRA
+ append(call, o_FILE);
+#else MANTRA
+ append(call, Nc_flag ? o_FILE : cv_FILE);
+#endif MANTRA
+ concat(call, &LD_HEAD);
+ concat(call, &LDFILES);
+ concat(call, &LD_TAIL);
+ if (runvec(call, (char *)0)) {
+ register i = GEN_LDFILES.al_argc;
+
+ while (i-- > 0)
+ remove(GEN_LDFILES.al_argv[i]);
+#ifdef MANTRA
+ /* convert to local a.out format */
+ if (Nc_flag == 0) {
+ init(call);
+ append(call, CV);
+ concat(call, &CV_FLAGS);
+ append(call, cv_FILE);
+ append(call, o_FILE);
+ if (runvec(call, (char *)0))
+ remove(cv_FILE);
+ }
+#endif MANTRA
+ }
+ }
+ exit(RET_CODE);
+}
+
+#define BUFSIZE (USTR_SIZE * MAXARGC)
+char alloc_buf[BUFSIZE];
+
+char *
+alloc(u)
+ unsigned u;
+{
+ static char *bufptr = &alloc_buf[0];
+ register char *p = bufptr;
+
+ if ((bufptr += u) >= &alloc_buf[BUFSIZE])
+ panic("no space");
+ return p;
+}
+
+append(al, arg)
+ register struct arglist *al;
+ char *arg;
+{
+ if (al->al_argc >= MAXARGC)
+ panic("argument list overflow");
+ al->al_argv[(al->al_argc)++] = arg;
+}
+
+concat(al1, al2)
+ struct arglist *al1, *al2;
+{
+ register int i = al2->al_argc;
+ register char **p = &(al1->al_argv[al1->al_argc]);
+ register char **q = &(al2->al_argv[0]);
+
+ if ((al1->al_argc += i) >= MAXARGC)
+ panic("argument list overflow");
+ while (i-- > 0)
+ *p++ = *q++;
+}
+
+/* The next function is a dirty old one, taking a variable number of
+ arguments.
+ Take care that the last argument is a null-valued pointer!
+*/
+/*VARARGS1*/
+char *
+mkstr(dst, arg)
+ char *dst, *arg;
+{
+ char **vec = (char **) &arg;
+ register char *p;
+ register char *q = dst;
+
+ while (p = *vec++) {
+ while (*q++ = *p++);
+ q--;
+ }
+ return dst;
+}
+
+Roption(str)
+ char *str; /* of the form "prog=/-arg" */
+{
+ char *eq;
+ char *prog, *arg;
+ char bc;
+ char *cindex();
+
+ prog = &str[2];
+ if (eq = cindex(prog, '='))
+ bc = '=';
+ else
+ if (eq = cindex(prog, '-'))
+ bc = '-';
+ else {
+ bad_option(str);
+ return;
+ }
+ *eq++ = '\0';
+ if (arg = eq) {
+ char *opt = 0;
+ struct prog *pp = &ProgParts[0];
+
+ if (bc == '-')
+ opt = mkstr(alloc((unsigned)strlen(arg) + 2),
+ "-", arg, 0);
+ while (pp->p_name) {
+ if (strcmp(prog, pp->p_name) == 0) {
+ if (opt)
+ append(pp->p_flags, opt);
+ else
+ *(pp->p_task) = arg;
+ return;
+ }
+ pp++;
+ }
+ }
+ bad_option(str);
+}
+
+basename(str, dst)
+ char *str;
+ register char *dst;
+{
+ register char *p1 = str;
+ register char *p2 = p1;
+
+ while (*p1)
+ if (*p1++ == '/')
+ p2 = p1;
+ p1--;
+ if (*--p1 == '.') {
+ *p1 = '\0';
+ while (*dst++ = *p2++) {}
+ *p1 = '.';
+ }
+ else
+ while (*dst++ = *p2++) {}
+}
+
+int
+extension(fn)
+ register char *fn;
+{
+ char c;
+
+ while (*fn++) {}
+ fn--;
+ c = *--fn;
+ return (*--fn == '.') ? c : 0;
+}
+
+long
+sizeof_file(nm)
+ char *nm;
+{
+ struct stat stbuf;
+
+ if (stat(nm, &stbuf) == 0)
+ return stbuf.st_size;
+ return -1;
+}
+
+char * sysmsg[] = {
+ 0,
+ "Hangup",
+ "Interrupt",
+ "Quit",
+ "Illegal instruction",
+ "Trace/BPT trap",
+ "IOT trap",
+ "EMT trap",
+ "Floating exception",
+ "Killed",
+ "Bus error",
+ "Memory fault",
+ "Bad system call",
+ "Broken pipe",
+ "Alarm call",
+ "Terminated",
+ "Signal 16"
+};
+
+runvec(vec, outp)
+ struct arglist *vec;
+ char *outp;
+{
+ int status, fd;
+ char *task = vec->al_argv[1];
+
+ vec->al_argv[vec->al_argc] = 0;
+ if (FLAG(v))
+ print_vec(vec);
+ if (exec == 0)
+ return 1;
+ if (fork() == 0) { /* start up the process */
+ extern int errno;
+ if (outp) { /* redirect standard output */
+ close(1);
+ if ((fd = creat(outp, 0666)) < 0)
+ panic("cannot create %s", outp);
+ if (fd != 1)
+ panic("illegal redirection");
+ }
+ if (debug) report("exec %s", task);
+ execv(task, &(vec->al_argv[1]));
+ /* not an a.out file, let's try it with the SHELL */
+ if (debug) report("try it with %s", SHELL);
+ if (errno == ENOEXEC) {
+ vec->al_argv[0] = SHELL;
+ execv(SHELL, &(vec->al_argv[0]));
+ }
+ /* failed, so ... */
+ panic("cannot execute %s", task);
+ exit(1);
+ }
+ else {
+ int loworder, highorder, sig;
+
+ wait(&status);
+ loworder = status & 0377;
+ highorder = (status >> 8) & 0377;
+ if (loworder == 0) {
+ if (highorder)
+ report("%s: exit status %d", task, highorder);
+ return highorder ? ((RET_CODE = 1), 0) : 1;
+ }
+ else {
+ sig = loworder & 0177;
+ if (sig == 0177)
+ report("%s: stopped by ptrace", task);
+ else
+ if (sysmsg[sig])
+ report("%s: %s%s", task, sysmsg[sig],
+ (loworder & 0200)
+ ? " - core dumped"
+ : "");
+ RET_CODE = 1;
+ return 0;
+ }
+ }
+ /*NOTREACHED*/
+}
+
+bad_option(str)
+ char *str;
+{
+ report("bad option %s", str);
+}
+
+/*VARARGS1*/
+report(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
+ char *fmt;
+{
+ fprintf(stderr, "%s: ", ProgCall);
+ fprintf(stderr, fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ fprintf(stderr, "\n");
+}
+
+/*VARARGS1*/
+panic(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
+ char *fmt;
+{
+ fprintf(stderr, "%s: ", ProgCall);
+ fprintf(stderr, fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+set_traps(f)
+ int (*f)();
+{
+ signal(SIGHUP, f);
+ signal(SIGINT, f);
+ signal(SIGQUIT, f);
+ signal(SIGALRM, f);
+ signal(SIGTERM, f);
+}
+
+/*ARGSUSED*/
+trap(sig)
+{
+ set_traps(SIG_IGN);
+ panic("Trapped");
+}
+
+print_vec(vec)
+ struct arglist *vec;
+{
+ register i;
+
+ for (i = 1; i < vec->al_argc; i++)
+ printf("%s ", vec->al_argv[i]);
+ printf("\n");
+}
+
+char *
+cindex(s, c)
+ char *s, c;
+{
+ while (*s)
+ if (*s++ == c)
+ return s - 1;
+ return (char *) 0;
+}
--- /dev/null
+.TH EM_CEMCOM 6ACK
+.ad
+.SH NAME
+em_cemcom \- C to EM compiler
+.SH SYNOPSIS
+\fB~/em/lib/em_cemcom\fP [\fIoptions\fP] \fIsource \fP[\fIdestination \fP[\fInamelist\fP]]
+.SH DESCRIPTION
+\fICemcom\fP is a compiler that translates C programs
+into EM compact code.
+The input is taken from \fIsource\fP, while the
+EM code is written on \fIdestination\fP.
+If either of these two names is "\fB-\fP", standard input or output respectively
+is taken.
+The file \fInamelist\fP, if supplied, will contain a list of the names
+of external, so-called \fBcommon\fP, variables.
+When the preprocessor is invoked to run stand-alone, \fIdestination\fP
+needs not be specified.
+.br
+\fIOptions\fP is a, possibly empty, sequence of the following combinations:
+.IP \fB\-D\fIname\fR=\fItext\fR
+.br
+define \fIname\fR as a macro with \fItext\fR as its replacement text.
+.IP \fB\-D\fIname\fR
+.br
+the same as \fB\-D\fIname\fR=1.
+.IP \fB\-I\fIdirname\fR
+.br
+insert \fIdirname\fR in the list of include directories.
+.IP \fB\-M\fP\fIn\fP
+set maximum identifier length to \fIn\fP.
+.IP \fB\-n\fR
+do not generate EM register messages.
+The user-declared variables are not stored into registers on the target
+machine.
+.IP \fB\-L\fR
+don't generate the EM \fBfil\fR and \fBlin\fR instructions
+that usually are generated to enable
+an interpreter to keep track of the current location in the source code.
+.IP \fB\-p\fR
+generate code at each procedure entry to call the routine
+.BR procentry ,
+and at each return to call the routine
+.BE procexit .
+These routines are supplied with one parameter, a pointer to a
+string containing the name of the procedure.
+.IP \fB\-R\fR
+interpret the input as restricted C (according to the language as
+described in \fIThe C programming language\fR by Kernighan and Ritchie.)
+.IP \fB\-U\fIname\fR
+.br
+get rid of the compiler-predefined macro \fIname\fR.
+.IP \fB\-V\fIcm\fR.\fIn\fR,\ \fB\-V\fIcm\fR.\fIncm\fR.\fIn\fR\ ...
+.br
+set the size and alignment requirements.
+The letter \fIc\fR indicates the simple type, which is one of
+\fBs\fR(short), \fBi\fR(int), \fBl\fR(long), \fBf\fR(float), \fBd\fR(double) or
+\fBp\fR(pointer).
+The \fIm\fR parameter can be used to specify the length of the type (in bytes)
+and the \fIn\fR parameter for the alignment of that type.
+Absence of \fIm\fR or \fIn\fR causes the default value to be retained.
+To specify that the bitfields should be right adjusted instead of the
+default left adjustment, specify \fBr\fR as \fIc\fR parameter.
+.IP \fB\-w\fR
+suppress warning messages
+.IP \fB\-\-\fItext\fR
+.br
+where \fItext\fR can be either of the above or
+a debug flag of the compiler (which is not useful for the common user.)
+This feature can be used in various shell scripts and surrounding programs
+to force a certain option to be handed over to \fBcemcom\fR.
+.LP
+.SH FILES
+.IR ~em/lib/em_cemcom :
+the compiler
+.SH DIAGNOSTICS
+All warning and error messages are written on standard error output.
+.SH REFERENCE
+Baalbergen, E.H., D. Grune, M. Waage ;"\fIThe CEM compiler\fR",
+Informatica Manual IM-4
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* S E M A N T I C A N A L Y S I S -- C H A P T E R 7 RM */
+
+#include "lint.h"
+#include "nofloat.h"
+#include "debug.h"
+#include "nobitfield.h"
+#include "idf.h"
+#include "arith.h"
+#include "proto.h"
+#include "type.h"
+#include "struct.h"
+#include "label.h"
+#include "expr.h"
+#include "def.h"
+#include "Lpars.h"
+#include "assert.h"
+#include "file_info.h"
+
+extern char options[];
+extern char *symbol2str();
+
+/* Most expression-handling routines have a pointer to a
+ (struct type *) as first parameter. The object under the pointer
+ gets updated in the process.
+*/
+
+ch7sel(expp, oper, idf)
+ struct expr **expp;
+ struct idf *idf;
+{
+ /* The selector idf is applied to *expp; oper may be '.' or
+ ARROW.
+ */
+ register struct expr *exp;
+ register struct type *tp;
+ register struct sdef *sd;
+
+ any2opnd(expp, oper);
+ exp = *expp;
+ tp = exp->ex_type;
+ if (oper == ARROW) {
+ if (tp->tp_fund == POINTER &&
+ ( tp->tp_up->tp_fund == STRUCT ||
+ tp->tp_up->tp_fund == UNION)) /* normal case */
+ tp = tp->tp_up;
+ else { /* constructions like "12->selector" and
+ "char c; c->selector"
+ */
+ switch (tp->tp_fund) {
+ case INT:
+ case LONG:
+ /* Allowed by RM 14.1 */
+ ch7cast(expp, CAST, pa_type);
+ sd = idf2sdef(idf, tp);
+ tp = sd->sd_stype;
+ break;
+ case POINTER:
+ break;
+ default:
+ expr_error(exp, "-> applied to %s",
+ symbol2str(tp->tp_fund));
+ case ERRONEOUS:
+ exp->ex_type = error_type;
+ return;
+ }
+ }
+ } /* oper == ARROW */
+ else { /* oper == '.' */
+ /* filter out illegal expressions "non_lvalue.sel" */
+ if (!exp->ex_lvalue) {
+ expr_error(exp, "dot requires lvalue");
+ return;
+ }
+ }
+ exp = *expp;
+ switch (tp->tp_fund) {
+ case POINTER: /* for int *p; p->next = ... */
+ case STRUCT:
+ case UNION:
+ break;
+ case INT:
+ case LONG:
+ /* warning will be given by idf2sdef() */
+ break;
+ default:
+ if (!is_anon_idf(idf))
+ expr_error(exp, "selector %s applied to %s",
+ idf->id_text, symbol2str(tp->tp_fund));
+ case ERRONEOUS:
+ exp->ex_type = error_type;
+ return;
+ }
+ sd = idf2sdef(idf, tp);
+ if (oper == '.') {
+ /* there are 3 cases in which the selection can be
+ performed compile-time:
+ I: n.sel (n either an identifier or a constant)
+ II: (e.s1).s2 (transformed into (e.(s1+s2)))
+ III: (e->s1).s2 (transformed into (e->(s1+s2)))
+ The code performing these conversions is
+ extremely obscure.
+ */
+ if (exp->ex_class == Value) {
+ /* It is an object we know the address of; so
+ we can calculate the address of the
+ selected member
+ */
+ exp->VL_VALUE += sd->sd_offset;
+ exp->ex_type = sd->sd_type;
+ if (exp->ex_type == error_type)
+ exp->ex_flags |= EX_ERROR;
+ }
+ else
+ if (exp->ex_class == Oper) {
+ struct oper *op = &(exp->ex_object.ex_oper);
+
+ if (op->op_oper == '.' || op->op_oper == ARROW) {
+ ASSERT(is_cp_cst(op->op_right));
+ op->op_right->VL_VALUE += sd->sd_offset;
+ exp->ex_type = sd->sd_type;
+ if (exp->ex_type == error_type)
+ exp->ex_flags |= EX_ERROR;
+ }
+ else
+ exp = new_oper(sd->sd_type, exp, '.',
+ intexpr(sd->sd_offset, INT));
+ }
+ }
+ else /* oper == ARROW */
+ exp = new_oper(sd->sd_type,
+ exp, oper, intexpr(sd->sd_offset, INT));
+ exp->ex_lvalue = (sd->sd_type->tp_fund != ARRAY);
+ if (sd->sd_type->tp_typequal & TQ_CONST)
+ exp->ex_flags |= EX_READONLY;
+ if (sd->sd_type->tp_typequal & TQ_VOLATILE)
+ exp->ex_flags |= EX_VOLATILE;
+ *expp = exp;
+}
+
+ch7incr(expp, oper)
+ struct expr **expp;
+{
+ /* The monadic prefix/postfix incr/decr operator oper is
+ applied to *expp.
+ */
+ ch7asgn(expp, oper, intexpr((arith)1, INT));
+}
+
+ch7cast(expp, oper, tp)
+ register struct expr **expp;
+ register struct type *tp;
+{
+ /* The expression *expp is cast to type tp; the cast is
+ caused by the operator oper. If the cast has
+ to be passed on to run time, its left operand will be an
+ expression of class Type.
+ */
+ register struct type *oldtp;
+
+ if ((*expp)->ex_type->tp_fund == FUNCTION)
+ function2pointer(*expp);
+ if ((*expp)->ex_type->tp_fund == ARRAY)
+ array2pointer(*expp);
+ if ((*expp)->ex_class == String)
+ string2pointer(*expp);
+ oldtp = (*expp)->ex_type;
+
+#ifndef NOBITFIELD
+ if (oldtp->tp_fund == FIELD) {
+ field2arith(expp);
+ ch7cast(expp, oper, tp);
+ }
+ else
+ if (tp->tp_fund == FIELD) {
+ ch7cast(expp, oper, tp->tp_up);
+ }
+ else
+#endif NOBITFIELD
+ if (equal_type(tp, oldtp)) {
+ /* life is easy */
+ }
+ else
+ if (tp->tp_fund == VOID) {
+ /* easy again */
+ (*expp)->ex_type = void_type;
+ }
+ else
+ if (is_arith_type(oldtp) && is_arith_type(tp)) {
+ int oldi = is_integral_type(oldtp);
+ int i = is_integral_type(tp);
+
+ if (oldi && i) {
+ if ( oper != CAST
+ && ( tp->tp_fund == ENUM
+ || oldtp->tp_fund == ENUM
+ )
+ ) {
+ expr_warning(*expp,
+ "dubious %s on enum",
+ symbol2str(oper));
+ }
+#ifdef LINT
+ if (oper == CAST)
+ (*expp)->ex_type = tp;
+ else
+ int2int(expp, tp);
+#else LINT
+ int2int(expp, tp);
+#endif LINT
+ }
+#ifndef NOFLOAT
+ else
+ if (oldi && !i) {
+ if (oldtp->tp_fund == ENUM && oper != CAST)
+ expr_warning(*expp,
+ "conversion of enum to %s\n",
+ symbol2str(tp->tp_fund));
+#ifdef LINT
+ if (oper == CAST)
+ (*expp)->ex_type = tp;
+ else
+ int2float(expp, tp);
+#else LINT
+ int2float(expp, tp);
+#endif LINT
+ }
+ else
+ if (!oldi && i) {
+#ifdef LINT
+ if (oper == CAST)
+ (*expp)->ex_type = tp;
+ else
+ float2int(expp, tp);
+#else LINT
+ float2int(expp, tp);
+#endif LINT
+ }
+ else {
+ /* !oldi && !i */
+#ifdef LINT
+ if (oper == CAST)
+ (*expp)->ex_type = tp;
+ else
+ float2float(expp, tp);
+#else LINT
+ float2float(expp, tp);
+#endif LINT
+ }
+#else NOFLOAT
+ else {
+ crash("(ch7cast) floats not implemented\n");
+ /*NOTREACHED*/
+ }
+#endif NOFLOAT
+ }
+ else
+ if (oldtp->tp_fund == POINTER && tp->tp_fund == POINTER) {
+ if (oper == CASTAB)
+ expr_warning(*expp, "incompatible pointers");
+ else
+ if (oper != CAST)
+ expr_warning(*expp, "incompatible pointers in %s",
+ symbol2str(oper));
+#ifdef LINT
+ if (oper != CAST)
+ lint_ptr_conv(oldtp->tp_up->tp_fund, tp->tp_up->tp_fund);
+#endif LINT
+ (*expp)->ex_type = tp; /* free conversion */
+ }
+ else
+ if (oldtp->tp_fund == POINTER && is_integral_type(tp)) {
+ /* from pointer to integral */
+ if (oper != CAST)
+ expr_warning(*expp,
+ "illegal conversion of pointer to %s",
+ symbol2str(tp->tp_fund));
+ if (oldtp->tp_size > tp->tp_size)
+ expr_warning(*expp,
+ "conversion of pointer to %s loses accuracy",
+ symbol2str(tp->tp_fund));
+ if (oldtp->tp_size != tp->tp_size)
+ int2int(expp, tp);
+ else
+ (*expp)->ex_type = tp;
+ }
+ else
+ if (tp->tp_fund == POINTER && is_integral_type(oldtp)) {
+ /* from integral to pointer */
+ switch (oper) {
+ case CAST:
+ break;
+ case CASTAB:
+ case EQUAL:
+ case NOTEQUAL:
+ case '=':
+ case RETURN:
+ if (is_cp_cst(*expp) && (*expp)->VL_VALUE == (arith)0)
+ break;
+ default:
+ expr_warning(*expp,
+ "illegal conversion of %s to pointer",
+ symbol2str(oldtp->tp_fund));
+ break;
+ }
+ if (oldtp->tp_size > tp->tp_size)
+ expr_warning(*expp,
+ "conversion of %s to pointer loses accuracy",
+ symbol2str(oldtp->tp_fund));
+ if (oldtp->tp_size != tp->tp_size)
+ int2int(expp, tp);
+ else
+ (*expp)->ex_type = tp;
+ }
+ else
+ if (oldtp->tp_fund == ERRONEOUS) {
+ /* we just won't look */
+ (*expp)->ex_type = tp; /* brute force */
+ }
+ else
+ if (oldtp->tp_size == tp->tp_size && oper == CAST) {
+ expr_warning(*expp, "dubious conversion based on equal size");
+ (*expp)->ex_type = tp; /* brute force */
+ }
+ else {
+ if (oldtp->tp_fund != ERRONEOUS && tp->tp_fund != ERRONEOUS)
+ expr_error(*expp, "cannot convert %s to %s",
+ symbol2str(oldtp->tp_fund),
+ symbol2str(tp->tp_fund)
+ );
+ (*expp)->ex_type = tp; /* brute force */
+ }
+}
+
+/* Determine whether two types are equal.
+*/
+equal_type(tp, otp)
+ register struct type *tp, *otp;
+{
+ if (tp == otp)
+ return 1;
+ if (!tp || !otp)
+ return 0;
+
+ if (tp->tp_fund != otp->tp_fund)
+ return 0;
+ if (tp->tp_unsigned != otp->tp_unsigned)
+ return 0;
+ if (tp->tp_align != otp->tp_align)
+ return 0;
+ if (tp->tp_fund != ARRAY)
+ if (tp->tp_size != otp->tp_size)
+ return 0;
+
+ switch (tp->tp_fund) {
+
+ case FUNCTION:
+ /* If both types have parameter type lists, the type of
+ each parameter in the composite parameter type list
+ is the composite type of the corresponding paramaters.
+ */
+ if (tp->tp_proto && otp->tp_proto &&
+ !equal_proto(tp->tp_proto, otp->tp_proto))
+ return 0;
+ return equal_type(tp->tp_up, otp->tp_up);
+
+ case ARRAY:
+ /* If one type is an array of known size, the composite
+ type is an array of that size
+ */
+ if (tp->tp_size != otp->tp_size &&
+ (tp->tp_size != -1 && otp->tp_size != -1))
+ return 0;
+ return equal_type(tp->tp_up, otp->tp_up);
+
+ case POINTER:
+ case FIELD:
+ return equal_type(tp->tp_up, otp->tp_up);
+
+ case STRUCT:
+ case UNION:
+ case ENUM:
+ return tp->tp_idf == otp->tp_idf && tp->tp_sdef == otp->tp_sdef;
+
+ default:
+ return 1;
+ }
+}
+
+equal_proto(pl, opl)
+ register struct proto *pl, *opl;
+{
+ if (pl == opl)
+ return 1;
+
+ /* If only one type is a function type with a parameter type list
+ (a function prototype), the composite type is a function
+ prototype with parameter type list.
+ */
+ if (pl == 0 || opl == 0) return 0;
+
+ if (pl->pl_flag != opl->pl_flag)
+ return 0;
+
+ if (!equal_type(pl->pl_type, opl->pl_type))
+ return 0;
+
+ return equal_proto(pl->next, opl->next);
+}
+
+ch7asgn(expp, oper, expr)
+ struct expr **expp;
+ struct expr *expr;
+{
+ /* The assignment operators.
+ "f op= e" should be interpreted as
+ "f = (typeof f)((typeof (f op e))f op (typeof (f op e))e)"
+ and not as "f = f op (typeof f)e".
+ Consider, for example, (i == 10) i *= 0.9; (i == 9), where
+ typeof i == int.
+ The resulting expression tree becomes:
+ op=
+ / \
+ / \
+ f (typeof (f op e))e
+ EVAL should however take care of evaluating (typeof (f op e))f
+ */
+ register struct expr *exp = *expp;
+ int fund = exp->ex_type->tp_fund;
+ int vol = 0;
+ struct type *tp;
+
+ /* We expect an lvalue */
+ if (!exp->ex_lvalue) {
+ expr_error(exp, "no lvalue in lhs of %s", symbol2str(oper));
+ exp->ex_depth = 99; /* no direct store/load at EVAL() */
+ /* what is 99 ??? DG */
+ }
+ if (exp->ex_flags & EX_READONLY)
+ strict("lhs of assignment is read-only");
+
+ /* Preserve volatile markers across the tree.
+ This is questionable, depending on the way the optimizer
+ wants this information.
+ vol = (exp->ex_flags & EX_VOLATILE) || (expr->ex_flags & EX_VOLATILE);
+ */
+
+ if (oper == '=') {
+ ch7cast(&expr, oper, exp->ex_type);
+ tp = expr->ex_type;
+ }
+ else { /* turn e into e' where typeof(e') = typeof (f op e) */
+ struct expr *extmp = intexpr((arith)0, INT);
+
+ /* this is really $#@&*%$# ! */
+ /* if you correct this, please correct lint_new_oper() too */
+ extmp->ex_lvalue = 1;
+ extmp->ex_type = exp->ex_type;
+ ch7bin(&extmp, oper, expr);
+ /* Note that ch7bin creates a tree of the expression
+ ((typeof (f op e))f op (typeof (f op e))e),
+ where f ~ extmp and e ~ expr.
+ We want to use (typeof (f op e))e.
+ Ch7bin does not create a tree if both operands
+ were illegal or constants!
+ */
+ tp = extmp->ex_type; /* perform the arithmetic in type tp */
+ if (extmp->ex_class == Oper) {
+ expr = extmp->OP_RIGHT;
+ extmp->OP_RIGHT = NILEXPR;
+ free_expression(extmp);
+ }
+ else
+ expr = extmp;
+ }
+#ifndef NOBITFIELD
+ if (fund == FIELD)
+ exp = new_oper(exp->ex_type->tp_up, exp, oper, expr);
+ else
+ exp = new_oper(exp->ex_type, exp, oper, expr);
+#else NOBITFIELD
+ exp = new_oper(exp->ex_type, exp, oper, expr);
+#endif NOBITFIELD
+ exp->OP_TYPE = tp; /* for EVAL() */
+ exp->ex_flags |= vol ? (EX_SIDEEFFECTS|EX_VOLATILE) : EX_SIDEEFFECTS;
+ *expp = exp;
+}
+
+/* Some interesting (?) questions answered.
+*/
+int
+is_integral_type(tp)
+ register struct type *tp;
+{
+ switch (tp->tp_fund) {
+ case GENERIC:
+ case CHAR:
+ case SHORT:
+ case INT:
+ case LONG:
+ case ENUM:
+ return 1;
+#ifndef NOBITFIELD
+ case FIELD:
+ return is_integral_type(tp->tp_up);
+#endif NOBITFIELD
+ default:
+ return 0;
+ }
+}
+
+int
+is_arith_type(tp)
+ register struct type *tp;
+{
+ switch (tp->tp_fund) {
+ case GENERIC:
+ case CHAR:
+ case SHORT:
+ case INT:
+ case LONG:
+ case ENUM:
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+#endif NOFLOAT
+ return 1;
+#ifndef NOBITFIELD
+ case FIELD:
+ return is_arith_type(tp->tp_up);
+#endif NOBITFIELD
+ default:
+ return 0;
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* SEMANTIC ANALYSIS (CHAPTER 7RM) -- BINARY OPERATORS */
+
+#include "botch_free.h"
+#include <alloc.h>
+#include "nofloat.h"
+#include "lint.h"
+#include "idf.h"
+#include "arith.h"
+#include "type.h"
+#include "struct.h"
+#include "label.h"
+#include "expr.h"
+#include "Lpars.h"
+#include "noRoption.h"
+
+extern char options[];
+extern char *symbol2str();
+
+/* This chapter asks for the repeated application of code to handle
+ an operation that may be executed at compile time or at run time,
+ depending on the constancy of the operands.
+*/
+
+#define commutative_binop(expp, oper, expr) mk_binop(expp, oper, expr, 1)
+#define non_commutative_binop(expp, oper, expr) mk_binop(expp, oper, expr, 0)
+
+ch7bin(expp, oper, expr)
+ register struct expr **expp;
+ struct expr *expr;
+{
+ /* apply binary operator oper between *expp and expr.
+ NB: don't swap operands if op is one of the op= operators!!!
+ */
+
+ any2opnd(expp, oper);
+ any2opnd(&expr, oper);
+ switch (oper) {
+ case '[': /* RM 7.1 */
+ /* RM 14.3 states that indexing follows the commutative laws */
+ switch ((*expp)->ex_type->tp_fund) {
+ case POINTER:
+ case ARRAY:
+ break;
+ case ERRONEOUS:
+ return;
+ default: /* unindexable */
+ switch (expr->ex_type->tp_fund) {
+ case POINTER:
+ case ARRAY:
+ break;
+ case ERRONEOUS:
+ return;
+ default:
+ expr_error(*expp,
+ "indexing an object of type %s",
+ symbol2str((*expp)->ex_type->tp_fund));
+ return;
+ }
+ break;
+ }
+ ch7bin(expp, '+', expr);
+ ch7mon('*', expp);
+ break;
+
+ case '(': /* RM 7.1 */
+ if ( (*expp)->ex_type->tp_fund == POINTER &&
+ (*expp)->ex_type->tp_up->tp_fund == FUNCTION
+ ) {
+#ifndef NOROPTION
+ if (options['R'])
+ warning("function pointer called");
+#endif NOROPTION
+ ch7mon('*', expp);
+ }
+ if ((*expp)->ex_type->tp_fund != FUNCTION) {
+ expr_error(*expp, "call of non-function (%s)",
+ symbol2str((*expp)->ex_type->tp_fund));
+ /* leave the expression; it may still serve */
+ free_expression(expr); /* there go the parameters */
+ }
+ else
+ *expp = new_oper((*expp)->ex_type->tp_up,
+ *expp, '(', expr);
+ (*expp)->ex_flags |= EX_SIDEEFFECTS;
+ break;
+
+ case PARCOMMA: /* RM 7.1 */
+ if ((*expp)->ex_type->tp_fund == FUNCTION)
+ function2pointer(*expp);
+ *expp = new_oper(expr->ex_type, *expp, PARCOMMA, expr);
+ break;
+
+ case '%':
+ case MODAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ opnd2integral(expp, oper);
+ opnd2integral(&expr, oper);
+ /* Fall through */
+ case '/':
+ case DIVAB:
+ case TIMESAB:
+ arithbalance(expp, oper, &expr);
+ non_commutative_binop(expp, oper, expr);
+ break;
+
+ case '&':
+ case '^':
+ case '|':
+ opnd2integral(expp, oper);
+ opnd2integral(&expr, oper);
+ /* Fall through */
+ case '*':
+ arithbalance(expp, oper, &expr);
+ commutative_binop(expp, oper, expr);
+ break;
+
+ case '+':
+ if (expr->ex_type->tp_fund == POINTER) { /* swap operands */
+ struct expr *etmp = expr;
+ expr = *expp;
+ *expp = etmp;
+ }
+ /*FALLTHROUGH*/
+ case PLUSAB:
+ case POSTINCR:
+ case PLUSPLUS:
+ if ((*expp)->ex_type->tp_fund == POINTER) {
+ pointer_arithmetic(expp, oper, &expr);
+ if (expr->ex_type->tp_size != (*expp)->ex_type->tp_size)
+ ch7cast(&expr, CAST, (*expp)->ex_type);
+ pointer_binary(expp, oper, expr);
+ }
+ else {
+ arithbalance(expp, oper, &expr);
+ if (oper == '+')
+ commutative_binop(expp, oper, expr);
+ else
+ non_commutative_binop(expp, oper, expr);
+ }
+ break;
+
+ case '-':
+ case MINAB:
+ case POSTDECR:
+ case MINMIN:
+ if ((*expp)->ex_type->tp_fund == POINTER) {
+ if (expr->ex_type->tp_fund == POINTER)
+ pntminuspnt(expp, oper, expr);
+ else {
+ pointer_arithmetic(expp, oper, &expr);
+ pointer_binary(expp, oper, expr);
+ }
+ }
+ else {
+ arithbalance(expp, oper, &expr);
+ non_commutative_binop(expp, oper, expr);
+ }
+ break;
+
+ case LEFT:
+ case RIGHT:
+ case LEFTAB:
+ case RIGHTAB:
+ opnd2integral(expp, oper);
+ opnd2integral(&expr, oper);
+ arithbalance(expp, oper, &expr); /* ch. 7.5 */
+ ch7cast(&expr, oper, int_type); /* cvt. rightop to int */
+ non_commutative_binop(expp, oper, expr);
+ break;
+
+ case '<':
+ case '>':
+ case LESSEQ:
+ case GREATEREQ:
+ case EQUAL:
+ case NOTEQUAL:
+ relbalance(expp, oper, &expr);
+ non_commutative_binop(expp, oper, expr);
+ (*expp)->ex_type = int_type;
+ break;
+
+ case AND:
+ case OR:
+ opnd2test(expp, oper);
+ opnd2test(&expr, oper);
+ if (is_cp_cst(*expp)) {
+ register struct expr *ex = *expp;
+
+ /* the following condition is a short-hand for
+ ((oper == AND) && o1) || ((oper == OR) && !o1)
+ where o1 == (*expp)->VL_VALUE;
+ and ((oper == AND) || (oper == OR))
+ */
+ if ((oper == AND) == (ex->VL_VALUE != (arith)0))
+ *expp = expr;
+ else {
+ ex->ex_flags |= expr->ex_flags;
+ free_expression(expr);
+ *expp = intexpr((arith)((oper == AND) ? 0 : 1),
+ INT);
+ }
+ (*expp)->ex_flags |= ex->ex_flags;
+ free_expression(ex);
+ }
+ else
+ if (is_cp_cst(expr)) {
+ /* Note!!!: the following condition is a short-hand for
+ ((oper == AND) && o2) || ((oper == OR) && !o2)
+ where o2 == expr->VL_VALUE
+ and ((oper == AND) || (oper == OR))
+ */
+ if ((oper == AND) == (expr->VL_VALUE != (arith)0)) {
+ (*expp)->ex_flags |= expr->ex_flags;
+ free_expression(expr);
+ }
+ else {
+ if (oper == OR)
+ expr->VL_VALUE = (arith)1;
+ ch7bin(expp, ',', expr);
+ }
+ }
+ else
+ *expp = new_oper(int_type, *expp, oper, expr);
+ (*expp)->ex_flags |= EX_LOGICAL;
+ break;
+
+ case ':':
+ if ( is_struct_or_union((*expp)->ex_type->tp_fund)
+ || is_struct_or_union(expr->ex_type->tp_fund)
+ ) {
+ if (!equal_type((*expp)->ex_type, expr->ex_type))
+ expr_error(*expp, "illegal balance");
+ }
+ else
+ relbalance(expp, oper, &expr);
+#ifdef LINT
+ if ( (is_cp_cst(*expp) && is_cp_cst(expr))
+ && (*expp)->VL_VALUE == expr->VL_VALUE
+ ) {
+ hwarning("operands of : are constant and equal");
+ }
+#endif LINT
+ *expp = new_oper((*expp)->ex_type, *expp, oper, expr);
+ break;
+
+ case '?':
+ opnd2logical(expp, oper);
+ if (is_cp_cst(*expp)) {
+#ifdef LINT
+ hwarning("condition in ?: expression is constant");
+#endif LINT
+ *expp = (*expp)->VL_VALUE ?
+ expr->OP_LEFT : expr->OP_RIGHT;
+ }
+ else {
+ *expp = new_oper(expr->ex_type, *expp, oper, expr);
+ }
+ break;
+
+ case ',':
+ if (is_cp_cst(*expp))
+ *expp = expr;
+ else
+ *expp = new_oper(expr->ex_type, *expp, oper, expr);
+ (*expp)->ex_flags |= EX_COMMA;
+ break;
+ }
+}
+
+pntminuspnt(expp, oper, expr)
+ register struct expr **expp, *expr;
+{
+ /* Subtracting two pointers is so complicated it merits a
+ routine of its own.
+ */
+ struct type *up_type = (*expp)->ex_type->tp_up;
+
+ if (!equal_type(up_type, expr->ex_type->tp_up)) {
+ expr_error(*expp, "subtracting incompatible pointers");
+ free_expression(expr);
+ erroneous2int(expp);
+ return;
+ }
+ /* we hope the optimizer will eliminate the load-time
+ pointer subtraction
+ */
+ *expp = new_oper((*expp)->ex_type, *expp, oper, expr);
+ ch7cast(expp, CAST, pa_type); /* ptr-ptr: result has pa_type */
+ ch7bin(expp, '/',
+ intexpr(size_of_type(up_type, "object"), pa_type->tp_fund));
+ ch7cast(expp, CAST, int_type); /* result will be an integer expr */
+}
+
+mk_binop(expp, oper, expr, commutative)
+ struct expr **expp;
+ register struct expr *expr;
+{
+ /* Constructs in *expp the operation indicated by the operands.
+ "commutative" indicates whether "oper" is a commutative
+ operator.
+ */
+ register struct expr *ex = *expp;
+
+ if (is_cp_cst(expr) && is_cp_cst(ex))
+ cstbin(expp, oper, expr);
+ else {
+ *expp = (commutative && expr->ex_depth >= ex->ex_depth) ?
+ new_oper(ex->ex_type, expr, oper, ex) :
+ new_oper(ex->ex_type, ex, oper, expr);
+ }
+}
+
+pointer_arithmetic(expp1, oper, expp2)
+ register struct expr **expp1, **expp2;
+{
+ /* prepares the integral expression expp2 in order to
+ apply it to the pointer expression expp1
+ */
+#ifndef NOFLOAT
+ if (any2arith(expp2, oper) == DOUBLE) {
+ expr_error(*expp2,
+ "illegal combination of float and pointer");
+ erroneous2int(expp2);
+ }
+#endif NOFLOAT
+ ch7bin( expp2, '*',
+ intexpr(size_of_type((*expp1)->ex_type->tp_up, "object"),
+ pa_type->tp_fund)
+ );
+}
+
+pointer_binary(expp, oper, expr)
+ register struct expr **expp, *expr;
+{
+ /* constructs the pointer arithmetic expression out of
+ a pointer expression, a binary operator and an integral
+ expression.
+ */
+ if (is_ld_cst(expr) && is_ld_cst(*expp))
+ cstbin(expp, oper, expr);
+ else
+ *expp = new_oper((*expp)->ex_type, *expp, oper, expr);
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* SEMANTIC ANALYSIS (CHAPTER 7RM) -- MONADIC OPERATORS */
+
+#include "botch_free.h"
+#include <alloc.h>
+#include "nofloat.h"
+#include "nobitfield.h"
+#include "Lpars.h"
+#include "arith.h"
+#include "type.h"
+#include "label.h"
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+
+extern char options[];
+extern long full_mask[/*MAXSIZE*/]; /* cstoper.c */
+char *symbol2str();
+
+ch7mon(oper, expp)
+ register struct expr **expp;
+{
+ /* The monadic prefix operator oper is applied to *expp.
+ */
+ register struct expr *expr;
+
+ switch (oper) {
+ case '*': /* RM 7.2 */
+ /* no FIELD type allowed */
+ if ((*expp)->ex_type->tp_fund == ARRAY)
+ array2pointer(*expp);
+ if ((*expp)->ex_type->tp_fund != POINTER) {
+ expr_error(*expp,
+ "* applied to non-pointer (%s)",
+ symbol2str((*expp)->ex_type->tp_fund));
+ }
+ else {
+ expr = *expp;
+ if (expr->ex_lvalue == 0 && expr->ex_class != String)
+ /* dereference in administration only */
+ expr->ex_type = expr->ex_type->tp_up;
+ else /* runtime code */
+ *expp = new_oper(expr->ex_type->tp_up, NILEXPR,
+ '*', expr);
+ (*expp)->ex_lvalue = (
+ (*expp)->ex_type->tp_fund != ARRAY &&
+ (*expp)->ex_type->tp_fund != FUNCTION
+ );
+ if ((*expp)->ex_type->tp_typequal & TQ_CONST)
+ (*expp)->ex_flags |= EX_READONLY;
+ if ((*expp)->ex_type->tp_typequal & TQ_VOLATILE)
+ (*expp)->ex_flags |= EX_VOLATILE;
+ }
+ break;
+ case '&':
+ if ((*expp)->ex_type->tp_fund == ARRAY) {
+ warning("& before array ignored");
+ array2pointer(*expp);
+ }
+ else
+ if ((*expp)->ex_type->tp_fund == FUNCTION) {
+ warning("& before function ignored");
+ function2pointer(*expp);
+ }
+ else
+#ifndef NOBITFIELD
+ if ((*expp)->ex_type->tp_fund == FIELD)
+ expr_error(*expp, "& applied to field variable");
+ else
+#endif NOBITFIELD
+ if (!(*expp)->ex_lvalue)
+ expr_error(*expp, "& applied to non-lvalue");
+ else {
+ /* assume that enums are already filtered out */
+ if (ISNAME(*expp)) {
+ register struct def *def =
+ (*expp)->VL_IDF->id_def;
+
+ /* &<var> indicates that <var>
+ cannot be used as register
+ anymore
+ */
+ if (def->df_sc == REGISTER) {
+ expr_error(*expp,
+ "& on register variable not allowed");
+ break; /* break case '&' */
+ }
+ }
+ (*expp)->ex_type = pointer_to((*expp)->ex_type);
+ (*expp)->ex_lvalue = 0;
+ (*expp)->ex_flags &= ~EX_READONLY;
+ }
+ break;
+ case '~':
+#ifndef NOFLOAT
+ {
+ int fund = (*expp)->ex_type->tp_fund;
+
+ if (fund == FLOAT || fund == DOUBLE) {
+ expr_error(
+ *expp,
+ "~ not allowed on %s operands",
+ symbol2str(fund)
+ );
+ erroneous2int(expp);
+ break;
+ }
+ /* FALLTHROUGH */
+ }
+#endif NOFLOAT
+ case '-':
+ any2arith(expp, oper);
+ if (is_cp_cst(*expp)) {
+ arith o1 = (*expp)->VL_VALUE;
+
+ (*expp)->VL_VALUE = (oper == '-') ? -o1 :
+ ((*expp)->ex_type->tp_unsigned ?
+ (~o1) & full_mask[(*expp)->ex_type->tp_size] :
+ ~o1
+ );
+ }
+ else
+#ifndef NOFLOAT
+ if (is_fp_cst(*expp))
+ switch_sign_fp(*expp);
+ else
+#endif NOFLOAT
+ *expp = new_oper((*expp)->ex_type,
+ NILEXPR, oper, *expp);
+ break;
+ case '!':
+ if ((*expp)->ex_type->tp_fund == FUNCTION)
+ function2pointer(*expp);
+ if ((*expp)->ex_type->tp_fund != POINTER)
+ any2arith(expp, oper);
+ opnd2test(expp, '!');
+ if (is_cp_cst(*expp)) {
+ (*expp)->VL_VALUE = !((*expp)->VL_VALUE);
+ (*expp)->ex_type = int_type; /* a cast ???(EB) */
+ }
+ else
+ *expp = new_oper(int_type, NILEXPR, oper, *expp);
+ (*expp)->ex_flags |= EX_LOGICAL;
+ break;
+ case PLUSPLUS:
+ case MINMIN:
+ ch7incr(expp, oper);
+ break;
+ case SIZEOF:
+ if (ISNAME(*expp) && (*expp)->VL_IDF->id_def->df_formal_array)
+ warning("sizeof formal array %s is sizeof pointer!",
+ (*expp)->VL_IDF->id_text);
+ expr = intexpr((*expp)->ex_class == String ?
+ (arith)((*expp)->SG_LEN) :
+ size_of_type((*expp)->ex_type, "object"),
+ INT);
+ expr->ex_flags |= EX_SIZEOF;
+ free_expression(*expp);
+ *expp = expr;
+ break;
+ }
+}
--- /dev/null
+%
+% CHARACTER CLASSES
+%
+% some general settings:
+%S129
+%F %s,
+%
+% START OF TOKEN
+%
+%iSTGARB
+STSKIP:\r \t\013\f
+STNL:\n
+STCOMP:-!&+<=>|
+STSIMP:%()*,/:;?[]^{}~
+STCHAR:'
+STIDF:a-zA-KM-Z_
+STELL:L
+STNUM:.0-9
+STSTR:"
+STEOI:\200
+%T/* character classes */
+%T#include "class.h"
+%Tchar tkclass[] = {
+%p
+%T};
+%
+% INIDF
+%
+%C
+1:a-zA-Z_0-9
+%Tchar inidf[] = {
+%F %s,
+%p
+%T};
+%
+% ISDIG
+%
+%C
+1:0-9
+%Tchar isdig[] = {
+%p
+%T};
+%
+% ISHEX
+%
+%C
+1:a-fA-F
+%Tchar ishex[] = {
+%p
+%T};
+%
+% ISOCT
+%
+%C
+1:0-7
+%Tchar isoct[] = {
+%p
+%T};
+%
+% ISSUF
+%
+%C
+1:lLuU
+%Tchar issuf[] = {
+%p
+%T};
+%
+% ISWSP
+%
+%C
+1: \t\n
+%Tchar iswsp[] = {
+%p
+%T};
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* U S E O F C H A R A C T E R C L A S S E S */
+
+/* As a starter, chars are divided into classes, according to which
+ token they can be the start of.
+ At present such a class number is supposed to fit in 4 bits.
+*/
+
+#define class(ch) (tkclass[ch])
+
+/* Being the start of a token is, fortunately, a mutual exclusive
+ property, so, although there are less than 16 classes they can be
+ packed in 4 bits.
+*/
+
+#define STSKIP 0 /* spaces and so on: skipped characters */
+#define STNL 1 /* newline character(s): update linenumber etc. */
+#define STGARB 2 /* garbage ascii character: not allowed in C */
+#define STSIMP 3 /* this character can occur as token in C */
+#define STCOMP 4 /* this one can start a compound token in C */
+#define STELL 5 /* possible start of wide char stuff or idf */
+#define STIDF 6 /* being the initial character of an identifier */
+#define STCHAR 7 /* the starter of a character constant */
+#define STSTR 8 /* the starter of a string */
+#define STNUM 9 /* the starter of a numeric constant */
+#define STEOI 10 /* End-Of-Information mark */
+
+/* But occurring inside a token is not, so we need 1 bit for each
+ class. This is implemented as a collection of tables to speed up
+ the decision whether a character has a special meaning.
+*/
+#define in_idf(ch) (inidf[ch])
+#define is_oct(ch) (isoct[ch])
+#define is_dig(ch) (isdig[ch])
+#define is_hex(ch) (ishex[ch])
+#define is_suf(ch) (issuf[ch])
+#define is_wsp(ch) (iswsp[ch])
+
+extern char tkclass[];
+extern char inidf[], isoct[], isdig[], ishex[], issuf[], iswsp[];
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* C O D E - G E N E R A T I N G R O U T I N E S */
+
+#include "lint.h"
+#include <em.h>
+#include "botch_free.h"
+#include <alloc.h>
+#include "dataflow.h"
+#include "use_tmp.h"
+#include "arith.h"
+#include "type.h"
+#include "idf.h"
+#include "label.h"
+#include "code.h"
+#include "stmt.h"
+#include "def.h"
+#include "expr.h"
+#include "sizes.h"
+#include "stack.h"
+#include "level.h"
+#include "decspecs.h"
+#include "declar.h"
+#include "Lpars.h"
+#include "specials.h"
+#include "atw.h"
+#include "assert.h"
+#include "noRoption.h"
+#include "file_info.h"
+#ifdef LINT
+#include "l_lint.h"
+#endif LINT
+
+label lab_count = 1;
+label datlab_count = 1;
+
+#ifndef NOFLOAT
+int fp_used;
+#endif NOFLOAT
+
+/* global function info */
+char *func_name;
+struct type *func_type;
+int func_notypegiven;
+
+#ifdef USE_TMP
+static int tmp_id;
+static int pro_id;
+#endif USE_TMP
+
+extern char options[];
+extern char *symbol2str();
+
+#ifndef LINT
+init_code(dst_file)
+ char *dst_file;
+{
+ /* init_code() initialises the output file on which the
+ compact EM code is written
+ */
+ C_init(word_size, pointer_size); /* initialise EM module */
+ if (C_open(dst_file) == 0)
+ fatal("cannot write to %s\n", dst_file);
+ C_magic();
+ C_ms_emx(word_size, pointer_size);
+#ifdef USE_TMP
+#ifdef PREPEND_SCOPES
+ C_insertpart(tmp_id = C_getid());
+#endif USE_TMP
+#endif PREPEND_SCOPES
+}
+#endif LINT
+
+struct string_cst *str_list = 0;
+
+code_string(val, len, dlb)
+ char *val;
+ int len;
+ label dlb;
+{
+ register struct string_cst *sc = new_string_cst();
+
+ C_ina_dlb(dlb);
+ sc->next = str_list;
+ str_list = sc;
+ sc->sc_value = val;
+ sc->sc_len = len;
+ sc->sc_dlb = dlb;
+}
+
+def_strings(sc)
+ register struct string_cst *sc;
+{
+ while (sc) {
+ struct string_cst *sc1 = sc;
+
+ C_df_dlb(sc->sc_dlb);
+ str_cst(sc->sc_value, sc->sc_len);
+ sc = sc->next;
+ free_string_cst(sc1);
+ }
+}
+
+end_code()
+{
+ /* end_code() performs the actions to be taken when closing
+ the output stream.
+ */
+#ifndef NOFLOAT
+ if (fp_used) {
+ /* floating point used */
+ C_ms_flt();
+ }
+#endif NOFLOAT
+ def_strings(str_list);
+ str_list = 0;
+ C_ms_src((int)(LineNumber - 2), FileName);
+ C_close();
+}
+
+#ifdef PREPEND_SCOPES
+prepend_scopes()
+{
+ /* prepend_scopes() runs down the list of global idf's
+ and generates those exa's, exp's, ina's and inp's
+ that superior hindsight has provided.
+ */
+ register struct stack_entry *se = local_level->sl_entry;
+
+#ifdef USE_TMP
+ C_beginpart(tmp_id);
+#endif USE_TMP
+ while (se != 0) {
+ register struct idf *id = se->se_idf;
+ register struct def *df = id->id_def;
+
+ if (df && (df->df_initialized || df->df_used || df->df_alloc))
+ code_scope(id->id_text, df);
+ se = se->next;
+ }
+#ifdef USE_TMP
+ C_endpart(tmp_id);
+#endif USE_TMP
+}
+#endif PREPEND_SCOPES
+
+code_scope(text, def)
+ char *text;
+ register struct def *def;
+{
+ /* generates code for one name, text, of the storage class
+ as given by def, if meaningful.
+ */
+ int fund = def->df_type->tp_fund;
+
+ switch (def->df_sc) {
+ case EXTERN:
+ case GLOBAL:
+ case IMPLICIT:
+ if (fund == FUNCTION)
+ C_exp(text);
+ else
+ C_exa_dnam(text);
+ break;
+ case STATIC:
+ if (fund == FUNCTION)
+ C_inp(text);
+ else
+ C_ina_dnam(text);
+ break;
+ }
+}
+
+static label return_label, return2_label;
+static char return_expr_occurred;
+static arith func_size;
+static label func_res_label;
+static char *last_fn_given = "";
+static label file_name_label;
+
+begin_proc(ds, idf) /* to be called when entering a procedure */
+ struct decspecs *ds;
+ struct idf *idf;
+{
+ /* begin_proc() is called at the entrance of a new function
+ and performs the necessary code generation:
+ - a scope indicator (if needed) exp/inp
+ - the procedure entry pro $name
+ - reserves some space if the result of the function
+ does not fit in the return area
+ - a fil pseudo instruction
+ */
+ register char *name = idf->id_text;
+ register struct def *def = idf->id_def;
+
+#ifndef PREPEND_SCOPES
+ code_scope(name, def);
+#endif PREPEND_SCOPES
+#ifdef DATAFLOW
+ if (options['d'])
+ DfaStartFunction(name);
+#endif DATAFLOW
+
+ /* set global function info */
+ func_name = name;
+ if (def->df_type->tp_fund != FUNCTION) {
+ error("making function body for non-function");
+ func_type = error_type;
+ }
+ else {
+ func_type = def->df_type->tp_up;
+ }
+ func_notypegiven = ds->ds_notypegiven;
+ func_size = ATW(func_type->tp_size);
+
+#ifndef USE_TMP
+ C_pro_narg(name);
+#else
+ C_insertpart(pro_id = C_getid());
+#endif
+ if (is_struct_or_union(func_type->tp_fund)) {
+ C_df_dlb(func_res_label = data_label());
+ C_bss_cst(func_size, (arith)0, 1);
+ }
+ else
+ func_res_label = 0;
+ /* Special arrangements if the function result doesn't fit in
+ the function return area of the EM machine. The size of
+ the function return area is implementation dependent.
+ */
+ lab_count = (label) 1;
+ return_label = text_label();
+ return2_label = text_label();
+ return_expr_occurred = 0;
+ LocalInit();
+ prc_entry(name);
+ if (! options['L']) { /* profiling */
+ if (strcmp(last_fn_given, FileName) != 0) {
+ /* previous function came from other file */
+ C_df_dlb(file_name_label = data_label());
+ C_con_scon(last_fn_given = FileName,
+ (arith)(strlen(FileName) + 1));
+ }
+ /* enable debug trace of EM source */
+ C_fil_dlb(file_name_label, (arith)0);
+ C_lin((arith)LineNumber);
+ }
+}
+
+end_proc(fbytes)
+ arith fbytes;
+{
+ /* end_proc() deals with the code to be generated at the end of
+ a function, as there is:
+ - the EM ret instruction: "ret 0"
+ - loading of the function result in the function
+ result area if there has been a return <expr>
+ in the function body (see do_return_expr())
+ - indication of the use of floating points
+ - indication of the number of bytes used for
+ formal parameters
+ - use of special identifiers such as "setjmp"
+ - "end" + number of bytes used for local variables
+ */
+ arith nbytes;
+ char optionsn = options['n'];
+
+#ifdef DATAFLOW
+ if (options['d'])
+ DfaEndFunction();
+#endif DATAFLOW
+ C_df_ilb(return2_label);
+ if (return_expr_occurred) C_asp(-func_size);
+ C_df_ilb(return_label);
+ prc_exit();
+#ifndef LINT
+ if (return_expr_occurred) {
+ if (func_res_label != 0) {
+ C_lae_dlb(func_res_label, (arith)0);
+ store_block(func_size, func_type->tp_align);
+ C_lae_dlb(func_res_label, (arith)0);
+ C_ret(pointer_size);
+ }
+ else
+ C_ret(func_size);
+ }
+ else C_ret((arith) 0);
+#endif LINT
+
+ /* getting the number of "local" bytes is posponed until here,
+ because copying the function result in "func_res_label" may
+ need temporaries! However, local_level is now L_FORMAL2, because
+ L_LOCAL is already unstacked. Therefore, "unstack_level" must
+ also pass "sl_max_block" to the level above L_LOCAL.
+ */
+ nbytes = ATW(- local_level->sl_max_block);
+#ifdef USE_TMP
+ C_beginpart(pro_id);
+ C_pro(func_name, nbytes);
+#endif
+ if (fbytes > max_int) {
+ error("%s has more than %ld parameter bytes",
+ func_name, (long) max_int);
+ }
+ C_ms_par(fbytes); /* # bytes for formals */
+ if (sp_occurred[SP_SETJMP]) { /* indicate use of "setjmp" */
+ options['n'] = 1;
+ C_ms_gto();
+ sp_occurred[SP_SETJMP] = 0;
+ }
+#ifdef USE_TMP
+ C_endpart(pro_id);
+#endif
+ LocalFinish();
+ C_end(nbytes);
+ if (nbytes > max_int) {
+ error("%s has more than %ld bytes of local variables",
+ func_name, (long) max_int);
+ }
+ options['n'] = optionsn;
+}
+
+do_return()
+{
+ /* do_return handles the case of a return without expression.
+ This version branches to the return label, which is
+ probably smarter than generating a direct return.
+ Return sequences may be expensive.
+ */
+ C_bra(return2_label);
+}
+
+do_return_expr(expr)
+ struct expr *expr;
+{
+ /* do_return_expr() generates the expression and the jump for
+ a return statement with an expression.
+ */
+ ch7cast(&expr, RETURN, func_type);
+ code_expr(expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
+ C_bra(return_label);
+ return_expr_occurred = 1;
+}
+
+code_declaration(idf, expr, lvl, sc)
+ register struct idf *idf; /* idf to be declared */
+ struct expr *expr; /* initialisation; NULL if absent */
+ int lvl; /* declaration level */
+ int sc; /* storage class, as in the declaration */
+{
+ /* code_declaration() does the actual declaration of the
+ variable indicated by "idf" on declaration level "lvl".
+ If the variable is initialised, the expression is given
+ in "expr", but for global and static initialisations it
+ is just non-zero, as the expression is not parsed yet.
+ There are some cases to be considered:
+ - filter out typedefs, they don't correspond to code;
+ - global variables, coded only if initialized;
+ - local static variables;
+ - local automatic variables;
+ Since the expression may be modified in the process,
+ code_declaration() frees it after use, as the caller can
+ no longer do so.
+
+ If there is a storage class indication (EXTERN/STATIC),
+ code_declaration() will generate an exa or ina.
+ The sc is the actual storage class, as given in the
+ declaration. This is to allow:
+ extern int a;
+ int a = 5;
+ while at the same time forbidding
+ extern int a = 5;
+ */
+ register struct def *def = idf->id_def;
+ register arith size = def->df_type->tp_size;
+ int def_sc = def->df_sc;
+
+ if (def_sc == TYPEDEF) /* no code for typedefs */
+ return;
+ if (sc == EXTERN && expr && !is_anon_idf(idf))
+ error("%s is extern; cannot initialize", idf->id_text);
+#ifndef PREPEND_SCOPES
+ if (def->df_type->tp_fund == FUNCTION) {
+ code_scope(idf->id_text, def);
+ }
+#endif PREPEND_SCOPES
+ if (lvl == L_GLOBAL) { /* global variable */
+ /* is this an allocating declaration? */
+ if ( (sc == 0 || sc == STATIC)
+ && def->df_type->tp_fund != FUNCTION
+ && size >= 0
+ )
+ def->df_alloc = ALLOC_SEEN;
+ if (expr) { /* code only if initialized */
+#ifndef PREPEND_SCOPES
+ code_scope(idf->id_text, def);
+#endif PREPEND_SCOPES
+ def->df_alloc = ALLOC_DONE;
+ C_df_dnam(idf->id_text);
+ }
+ }
+ else
+ if (lvl >= L_LOCAL) { /* local variable */
+ /* STATIC, EXTERN, GLOBAL, IMPLICIT, AUTO or REGISTER */
+ switch (def_sc) {
+ case STATIC:
+ if (def->df_type->tp_fund == FUNCTION) {
+ /* should produce "inp $function" ??? */
+ break;
+ }
+ /* they are handled on the spot and get an
+ integer label in EM.
+ */
+ C_df_dlb((label)def->df_address);
+ if (expr) { /* there is an initialisation */
+ }
+ else { /* produce blank space */
+ if (size <= 0) {
+ error("size of %s unknown", idf->id_text);
+ size = (arith)0;
+ }
+ C_bss_cst(ATW(size), (arith)0, 1);
+ }
+ break;
+ case EXTERN:
+ case GLOBAL:
+ case IMPLICIT:
+ /* we are sure there is no expression */
+#ifndef PREPEND_SCOPES
+ code_scope(idf->id_text, def);
+#endif PREPEND_SCOPES
+ break;
+ case AUTO:
+ case REGISTER:
+ if (expr)
+ loc_init(expr, idf);
+ break;
+ default:
+ crash("bad local storage class");
+ /*NOTREACHED*/
+ }
+ }
+}
+
+loc_init(expr, id)
+ struct expr *expr;
+ register struct idf *id;
+{
+ /* loc_init() generates code for the assignment of
+ expression expr to the local variable described by id.
+ It frees the expression afterwards.
+ */
+ register struct expr *e = expr;
+ register struct type *tp = id->id_def->df_type;
+
+ ASSERT(id->id_def->df_sc != STATIC);
+ switch (tp->tp_fund) {
+ case ARRAY:
+ case STRUCT:
+ case UNION:
+ error("automatic %s cannot be initialized in declaration",
+ symbol2str(tp->tp_fund));
+ free_expression(e);
+ return;
+ }
+ if (ISCOMMA(e)) { /* embraced: int i = {12}; */
+#ifndef NOROPTION
+ if (options['R']) {
+ if (ISCOMMA(e->OP_LEFT)) /* int i = {{1}} */
+ expr_error(e, "extra braces not allowed");
+ else
+ if (e->OP_RIGHT != 0) /* int i = {1 , 2} */
+ expr_error(e, "too many initializers");
+ }
+#endif NOROPTION
+ while (e) {
+ loc_init(e->OP_LEFT, id);
+ e = e->OP_RIGHT;
+ }
+ }
+ else { /* not embraced */
+ ch7cast(&expr, '=', tp); /* may modify expr */
+#ifndef LINT
+ {
+ struct value vl;
+
+ EVAL(expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
+ vl.vl_class = Name;
+ vl.vl_data.vl_idf = id;
+ vl.vl_value = (arith)0;
+ store_val(&vl, tp);
+ }
+#else LINT
+ id->id_def->df_set = 1;
+#endif LINT
+ free_expression(expr);
+ }
+}
+
+bss(idf)
+ register struct idf *idf;
+{
+ /* bss() allocates bss space for the global idf.
+ */
+ arith size = idf->id_def->df_type->tp_size;
+
+#ifndef PREPEND_SCOPES
+ code_scope(idf->id_text, idf->id_def);
+#endif PREPEND_SCOPES
+ /* Since bss() is only called if df_alloc is non-zero, and
+ since df_alloc is only non-zero if size >= 0, we have:
+ */
+ /* but we already gave a warning at the declaration of the
+ array. Besides, the message given here does not apply to
+ voids
+
+ if (options['R'] && size == 0)
+ warning("actual array of size 0");
+ */
+ C_df_dnam(idf->id_text);
+ C_bss_cst(ATW(size), (arith)0, 1);
+}
+
+formal_cvt(df)
+ register struct def *df;
+{
+ /* formal_cvt() converts a formal parameter of type char or
+ short from int to that type.
+ */
+ register struct type *tp = df->df_type;
+
+ if (tp->tp_size != int_size &&
+ (tp->tp_fund == CHAR || tp->tp_fund == SHORT)
+ ) {
+ LoadLocal(df->df_address, int_size);
+ /* conversion(int_type, df->df_type); ???
+ No, you can't do this on the stack! (CJ)
+ */
+ StoreLocal(df->df_address, tp->tp_size);
+ }
+}
+
+#ifdef LINT
+/*ARGSUSED*/
+#endif LINT
+code_expr(expr, val, code, tlbl, flbl)
+ struct expr *expr;
+ label tlbl, flbl;
+{
+ /* code_expr() is the parser's interface to the expression code
+ generator. If line number trace is wanted, it generates a
+ lin instruction. EVAL() is called directly.
+ */
+#ifndef LINT
+ if (! options['L']) /* profiling */
+ C_lin((arith)(expr->ex_line));
+
+ /* HERE WE SHOULD GENERATE A MESSAGE:
+ if (expr->ex_flags & EX_VOLATILE)
+ HANDS_OFF
+ */
+ EVAL(expr, val, code, tlbl, flbl);
+#else LINT
+ lint_expr(expr, code ? USED : IGNORED);
+#endif LINT
+}
+
+/* The FOR/WHILE/DO/SWITCH stacking mechanism:
+ stack_stmt() has to be called at the entrance of a
+ for, while, do or switch statement to indicate the
+ EM labels where a subsequent break or continue causes
+ the program to jump to.
+*/
+static struct stmt_block *stmt_stack; /* top of statement stack */
+
+/* code_break() generates EM code needed at the occurrence of "break":
+ it generates a branch instruction to the break label of the
+ innermost statement in which break has a meaning.
+ As "break" is legal in any of 'while', 'do', 'for' or 'switch',
+ which are the only ones that are stacked, only the top of
+ the stack is interesting.
+*/
+code_break()
+{
+ register struct stmt_block *stmt_block = stmt_stack;
+
+ if (stmt_block)
+ C_bra(stmt_block->st_break);
+ else
+ error("break not inside for, while, do or switch");
+}
+
+/* code_continue() generates EM code needed at the occurrence of
+ "continue":
+ it generates a branch instruction to the continue label of the
+ innermost statement in which continue has a meaning.
+*/
+code_continue()
+{
+ register struct stmt_block *stmt_block = stmt_stack;
+
+ while (stmt_block) {
+ if (stmt_block->st_continue) {
+ C_bra(stmt_block->st_continue);
+ return;
+ }
+ stmt_block = stmt_block->next;
+ }
+ error("continue not inside for, while or do");
+}
+
+stack_stmt(break_label, cont_label)
+ label break_label, cont_label;
+{
+ register struct stmt_block *stmt_block = new_stmt_block();
+
+ stmt_block->next = stmt_stack;
+ stmt_block->st_break = break_label;
+ stmt_block->st_continue = cont_label;
+ stmt_stack = stmt_block;
+}
+
+unstack_stmt()
+{
+ /* unstack_stmt() unstacks the data of a statement
+ which may contain break or continue
+ */
+ register struct stmt_block *sbp = stmt_stack;
+ stmt_stack = sbp->next;
+ free_stmt_block(sbp);
+}
+
+static label prc_name;
+
+prc_entry(name)
+ char *name;
+{
+ if (options['p']) {
+ C_df_dlb(prc_name = data_label());
+ C_rom_scon(name, (arith) (strlen(name) + 1));
+ C_lae_dlb(prc_name, (arith) 0);
+ C_cal("procentry");
+ C_asp(pointer_size);
+ }
+}
+
+prc_exit()
+{
+ if (options['p']) {
+ C_lae_dlb(prc_name, (arith) 0);
+ C_cal("procexit");
+ C_asp(pointer_size);
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* C O D E - G E N E R A T O R D E F I N I T I O N S */
+
+struct string_cst { /* storing string constants */
+ struct string_cst *next;
+ char *sc_value;
+ int sc_len;
+ label sc_dlb;
+};
+
+extern struct string_cst *str_list;
+
+/* ALLOCDEF "string_cst" 10 */
+
+#define LVAL 0
+#define RVAL 1
+#define FALSE 0
+#define TRUE 1
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* C O N V E R S I O N - C O D E G E N E R A T O R */
+
+#include "lint.h"
+#ifndef LINT
+
+#include "nofloat.h"
+#include <em.h>
+#include "arith.h"
+#include "type.h"
+#include "sizes.h"
+#include "Lpars.h"
+
+#define T_SIGNED 1
+#define T_UNSIGNED 2
+#ifndef NOFLOAT
+#define T_FLOATING 3
+#endif NOFLOAT
+
+/* conversion() generates the EM code for a conversion between
+ the types char, short, int, long, float, double and pointer.
+ There are three conversion types: signed, unsigned and floating.
+ The EM code to obtain this conversion looks like:
+ LOC sizeof(from_type)
+ LOC sizeof(to_type)
+ C??
+*/
+
+static int convtype();
+
+conversion(from_type, to_type)
+ register struct type *from_type, *to_type;
+{
+ register arith from_size = from_type->tp_size;
+ register arith to_size = to_type->tp_size;
+ int from_cnvtype = convtype(from_type);
+ int to_cnvtype = convtype(to_type);
+
+ if ((int)to_size < (int)word_size) to_size = word_size;
+ if ((int)from_size == (int)to_size && from_cnvtype == to_cnvtype)
+ return;
+ switch (from_cnvtype) {
+ case T_SIGNED:
+ switch (to_cnvtype) {
+ case T_SIGNED:
+ C_loc(from_size);
+ C_loc(to_size);
+ C_cii();
+ break;
+ case T_UNSIGNED:
+#ifndef NOFLOAT
+ case T_FLOATING:
+#endif NOOFLOAT
+ if ((int)from_size < (int)word_size) {
+ C_loc(from_size);
+ C_loc(word_size);
+ C_cii();
+ from_size = word_size;
+ }
+ C_loc(from_size);
+ C_loc(to_size);
+ if (to_cnvtype == T_UNSIGNED) C_ciu();
+ else C_cif();
+ break;
+ }
+ break;
+ case T_UNSIGNED:
+ if ((int)from_size < (int)word_size) from_size = word_size;
+ C_loc(from_size);
+ C_loc(to_size);
+ switch (to_cnvtype) {
+ case T_SIGNED:
+ C_cui();
+ break;
+ case T_UNSIGNED:
+ C_cuu();
+ break;
+#ifndef NOFLOAT
+ case T_FLOATING:
+ C_cuf();
+ break;
+#endif NOFLOAT
+ }
+ break;
+#ifndef NOFLOAT
+ case T_FLOATING:
+ C_loc(from_size);
+ C_loc(to_size);
+ switch (to_cnvtype) {
+ case T_SIGNED:
+ C_cfi();
+ break;
+ case T_UNSIGNED:
+ C_cfu();
+ break;
+ case T_FLOATING:
+ C_cff();
+ break;
+ }
+ break;
+#endif NOFLOAT
+ default:
+ crash("(conversion) illegal type conversion");
+ /*NOTREACHED*/
+ }
+ if ((int)(to_type->tp_size) < (int)word_size
+#ifndef NOFLOAT
+ && to_cnvtype != T_FLOATING
+#endif NOFLOAT
+ ) {
+ extern long full_mask[];
+
+ if (to_cnvtype == T_SIGNED) {
+ C_loc(to_type->tp_size);
+ C_loc(word_size);
+ C_cii();
+ }
+ else {
+ C_loc((arith) full_mask[(int)(to_type->tp_size)]);
+ C_and(word_size);
+ }
+ }
+}
+
+/* convtype() returns in which category a given type falls:
+ signed, unsigned or floating
+*/
+static int
+convtype(tp)
+ register struct type *tp;
+{
+ switch (tp->tp_fund) {
+ case GENERIC:
+ case CHAR:
+ case SHORT:
+ case INT:
+ case ERRONEOUS:
+ case LONG:
+ case ENUM:
+ return tp->tp_unsigned ? T_UNSIGNED : T_SIGNED;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+ return T_FLOATING;
+#endif NOFLOAT
+ case POINTER:
+ return T_UNSIGNED;
+ }
+ return 0;
+}
+
+#endif LINT
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* C O N S T A N T E X P R E S S I O N H A N D L I N G */
+
+#include "target_sizes.h"
+#include "idf.h"
+#include "arith.h"
+#include "type.h"
+#include "label.h"
+#include "expr.h"
+#include "sizes.h"
+#include "Lpars.h"
+#include "assert.h"
+
+long mach_long_sign; /* sign bit of the machine long */
+int mach_long_size; /* size of long on this machine == sizeof(long) */
+long full_mask[MAXSIZE];/* full_mask[1] == 0XFF, full_mask[2] == 0XFFFF, .. */
+arith max_int; /* maximum integer on target machine */
+arith max_unsigned; /* maximum unsigned on target machine */
+
+cstbin(expp, oper, expr)
+ register struct expr **expp, *expr;
+{
+ /* The operation oper is performed on the constant
+ expressions *expp(ld) and expr(ct), and the result restored in
+ *expp.
+ */
+ register arith o1 = (*expp)->VL_VALUE;
+ register arith o2 = expr->VL_VALUE;
+ int uns = (*expp)->ex_type->tp_unsigned;
+
+ ASSERT(is_ld_cst(*expp) && is_cp_cst(expr));
+ switch (oper) {
+ case '*':
+ o1 *= o2;
+ break;
+ case '/':
+ if (o2 == 0) {
+ expr_error(expr, "division by 0");
+ break;
+ }
+ if (uns) {
+ /* this is more of a problem than you might
+ think on C compilers which do not have
+ unsigned long.
+ */
+ if (o2 & mach_long_sign) {/* o2 > max_long */
+ o1 = ! (o1 >= 0 || o1 < o2);
+ /* this is the unsigned test
+ o1 < o2 for o2 > max_long
+ */
+ }
+ else { /* o2 <= max_long */
+ long half, bit, hdiv, hrem, rem;
+
+ half = (o1 >> 1) & ~mach_long_sign;
+ bit = o1 & 01;
+ /* now o1 == 2 * half + bit
+ and half <= max_long
+ and bit <= max_long
+ */
+ hdiv = half / o2;
+ hrem = half % o2;
+ rem = 2 * hrem + bit;
+ o1 = 2 * hdiv + (rem < 0 || rem >= o2);
+ /* that is the unsigned compare
+ rem >= o2 for o2 <= max_long
+ */
+ }
+ }
+ else
+ o1 /= o2;
+ break;
+ case '%':
+ if (o2 == 0) {
+ expr_error(expr, "modulo by 0");
+ break;
+ }
+ if (uns) {
+ if (o2 & mach_long_sign) {/* o2 > max_long */
+ o1 = (o1 >= 0 || o1 < o2) ? o1 : o1 - o2;
+ /* this is the unsigned test
+ o1 < o2 for o2 > max_long
+ */
+ }
+ else { /* o2 <= max_long */
+ long half, bit, hrem, rem;
+
+ half = (o1 >> 1) & ~mach_long_sign;
+ bit = o1 & 01;
+ /* now o1 == 2 * half + bit
+ and half <= max_long
+ and bit <= max_long
+ */
+ hrem = half % o2;
+ rem = 2 * hrem + bit;
+ o1 = (rem < 0 || rem >= o2) ? rem - o2 : rem;
+ }
+ }
+ else
+ o1 %= o2;
+ break;
+ case '+':
+ o1 += o2;
+ break;
+ case '-':
+ o1 -= o2;
+ break;
+ case LEFT:
+ o1 <<= o2;
+ break;
+ case RIGHT:
+ if (o2 == 0)
+ break;
+ if (uns) {
+ o1 >>= 1;
+ o1 &= ~mach_long_sign;
+ o1 >>= (o2-1);
+ }
+ else
+ o1 >>= o2;
+ break;
+ case '<':
+ {
+ arith tmp = o1;
+
+ o1 = o2;
+ o2 = tmp;
+ }
+ /* Fall through */
+ case '>':
+ if (uns) {
+ o1 = (o1 & mach_long_sign ?
+ (o2 & mach_long_sign ? o1 > o2 : 1) :
+ (o2 & mach_long_sign ? 0 : o1 > o2)
+ );
+ }
+ else
+ o1 = o1 > o2;
+ break;
+ case LESSEQ:
+ {
+ arith tmp = o1;
+
+ o1 = o2;
+ o2 = tmp;
+ }
+ /* Fall through */
+ case GREATEREQ:
+ if (uns) {
+ o1 = (o1 & mach_long_sign ?
+ (o2 & mach_long_sign ? o1 >= o2 : 1) :
+ (o2 & mach_long_sign ? 0 : o1 >= o2)
+ );
+ }
+ else
+ o1 = o1 >= o2;
+ break;
+ case EQUAL:
+ o1 = o1 == o2;
+ break;
+ case NOTEQUAL:
+ o1 = o1 != o2;
+ break;
+ case '&':
+ o1 &= o2;
+ break;
+ case '|':
+ o1 |= o2;
+ break;
+ case '^':
+ o1 ^= o2;
+ break;
+ }
+ (*expp)->VL_VALUE = o1;
+ cut_size(*expp);
+ (*expp)->ex_flags |= expr->ex_flags;
+ (*expp)->ex_flags &= ~EX_PARENS;
+ free_expression(expr);
+}
+
+cut_size(expr)
+ register struct expr *expr;
+{
+ /* The constant value of the expression expr is made to
+ conform to the size of the type of the expression.
+ */
+ register arith o1 = expr->VL_VALUE;
+ int uns = expr->ex_type->tp_unsigned;
+ int size = (int) expr->ex_type->tp_size;
+
+ ASSERT(expr->ex_class == Value);
+ if (expr->ex_type->tp_fund == POINTER) {
+ /* why warn on "ptr-3" ?
+ This quick hack fixes it
+ */
+ uns = 0;
+ }
+ if (uns) {
+ if (o1 & ~full_mask[size])
+ expr_warning(expr,
+ "overflow in unsigned constant expression");
+ o1 &= full_mask[size];
+ }
+ else {
+ int nbits = (int) (mach_long_size - size) * 8;
+ long remainder = o1 & ~full_mask[size];
+
+ if (remainder != 0 && remainder != ~full_mask[size])
+ expr_warning(expr, "overflow in constant expression");
+ o1 <<= nbits; /* ??? */
+ o1 >>= nbits;
+ }
+ expr->VL_VALUE = o1;
+}
+
+init_cst()
+{
+ register int i = 0;
+ register arith bt = (arith)0;
+
+ while (!(bt < 0)) {
+ bt = (bt << 8) + 0377, i++;
+ if (i == MAXSIZE)
+ fatal("array full_mask too small for this machine");
+ full_mask[i] = bt;
+ }
+ mach_long_size = i;
+ mach_long_sign = 1L << (mach_long_size * 8 - 1);
+ if ((int)long_size < mach_long_size)
+ fatal("sizeof (long) insufficient on this machine");
+ max_int = full_mask[(int)int_size] & ~(1L << ((int)int_size * 8 - 1));
+ max_unsigned = full_mask[(int)int_size];
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* DATAFLOW ANALYSIS ON C PROGRAMS */
+
+/* Compile the C compiler with flag DATAFLOW.
+ Use the compiler option --d.
+*/
+
+#include "dataflow.h" /* UF */
+
+#ifdef DATAFLOW
+char *CurrentFunction = 0;
+int NumberOfCalls;
+
+DfaStartFunction(nm)
+ char *nm;
+{
+ CurrentFunction = nm;
+ NumberOfCalls = 0;
+}
+
+DfaEndFunction()
+{
+ if (NumberOfCalls == 0)
+ print("DFA: %s: --none--\n", CurrentFunction);
+}
+
+DfaCallFunction(s)
+ char *s;
+{
+ print("DFA: %s: %s\n", CurrentFunction, s);
+ ++NumberOfCalls;
+}
+#endif DATAFLOW
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* DECLARATION SYNTAX PARSER */
+
+{
+#include "lint.h"
+#include <alloc.h>
+#include "nobitfield.h"
+#include "debug.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "label.h"
+#include "code.h"
+#include "idf.h"
+#include "type.h"
+#include "proto.h"
+#include "struct.h"
+#include "field.h"
+#include "decspecs.h"
+#include "def.h"
+#include "declar.h"
+#include "label.h"
+#include "expr.h"
+#include "sizes.h"
+#include "level.h"
+#ifdef LINT
+#include "l_lint.h"
+#include "l_state.h"
+#endif LINT
+}
+
+/* 8 */
+declaration
+ {struct decspecs Ds;}
+:
+ {Ds = null_decspecs;}
+ decl_specifiers(&Ds)
+ init_declarator_list(&Ds)?
+ ';'
+;
+
+/* A `decl_specifiers' describes a sequence of a storage_class_specifier,
+ an unsigned_specifier, a size_specifier and a simple type_specifier,
+ which may occur in arbitrary order and each of which may be absent;
+ at least one of them must be present, however, since the totally
+ empty case has already be dealt with in `external_definition'.
+ This means that something like:
+ unsigned extern int short xx;
+ is perfectly good C.
+
+ On top of that, multiple occurrences of storage_class_specifiers,
+ unsigned_specifiers and size_specifiers are errors, but a second
+ type_specifier should end the decl_specifiers and be treated as
+ the name to be declared (see the thin ice in RM11.1).
+ Such a language is not easily expressed in a grammar; enumeration
+ of the permutations is unattractive. We solve the problem by
+ having a regular grammar for the "soft" items, handling the single
+ occurrence of the type_specifier in the grammar (we have no choice),
+ collecting all data in a `struct decspecs' and turning that data
+ structure into what we want.
+
+ The existence of declarations like
+ short typedef yepp;
+ makes all hope of writing a specific grammar for typedefs illusory.
+*/
+
+decl_specifiers /* non-empty */ (register struct decspecs *ds;)
+ /* Reads a non-empty decl_specifiers and fills the struct
+ decspecs *ds.
+ */
+:
+[
+ other_specifier(ds)+
+ [%if (DOT != IDENTIFIER || AHEAD == IDENTIFIER)
+ /* the thin ice in R.M. 11.1 */
+ single_type_specifier(ds) other_specifier(ds)*
+ |
+ empty
+ ]
+|
+ single_type_specifier(ds) other_specifier(ds)*
+]
+ {do_decspecs(ds);}
+;
+
+/* 8.1 */
+other_specifier(register struct decspecs *ds;)
+:
+ [ AUTO | STATIC | EXTERN | TYPEDEF | REGISTER ]
+ { if (ds->ds_sc_given)
+ error("repeated storage class specifier");
+ ds->ds_sc_given = 1;
+ ds->ds_sc = DOT;
+ }
+|
+ [ SHORT | LONG ]
+ { if (ds->ds_size)
+ error("repeated size specifier");
+ ds->ds_size = DOT;
+ }
+|
+ [ SIGNED | UNSIGNED ]
+ { if (ds->ds_unsigned != 0)
+ error("repeated sign specifier");
+ ds->ds_unsigned = DOT;
+ }
+|
+ /* This qualifier applies to the top type.
+ E.g. const float * is a pointer to const float.
+ */
+ [ VOLATILE | CONST ]
+ { if (DOT == VOLATILE) {
+ if (ds->ds_typequal & TQ_VOLATILE)
+ error("repeated type qualifier");
+ ds->ds_typequal |= TQ_VOLATILE;
+ }
+ if (DOT == CONST) {
+ if (ds->ds_typequal & TQ_CONST)
+ error("repeated type qualifier");
+ ds->ds_typequal |= TQ_CONST;
+ }
+ }
+;
+
+/* 8.2 */
+type_specifier(struct type **tpp;)
+ /* Used in struct/union declarations and in casts; only the
+ type is relevant.
+ */
+ {struct decspecs Ds; Ds = null_decspecs;}
+:
+ decl_specifiers(&Ds)
+ {
+ if (Ds.ds_sc_given)
+ error("storage class ignored");
+ if (Ds.ds_sc == REGISTER)
+ error("register ignored");
+ }
+ {*tpp = Ds.ds_type;}
+;
+
+single_type_specifier(register struct decspecs *ds;):
+ %default TYPE_IDENTIFIER /* this includes INT, CHAR, etc. */
+ {idf2type(dot.tk_idf, &ds->ds_type);}
+|
+ IDENTIFIER
+ {
+ error("%s is not a type identifier", dot.tk_idf->id_text);
+ ds->ds_type = error_type;
+ if (dot.tk_idf->id_def) {
+ dot.tk_idf->id_def->df_type = error_type;
+ dot.tk_idf->id_def->df_sc = TYPEDEF;
+ }
+ }
+|
+ struct_or_union_specifier(&ds->ds_type)
+|
+ enum_specifier(&ds->ds_type)
+;
+
+/* 8.3 */
+init_declarator_list(struct decspecs *ds;):
+ init_declarator(ds)
+ [ ',' init_declarator(ds) ]*
+;
+
+init_declarator(register struct decspecs *ds;)
+ {
+ struct declarator Dc;
+ }
+:
+ {
+ Dc = null_declarator;
+ }
+[
+ declarator(&Dc)
+ {
+ reject_params(&Dc);
+ declare_idf(ds, &Dc, level);
+#ifdef LINT
+ lint_declare_idf(Dc.dc_idf, ds->ds_sc);
+#endif LINT
+ }
+ [
+ initializer(Dc.dc_idf, ds->ds_sc)
+ |
+ { code_declaration(Dc.dc_idf, (struct expr *) 0, level, ds->ds_sc); }
+ ]
+]
+ {
+#ifdef LINT
+ add_auto(Dc.dc_idf);
+#endif LINT
+ remove_declarator(&Dc);
+ }
+;
+
+/* 8.6: initializer */
+initializer(struct idf *idf; int sc;)
+ {
+ struct expr *expr = (struct expr *) 0;
+ int globalflag = level == L_GLOBAL ||
+ (level >= L_LOCAL && sc == STATIC);
+ }
+:
+ { if (idf->id_def->df_type->tp_fund == FUNCTION) {
+ error("illegal initialization of function");
+ idf->id_def->df_type->tp_fund = ERRONEOUS;
+ }
+ }
+ '='
+ {
+#ifdef LINT
+ lint_statement();
+#endif LINT
+ if (globalflag) {
+ struct expr ex;
+ code_declaration(idf, &ex, level, sc);
+ }
+ }
+ initial_value(globalflag ? &(idf->id_def->df_type) : (struct type **)0,
+ &expr)
+ { if (! globalflag) {
+ if (idf->id_def->df_type->tp_fund == FUNCTION) {
+ free_expression(expr);
+ expr = 0;
+ }
+#ifdef DEBUG
+ print_expr("initializer-expression", expr);
+#endif DEBUG
+#ifdef LINT
+ change_state(idf, SET);
+#endif LINT
+ code_declaration(idf, expr, level, sc);
+ }
+ init_idf(idf);
+ }
+;
+
+/*
+ Functions yielding pointers to functions must be declared as, e.g.,
+ int (*hehe(par1, par2))() char *par1, *par2; {}
+ Since the function heading is read as a normal declarator,
+ we just include the (formal) parameter list in the declarator
+ description list dc.
+*/
+declarator(register struct declarator *dc;)
+ { struct formal *fm = NO_PARAMS;
+ struct proto *pl = NO_PROTO;
+ arith count;
+ int qual;
+ }
+:
+ primary_declarator(dc)
+ [/*%while(1)*/
+ '('
+ [ %if (DOT != IDENTIFIER && DOT != ')')
+ parameter_type_list(&pl)
+ |
+ formal_list(&fm)
+ |
+ empty
+ ]
+ ')'
+ { add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl);
+ fm = NO_PARAMS;
+ }
+ |
+ arrayer(&count)
+ {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
+ ]*
+|
+ pointer(&qual) declarator(dc)
+ {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
+;
+
+primary_declarator(register struct declarator *dc;) :
+ identifier(&dc->dc_idf)
+|
+ '(' declarator(dc) ')'
+;
+
+arrayer(arith *sizep;)
+ { struct expr *expr; }
+:
+ '['
+ [
+ constant_expression(&expr)
+ {
+ check_array_subscript(expr);
+ *sizep = expr->VL_VALUE;
+ free_expression(expr);
+ }
+ |
+ empty
+ { *sizep = (arith)-1; }
+ ]
+ ']'
+;
+
+formal_list (struct formal **fmp;)
+:
+ formal(fmp) [ ',' formal(fmp) ]*
+;
+
+formal(struct formal **fmp;)
+ {struct idf *idf; }
+:
+ identifier(&idf)
+ {
+ register struct formal *new = new_formal();
+
+ new->fm_idf = idf;
+ new->next = *fmp;
+ *fmp = new;
+ }
+;
+
+/* Change 2 */
+enum_specifier(register struct type **tpp;)
+ {
+ struct idf *idf;
+ arith l = (arith)0;
+ }
+:
+ ENUM
+ [
+ {declare_struct(ENUM, (struct idf *) 0, tpp);}
+ enumerator_pack(*tpp, &l)
+ |
+ identifier(&idf)
+ [
+ {declare_struct(ENUM, idf, tpp);}
+ enumerator_pack(*tpp, &l)
+ |
+ {apply_struct(ENUM, idf, tpp);}
+ empty
+ ]
+ ]
+;
+
+enumerator_pack(register struct type *tp; arith *lp;) :
+ '{'
+ enumerator(tp, lp)
+ [%while (AHEAD != '}')
+ ','
+ enumerator(tp, lp)
+ ]*
+ [
+ ',' {warning("unexpected trailing comma in enumerator pack");}
+ ]?
+ '}'
+ {tp->tp_size = int_size;}
+ /* fancy implementations that put small enums in 1 byte
+ or so should start here.
+ */
+;
+
+enumerator(struct type *tp; arith *lp;)
+ {
+ struct idf *idf;
+ struct expr *expr;
+ }
+:
+ identifier(&idf)
+ [
+ '='
+ constant_expression(&expr)
+ {
+ *lp = expr->VL_VALUE;
+ free_expression(expr);
+ }
+ ]?
+ {declare_enum(tp, idf, (*lp)++);}
+;
+
+/* 8.5 */
+struct_or_union_specifier(register struct type **tpp;)
+ {
+ int fund;
+ struct idf *idfX;
+ register struct idf *idf;
+ }
+:
+ [ STRUCT | UNION ]
+ {fund = DOT;}
+ [
+ {
+ declare_struct(fund, (struct idf *)0, tpp);
+ }
+ struct_declaration_pack(*tpp)
+ |
+ identifier(&idfX) { idf = idfX; }
+ [
+ {
+ declare_struct(fund, idf, tpp);
+ (idf->id_struct->tg_busy)++;
+ }
+ struct_declaration_pack(*tpp)
+ {
+ (idf->id_struct->tg_busy)--;
+ }
+ |
+ {apply_struct(fund, idf, tpp);}
+ empty
+ ]
+ ]
+;
+
+struct_declaration_pack(register struct type *stp;)
+ {
+ struct sdef **sdefp = &stp->tp_sdef;
+ arith size = (arith)0;
+ }
+:
+ /* The size is only filled in after the whole struct has
+ been read, to prevent recursive definitions.
+ */
+ '{'
+ struct_declaration(stp, &sdefp, &size)+
+ '}'
+ {stp->tp_size = align(size, stp->tp_align);}
+;
+
+struct_declaration(struct type *stp; struct sdef ***sdefpp; arith *szp;)
+ {struct type *tp;}
+:
+ type_specifier(&tp) struct_declarator_list(tp, stp, sdefpp, szp) ';'
+;
+
+struct_declarator_list(struct type *tp, *stp;
+ struct sdef ***sdefpp; arith *szp;)
+:
+ struct_declarator(tp, stp, sdefpp, szp)
+ [ ',' struct_declarator(tp, stp, sdefpp, szp) ]*
+;
+
+struct_declarator(struct type *tp; struct type *stp;
+ struct sdef ***sdefpp; arith *szp;)
+ {
+ struct declarator Dc;
+ struct field *fd = 0;
+ }
+:
+ {
+ Dc = null_declarator;
+ }
+[
+ declarator(&Dc)
+ {reject_params(&Dc);}
+ bit_expression(&fd)?
+|
+ {Dc.dc_idf = gen_idf();}
+ bit_expression(&fd)
+]
+ {add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd);}
+ {remove_declarator(&Dc);}
+;
+
+bit_expression(struct field **fd;)
+ { struct expr *expr; }
+:
+ {
+ *fd = new_field();
+ }
+ ':'
+ constant_expression(&expr)
+ {
+ (*fd)->fd_width = expr->VL_VALUE;
+ free_expression(expr);
+#ifdef NOBITFIELD
+ error("bitfields are not implemented");
+#endif NOBITFIELD
+ }
+;
+
+/* 8.7 */
+cast(struct type **tpp;)
+ {struct declarator Dc;}
+:
+ {Dc = null_declarator;}
+ '('
+ type_specifier(tpp)
+ abstract_declarator(&Dc)
+ ')'
+ {*tpp = declare_type(*tpp, &Dc);}
+ {remove_declarator(&Dc);}
+;
+
+/* This code is an abject copy of that of 'declarator', for lack of
+ a two-level grammar.
+*/
+abstract_declarator(register struct declarator *dc;)
+ { struct proto *pl = NO_PROTO;
+ arith count;
+ int qual;
+ }
+:
+ primary_abstract_declarator(dc)
+ [
+ '('
+ [
+ parameter_type_list(&pl)
+ |
+ empty
+ ]
+ ')'
+ {add_decl_unary(dc, FUNCTION, 0, (arith)0, NO_PARAMS, pl);}
+ |
+ arrayer(&count)
+ {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
+ ]*
+|
+ pointer(&qual) abstract_declarator(dc)
+ {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
+;
+
+primary_abstract_declarator(struct declarator *dc;)
+:
+[%if (AHEAD == ')')
+ empty
+|
+ '(' abstract_declarator(dc) ')'
+]
+;
+
+parameter_type_list(struct proto **plp;)
+ { int save_level; }
+:
+ { if (level > L_PROTO) {
+ save_level = level;
+ level = L_PROTO;
+ } else level--;
+ }
+ parameter_decl_list(plp)
+ [
+ ',' ELLIPSIS
+ { register struct proto *new = new_proto();
+
+ new->next = *plp;
+ new->pl_flag = ELLIPSIS;
+ *plp = new;
+ }
+
+ ]?
+ { if (level == L_PROTO)
+ level = save_level;
+ else level++;
+ }
+;
+
+parameter_decl_list(struct proto **plp;)
+:
+ parameter_decl(plp)
+ [ %while (AHEAD != ELLIPSIS)
+ ',' parameter_decl(plp)
+ ]*
+;
+
+parameter_decl(struct proto **plp;)
+ { register struct proto *new = new_proto();
+ struct declarator Dc;
+ struct decspecs Ds;
+ }
+:
+ { Dc = null_declarator;
+ Ds = null_decspecs;
+ }
+ decl_specifiers(&Ds)
+ parameter_declarator(&Dc)
+ { add_proto(new, &Ds, &Dc, level);
+ new->next = *plp;
+ *plp = new;
+ }
+;
+
+/* This is weird. Due to the LR structure of the ANSI C grammar
+ we have to duplicate the actions of 'declarator' and
+ 'abstract_declarator'. Calling these separate, as in
+
+ parameter_decl:
+ decl_specifiers
+ [
+ declarator
+ |
+ abstract_declarator
+ ]
+
+
+ gives us a conflict on the terminals '(' and '*'. E.i. on
+ some input, it is impossible to decide which rule we take.
+ Combining the two declarators into one common declarator
+ is out of the question, since this results in an empty
+ string for the non-terminal 'declarator'.
+ So we combine the two only for the use of parameter_decl,
+ since this is the only place where they don't give
+ conflicts. However, this makes the grammar messy.
+*/
+parameter_declarator(register struct declarator *dc;)
+ { struct formal *fm = NO_PARAMS;
+ struct proto *pl = NO_PROTO;
+ arith count;
+ int qual;
+ }
+:
+ primary_parameter_declarator(dc)
+ [
+ '('
+ [ %if(DOT != IDENTIFIER && DOT != ')')
+ parameter_type_list(&pl)
+ |
+ formal_list(&fm)
+ |
+ empty
+ ]
+ ')'
+ {add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl);}
+ |
+ arrayer(&count)
+ {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
+ ]*
+|
+ pointer(&qual) parameter_declarator(dc)
+ {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
+;
+
+primary_parameter_declarator(register struct declarator *dc;)
+:
+[ %if(AHEAD == ')')
+ empty
+|
+ identifier(&dc->dc_idf)
+|
+ '(' parameter_declarator(dc) ')'
+]
+;
+
+pointer(int *qual;)
+:
+ '*' type_qualifier_list(qual)
+;
+
+
+/* Type qualifiers may come in three flavours:
+ volatile, const, const volatile.
+ These all have different semantic properties:
+
+ volatile:
+ means that the object can be modified
+ without prior knowledge of the implementation.
+
+ const:
+ means that the object can not be modified; thus
+ it's illegal to use this as a l-value.
+
+ const volatile:
+ means that the object can be modified without
+ prior knowledge of the implementation, but may
+ not be used as a l-value.
+*/
+type_qualifier_list(int *qual;)
+:
+[
+ [ VOLATILE | CONST ]
+ { *qual = (DOT == VOLATILE) ? TQ_VOLATILE : TQ_CONST; }
+
+ [
+ [ VOLATILE | CONST ]
+ { if (DOT == VOLATILE) {
+ if (*qual & TQ_VOLATILE)
+ error("repeated type qualifier");
+ *qual |= TQ_VOLATILE;
+ }
+ if (DOT == CONST) {
+ if (*qual & TQ_CONST)
+ error("repeated type qualifier");
+ *qual |= TQ_CONST;
+ }
+ }
+
+ ]*
+|
+ empty
+ { *qual = 0; }
+]
+;
+
+
+empty:
+;
+
+/* 8.8 */
+/* included in the IDENTIFIER/TYPE_IDENTIFIER mechanism */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* DEFINITION OF DECLARATOR DESCRIPTORS */
+
+/* A 'declarator' consists of an idf and a linked list of
+ language-defined unary operations: *, [] and (), called
+ decl_unary's.
+*/
+
+struct declarator {
+ struct declarator *next;
+ struct idf *dc_idf;
+ struct decl_unary *dc_decl_unary;
+ struct formal *dc_formal; /* params for function */
+};
+
+/* ALLOCDEF "declarator" 50 */
+
+
+struct formal { /* list of formals */
+ struct formal *next;
+ struct idf *fm_idf;
+};
+
+/* ALLOCDEF "formal" 5 */
+
+
+#define NO_PARAMS ((struct formal *) 0)
+
+struct decl_unary {
+ struct decl_unary *next;
+ int du_fund; /* POINTER, ARRAY or FUNCTION */
+ int du_typequal; /* CONST, VOLATILE, or 0 */
+ arith du_count; /* for ARRAYs only */
+ struct proto *du_proto; /* params for function or prototype */
+};
+
+/* ALLOCDEF "decl_unary" 10 */
+
+extern struct type *declare_type();
+extern struct declarator null_declarator;
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* D E C L A R A T O R M A N I P U L A T I O N */
+
+#include "botch_free.h"
+#include <alloc.h>
+#include "arith.h"
+#include "type.h"
+#include "proto.h"
+#include "Lpars.h"
+#include "declar.h"
+#include "def.h"
+#include "idf.h"
+#include "label.h"
+#include "expr.h"
+#include "sizes.h"
+#include "debug.h"
+#include "level.h"
+
+extern char options[];
+struct declarator null_declarator;
+
+struct type *
+declare_type(tp, dc)
+ struct type *tp;
+ struct declarator *dc;
+{
+ /* Applies the decl_unary list starting at dc->dc_decl_unary
+ to the type tp and returns the result.
+ Functions that are declared within a parameter type list
+ are purely prototypes. Simply add the type list to the
+ function node.
+ */
+ register struct decl_unary *du = dc->dc_decl_unary;
+
+ while (du) {
+ tp = construct_type(du->du_fund, tp, du->du_typequal,
+ du->du_count, du->du_proto);
+ du = du->next;
+ }
+ return tp;
+}
+
+add_decl_unary(dc, fund, qual, count, fm, pl)
+ register struct declarator *dc;
+ int qual;
+ arith count;
+ struct formal *fm;
+ struct proto *pl;
+{
+ /* A decl_unary describing a constructor with fundamental
+ type fund and with size count is inserted in front of the
+ declarator dc.
+ */
+ register struct decl_unary *new = new_decl_unary();
+
+ new->next = dc->dc_decl_unary;
+ new->du_fund = fund;
+ new->du_count = count;
+ new->du_typequal = qual;
+ new->du_proto = pl;
+ if (fm) {
+ if (dc->dc_decl_unary) {
+ /* parameters only allowed at first decl_unary */
+ error("formal parameters list discarded");
+ }
+ else {
+ /* register the proto */
+ dc->dc_formal = fm;
+ }
+ }
+
+ dc->dc_decl_unary = new;
+}
+
+remove_declarator(dc)
+ struct declarator *dc;
+{
+ /* The decl_unary list starting at dc->dc_decl_unary is
+ removed.
+ */
+ register struct decl_unary *du = dc->dc_decl_unary;
+
+ while (du) {
+ struct decl_unary *old_du = du;
+
+ du = du->next;
+ free_decl_unary(old_du);
+ }
+}
+
+reject_params(dc)
+ register struct declarator *dc;
+{
+ /* The declarator is checked to have no parameters, if it
+ is a function.
+ */
+ if (dc->dc_formal) {
+ error("non_empty formal parameter pack");
+ free_formals(dc->dc_formal);
+ dc->dc_formal = 0;
+ }
+}
+
+check_array_subscript(expr)
+ register struct expr *expr;
+{
+ arith size = expr->VL_VALUE;
+
+ if (size < 0) {
+ error("array size is negative");
+ expr->VL_VALUE = (arith)1;
+ }
+ else
+ if (size == 0) {
+ warning("array size is 0");
+ }
+ else
+ if (size & ~max_unsigned) { /* absolutely ridiculous */
+ expr_error(expr, "overflow in array size");
+ expr->VL_VALUE = (arith)1;
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* D E C L A R A T I O N S P E C I F I E R C H E C K I N G */
+
+#include "nofloat.h"
+#include "assert.h"
+#include "Lpars.h"
+#include "decspecs.h"
+#include "arith.h"
+#include "type.h"
+#include "level.h"
+#include "def.h"
+#include "noRoption.h"
+
+extern char options[];
+extern int level;
+extern char *symbol2str();
+extern char *type2str();
+extern char *qual2str();
+extern struct type *qualifier_type();
+
+struct decspecs null_decspecs;
+
+do_decspecs(ds)
+ register struct decspecs *ds;
+{
+ /* The provisional decspecs ds as obtained from the program
+ is turned into a legal consistent decspecs.
+ */
+ register struct type *tp = ds->ds_type;
+
+ ASSERT(level != L_FORMAL1);
+
+ /*
+ if (ds->ds_notypegiven && !ds->ds_sc_given)
+ strict("data definition lacking type or storage class");
+ */
+
+ if ( level == L_GLOBAL &&
+ (ds->ds_sc == AUTO || ds->ds_sc == REGISTER)
+ ) {
+ warning("no global %s variable allowed",
+ symbol2str(ds->ds_sc));
+ ds->ds_sc = GLOBAL;
+ }
+
+ if (level == L_FORMAL2) {
+ if (ds->ds_sc_given &&
+ ds->ds_sc != REGISTER){
+ error("%s formal illegal", symbol2str(ds->ds_sc));
+ ds->ds_sc = FORMAL;
+ }
+ }
+
+ /* Since type qualifiers may be associated with types by means
+ of typedefs, we have to perform same basic tests down here.
+ */
+ if (tp != (struct type *)0) {
+ if ((ds->ds_typequal & TQ_VOLATILE) && (tp->tp_typequal & TQ_VOLATILE))
+ error("indirect repeated type qualifier");
+ if ((ds->ds_typequal & TQ_CONST) && (tp->tp_typequal & TQ_CONST))
+ error("indirect repeated type qualifier");
+ ds->ds_typequal |= tp->tp_typequal;
+ }
+
+ /* The tests concerning types require a full knowledge of the
+ type and will have to be postponed to declare_idf.
+ */
+
+ /* some adjustments as described in RM 8.2 */
+ if (tp == 0) {
+ ds->ds_notypegiven = 1;
+ tp = int_type;
+ }
+ switch (ds->ds_size) {
+ case SHORT:
+ if (tp == int_type)
+ tp = short_type;
+ else
+ error("short with illegal type");
+ break;
+ case LONG:
+ if (tp == int_type)
+ tp = long_type;
+ else
+#ifndef NOFLOAT
+ if (tp == double_type)
+ tp = lngdbl_type;
+ else
+#endif NOFLOAT
+ error("long with illegal type");
+ break;
+ }
+ if (ds->ds_unsigned == UNSIGNED) {
+ switch (tp->tp_fund) {
+ case CHAR:
+#ifndef NOROPTION
+ if (options['R'])
+ warning("unsigned char not allowed");
+#endif
+ tp = uchar_type;
+ break;
+ case SHORT:
+#ifndef NOROPTION
+ if (options['R'])
+ warning("unsigned short not allowed");
+#endif
+ tp = ushort_type;
+ break;
+ case INT:
+ tp = uint_type;
+ break;
+ case LONG:
+#ifndef NOROPTION
+ if (options['R'])
+ warning("unsigned long not allowed");
+#endif
+ tp = ulong_type;
+ break;
+ default:
+ error("unsigned with illegal type");
+ break;
+ }
+ }
+ if (ds->ds_unsigned == SIGNED) {
+ switch (tp->tp_fund) {
+ case CHAR:
+ tp = char_type;
+ break;
+ case SHORT:
+ tp = short_type;
+ break;
+ case INT:
+ tp = int_type;
+ break;
+ case LONG:
+ tp = long_type;
+ break;
+ default:
+ error("signed with illegal type");
+ break;
+ }
+ }
+
+ ds->ds_type = qualifier_type(tp, ds->ds_typequal);
+}
+
+/* Make tp into a qualified type. This is not as trivial as it
+ may seem. If tp is a fundamental type the qualified type is
+ either existent or will be generated.
+ In case of a complex type the top of the type list will be
+ replaced by a qualified version.
+*/
+struct type *
+qualifier_type(tp, typequal)
+ register struct type *tp;
+ int typequal;
+{
+ register struct type *dtp = tp;
+ register int fund = tp->tp_fund;
+
+ while (dtp && dtp->tp_typequal != typequal)
+ dtp = dtp->next;
+
+ if (!dtp) {
+ dtp = create_type(fund);
+ dtp->tp_unsigned = tp->tp_unsigned;
+ dtp->tp_align = tp->tp_align;
+ dtp->tp_typequal = typequal;
+ dtp->tp_size = tp->tp_size;
+ switch (fund) {
+ case POINTER:
+ case ARRAY:
+ case FUNCTION:
+ case STRUCT:
+ case UNION:
+ case ENUM:
+ dtp->tp_idf = tp->tp_idf;
+ dtp->tp_sdef = tp->tp_sdef;
+ dtp->tp_up = tp->tp_up;
+ dtp->tp_field = tp->tp_field;
+ dtp->tp_pointer = tp->tp_pointer;
+ dtp->tp_array = tp->tp_array;
+ dtp->tp_function = tp->tp_function;
+ break;
+ default:
+ break;
+ }
+ dtp->next = tp->next; /* don't know head or tail */
+ tp->next = dtp;
+ }
+ return(dtp);
+}
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* DECLARATION SPECIFIER DEFINITION */
+
+struct decspecs {
+ struct decspecs *next;
+ struct type *ds_type; /* single type */
+ int ds_notypegiven; /* set if type not given explicitly */
+ int ds_sc_given; /* 1 if the st. class is explicitly given */
+ int ds_sc; /* storage class, given or implied */
+ int ds_size; /* LONG, SHORT or 0 */
+ int ds_unsigned; /* SIGNED, UNSIGNED or 0 */
+ int ds_typequal; /* type qualifiers - see type.str */
+};
+
+extern struct type *qualifier_type();
+extern struct decspecs null_decspecs;
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* IDENTIFIER DEFINITION DESCRIPTOR */
+
+#include "lint.h"
+
+struct def { /* for ordinary tags */
+ struct def *next;
+ int df_level;
+ struct type *df_type;
+ int df_sc; /* may be:
+ GLOBAL, STATIC, EXTERN, IMPLICIT,
+ TYPEDEF,
+ FORMAL, AUTO,
+ ENUM, LABEL
+ */
+ char df_initialized; /* an initialization has been generated */
+ char df_alloc; /* 0, ALLOC_SEEN or ALLOC_DONE */
+ char df_used; /* set if idf is used */
+ char *df_file; /* file containing the definition */
+ unsigned int df_line; /* line number of the definition */
+#ifdef LINT
+ char df_set;
+ int df_firstbrace; /* brace number of its first occurrence */
+ int df_minlevel; /* the lowest level needed for this def */
+#endif LINT
+ char df_formal_array; /* to warn if sizeof is taken */
+ arith df_address;
+};
+
+#define ALLOC_SEEN 1 /* an allocating declaration has been seen */
+#define ALLOC_DONE 2 /* the allocating declaration has been done */
+
+#define REG_DEFAULT 0 /* register candidate, not declared as such */
+#define REG_BONUS 10 /* register candidate, declared as such */
+
+/* ALLOCDEF "def" 50 */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: CONTROLLINE INTERPRETER */
+
+#include "arith.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "debug.h"
+#include "idf.h"
+#include "input.h"
+#include "nopp.h"
+
+#ifndef NOPP
+#include "ifdepth.h"
+#include "botch_free.h"
+#include "nparams.h"
+#include "parbufsize.h"
+#include "textsize.h"
+#include "idfsize.h"
+#include "assert.h"
+#include <alloc.h>
+#include "class.h"
+#include "macro.h"
+
+extern char **inctable; /* list of include directories */
+extern char *getwdir();
+char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */
+ /* 1 if a corresponding ELSE has been */
+ /* encountered. */
+
+int nestlevel = -1;
+
+struct idf *
+GetIdentifier()
+{
+ /* returns a pointer to the descriptor of the identifier that is
+ read from the input stream. A null-pointer is returned if
+ the input does not contain an identifier.
+ The substitution of macros is disabled.
+ */
+ int tok;
+ struct token tk;
+
+ ReplaceMacros = 0;
+ tok = GetToken(&tk);
+ ReplaceMacros = 1;
+ return tok == IDENTIFIER ? tk.tk_idf : (struct idf *)0;
+}
+
+/* domacro() is the control line interpreter. The '#' has already
+ been read by the lexical analyzer by which domacro() is called.
+ The token appearing directly after the '#' is obtained by calling
+ the basic lexical analyzing function GetToken() and is interpreted
+ to perform the action belonging to that token.
+ An error message is produced when the token is not recognized,
+ i.e. it is not one of "define" .. "undef" , integer or newline.
+*/
+domacro()
+{
+ struct token tk; /* the token itself */
+
+ EoiForNewline = 1;
+ switch(GetToken(&tk)) { /* select control line action */
+ case IDENTIFIER: /* is it a macro keyword? */
+ switch (tk.tk_idf->id_resmac) {
+ case K_DEFINE: /* "define" */
+ do_define();
+ break;
+ case K_ELIF: /* "elif" */
+ do_elif();
+ break;
+ case K_ELSE: /* "else" */
+ do_else();
+ break;
+ case K_ENDIF: /* "endif" */
+ do_endif();
+ break;
+ case K_IF: /* "if" */
+ do_if();
+ break;
+ case K_IFDEF: /* "ifdef" */
+ do_ifdef(1);
+ break;
+ case K_IFNDEF: /* "ifndef" */
+ do_ifdef(0);
+ break;
+ case K_INCLUDE: /* "include" */
+ do_include();
+ break;
+ case K_LINE: /* "line" */
+ /* set LineNumber and FileName according to
+ the arguments.
+ */
+ if (GetToken(&tk) != INTEGER) {
+ lexerror("#line without linenumber");
+ SkipToNewLine(0);
+ }
+ else
+ do_line((unsigned int)tk.tk_ival);
+ break;
+ case K_ERROR: /* "error" */
+ do_error();
+ break;
+ case K_PRAGMA: /* "pragma" */
+ do_pragma();
+ break;
+ case K_UNDEF: /* "undef" */
+ do_undef();
+ break;
+ default:
+ /* invalid word seen after the '#' */
+ lexerror("%s: unknown control", tk.tk_idf->id_text);
+ SkipToNewLine(0);
+ }
+ break;
+ case INTEGER: /* # <integer> [<filespecifier>]? */
+ do_line((unsigned int)tk.tk_ival);
+ break;
+ case EOI: /* only `#' on this line: do nothing, ignore */
+ break;
+ default: /* invalid token following '#' */
+ lexerror("illegal # line");
+ SkipToNewLine(0);
+ }
+ EoiForNewline = 0;
+}
+
+
+skip_block()
+{
+ /* skip_block() skips the input from
+ 1) a false #if, #ifdef, #ifndef or #elif until the
+ corresponding #elif (resulting in true), #else or
+ #endif is read.
+ 2) a #else corresponding to a true #if, #ifdef,
+ #ifndef or #elif until the corresponding #endif is
+ seen.
+ */
+ register int ch;
+ register int skiplevel = nestlevel; /* current nesting level */
+ struct token tk;
+
+ NoUnstack++;
+ for (;;) {
+ ch = GetChar(); /* read first character after newline */
+ while (class(ch) == STSKIP)
+ ch = GetChar();
+ if (ch != '#') {
+ if (ch == EOI) {
+ NoUnstack--;
+ return;
+ }
+ SkipToNewLine(0);
+ continue;
+ }
+ if (GetToken(&tk) != IDENTIFIER) {
+ SkipToNewLine(0);
+ continue;
+ }
+ /* an IDENTIFIER: look for #if, #ifdef and #ifndef
+ without interpreting them.
+ Interpret #else, #elif and #endif if they occur
+ on the same level.
+ */
+ switch(tk.tk_idf->id_resmac) {
+ case K_IF:
+ case K_IFDEF:
+ case K_IFNDEF:
+ push_if();
+ break;
+ case K_ELIF:
+ if (nestlevel == skiplevel) {
+ nestlevel--;
+ push_if();
+ if (ifexpr()) {
+ NoUnstack--;
+ return;
+ }
+ }
+ break;
+ case K_ELSE:
+ ++(ifstack[nestlevel]);
+ if (nestlevel == skiplevel) {
+ if (SkipToNewLine(1))
+ strict("garbage following #endif");
+ NoUnstack--;
+ return;
+ }
+ break;
+ case K_ENDIF:
+ ASSERT(nestlevel > nestlow);
+ if (nestlevel == skiplevel) {
+ if (SkipToNewLine(1))
+ strict("garbage following #endif");
+ nestlevel--;
+ NoUnstack--;
+ return;
+ }
+ nestlevel--;
+ break;
+ }
+ }
+}
+
+
+ifexpr()
+{
+ /* ifexpr() returns whether the restricted constant
+ expression following #if or #elif evaluates to true. This
+ is done by calling the LLgen generated subparser for
+ constant expressions. The result of this expression will
+ be given in the extern long variable "ifval".
+ */
+ extern arith ifval;
+ int errors = err_occurred;
+
+ ifval = (arith)0;
+ AccDefined = 1;
+ UnknownIdIsZero = 1;
+ PushLex(); /* NEW parser */
+ If_expr(); /* invoke constant expression parser */
+ PopLex(); /* OLD parser */
+ AccDefined = 0;
+ UnknownIdIsZero = 0;
+ return (errors == err_occurred) && (ifval != (arith)0);
+}
+
+do_include()
+{
+ /* do_include() performs the inclusion of a file.
+ */
+ char *filenm;
+ char *result;
+ int tok;
+ struct token tk;
+
+ AccFileSpecifier = 1;
+ if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
+ filenm = tk.tk_bts;
+ else {
+ lexerror("bad include syntax");
+ filenm = (char *)0;
+ }
+ AccFileSpecifier = 0;
+ SkipToNewLine(0);
+ inctable[0] = WorkingDir;
+ if (filenm) {
+ if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
+ fatal("cannot open include file \"%s\"", filenm);
+ }
+ else {
+ WorkingDir = getwdir(result);
+ File_Inserted = 1;
+ FileName = result;
+ LineNumber = 0;
+ nestlow = nestlevel;
+ }
+ }
+}
+
+do_define()
+{
+ /* do_define() interprets a #define control line.
+ */
+ struct idf *id; /* the #defined identifier's descriptor */
+ int nformals = -1; /* keep track of the number of formals */
+ char *formals[NPARAMS]; /* pointers to the names of the formals */
+ char parbuf[PARBUFSIZE]; /* names of formals */
+ char *repl_text; /* start of the replacement text */
+ int length; /* length of the replacement text */
+ register ch;
+ char *get_text();
+
+ /* read the #defined macro's name */
+ if (!(id = GetIdentifier())) {
+ lexerror("#define: illegal macro name");
+ SkipToNewLine(0);
+ return;
+ }
+ /* there is a formal parameter list if the identifier is
+ followed immediately by a '('.
+ */
+ ch = GetChar();
+ if (ch == '(') {
+ if ((nformals = getparams(formals, parbuf)) == -1) {
+ SkipToNewLine(0);
+ return; /* an error occurred */
+ }
+ ch = GetChar();
+ }
+ /* read the replacement text if there is any */
+ ch = skipspaces(ch,0); /* find first character of the text */
+ ASSERT(ch != EOI);
+ if (class(ch) == STNL) {
+ /* Treat `#define something' as `#define something ""'
+ */
+ repl_text = "";
+ length = 0;
+ }
+ else {
+ UnGetChar();
+ repl_text = get_text((nformals > 0) ? formals : 0, &length);
+ }
+ macro_def(id, repl_text, nformals, length, NOFLAG);
+ LineNumber++;
+}
+
+push_if()
+{
+ if (nestlevel >= IFDEPTH)
+ fatal("too many nested #if/#ifdef/#ifndef");
+ else
+ ifstack[++nestlevel] = 0;
+}
+
+do_elif()
+{
+ if (nestlevel <= nestlow || (ifstack[nestlevel])) {
+ lexerror("#elif without corresponding #if");
+ SkipToNewLine(0);
+ }
+ else { /* restart at this level as if a #if is detected. */
+ nestlevel--;
+ push_if();
+ skip_block();
+ }
+}
+
+do_else()
+{
+ struct token tok;
+
+ if (SkipToNewLine(1))
+ strict("garbage following #else");
+ if (nestlevel <= nestlow || (ifstack[nestlevel]))
+ lexerror("#else without corresponding #if");
+ else { /* mark this level as else-d */
+ ++(ifstack[nestlevel]);
+ skip_block();
+ }
+}
+
+do_endif()
+{
+ struct token tok;
+
+ if (SkipToNewLine(1))
+ strict("garbage following #endif");
+ if (nestlevel <= nestlow) {
+ lexerror("#endif without corresponding #if");
+ }
+ else nestlevel--;
+}
+
+do_if()
+{
+ push_if();
+ if (!ifexpr()) /* a false #if/#elif expression */
+ skip_block();
+}
+
+do_ifdef(how)
+{
+ register struct idf *id;
+
+ /* how == 1 : ifdef; how == 0 : ifndef
+ */
+ push_if();
+ if (!(id = GetIdentifier()))
+ lexerror("illegal #ifdef construction");
+
+ /* The next test is a shorthand for:
+ (how && !id->id_macro) || (!how && id->id_macro)
+ */
+ if (how ^ (id && id->id_macro != 0))
+ skip_block();
+ else
+ SkipToNewLine(0);
+}
+
+do_undef()
+{
+ register struct idf *id;
+
+ /* Forget a macro definition. */
+ if (id = GetIdentifier()) {
+ if (id->id_macro) { /* forget the macro */
+ free_macro(id->id_macro);
+ id->id_macro = (struct macro *) 0;
+ } /* else: don't complain */
+ }
+ else
+ lexerror("illegal #undef construction");
+ SkipToNewLine(0);
+}
+
+do_error()
+{
+ static char errbuf[512];
+ register char *bp = errbuf;
+ register int ch;
+
+ while ((ch = GetChar()) != '\n')
+ *bp++ = ch;
+ *bp = '\0';
+ UnGetChar();
+ lexerror("user error: %s", errbuf);
+}
+
+int
+getparams(buf, parbuf)
+ char *buf[];
+ char parbuf[];
+{
+ /* getparams() reads the formal parameter list of a macro
+ definition.
+ The number of parameters is returned.
+ As a formal parameter list is expected when calling this
+ routine, -1 is returned if an error is detected, for
+ example:
+ #define one(1), where 1 is not an identifier.
+ Note that the '(' has already been eaten.
+ The names of the formal parameters are stored into parbuf.
+ */
+ register char **pbuf = &buf[0];
+ register int c;
+ register char *ptr = &parbuf[0];
+ register char **pbuf2;
+
+ c = GetChar();
+ c = skipspaces(c,0);
+ if (c == ')') { /* no parameters: #define name() */
+ *pbuf = (char *) 0;
+ return 0;
+ }
+ for (;;) { /* eat the formal parameter list */
+ if (class(c) != STIDF && class(c) != STELL) {
+ lexerror("#define: bad formal parameter");
+ return -1;
+ }
+ *pbuf = ptr; /* name of the formal */
+ *ptr++ = c;
+ if (ptr >= &parbuf[PARBUFSIZE])
+ fatal("formal parameter buffer overflow");
+ do { /* eat the identifier name */
+ c = GetChar();
+ *ptr++ = c;
+ if (ptr >= &parbuf[PARBUFSIZE])
+ fatal("formal parameter buffer overflow");
+ } while (in_idf(c));
+ *(ptr - 1) = '\0'; /* mark end of the name */
+
+ /* Check if this formal parameter is already used.
+ Usually, macros do not have many parameters, so ...
+ */
+ for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--) {
+ if (!strcmp(*pbuf2, *pbuf)) {
+ warning("formal parameter \"%s\" already used",
+ *pbuf);
+ }
+ }
+
+ pbuf++;
+ c = skipspaces(c,0);
+ if (c == ')') { /* end of the formal parameter list */
+ *pbuf = (char *) 0;
+ return pbuf - buf;
+ }
+ if (c != ',') {
+ lexerror("#define: bad formal parameter list");
+ return -1;
+ }
+ c = GetChar();
+ c = skipspaces(c,0);
+ }
+ /*NOTREACHED*/
+}
+
+macro_def(id, text, nformals, length, flags)
+ register struct idf *id;
+ char *text;
+{
+ register struct macro *newdef = id->id_macro;
+
+ /* macro_def() puts the contents and information of a macro
+ definition into a structure and stores it into the symbol
+ table entry belonging to the name of the macro.
+ A warning is given if the definition overwrites another.
+ */
+ if (newdef) { /* is there a redefinition? */
+ if (macroeq(newdef->mc_text, text))
+ return;
+ lexwarning("redefine \"%s\"", id->id_text);
+ }
+ else
+ id->id_macro = newdef = new_macro();
+ newdef->mc_text = text; /* replacement text */
+ newdef->mc_nps = nformals; /* nr of formals */
+ newdef->mc_length = length; /* length of repl. text */
+ newdef->mc_flag = flags; /* special flags */
+ newdef->mc_count = 0;
+}
+
+int
+find_name(nm, index)
+ char *nm, *index[];
+{
+ /* find_name() returns the index of "nm" in the namelist
+ "index" if it can be found there. 0 is returned if it is
+ not there.
+ */
+ register char **ip = &index[0];
+
+ while (*ip)
+ if (strcmp(nm, *ip++) == 0)
+ return ip - &index[0];
+ /* arrived here, nm is not in the name list. */
+ return 0;
+}
+
+char *
+get_text(formals, length)
+ char *formals[];
+ int *length;
+{
+ /* get_text() copies the replacement text of a macro
+ definition with zero, one or more parameters, thereby
+ substituting each formal parameter by a special character
+ (non-ascii: 0200 & (order-number in the formal parameter
+ list)) in order to substitute this character later by the
+ actual parameter. The replacement text is copied into
+ itself because the copied text will contain fewer or the
+ same amount of characters. The length of the replacement
+ text is returned.
+
+ Implementation:
+ finite automaton : we are only interested in
+ identifiers, because they might be replaced by some actual
+ parameter. Other tokens will not be seen as such.
+ */
+ register int c;
+ register int text_size;
+ char *text = Malloc(text_size = ITEXTSIZE);
+ register int pos = 0;
+
+ c = GetChar();
+
+ while ((c != EOI) && (class(c) != STNL)) {
+ if (c == '\'' || c == '"') {
+ register int delim = c;
+
+ do {
+ /* being careful, as ever */
+ if (pos+3 >= text_size)
+ text = Srealloc(text,
+ text_size += RTEXTSIZE);
+ text[pos++] = c;
+ if (c == '\\')
+ text[pos++] = GetChar();
+ c = GetChar();
+ } while (c != delim && c != EOI && class(c) != STNL);
+ text[pos++] = c;
+ c = GetChar();
+ }
+ else
+ if (c == '/') {
+ c = GetChar();
+ if (pos+1 >= text_size)
+ text = Srealloc(text, text_size += RTEXTSIZE);
+ if (c == '*') {
+ skipcomment();
+ text[pos++] = ' ';
+ c = GetChar();
+ }
+ else
+ text[pos++] = '/';
+ }
+ else
+ if (formals && (class(c) == STIDF || class(c) == STELL)) {
+ char id_buf[IDFSIZE + 1];
+ register id_size = 0;
+ register n;
+
+ /* read identifier: it may be a formal parameter */
+ id_buf[id_size++] = c;
+ do {
+ c = GetChar();
+ if (id_size <= IDFSIZE)
+ id_buf[id_size++] = c;
+ } while (in_idf(c));
+ id_buf[--id_size] = '\0';
+ if (n = find_name(id_buf, formals)) {
+ /* construct the formal parameter mark */
+ if (pos+1 >= text_size)
+ text = Srealloc(text,
+ text_size += RTEXTSIZE);
+ text[pos++] = FORMALP | (char) n;
+ }
+ else {
+ register char *ptr = &id_buf[0];
+
+ while (pos + id_size >= text_size)
+ text = Srealloc(text,
+ text_size += RTEXTSIZE);
+ while (text[pos++] = *ptr++) ;
+ pos--;
+ }
+ }
+ else {
+ if (pos+1 >= text_size)
+ text = Srealloc(text, text_size += RTEXTSIZE);
+ text[pos++] = c;
+ c = GetChar();
+ }
+ }
+ text[pos++] = '\0';
+ *length = pos - 1;
+ return text;
+}
+
+#define BLANK(ch) ((ch == ' ') || (ch == '\t'))
+
+/* macroeq() decides whether two macro replacement texts are
+ identical. This version compares the texts, which occur
+ as strings, without taking care of the leading and trailing
+ blanks (spaces and tabs).
+*/
+macroeq(s, t)
+ register char *s, *t;
+{
+
+ /* skip leading spaces */
+ while (BLANK(*s)) s++;
+ while (BLANK(*t)) t++;
+ /* first non-blank encountered in both strings */
+ /* The actual comparison loop: */
+ while (*s && *s == *t)
+ s++, t++;
+ /* two cases are possible when arrived here: */
+ if (*s == '\0') { /* *s == '\0' */
+ while (BLANK(*t)) t++;
+ return *t == '\0';
+ }
+ else { /* *s != *t */
+ while (BLANK(*s)) s++;
+ while (BLANK(*t)) t++;
+ return (*s == '\0') && (*t == '\0');
+ }
+}
+#else NOPP
+domacro()
+{
+ int tok;
+ struct token tk;
+
+ EoiForNewline = 1;
+ if ((tok = GetToken(&tk)) == IDENTIFIER) {
+ if (strcmp(tk.tk_idf->id_text, "line") != 0) {
+ error("illegal # line");
+ SkipToNewLine(0);
+ return;
+ }
+ tok = GetToken(&tk);
+ }
+ if (tok != INTEGER) {
+ error("illegal # line");
+ SkipToNewLine(0);
+ return;
+ }
+ do_line((unsigned int) tk.tk_ival);
+ EoiForNewline = 0;
+}
+#endif NOPP
+
+
+do_line(l)
+ unsigned int l;
+{
+ struct token tk;
+
+ LineNumber = l - 1; /* the number of the next input line */
+ if (GetToken(&tk) == STRING) /* is there a filespecifier? */
+ FileName = tk.tk_bts;
+ SkipToNewLine(0);
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* DUMP ROUTINES */
+
+#include "debug.h"
+
+#ifdef DEBUG
+#include "nofloat.h"
+#include "nopp.h"
+#include "nobitfield.h"
+#include "arith.h"
+#include "stack.h"
+#include "idf.h"
+#include "def.h"
+#include "type.h"
+#include "proto.h"
+#include "struct.h"
+#include "field.h"
+#include "Lpars.h"
+#include "label.h"
+#include "expr.h"
+#include "static.h"
+#include "declar.h"
+
+/* Some routines (symbol2str, token2str, type2str) which should have
+ * yielded strings are written to yield a pointer to a transient piece
+ * of memory, containing the string, since this is the only reasonable
+ * thing to do in C. `Transient' means that the result may soon
+ * disappear, which is generally not a problem, since normally it is
+ * consumed immediately. Sometimes we need more than one of them, and
+ * MAXTRANS is the maximum number we will need simultaneously.
+ */
+#define MAXTRANS 6
+
+extern char options[];
+
+extern char *sprint();
+
+extern struct idf *idf_hashtable[];
+extern char *symbol2str(), *type2str(), *qual2str(), *next_transient();
+
+enum sdef_kind {selector, field}; /* parameter for dumpsdefs */
+
+static int dumplevel;
+
+newline() {
+ register int dl = dumplevel;
+
+ print("\n");
+ while (dl >= 2) {
+ print("\t");
+ dl -= 2;
+ }
+ if (dl)
+ print(" ");
+}
+
+dumpidftab(msg, opt)
+ char msg[];
+{
+ /* Dumps the identifier table in readable form (but in
+ arbitrary order).
+ Unless opt & 1, macros are not dumped.
+ Unless opt & 2, reserved identifiers are not dumped.
+ Unless opt & 4, universal identifiers are not dumped.
+ */
+ int i;
+
+ print(">>> DUMPIDF, %s (start)", msg);
+ dumpstack();
+ for (i = 0; i < HASHSIZE; i++) {
+ register struct idf *notch = idf_hashtable[i];
+
+ while (notch) {
+ dumpidf(notch, opt);
+ notch = notch->next;
+ }
+ }
+ newline();
+ print(">>> DUMPIDF, %s (end)\n", msg);
+}
+
+dumpstack()
+{
+ /* Dumps the identifier stack, starting at the top.
+ */
+ register struct stack_level *stl = local_level;
+
+ while (stl) {
+ register struct stack_entry *se = stl->sl_entry;
+
+ newline();
+ print("%3d: ", stl->sl_level);
+ while (se) {
+ print("%s ", se->se_idf->id_text);
+ se = se->next;
+ }
+ stl = stl->sl_previous;
+ }
+ print("\n");
+}
+
+dumpidf(idf, opt)
+ register struct idf *idf;
+{
+ /* All information about the identifier idf is divulged in a
+ hopefully readable format.
+ */
+ int started = 0;
+
+ if (!idf)
+ return;
+#ifndef NOPP
+ if ((opt&1) && idf->id_macro) {
+ if (!started++) {
+ newline();
+ print("%s:", idf->id_text);
+ }
+ print(" macro");
+ }
+#endif NOPP
+ if ((opt&2) && idf->id_reserved) {
+ if (!started++) {
+ newline();
+ print("%s:", idf->id_text);
+ }
+ print(" reserved: %d;", idf->id_reserved);
+ }
+ if (idf->id_def && ((opt&4) || idf->id_def->df_level)) {
+ if (!started++) {
+ newline();
+ print("%s:", idf->id_text);
+ }
+ dumpdefs(idf->id_def, opt);
+ }
+ if (idf->id_sdef) {
+ if (!started++) {
+ newline();
+ print("%s:", idf->id_text);
+ }
+ dumpsdefs(idf->id_sdef, selector);
+ }
+ if (idf->id_struct) {
+ if (!started++) {
+ newline();
+ print("%s:", idf->id_text);
+ }
+ dumptags(idf->id_struct);
+ }
+ if (idf->id_enum) {
+ if (!started++) {
+ newline();
+ print("%s:", idf->id_text);
+ }
+ dumptags(idf->id_enum);
+ }
+}
+
+dumpdefs(def, opt)
+ register struct def *def;
+{
+ dumplevel++;
+ while (def && ((opt&4) || def->df_level)) {
+ newline();
+ print("L%d: %s %s%stype%s %lo; ",
+ def->df_level,
+ symbol2str(def->df_sc),
+ def->df_initialized ? "init'd " : "",
+ def->df_used ? "used " : "",
+ def->df_sc == ENUM ? ", =" : " at",
+ def->df_address
+ );
+ print("%s, line %u",
+ def->df_file ? def->df_file : "NO_FILE", def->df_line);
+ dump_type(def->df_type);
+ def = def->next;
+ }
+ dumplevel--;
+}
+
+dumptags(tag)
+ register struct tag *tag;
+{
+ dumplevel++;
+ while (tag) {
+ register struct type *tp = tag->tg_type;
+ register int fund = tp->tp_fund;
+
+ newline();
+ print("L%d: %s %s",
+ tag->tg_level,
+ fund == STRUCT ? "struct" :
+ fund == UNION ? "union" :
+ fund == ENUM ? "enum" : "<UNKNOWN>",
+ tp->tp_idf->id_text
+ );
+ if (is_struct_or_union(fund)) {
+ print(" {");
+ dumpsdefs(tp->tp_sdef, field);
+ newline();
+ print("}");
+ }
+ print(";");
+ tag = tag->next;
+ }
+ dumplevel--;
+}
+
+dumpsdefs(sdef, sdk)
+ register struct sdef *sdef;
+ enum sdef_kind sdk;
+{
+ /* Since sdef's are members of two chains, there are actually
+ two dumpsdefs's, one following the chain of all selectors
+ belonging to the same idf, starting at idf->id_sdef;
+ and the other following the chain of all selectors belonging
+ to the same struct, starting at stp->tp_sdef.
+ */
+
+ dumplevel++;
+ while (sdef) {
+ newline();
+ print("L%d: ", sdef->sd_level);
+#ifndef NOBITFIELD
+ if (sdk == selector)
+#endif NOBITFIELD
+ print("selector %s at offset %lu in %s;",
+ type2str(sdef->sd_type),
+ sdef->sd_offset, type2str(sdef->sd_stype)
+ );
+#ifndef NOBITFIELD
+ else print("field %s at offset %lu;",
+ type2str(sdef->sd_type), sdef->sd_offset
+ );
+#endif NOBITFIELD
+ sdef = (sdk == selector ? sdef->next : sdef->sd_sdef);
+ }
+ dumplevel--;
+}
+
+dump_proto(pl)
+ register struct proto *pl;
+{
+ register struct type *type;
+ register int argcnt = 0;
+
+ newline();
+ print("dump proto type list (start)");
+ newline();
+ while (pl) {
+ print("%d: %s", argcnt++,
+ pl->pl_flag == FORMAL ?
+ (pl->pl_flag == VOID ? "void" : "formal")
+ : "ellipsis");
+ newline();
+ if (type = pl->pl_type){
+ dump_type(type);
+ newline();
+ }
+ if (pl->pl_idf) {
+ dumplevel++;
+ print("idf:");
+ dumpidf(pl->pl_idf, 7);
+ dumplevel--;
+ }
+ newline();
+ pl = pl->next;
+ }
+ print("dump proto type list (end)\n");
+}
+
+dump_type(tp)
+ register struct type *tp;
+{
+ int ops = 1;
+
+ dumplevel++;
+ newline();
+ if (!tp) {
+ print("<NILTYPE>");
+ newline();
+ return;
+ }
+
+ print("(@%lx, #%ld, &%d) ", tp, (long)tp->tp_size, tp->tp_align);
+
+ while (ops) {
+ print("%s", qual2str(tp->tp_typequal));
+ switch (tp->tp_fund) {
+ case POINTER:
+ print("pointer to ");
+ break;
+ case ARRAY:
+ print("array [%ld] of ", tp->tp_size);
+ break;
+ case FUNCTION:
+ print("function ");
+ if (tp->tp_proto) {
+ print("with prototype");
+ dumplevel++;
+ dump_proto(tp->tp_proto);
+ dumplevel--;
+ newline();
+ }
+ print("yielding ");
+ break;
+ default:
+ print("%s%s ", tp->tp_unsigned ? "unsigned " : "",
+ symbol2str(tp->tp_fund));
+ if (tp->tp_idf)
+ print("%s ", tp->tp_idf->id_text);
+#ifndef NOBITFIELD
+ if (tp->tp_field) {
+ struct field *fd = tp->tp_field;
+
+ print("[s=%ld,w=%ld] of ",
+ fd->fd_shift, fd->fd_width);
+ }
+ else
+#endif NOBITFIELD
+ ops = 0;
+ break;
+ }
+ tp = tp->tp_up;
+ }
+ dumplevel--;
+}
+
+char *
+type2str(tp)
+ register struct type *tp;
+{
+ /* Yields a pointer to a one-line description of the type tp.
+ */
+ char *buf = next_transient();
+ int ops = 1;
+
+ buf[0] = '\0';
+ if (!tp) {
+ sprint(buf, "<NILTYPE>");
+ return buf;
+ }
+ sprint(buf, "%s(@%lx, #%ld, &%d) ",
+ buf, tp, (long)tp->tp_size, tp->tp_align);
+
+ while (ops) {
+ sprint(buf, "%s%s", buf, qual2str(tp->tp_typequal));
+ switch (tp->tp_fund) {
+ case POINTER:
+ sprint(buf, "%spointer to ", buf);
+ break;
+ case ARRAY:
+ sprint(buf, "%sarray [%ld] of ", buf, tp->tp_size);
+ break;
+ case FUNCTION:
+ sprint(buf, "%sfunction yielding ", buf);
+ break;
+ default:
+ sprint(buf, "%s%s%s ", buf,
+ tp->tp_unsigned ? "unsigned " : "",
+ symbol2str(tp->tp_fund)
+ );
+ if (tp->tp_idf)
+ sprint(buf, "%s %s ", buf,
+ tp->tp_idf->id_text);
+#ifndef NOBITFIELD
+ if (tp->tp_field) {
+ struct field *fd = tp->tp_field;
+
+ sprint(buf, "%s [s=%ld,w=%ld] of ", buf,
+ fd->fd_shift, fd->fd_width);
+ }
+ else
+#endif NOBITFIELD
+ ops = 0;
+ break;
+ }
+ tp = tp->tp_up;
+ }
+ return buf;
+}
+
+char *
+qual2str(qual)
+ int qual;
+{
+ char *buf = next_transient();
+
+ *buf = '\0';
+ if (qual == 0)
+ sprint(buf, "(none)");
+ if (qual & TQ_CONST)
+ sprint(buf, "%sconst ", buf);
+ if (qual & TQ_VOLATILE)
+ sprint(buf, "%svolatile ", buf);
+
+ return qual == 0 ? "" : buf;
+}
+
+GSTATIC char trans_buf[MAXTRANS][300];
+
+char * /* the ultimate transient buffer supplier */
+next_transient()
+{
+ static int bnum;
+
+ if (++bnum == MAXTRANS)
+ bnum = 0;
+ return trans_buf[bnum];
+}
+
+print_expr(msg, expr)
+ char msg[];
+ struct expr *expr;
+{
+ /* Provisional routine to print an expression preceded by a
+ message msg.
+ */
+ if (options['x']) {
+ print("\n%s: ", msg);
+ print("(L=line, T=type, r/lV=r/lvalue, F=flags, D=depth)\n");
+ p1_expr(0, expr);
+ }
+}
+
+p1_expr(lvl, expr)
+ register struct expr *expr;
+{
+ p1_indent(lvl);
+ if (!expr) {
+ print("NILEXPR\n");
+ return;
+ }
+ print("expr: L=%u, T=%s, %cV, F=%03o, D=%d, %s: ",
+ expr->ex_line,
+ type2str(expr->ex_type),
+ expr->ex_lvalue ? 'l' : 'r',
+ expr->ex_flags & 0xFF,
+ expr->ex_depth,
+ expr->ex_class == Value ? "Value" :
+ expr->ex_class == String ? "String" :
+#ifndef NOFLOAT
+ expr->ex_class == Float ? "Float" :
+#endif NOFLOAT
+ expr->ex_class == Oper ? "Oper" :
+ expr->ex_class == Type ? "Type" : "UNKNOWN CLASS"
+ );
+ switch (expr->ex_class) {
+ struct oper *o;
+ case Value:
+ switch (expr->VL_CLASS) {
+ case Const:
+ print("(Const) ");
+ break;
+ case Name:
+ print("(Name) %s + ", expr->VL_IDF->id_text);
+ break;
+ case Label:
+ print("(Label) .%lu + ", expr->VL_LBL);
+ break;
+ default:
+ print("(Unknown) ");
+ break;
+ }
+ print(expr->ex_type->tp_unsigned ? "%lu\n" : "%ld\n",
+ expr->VL_VALUE);
+ break;
+ case String:
+ {
+ char *bts2str();
+
+ print(
+ "\"%s\"\n",
+ bts2str(expr->SG_VALUE, expr->SG_LEN-1,
+ next_transient())
+ );
+ break;
+ }
+#ifndef NOFLOAT
+ case Float:
+ print("%s\n", expr->FL_VALUE);
+ break;
+#endif NOFLOAT
+ case Oper:
+ o = &expr->ex_object.ex_oper;
+ print("\n");
+ p1_expr(lvl+1, o->op_left);
+ p1_indent(lvl);
+ print("%s <%s>\n", symbol2str(o->op_oper),
+ type2str(o->op_type)
+ );
+ p1_expr(lvl+1, o->op_right);
+ break;
+ case Type:
+ print("\n");
+ break;
+ default:
+ print("UNKNOWN CLASS\n");
+ break;
+ }
+}
+
+p1_indent(lvl)
+ register int lvl;
+{
+ while (lvl--)
+ print(" ");
+}
+#endif DEBUG
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* E R R O R A N D D I A G N O S T I C R O U T I N E S */
+
+#include <varargs.h>
+#include <system.h>
+#include <em.h>
+
+#include "lint.h"
+#include "nopp.h"
+#include "errout.h"
+#include "debug.h"
+
+#include "tokenname.h"
+#include "arith.h"
+#include "label.h"
+#include "expr.h"
+#include "def.h"
+#include "LLlex.h"
+
+/* This file contains the error-message and diagnostic
+ functions. Beware, they are called with a variable number of
+ arguments!
+*/
+
+/* error classes */
+#define STRICT 1
+#define WARNING 2
+#define ERROR 3
+#define CRASH 4
+#define FATAL 5
+
+int err_occurred = 0;
+
+extern char options[];
+#ifdef LINT
+extern char loptions[];
+#endif LINT
+
+/* There are three general error-message functions:
+ lexerror() lexical and pre-processor error messages
+ error() syntactic and semantic error messages
+ expr_error() errors in expressions
+ The difference lies in the place where the file name and line
+ number come from.
+ Lexical errors report from the global variables LineNumber and
+ FileName, expression errors get their information from the
+ expression, whereas other errors use the information in the token.
+*/
+
+static _error();
+
+/*VARARGS*/
+error(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ _error(ERROR, dot.tk_file, dot.tk_line, ap);
+ }
+ va_end(ap);
+}
+
+/*VARARGS*/
+expr_error(va_alist) /* expr, fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ register struct expr *expr = va_arg(ap, struct expr *);
+
+ if (!(expr->ex_flags & EX_ERROR)) {
+ /* to prevent proliferation */
+ _error(ERROR, expr->ex_file, expr->ex_line, ap);
+ expr->ex_flags |= EX_ERROR;
+ }
+ }
+ va_end(ap);
+}
+
+/*VARARGS*/
+strict(va_alist)
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ _error(STRICT, FileName, LineNumber, ap);
+ }
+ va_end(ap);
+}
+
+/*VARARGS*/
+warning(va_alist)
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ _error(WARNING, NILEXPR, ap);
+ }
+ va_end(ap);
+}
+
+/*VARARGS*/
+expr_warning(va_alist) /* expr, fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ struct expr *expr = va_arg(ap, struct expr *);
+
+ if (!(expr->ex_flags & EX_ERROR)) {
+ /* to prevent proliferation */
+ _error(WARNING, expr->ex_file, expr->ex_line, ap);
+ }
+ }
+ va_end(ap);
+}
+
+#ifdef LINT
+
+/*VARARGS*/
+def_warning(va_alist) /* def, fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ register struct def *def = va_arg(ap, struct def *);
+
+ _error(WARNING, def->df_file, def->df_line, ap);
+ }
+ va_end(ap);
+}
+
+
+/*VARARGS*/
+hwarning(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ if (loptions['h'])
+ _error(WARNING, dot.tk_file, dot.tk_line, ap);
+ }
+ va_end(ap);
+}
+
+/*VARARGS*/
+awarning(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ if (loptions['a'])
+ _error(WARNING, dot.tk_file, dot.tk_line, ap);
+ }
+ va_end(ap);
+}
+
+#endif LINT
+
+/*VARARGS*/
+lexerror(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ _error(ERROR, FileName, LineNumber, ap);
+ }
+ va_end(ap);
+}
+
+#ifndef NOPP
+/*VARARGS*/
+lexwarning(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ _error(WARNING, FileName, LineNumber, ap);
+ }
+ va_end(ap);
+}
+#endif NOPP
+
+/*VARARGS*/
+crash(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ _error(CRASH, FileName, LineNumber, ap);
+ }
+ va_end(ap);
+
+ C_close();
+#ifdef DEBUG
+ sys_stop(S_ABORT);
+#else DEBUG
+ sys_stop(S_EXIT);
+#endif DEBUG
+ /* NOTREACHED */
+}
+
+/*VARARGS*/
+fatal(va_alist) /* fmt, args */
+ va_dcl
+{
+ va_list ap;
+
+ va_start(ap);
+ {
+ _error(FATAL, FileName, LineNumber, ap);
+ }
+ va_end(ap);
+
+ if (C_busy()) C_close();
+ sys_stop(S_EXIT);
+ /*NOTREACHED*/
+}
+
+static
+_error(class, fn, ln, ap)
+ int class;
+ char *fn;
+ unsigned int ln;
+ va_list ap;
+{
+ /* _error attempts to limit the number of error messages
+ for a given line to MAXERR_LINE.
+ */
+#ifndef LINT
+ static char *last_fn = 0;
+ static unsigned int last_ln = 0;
+ static int e_seen = 0;
+#endif LINT
+ char *remark;
+ char *fmt = va_arg(ap, char *);
+
+ /* Since name and number are gathered from different places
+ depending on the class, we first collect the relevant
+ values and then decide what to print.
+ */
+ /* preliminaries */
+ switch (class) {
+ case WARNING:
+ if (options['w'])
+ return;
+ break;
+
+ case STRICT:
+ if (options['s'])
+ return;
+ break;
+
+ case ERROR:
+ case CRASH:
+ case FATAL:
+ if (C_busy())
+ C_ms_err();
+ err_occurred = 1;
+ break;
+ }
+
+ /* the remark */
+ switch (class) {
+ case STRICT:
+ remark = "(strict)";
+ break;
+ case WARNING:
+#ifndef LINT
+ remark = "(warning)";
+#else LINT
+ remark = 0;
+#endif LINT
+ break;
+
+ case ERROR:
+ remark = 0;
+ break;
+
+ case CRASH:
+ remark = "CRASH\007";
+ break;
+
+ case FATAL:
+ remark = "fatal error --";
+ break;
+ default:
+ /*NOTREACHED*/;
+ }
+
+#ifndef LINT
+ if (ln == last_ln && fn && last_fn && strcmp(fn, last_fn) == 0) {
+ /* we've seen this place before */
+ e_seen++;
+ if (e_seen == MAXERR_LINE)
+ fmt = "etc ...";
+ else
+ if (e_seen > MAXERR_LINE)
+ /* and too often, I'd say ! */
+ return;
+ }
+ else {
+ /* brand new place */
+ last_fn = fn;
+ last_ln = ln;
+ e_seen = 0;
+ }
+#endif LINT
+
+#ifdef LINT
+ if ( /* there is a file name */
+ fn
+ && /* the file name is global */
+ fn[0] == '/'
+ && /* it is not a .c file */
+ strcmp(&fn[strlen(fn)-2], ".c") != 0
+ ) {
+ /* we skip this message */
+ return;
+ }
+#endif LINT
+
+ if (fn)
+ fprint(ERROUT, "\"%s\", line %u: ", fn, ln);
+ if (remark)
+ fprint(ERROUT, "%s ", remark);
+ doprnt(ERROUT, fmt, ap); /* contents of error */
+ fprint(ERROUT, "\n");
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EXPRESSION STACK */
+/* Used for global initializations */
+struct e_stack {
+ struct e_stack *next;
+ arith s_cnt1, s_cnt2;
+ struct sdef *s_def;
+ struct type **s_tpp;
+ char s_nested;
+};
+
+/* ALLOCDEF "e_stack" 5 */
+
+#define bytes_upto_here s_cnt1
+#define last_offset s_cnt2
+#define elem_count s_cnt1
+#define nelem s_cnt2
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EXPRESSION-CODE GENERATOR */
+
+#include "lint.h"
+#ifndef LINT
+
+#include "nofloat.h"
+#include <em.h>
+#include <em_reg.h>
+#include "debug.h"
+#include "nobitfield.h"
+#include "dataflow.h"
+#include "arith.h"
+#include "type.h"
+#include "idf.h"
+#include "label.h"
+#include "code.h"
+#include "assert.h"
+#include "def.h"
+#include "expr.h"
+#include "sizes.h"
+#include "Lpars.h"
+#include "level.h"
+#include "stack.h"
+#include "align.h"
+#include "mes.h"
+#include "atw.h"
+#include "specials.h"
+
+#define CRASH() crash("EVAL: CRASH at line %u", __LINE__)
+
+char *symbol2str();
+char *long2str();
+arith NewLocal(); /* util.c */
+#define LocalPtrVar() NewLocal(pointer_size, pointer_align, reg_pointer, REGISTER)
+
+/* EVAL() is the main expression-tree evaluator, which turns
+ any legal expression tree into EM code. Parameters:
+
+ struct expr *expr
+ pointer to root of the expression tree to be evaluated
+
+ int val
+ indicates whether the resulting expression is to be
+ dereferenced (if val == RVAL and expr->ex_lvalue == 1)
+ or not (val == LVAL). The latter case indicates that
+ the resulting expression is an lvalue expression which
+ should not be dereferenced by EVAL
+
+ int code
+ indicates whether the expression tree must be turned
+ into EM code or not. E.g. the expression statement "12;"
+ delivers the expression "12" to EVAL while this should
+ not result in any EM code
+
+ label false_label, label true_label
+ if the expression is a logical or relational expression
+ and if the loop of the program depends on the resulting
+ value then EVAL generates jumps to the specified program
+ labels, in case they are specified (i.e. are non-zero)
+*/
+
+EVAL(expr, val, code, true_label, false_label)
+ register struct expr *expr;
+ int val, code;
+ label true_label, false_label;
+{
+ register int gencode = (code == TRUE);
+
+ switch (expr->ex_class) {
+ case Value: /* just a simple value */
+ if (gencode)
+ load_val(expr, val);
+ break;
+ case String: /* a string constant */
+ if (gencode) {
+ string2pointer(expr);
+ C_lae_dlb(expr->VL_LBL, expr->VL_VALUE);
+ }
+ break;
+#ifndef NOFLOAT
+ case Float: /* a floating constant */
+ if (gencode) {
+ label datlab = data_label();
+
+ C_df_dlb(datlab);
+ C_rom_fcon(expr->FL_VALUE, expr->ex_type->tp_size);
+ C_lae_dlb(datlab, (arith)0);
+ C_loi(expr->ex_type->tp_size);
+ }
+ break;
+#endif NOFLOAT
+ case Oper: /* compound expression */
+ {
+ int oper = expr->OP_OPER;
+ register struct expr *left = expr->OP_LEFT;
+ register struct expr *right = expr->OP_RIGHT;
+ register struct type *tp = expr->OP_TYPE;
+
+ if (tp->tp_fund == ERRONEOUS || (expr->ex_flags & EX_ERROR)) {
+ /* stop immediately */
+ break;
+ }
+ if (tp->tp_fund == VOID)
+ gencode = 0;
+ switch (oper) {
+ case '+':
+ /* We have the following possibilities :
+ int + int, pointer + int, pointer + long,
+ long + long, double + double
+ */
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode) {
+ switch (tp->tp_fund) {
+ case INT:
+ case LONG:
+ if (tp->tp_unsigned)
+ C_adu(tp->tp_size);
+ else
+ C_adi(tp->tp_size);
+ break;
+ case POINTER:
+ C_loc(right->ex_type->tp_size);
+ C_loc(pointer_size);
+ C_cuu();
+ C_ads(pointer_size);
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+ C_adf(tp->tp_size);
+ break;
+#endif NOFLOAT
+ default:
+ crash("bad type +");
+ }
+ }
+ break;
+ case '-':
+ if (left == 0) { /* unary */
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode) {
+ switch (tp->tp_fund) {
+ case INT:
+ case LONG:
+ case POINTER:
+ C_ngi(tp->tp_size);
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+ C_ngf(tp->tp_size);
+ break;
+#endif NOFLOAT
+ default:
+ CRASH();
+ }
+ }
+ break;
+ }
+ /* else binary; we have the following flavours:
+ int - int, pointer - int, pointer - long,
+ pointer - pointer, long - long, double - double
+ */
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (!gencode)
+ break;
+ switch (tp->tp_fund) {
+ case INT:
+ case LONG:
+ if (tp->tp_unsigned)
+ C_sbu(tp->tp_size);
+ else
+ C_sbi(tp->tp_size);
+ break;
+ case POINTER:
+ if (right->ex_type->tp_fund == POINTER)
+ C_sbs(pointer_size);
+ else {
+ C_ngi(right->ex_type->tp_size);
+ C_loc(right->ex_type->tp_size);
+ C_loc(pointer_size);
+ C_cuu();
+ C_ads(pointer_size);
+ }
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+ C_sbf(tp->tp_size);
+ break;
+#endif NOFLOAT
+ default:
+ crash("bad type -");
+ }
+ break;
+ case '*':
+ if (left == 0) { /* unary */
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode && right->ex_class == String) {
+ C_loi((arith)1);
+ }
+ }
+ else { /* binary */
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode)
+ switch (tp->tp_fund) {
+ case INT:
+ case LONG:
+ case POINTER:
+ if (tp->tp_unsigned)
+ C_mlu(tp->tp_size);
+ else
+ C_mli(tp->tp_size);
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+ /*C_mlf(double_size);*/
+ C_mlf(tp->tp_size);
+ break;
+#endif NOFLOAT
+ default:
+ crash("bad type *");
+ }
+ }
+ break;
+ case '/':
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode)
+ switch (tp->tp_fund) {
+ case INT:
+ case LONG:
+ case POINTER:
+ if (tp->tp_unsigned)
+ C_dvu(tp->tp_size);
+ else
+ C_dvi(tp->tp_size);
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+ /*C_dvf(double_size);*/
+ C_dvf(tp->tp_size);
+ break;
+#endif NOFLOAT
+ default:
+ crash("bad type /");
+ }
+ break;
+ case '%':
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ ASSERT(tp->tp_fund==INT || tp->tp_fund==LONG);
+ if (gencode)
+ if (tp->tp_unsigned)
+ C_rmu(tp->tp_size);
+ else
+ C_rmi(tp->tp_size);
+ break;
+ case LEFT:
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode)
+ if (tp->tp_unsigned)
+ C_slu(tp->tp_size);
+ else
+ C_sli(tp->tp_size);
+ break;
+ case RIGHT:
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode)
+ if (tp->tp_unsigned)
+ C_sru(tp->tp_size);
+ else
+ C_sri(tp->tp_size);
+ break;
+ case '<':
+ case LESSEQ:
+ case '>':
+ case GREATEREQ:
+ case EQUAL:
+ case NOTEQUAL:
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode) {
+ /* The operands have the same type */
+ arith size = left->ex_type->tp_size;
+
+ switch (tp->tp_fund) {
+ case INT:
+ case LONG:
+ if (left->ex_type->tp_unsigned)
+ C_cmu(size);
+ else
+ C_cmi(size);
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+ C_cmf(size);
+ break;
+#endif NOFLOAT
+ case POINTER:
+ C_cmp();
+ break;
+ case ENUM:
+ C_cmi(size);
+ break;
+ default:
+ CRASH();
+ }
+ if (true_label != 0) {
+ compare(oper, true_label);
+ C_bra(false_label);
+ }
+ else {
+ truthvalue(oper);
+ }
+ }
+ break;
+ case '&':
+ case '|':
+ case '^':
+ /* both operands should have type int */
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode) {
+ arith size = tp->tp_size;
+
+ if ((int)size < (int)word_size)
+ size = word_size;
+ switch (oper) {
+ case '&':
+ C_and(size);
+ break;
+ case '|':
+ C_ior(size);
+ break;
+ case '^':
+ C_xor(size);
+ break;
+ }
+ }
+ break;
+ case '=': {
+ int newcode = tp->tp_size > 0; /* CJ */
+#ifndef NOBITFIELD
+ if (left->ex_type->tp_fund == FIELD) {
+ eval_field(expr, gencode);
+ break;
+ }
+#endif NOBITFIELD
+ EVAL(right, RVAL, newcode, NO_LABEL, NO_LABEL);
+ if (gencode)
+ C_dup(ATW(tp->tp_size));
+ if (left->ex_class != Value) {
+ EVAL(left, LVAL, newcode, NO_LABEL, NO_LABEL);
+ if (newcode)
+ store_block(tp->tp_size, tp->tp_align);
+ }
+ else if (newcode)
+ store_val(&(left->EX_VALUE), left->ex_type);
+ }
+ break;
+ case PLUSAB:
+ case MINAB:
+ case TIMESAB:
+ case DIVAB:
+ case MODAB:
+ case LEFTAB:
+ case RIGHTAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ case POSTINCR:
+ case POSTDECR:
+ case PLUSPLUS:
+ case MINMIN:
+ {
+ arith tmp;
+ int compl; /* Complexity of left operand */
+ int newcode = left->ex_type->tp_size > 0; /* CJ */
+#ifndef NOBITFIELD
+ if (left->ex_type->tp_fund == FIELD) {
+ eval_field(expr, gencode);
+ break;
+ }
+#endif NOBITFIELD
+ if (newcode && left->ex_class == Value) {
+ compl = 0; /* Value */
+ load_val(left, RVAL);
+ }
+ else
+ if (left->ex_depth == 1 &&
+ !(left->ex_flags & EX_SIDEEFFECTS)) {
+ compl = 1;
+ EVAL(left, RVAL, newcode, NO_LABEL, NO_LABEL);
+ }
+ else {
+ compl = 2; /* otherwise */
+ EVAL(left, LVAL, newcode, NO_LABEL, NO_LABEL);
+ if (newcode) {
+ tmp = LocalPtrVar();
+ C_dup(pointer_size);
+ StoreLocal(tmp, pointer_size);
+ C_loi(left->ex_type->tp_size);
+ }
+ }
+ if (newcode) {
+ if (gencode && (oper == POSTINCR ||
+ oper == POSTDECR))
+ C_dup(ATW(left->ex_type->tp_size));
+ conversion(left->ex_type, tp);
+ }
+ EVAL(right, RVAL, newcode, NO_LABEL, NO_LABEL);
+ if (newcode) {
+ int dupval = gencode && oper != POSTINCR &&
+ oper != POSTDECR;
+ assop(tp, oper);
+ conversion(tp, left->ex_type);
+ if (compl == 0) {
+ store_val(&(left->EX_VALUE),
+ left->ex_type);
+ if (dupval) load_val(left, RVAL);
+ }
+ else if (compl == 1) {
+ EVAL(left, LVAL,1, NO_LABEL, NO_LABEL);
+ C_sti(left->ex_type->tp_size);
+ if (dupval) {
+ EVAL(left, LVAL, 1, NO_LABEL,
+ NO_LABEL);
+ C_loi(left->ex_type->tp_size);
+ }
+ }
+ else {
+ LoadLocal(tmp, pointer_size);
+ C_sti(left->ex_type->tp_size);
+ if (dupval) {
+ LoadLocal(tmp, pointer_size);
+ C_loi(left->ex_type->tp_size);
+ }
+ FreeLocal(tmp);
+ }
+ }
+ break;
+ }
+ case '(':
+ {
+ register struct expr *ex;
+ arith ParSize = (arith)0;
+ label setjmp_label = 0;
+
+ if (ISNAME(left)) {
+ if (left->VL_IDF->id_special == SP_SETJMP) {
+ label addr_label = data_label();
+
+ setjmp_label = text_label();
+ C_df_dlb(addr_label);
+ C_rom_ilb(setjmp_label);
+ C_lae_dlb(addr_label, (arith) 0);
+ C_loi(pointer_size);
+ ParSize += pointer_size;
+ }
+ }
+ if ((ex = right) != NILEXPR) {
+ /* function call with parameters*/
+ while ( ex->ex_class == Oper &&
+ ex->OP_OPER == PARCOMMA
+ ) {
+ EVAL(ex->OP_RIGHT, RVAL,
+ ex->ex_type->tp_size > 0,
+ NO_LABEL, NO_LABEL);
+ ParSize += ATW(ex->ex_type->tp_size);
+ ex = ex->OP_LEFT;
+ }
+ EVAL(ex, RVAL, ex->ex_type->tp_size > 0,
+ NO_LABEL, NO_LABEL);
+ ParSize += ATW(ex->ex_type->tp_size);
+ }
+ if (ISNAME(left)) {
+ /* e.g., main() { (*((int (*)())0))(); } */
+ C_cal(left->VL_IDF->id_text);
+ if (setjmp_label) {
+ C_df_ilb(setjmp_label);
+ }
+#ifdef DATAFLOW
+ { extern char options[];
+ if (options['d'])
+ DfaCallFunction(
+ left->VL_IDF->id_text);
+ }
+#endif DATAFLOW
+ }
+ else {
+ EVAL(left, LVAL, TRUE, NO_LABEL, NO_LABEL);
+ C_cai();
+ }
+ /* remove parameters from stack */
+ if (ParSize > (arith)0)
+ C_asp(ParSize);
+ if (gencode) {
+ if (is_struct_or_union(tp->tp_fund)) {
+ C_lfr(pointer_size);
+ load_block(tp->tp_size, (int) word_size);
+ }
+ else
+ C_lfr(ATW(tp->tp_size));
+ }
+ break;
+ }
+ case '.':
+ EVAL(left, LVAL, gencode, NO_LABEL, NO_LABEL);
+ ASSERT(is_cp_cst(right));
+ if (gencode)
+ C_adp(right->VL_VALUE);
+ break;
+ case ARROW:
+ EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
+ ASSERT(is_cp_cst(right));
+ if (gencode)
+ C_adp(right->VL_VALUE);
+ break;
+ case ',':
+ EVAL(left, RVAL, FALSE, NO_LABEL, NO_LABEL);
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ break;
+ case '~':
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode)
+ C_com(tp->tp_size);
+ break;
+ case '?': /* must be followed by ':' */
+ {
+ label l_true = text_label();
+ label l_false = text_label();
+ label l_end = text_label();
+
+ EVAL(left, RVAL, TRUE, l_true, l_false);
+ C_df_ilb(l_true);
+ EVAL(right->OP_LEFT, RVAL, gencode, NO_LABEL, NO_LABEL);
+ C_bra(l_end);
+ C_df_ilb(l_false);
+ EVAL(right->OP_RIGHT, RVAL, gencode, NO_LABEL, NO_LABEL);
+ C_df_ilb(l_end);
+ break;
+ }
+ case OR:
+ case AND: {
+ label l_false, l_true, l_maybe;
+
+ l_maybe = text_label();
+ if (true_label) {
+ l_false = false_label;
+ l_true = true_label;
+ }
+ else {
+ l_false = text_label();
+ l_true = gencode ? text_label(): l_false;
+ }
+
+ EVAL(left, RVAL, TRUE, oper == AND ? l_maybe : l_true,
+ oper == AND ? l_false : l_maybe);
+ C_df_ilb(l_maybe);
+ EVAL(right, RVAL, gencode, l_true, l_false);
+ if (gencode && !true_label) {
+ label l_end = text_label();
+
+ C_df_ilb(l_true);
+ C_loc((arith)1);
+ C_bra(l_end);
+ C_df_ilb(l_false);
+ C_loc((arith)0);
+ C_df_ilb(l_end);
+ }
+ else {
+ if (! true_label) C_df_ilb(l_false);
+ }
+ }
+ break;
+ case '!':
+ if (true_label == 0) {
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode) {
+ C_teq();
+ }
+ }
+ else
+ EVAL(right, RVAL, gencode, false_label,
+ true_label);
+ break;
+ case INT2INT:
+#ifndef NOFLOAT
+ case INT2FLOAT:
+ case FLOAT2INT:
+ case FLOAT2FLOAT:
+#endif NOFLOAT
+ EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
+ if (gencode)
+ conversion(right->ex_type, left->ex_type);
+ break;
+ default:
+ crash("(EVAL) bad operator %s\n", symbol2str(oper));
+ }
+ /* If the rvalue of the expression is required but
+ only its lvalue is evaluated, its rvalue is
+ loaded by the following statements:
+ */
+ if (gencode && val == RVAL && expr->ex_lvalue == 1)
+ load_block(expr->ex_type->tp_size,
+ expr->ex_type->tp_align);
+ break;
+ }
+ default:
+ crash("(EVAL) bad expression class");
+ }
+}
+
+/* compare() serves as an auxiliary function of EVAL */
+compare(relop, lbl)
+ int relop;
+ label lbl;
+{
+ switch (relop) {
+ case '<':
+ C_zlt(lbl);
+ break;
+ case LESSEQ:
+ C_zle(lbl);
+ break;
+ case '>':
+ C_zgt(lbl);
+ break;
+ case GREATEREQ:
+ C_zge(lbl);
+ break;
+ case EQUAL:
+ C_zeq(lbl);
+ break;
+ case NOTEQUAL:
+ C_zne(lbl);
+ break;
+ default:
+ CRASH();
+ }
+}
+
+/* truthvalue() serves as an auxiliary function of EVAL */
+truthvalue(relop)
+ int relop;
+{
+ switch (relop) {
+ case '<':
+ C_tlt();
+ break;
+ case LESSEQ:
+ C_tle();
+ break;
+ case '>':
+ C_tgt();
+ break;
+ case GREATEREQ:
+ C_tge();
+ break;
+ case EQUAL:
+ C_teq();
+ break;
+ case NOTEQUAL:
+ C_tne();
+ break;
+ default:
+ CRASH();
+ }
+}
+
+
+/* assop() generates the opcode of an assignment operators op= */
+assop(type, oper)
+ register struct type *type;
+ int oper;
+{
+ register arith size;
+ register uns = type->tp_unsigned;
+
+ if ((int)(size = type->tp_size) < (int)word_size)
+ size = word_size;
+ switch (type->tp_fund) {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case LONG:
+ case ENUM:
+ switch (oper) {
+ case PLUSAB:
+ case PLUSPLUS:
+ case POSTINCR:
+ if (uns)
+ C_adu(size);
+ else
+ C_adi(size);
+ break;
+ case MINAB:
+ case MINMIN:
+ case POSTDECR:
+ if (uns)
+ C_sbu(size);
+ else
+ C_sbi(size);
+ break;
+ case TIMESAB:
+ if (uns)
+ C_mlu(size);
+ else
+ C_mli(size);
+ break;
+ case DIVAB:
+ if (uns)
+ C_dvu(size);
+ else
+ C_dvi(size);
+ break;
+ case MODAB:
+ if (uns)
+ C_rmu(size);
+ else
+ C_rmi(size);
+ break;
+ case LEFTAB:
+ if (uns)
+ C_slu(size);
+ else
+ C_sli(size);
+ break;
+ case RIGHTAB:
+ if (uns)
+ C_sru(size);
+ else
+ C_sri(size);
+ break;
+ case ANDAB:
+ C_and(size);
+ break;
+ case XORAB:
+ C_xor(size);
+ break;
+ case ORAB:
+ C_ior(size);
+ break;
+ }
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ case LNGDBL:
+ switch (oper) {
+ case PLUSAB:
+ case PLUSPLUS:
+ case POSTINCR:
+ C_adf(size);
+ break;
+ case MINAB:
+ case MINMIN:
+ case POSTDECR:
+ C_sbf(size);
+ break;
+ case TIMESAB:
+ C_mlf(size);
+ break;
+ case DIVAB:
+ C_dvf(size);
+ break;
+ }
+ break;
+#endif NOFLOAT
+ case POINTER:
+ if (oper == MINAB || oper == MINMIN || oper == POSTDECR)
+ C_ngi(size);
+ C_loc(size);
+ C_loc(pointer_size);
+ C_cuu();
+ C_ads(pointer_size);
+ break;
+ case ERRONEOUS:
+ break;
+ default:
+ crash("(assop) bad type %s\n", symbol2str(type->tp_fund));
+ }
+}
+
+/* store_val() generates code for a store operation.
+ There are four ways of storing data:
+ - into a global variable
+ - into an automatic local variable
+ - into a local static variable
+ - absolute addressing
+*/
+store_val(vl, tp)
+ register struct value *vl;
+ struct type *tp;
+{
+ arith size = tp->tp_size;
+ int tpalign = tp->tp_align;
+ int al_on_word;
+ register int inword;
+ register int indword;
+ arith val = vl->vl_value;
+
+ if (vl->vl_class == Const) { /* absolute addressing */
+ load_cst(val, pointer_size);
+ store_block(size, tpalign);
+ return;
+ }
+ al_on_word = (tpalign % word_align == 0);
+ if (!(inword = (size == word_size && al_on_word)))
+ indword = (size == dword_size && al_on_word);
+ if (vl->vl_class == Name) {
+ register struct idf *id = vl->vl_data.vl_idf;
+ register struct def *df = id->id_def;
+
+ if (df->df_level == L_GLOBAL) {
+ if (inword)
+ C_ste_dnam(id->id_text, val);
+ else
+ if (indword)
+ C_sde_dnam(id->id_text, val);
+ else {
+ C_lae_dnam(id->id_text, val);
+ store_block(size, tpalign);
+ }
+ }
+ else {
+ ASSERT(df->df_sc != STATIC);
+ if (inword || indword)
+ StoreLocal(df->df_address + val, size);
+ else {
+ AddrLocal(df->df_address + val);
+ store_block(size, tpalign);
+ }
+ }
+ }
+ else {
+ label dlb = vl->vl_data.vl_lbl;
+
+ ASSERT(vl->vl_class == Label);
+ if (inword)
+ C_ste_dlb(dlb, val);
+ else
+ if (indword)
+ C_sde_dlb(dlb, val);
+ else {
+ C_lae_dlb(dlb, val);
+ store_block(size, tpalign);
+ }
+ }
+}
+
+
+/* load_val() generates code for stacking a certain value (from ex),
+ which can be obtained in one of the following ways:
+ - value from absolute addressed memory
+ - constant value
+ - function result
+ - global variable
+ - static variable
+ - local variable
+*/
+load_val(expr, rlval)
+ register struct expr *expr; /* expression containing the value */
+ int rlval; /* generate either LVAL or RVAL */
+{
+ register struct type *tp = expr->ex_type;
+ int rvalue = (rlval == RVAL && expr->ex_lvalue != 0);
+ arith size = tp->tp_size;
+ int tpalign = tp->tp_align;
+ int al_on_word;
+ register int inword, indword;
+ register arith val = expr->VL_VALUE;
+
+ if (expr->VL_CLASS == Const) {
+ if (rvalue) { /* absolute addressing */
+ load_cst(val, pointer_size);
+ load_block(size, tpalign);
+ }
+ else /* integer, unsigned, long, enum etc */
+ load_cst(val, size);
+ return;
+ }
+ if (rvalue) {
+ al_on_word = (tpalign % word_align == 0);
+ if (!(inword = (size == word_size && al_on_word)))
+ indword = (size == dword_size && al_on_word);
+ }
+ if (expr->VL_CLASS == Label) {
+ if (rvalue) {
+ if (inword)
+ C_loe_dlb(expr->VL_LBL, val);
+ else
+ if (indword)
+ C_lde_dlb(expr->VL_LBL, val);
+ else {
+ C_lae_dlb(expr->VL_LBL, val);
+ load_block(size, tpalign);
+ }
+
+ }
+ else {
+ C_lae_dlb(expr->VL_LBL, (arith)0);
+ C_adp(val);
+ }
+ }
+ else {
+ register struct idf *id = expr->VL_IDF;
+ register struct def *df = id->id_def;
+
+ ASSERT(ISNAME(expr));
+ if (df->df_type->tp_fund == FUNCTION) {
+ /* the previous statement tried to catch a function
+ identifier, which may be cast to a pointer to a
+ function.
+ ASSERT(!(rvalue)); ???
+ */
+ C_lpi(id->id_text);
+ }
+ else
+ if (df->df_level == L_GLOBAL) {
+ if (rvalue) {
+ if (inword)
+ C_loe_dnam(id->id_text, val);
+ else
+ if (indword)
+ C_lde_dnam(id->id_text, val);
+ else {
+ C_lae_dnam(id->id_text, val);
+ load_block(size, tpalign);
+ }
+ }
+ else {
+ C_lae_dnam(id->id_text, (arith)0);
+ C_adp(val);
+ }
+ }
+ else {
+ ASSERT(df->df_sc != STATIC);
+ if (rvalue) {
+ if (inword || indword)
+ LoadLocal(df->df_address + val, size);
+ else {
+ AddrLocal(df->df_address + val);
+ load_block(size, tpalign);
+ }
+ }
+ else {
+ AddrLocal(df->df_address);
+ C_adp(val);
+ }
+ }
+ }
+}
+
+load_cst(val, siz)
+ arith val, siz;
+{
+ if (siz <= word_size)
+ C_loc(val);
+ else
+ if (siz == dword_size)
+ C_ldc(val);
+ else {
+ label datlab;
+
+ C_df_dlb(datlab = data_label());
+ C_rom_icon(long2str((long)val, 10), siz);
+ C_lae_dlb(datlab, (arith)0);
+ C_loi(siz);
+ }
+}
+
+#endif LINT
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EXPRESSION TREE HANDLING */
+
+#include "lint.h"
+#include "nofloat.h"
+#include "botch_free.h"
+#include <alloc.h>
+#include "idf.h"
+#include "arith.h"
+#include "def.h"
+#include "type.h"
+#include "label.h"
+#include "expr.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "decspecs.h"
+#include "declar.h"
+#include "sizes.h"
+#include "level.h"
+#include "noRoption.h"
+
+extern char *symbol2str();
+extern char options[];
+
+int
+rank_of(oper)
+ int oper;
+{
+ /* The rank of the operator oper is returned.
+ */
+ switch (oper) {
+ default:
+ return 0; /* INT2INT etc. */
+ case '[':
+ case '(':
+ case '.':
+ case ARROW:
+ case PARCOMMA:
+ return 1;
+ case '!':
+ case PLUSPLUS:
+ case MINMIN:
+ case CAST:
+ case SIZEOF:
+ return 2; /* monadic */
+ case '*':
+ case '/':
+ case '%':
+ return 3;
+ case '+':
+ case '-':
+ return 4;
+ case LEFT:
+ case RIGHT:
+ return 5;
+ case '<':
+ case '>':
+ case LESSEQ:
+ case GREATEREQ:
+ return 6;
+ case EQUAL:
+ case NOTEQUAL:
+ return 7;
+ case '&':
+ return 8;
+ case '^':
+ return 9;
+ case '|':
+ return 10;
+ case AND:
+ return 11;
+ case OR:
+ return 12;
+ case '?':
+ case ':':
+ return 13;
+ case '=':
+ case PLUSAB:
+ case MINAB:
+ case TIMESAB:
+ case DIVAB:
+ case MODAB:
+ case RIGHTAB:
+ case LEFTAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ return 14;
+ case ',':
+ return 15;
+ }
+ /*NOTREACHED*/
+}
+
+#ifndef NOROPTION
+int
+rank_of_expression(ex)
+ register struct expr *ex;
+{
+ /* Returns the rank of the top node in the expression.
+ */
+ if (!ex || (ex->ex_flags & EX_PARENS) || ex->ex_class != Oper)
+ return 0;
+ return rank_of(ex->OP_OPER);
+}
+
+check_conditional(expr, oper, pos_descr)
+ register struct expr *expr;
+ char *pos_descr;
+{
+ /* Warn if restricted C is in effect and the expression expr,
+ which occurs at the position pos_descr, is not lighter than
+ the operator oper.
+ */
+ if (options['R'] && rank_of_expression(expr) >= rank_of(oper))
+ expr_warning(expr, "%s %s is ungrammatical",
+ symbol2str(expr->OP_OPER), pos_descr);
+}
+#endif
+
+dot2expr(expp)
+ struct expr **expp;
+{
+ /* The token in dot is converted into an expression, a
+ pointer to which is stored in *expp.
+ */
+ register struct expr *ex = new_expr();
+
+ *expp = ex;
+ ex->ex_file = dot.tk_file;
+ ex->ex_line = dot.tk_line;
+ switch (DOT) {
+ case IDENTIFIER:
+ idf2expr(ex);
+ break;
+ case INTEGER:
+ int2expr(ex);
+ break;
+#ifndef NOFLOAT
+ case FLOATING:
+ float2expr(ex);
+ break;
+#endif NOFLOAT
+ default:
+ crash("bad conversion to expression");
+ /*NOTREACHED*/
+ }
+}
+
+idf2expr(expr)
+ register struct expr *expr;
+{
+ /* Dot contains an identifier which is turned into an
+ expression.
+ Note that this constitutes an applied occurrence of
+ the identifier.
+ */
+ register struct idf *idf = dot.tk_idf; /* != 0*/
+ register struct def *def = idf->id_def;
+
+ if (def == 0) {
+ if (AHEAD == '(') /* function call, declare name IMPLICITly */
+ add_def(idf, IMPLICIT, funint_type, level); /* RM 13 */
+ else {
+ if (!is_anon_idf(idf))
+ error("%s undefined", idf->id_text);
+ /* declare idf anyway */
+ add_def(idf, 0, error_type, level);
+ }
+ def = idf->id_def;
+ }
+ /* now def != 0 */
+ if (def->df_type->tp_fund == LABEL) {
+ expr_error(expr, "illegal use of label %s", idf->id_text);
+ expr->ex_type = error_type;
+ }
+ else {
+#ifndef LINT
+ def->df_used = 1;
+#endif LINT
+ expr->ex_type = def->df_type;
+ if (expr->ex_type == error_type)
+ expr->ex_flags |= EX_ERROR;
+ }
+ expr->ex_lvalue =
+ ( def->df_type->tp_fund == FUNCTION ||
+ def->df_type->tp_fund == ARRAY ||
+ def->df_sc == ENUM
+ ) ? 0 : 1;
+ if (def->df_type->tp_typequal & TQ_CONST)
+ expr->ex_flags |= EX_READONLY;
+ if (def->df_type->tp_typequal & TQ_VOLATILE)
+ expr->ex_flags |= EX_VOLATILE;
+ expr->ex_class = Value;
+ if (def->df_sc == ENUM) {
+ expr->VL_CLASS = Const;
+ expr->VL_VALUE = def->df_address;
+ }
+#ifndef LINT
+ else
+ if (def->df_sc == STATIC && def->df_level >= L_LOCAL) {
+ expr->VL_CLASS = Label;
+ expr->VL_LBL = def->df_address;
+ expr->VL_VALUE = (arith)0;
+ }
+#endif LINT
+ else {
+ expr->VL_CLASS = Name;
+ expr->VL_IDF = idf;
+ expr->VL_VALUE = (arith)0;
+ }
+}
+
+string2expr(expp, typ, str, len)
+ register struct expr **expp;
+ int typ, len;
+ char *str;
+{
+ /* The string in the argument is converted into an expression,
+ a pointer to which is stored in *expp.
+ */
+ register struct expr *ex = new_expr();
+
+ *expp = ex;
+ ex->ex_file = dot.tk_file;
+ ex->ex_line = dot.tk_line;
+ ex->ex_type = string_type;
+/*
+ ex->ex_type = qualifier_type(ex->ex_type, TQ_CONST);
+*/
+ ex->ex_flags |= EX_READONLY;
+ ex->ex_lvalue = 0;
+ ex->ex_class = String;
+ ex->SG_VALUE = str;
+ ex->SG_LEN = len;
+ ex->SG_DATLAB = 0;
+}
+
+int2expr(expr)
+ struct expr *expr;
+{
+ /* Dot contains an integer constant which is turned
+ into an expression.
+ */
+ fill_int_expr(expr, dot.tk_ival, dot.tk_fund);
+}
+
+#ifndef NOFLOAT
+float2expr(expr)
+ register struct expr *expr;
+{
+ /* Dot contains a floating point constant which is turned
+ into an expression.
+ */
+ register int fund;
+
+ fund = dot.tk_fund;
+ switch (fund) {
+ case FLOAT:
+ expr->ex_type = float_type;
+ break;
+ case DOUBLE:
+ expr->ex_type = double_type;
+ break;
+ case LNGDBL:
+ expr->ex_type = lngdbl_type;
+ break;
+ default:
+ crash("(float2expr) bad fund %s\n", symbol2str(fund));
+ }
+ expr->ex_class = Float;
+ expr->FL_VALUE = dot.tk_fval;
+ expr->FL_DATLAB = 0;
+}
+#endif NOFLOAT
+
+struct expr*
+intexpr(ivalue, fund)
+ arith ivalue;
+ int fund;
+{
+ /* The value ivalue is turned into an integer expression of
+ the size indicated by fund.
+ */
+ register struct expr *expr = new_expr();
+
+ expr->ex_file = dot.tk_file;
+ expr->ex_line = dot.tk_line;
+ fill_int_expr(expr, ivalue, fund);
+ return expr;
+}
+
+fill_int_expr(ex, ivalue, fund)
+ register struct expr *ex;
+ arith ivalue;
+ int fund;
+{
+ /* Details derived from ivalue and fund are put into the
+ constant integer expression ex.
+ */
+ switch (fund) {
+ case INT:
+ ex->ex_type = int_type;
+ break;
+ case INTEGER:
+ if (ivalue >= 0 && ivalue <= max_int) {
+ ex->ex_type = int_type;
+ break;
+ }
+ /*FALL THROUGH*/
+ case LONG:
+ ex->ex_type =
+ (ivalue & (1L << (8*long_size - 1))) ? ulong_type
+ : long_type;
+ break;
+ case ULONG:
+ ex->ex_type = ulong_type;
+ break;
+ case UNSIGNED:
+ /* We cannot make a test like
+ ivalue <= max_unsigned
+ because, if
+ sizeof(long) == int_size
+ holds, max_unsigned may be a negative long in
+ which case the comparison results in an unexpected
+ answer.
+ */
+ ex->ex_type =
+ (ivalue & ~max_int) ?
+ ( (ivalue & ~max_unsigned) ?
+ ( ivalue & (1L<<(8*long_size-1)) ?
+ ulong_type : long_type
+ ) : uint_type
+ ) : int_type;
+ break;
+ default:
+ crash("(intexpr) bad fund %s\n", symbol2str(fund));
+ /*NOTREACHED*/
+ }
+ ex->ex_class = Value;
+ ex->VL_CLASS = Const;
+ ex->VL_VALUE = ivalue;
+ cut_size(ex);
+}
+
+struct expr *
+new_oper(tp, e1, oper, e2)
+ struct type *tp;
+ register struct expr *e1, *e2;
+{
+ /* A new expression is constructed which consists of the
+ operator oper which has e1 and e2 as operands; for a
+ monadic operator e1 == NILEXPR.
+ During the construction of the right recursive initialisation
+ tree it is possible for e2 to be NILEXPR.
+ */
+ register struct expr *expr = new_expr();
+ register struct oper *op;
+
+ if (e2) {
+ register struct expr *e = e2;
+
+ while (e->ex_class == Oper && e->OP_LEFT)
+ e = e->OP_LEFT;
+ expr->ex_file = e->ex_file;
+ expr->ex_line = e->ex_line;
+ }
+ else
+ if (e1) {
+ register struct expr *e = e1;
+
+ while (e->ex_class == Oper && e->OP_RIGHT)
+ e = e->OP_RIGHT;
+ expr->ex_file = e->ex_file;
+ expr->ex_line = e->ex_line;
+ }
+ else {
+ expr->ex_file = dot.tk_file;
+ expr->ex_line = dot.tk_line;
+ }
+
+ expr->ex_type = tp;
+ expr->ex_class = Oper;
+ /* combine depths and flags of both expressions */
+ if (e2) {
+ int e1_depth = e1 ? e1->ex_depth : 0;
+ int e1_flags = e1 ? e1->ex_flags : 0;
+
+ expr->ex_depth =
+ (e1_depth > e2->ex_depth ? e1_depth : e2->ex_depth) + 1;
+ expr->ex_flags = (e1_flags | e2->ex_flags) & ~EX_PARENS;
+ }
+ op = &expr->ex_object.ex_oper;
+ op->op_type = tp;
+ op->op_oper = oper;
+ op->op_left = e1;
+ op->op_right = e2;
+#ifdef LINT
+ lint_new_oper(expr);
+#endif LINT
+ return expr;
+}
+
+chk_cst_expr(expp)
+ register struct expr **expp;
+{
+ /* The expression expr is checked for constancy.
+
+ There are 6 places where constant expressions occur in C:
+ 1. after #if
+ 2. in a global initialization
+ 3. as size in an array declaration
+ 4. as value in an enum declaration
+ 5. as width in a bit field
+ 6. as case value in a switch
+
+ The constant expression in a global initialization is
+ handled separately (by IVAL()).
+
+ There are various disparate restrictions on each of
+ the others in the various C compilers. I have tried some
+ hypotheses to unify them, but all have failed.
+
+ This routine will give a warning for those operators
+ not allowed by K&R, under the R-option only. The anomalies
+ are cast, logical operators and the expression comma.
+ Special problems (of which there is only one, sizeof in
+ Preprocessor #if) have to be dealt with locally
+
+ Note that according to K&R the negation ! is illegal in
+ constant expressions and is indeed rejected by the
+ Ritchie compiler.
+ */
+ register struct expr *expr = *expp;
+ register int fund = expr->ex_type->tp_fund;
+ register int flags = expr->ex_flags;
+ int err = 0;
+
+#ifdef DEBUG
+ print_expr("constant_expression", expr);
+#endif DEBUG
+ if ( fund != CHAR && fund != SHORT && fund != INT &&
+ fund != ENUM && fund != LONG
+ )
+ expr_error(expr, "non-numerical constant expression"), err++;
+ else
+ if (!is_ld_cst(expr))
+ expr_error(expr, "expression is not constant"), err++;
+#ifndef NOROPTION
+ if (options['R']) {
+ if (flags & EX_CAST)
+ expr_warning(expr, "cast in constant expression");
+ if (flags & EX_LOGICAL)
+ expr_warning(expr,
+ "logical operator in constant expression");
+ if (flags & EX_COMMA)
+ expr_warning(expr,
+ "expression comma in constant expression");
+ }
+#endif NOROPTION
+ if (err)
+ erroneous2int(expp);
+}
+
+init_expression(eppp, expr)
+ register struct expr ***eppp, *expr;
+{
+ /* The expression expr is added to the tree designated
+ indirectly by **eppp.
+ The natural form of a tree representing an
+ initial_value_list is right-recursive, ie. with the
+ left-most comma as main operator. The iterative grammar in
+ expression.g, however, tends to produce a left-recursive
+ tree, ie. one with the right-most comma as its main
+ operator.
+ To produce a right-recursive tree from the iterative
+ grammar, we keep track of the address of the pointer where
+ the next expression must be hooked in.
+ */
+ **eppp = new_oper(void_type, expr, INITCOMMA, NILEXPR);
+ *eppp = &(**eppp)->OP_RIGHT;
+}
+
+int
+is_ld_cst(expr)
+ register struct expr *expr;
+{
+ /* An expression is a `load-time constant' if it is of the form
+ <idf> +/- <integral> or <integral>.
+ */
+#ifdef LINT
+ if (expr->ex_class == String)
+ return 1;
+#endif LINT
+ return expr->ex_lvalue == 0 && expr->ex_class == Value;
+}
+
+int
+is_cp_cst(expr)
+ register struct expr *expr;
+{
+ /* An expression is a `compile-time constant' if it is a
+ load-time constant, and the idf is not there.
+ */
+ return is_ld_cst(expr) && expr->VL_CLASS == Const;
+}
+
+#ifndef NOFLOAT
+int
+is_fp_cst(expr)
+ register struct expr *expr;
+{
+ /* An expression is a `floating-point constant' if it consists
+ of the float only.
+ */
+ return expr->ex_class == Float;
+}
+#endif NOFLOAT
+
+free_expression(expr)
+ register struct expr *expr;
+{
+ /* The expression expr is freed recursively.
+ */
+ if (expr) {
+ if (expr->ex_class == Oper) {
+ free_expression(expr->OP_LEFT);
+ free_expression(expr->OP_RIGHT);
+ }
+ free_expr(expr);
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EXPRESSION DESCRIPTOR */
+
+/* What we want to define is the struct expr, but since it contains
+ a union of various goodies, we define them first; so be patient.
+*/
+
+#include "nofloat.h"
+
+/* classes of value */
+#define Const 1
+#define Name 2
+#define Label 3
+
+struct value {
+ int vl_class; /* Const, Name or Label */
+ arith vl_value; /* constant value or offset */
+ union {
+ struct idf *vl_idf; /* external name */
+ label vl_lbl; /* compiler-generated label */
+ } vl_data;
+};
+
+struct string {
+ char *sg_value; /* row of bytes repr. the constant */
+ int sg_len; /* length of the row */
+ label sg_datlab; /* global data-label */
+};
+
+#ifndef NOFLOAT
+struct floating {
+ char *fl_value; /* pointer to string repr. the fp const. */
+ label fl_datlab; /* global data_label */
+};
+#endif NOFLOAT
+
+struct oper {
+ struct type *op_type; /* resulting type of the operation */
+ struct expr *op_left;
+ int op_oper; /* the symbol of the operator */
+ struct expr *op_right;
+};
+
+/* The following constants indicate the class of the expression: */
+#define Value 0 /* it is a value known at load time */
+#define String 1 /* it is a string constant */
+#ifndef NOFLOAT
+#define Float 2 /* it is a floating point constant */
+#endif NOFLOAT
+#define Oper 3 /* it is a run-time expression */
+#define Type 4 /* only its type is relevant */
+
+struct expr {
+ struct expr *next;
+ char *ex_file; /* the file it (probably) comes from */
+ unsigned int ex_line; /* the line it (probably) comes from */
+ struct type *ex_type;
+ char ex_lvalue;
+ short ex_flags;
+ int ex_class;
+ int ex_depth;
+ union {
+ struct value ex_value;
+ struct string ex_string;
+#ifndef NOFLOAT
+ struct floating ex_float;
+#endif NOFLOAT
+ struct oper ex_oper;
+ } ex_object;
+};
+
+/* some abbreviated selections */
+#define EX_VALUE ex_object.ex_value
+#define VL_CLASS EX_VALUE.vl_class
+#define VL_VALUE EX_VALUE.vl_value
+#define VL_IDF EX_VALUE.vl_data.vl_idf
+#define VL_LBL EX_VALUE.vl_data.vl_lbl
+#define SG_VALUE ex_object.ex_string.sg_value
+#define SG_LEN ex_object.ex_string.sg_len
+#define SG_DATLAB ex_object.ex_string.sg_datlab
+#ifndef NOFLOAT
+#define FL_VALUE ex_object.ex_float.fl_value
+#define FL_DATLAB ex_object.ex_float.fl_datlab
+#endif NOFLOAT
+#define OP_TYPE ex_object.ex_oper.op_type
+#define OP_LEFT ex_object.ex_oper.op_left
+#define OP_OPER ex_object.ex_oper.op_oper
+#define OP_RIGHT ex_object.ex_oper.op_right
+
+/* some bits for the ex_flag field, to keep track of various
+ interesting properties of an expression.
+*/
+#define EX_SIZEOF 0001 /* contains sizeof operator */
+#define EX_CAST 0002 /* contains cast */
+#define EX_LOGICAL 0004 /* contains logical operator */
+#define EX_COMMA 0010 /* contains expression comma */
+#define EX_PARENS 0020 /* the top level is parenthesized */
+#define EX_SIDEEFFECTS 0040 /* expression has side effects */
+#define EX_READONLY 0100 /* read only variabele */
+#define EX_VOLATILE 0200 /* volatile variabele */
+#define EX_ERROR 0400 /* the expression is wrong */
+
+#define NILEXPR ((struct expr *)0)
+
+/* some useful tests */
+#define ISNAME(e) ((e)->ex_class == Value && (e)->VL_CLASS == Name)
+#define ISCOMMA(e) ((e)->ex_class == Oper && (e)->OP_OPER == INITCOMMA)
+
+extern struct expr *intexpr(), *new_oper();
+
+/* ALLOCDEF "expr" 20 */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* EXPRESSION SYNTAX PARSER */
+
+{
+#include <alloc.h>
+#include "lint.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "type.h"
+#include "idf.h"
+#include "label.h"
+#include "expr.h"
+#include "code.h"
+#include "noRoption.h"
+
+extern struct expr *intexpr();
+}
+
+/* 7.1 */
+primary(register struct expr **expp;) :
+ IDENTIFIER
+ {dot2expr(expp);}
+|
+ constant(expp)
+|
+ string(expp)
+|
+ '(' expression(expp) ')'
+ {(*expp)->ex_flags |= EX_PARENS;}
+;
+
+
+/* Character string literals that are adjacent tokens
+ are concatenated into a single character string
+ literal.
+*/
+string(register struct expr **expp;)
+ { register int i, len;
+ register char *str;
+ register int fund;
+ }
+:
+ STRING
+ { str = dot.tk_bts;
+ len = dot.tk_len;
+ fund = dot.tk_fund;
+ }
+ [
+ STRING
+ { /* A pasted string keeps the type of the first
+ string literal.
+ The pasting of normal strings and wide
+ character strings are stated as having an
+ undefined behaviour.
+ */
+ if (dot.tk_fund != fund)
+ warning("illegal pasting of string literals");
+ str = Srealloc(str, (unsigned) (--len + dot.tk_len));
+ for (i = 0; i < dot.tk_len; i++)
+ str[len++] = dot.tk_bts[i];
+ }
+ ]*
+ {string2expr(expp, STRING, str, len);}
+;
+
+secundary(register struct expr **expp;) :
+ primary(expp)
+ [
+ index_pack(expp)
+ |
+ parameter_pack(expp)
+ |
+ selection(expp)
+ ]*
+;
+
+index_pack(struct expr **expp;)
+ {struct expr *e1;}
+:
+ '[' expression(&e1) ']'
+ {ch7bin(expp, '[', e1);}
+;
+
+parameter_pack(struct expr **expp;)
+ {struct expr *e1 = 0;}
+:
+ '(' parameter_list(&e1)? ')'
+ { ch7bin(expp, '(', e1);
+ call_proto(expp);
+ }
+;
+
+selection(struct expr **expp;)
+ {int oper; struct idf *idf;}
+:
+ [ '.' | ARROW ]
+ {oper = DOT;}
+ identifier(&idf)
+ {ch7sel(expp, oper, idf);}
+;
+
+parameter_list(struct expr **expp;)
+ {struct expr *e1 = 0;}
+:
+ assignment_expression(expp)
+ {any2opnd(expp, PARCOMMA);}
+ [ ','
+ assignment_expression(&e1)
+ {any2opnd(&e1, PARCOMMA);}
+ {ch7bin(expp, PARCOMMA, e1);}
+ ]*
+;
+
+/* 7.2 */
+postfixed(struct expr **expp;)
+ {int oper;}
+:
+ secundary(expp)
+ [
+ postop(&oper)
+ {ch7incr(expp, oper);}
+ |
+ empty
+ ]
+;
+
+%first first_of_type_specifier, type_specifier;
+
+unary(register struct expr **expp;)
+ {struct type *tp; int oper;}
+:
+%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER)
+ cast(&tp) unary(expp)
+ { ch7cast(expp, CAST, tp);
+ (*expp)->ex_flags |= EX_CAST;
+ }
+|
+ postfixed(expp)
+|
+ unop(&oper) unary(expp)
+ {ch7mon(oper, expp);}
+|
+ size_of(expp)
+;
+
+size_of(register struct expr **expp;)
+ {struct type *tp;}
+:
+ SIZEOF
+ [%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER)
+ cast(&tp)
+ {
+ *expp = intexpr(size_of_type(tp, "type"), INT);
+ (*expp)->ex_flags |= EX_SIZEOF;
+ }
+ |
+ unary(expp)
+ {ch7mon(SIZEOF, expp);}
+ ]
+;
+
+/* 7.3-7.12 */
+/* The set of operators in C is stratified in 15 levels, with level
+ N being treated in RM 7.N. In principle each operator is
+ assigned a rank, ranging from 1 to 15. Such an expression can
+ be parsed by a construct like:
+ binary_expression(int maxrank;)
+ {int oper;}
+ :
+ binary_expression(maxrank - 1)
+ [%if (rank_of(DOT) <= maxrank)
+ binop(&oper)
+ binary_expression(rank_of(oper)-1)
+ ]?
+ ;
+ except that some call of 'unary' is necessary, depending on the
+ grammar.
+
+ This simple view is marred by three complications:
+ 1. Level 15 (comma operator) is not allowed in many
+ contexts and is different.
+ 2. Level 13 (conditional operator) is a ternary operator,
+ which does not fit this scheme at all.
+ 3. Level 14 (assignment operators) group right-to-left, as
+ opposed to 2-12, which group left-to-right (or are
+ immaterial).
+ 4. The operators in level 14 start with operators in levels
+ 2-13 (RM 7.14: The two parts of a compound assignment
+ operator are separate tokens.) This causes LL1 problems.
+ This forces us to have four rules:
+ binary_expression for level 2-12
+ conditional_expression for level 13
+ assignment_expression for level 14 and
+ expression for the most general expression
+*/
+
+binary_expression(int maxrank; struct expr **expp;)
+ {int oper; struct expr *e1;}
+:
+ unary(expp)
+ [%while (rank_of(DOT) <= maxrank && AHEAD != '=')
+ /* '?', '=', and ',' are no binops, and the test
+ for AHEAD != '=' keeps the other assignment
+ operators out
+ */
+ binop(&oper)
+ binary_expression(rank_of(oper)-1, &e1)
+ {
+ ch7bin(expp, oper, e1);
+ }
+ ]*
+;
+
+/* 7.13 */
+conditional_expression(struct expr **expp;)
+/* There is some unfortunate disagreement about what is allowed
+ between the '?' and the ':' of a conditional_expression.
+ Although the Ritchie compiler does not even allow
+ conditional_expressions there, some other compilers (e.g., VAX)
+ accept a full assignment_expression there, and programs
+ (like, e.g., emacs) rely on it. So we have little choice.
+*/
+ {struct expr *e1 = 0, *e2 = 0;}
+:
+ /* allow all binary operators */
+ binary_expression(rank_of('?') - 1, expp)
+ [ '?'
+ expression(&e1)
+ {
+#ifndef NOROPTION
+ check_conditional(e1, '?', "between ? and :");
+#endif
+ }
+ ':'
+ assignment_expression(&e2)
+ {
+#ifndef NOROPTION
+ check_conditional(e2, '=', "after :");
+#endif
+ ch7bin(&e1, ':', e2);
+ opnd2test(expp, '?');
+ ch7bin(expp, '?', e1);
+ }
+ ]?
+;
+
+/* 7.14 */
+assignment_expression(struct expr **expp;)
+ {
+ int oper;
+ struct expr *e1 = 0;
+ }
+:
+ conditional_expression(expp)
+ [%prefer /* (rank_of(DOT) <= maxrank) for any asgnop */
+ asgnop(&oper)
+ assignment_expression(&e1)
+ {ch7asgn(expp, oper, e1);}
+ |
+ empty /* LLgen artefact ??? */
+ ]
+;
+
+/* 7.15 */
+expression(struct expr **expp;)
+ {struct expr *e1;}
+:
+ assignment_expression(expp)
+ [ ','
+ assignment_expression(&e1)
+ {
+ ch7bin(expp, ',', e1);
+ }
+ ]*
+;
+
+unop(int *oper;) :
+ ['*' | '&' | '-' | '+' | '!' | '~' | PLUSPLUS | MINMIN]
+ {*oper = DOT;}
+;
+
+postop(int *oper;):
+ PLUSPLUS {*oper = POSTINCR;}
+|
+ MINMIN {*oper = POSTDECR;}
+;
+
+multop:
+ '*' | '/' | '%'
+;
+
+addop:
+ '+' | '-'
+;
+
+shiftop:
+ LEFT | RIGHT
+;
+
+relop:
+ '<' | '>' | LESSEQ | GREATEREQ
+;
+
+eqop:
+ EQUAL | NOTEQUAL
+;
+
+arithop:
+ multop | addop | shiftop
+|
+ '&' | '^' | '|'
+;
+
+binop(int *oper;) :
+ [ arithop | relop | eqop | AND | OR ]
+ {*oper = DOT;}
+;
+
+asgnop(register int *oper;):
+ '=' {*oper = DOT;}
+|
+ '+' '=' {*oper = PLUSAB;}
+|
+ '-' '=' {*oper = MINAB;}
+|
+ '*' '=' {*oper = TIMESAB;}
+|
+ '/' '=' {*oper = DIVAB;}
+|
+ '%' '=' {*oper = MODAB;}
+|
+ LEFT '=' {*oper = LEFTAB;}
+|
+ RIGHT '=' {*oper = RIGHTAB;}
+|
+ '&' '=' {*oper = ANDAB;}
+|
+ '^' '=' {*oper = XORAB;}
+|
+ '|' '=' {*oper = ORAB;}
+|
+ [ PLUSAB | MINAB | TIMESAB | DIVAB | MODAB | LEFTAB | RIGHTAB
+ | ANDAB | XORAB | ORAB ]
+ { *oper = DOT; }
+
+;
+
+constant(struct expr **expp;) :
+[
+ INTEGER
+|
+ FLOATING
+] {dot2expr(expp);}
+;
+
+/* 15 */
+constant_expression (struct expr **expp;) :
+ assignment_expression(expp)
+ {chk_cst_expr(expp);}
+;
+
+identifier(struct idf **idfp;) :
+[
+ IDENTIFIER
+|
+ TYPE_IDENTIFIER
+]
+ {
+ *idfp = dot.tk_idf;
+ }
+;
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* BITFIELD EXPRESSION EVALUATOR */
+
+#include "lint.h"
+#ifndef LINT
+
+#include "nobitfield.h"
+
+#ifndef NOBITFIELD
+#include <em.h>
+#include <em_reg.h>
+#include "debug.h"
+#include "arith.h"
+#include "type.h"
+#include "idf.h"
+#include "label.h"
+#include "code.h"
+#include "assert.h"
+#include "expr.h"
+#include "sizes.h"
+#include "align.h"
+#include "Lpars.h"
+#include "field.h"
+
+arith NewLocal(); /* util.c */
+char *symbol2str(); /* symbol2str.c */
+
+/* Eval_field() evaluates expressions involving bit fields.
+ The various instructions are not yet optimised in the expression
+ tree and are therefore dealt with in this function.
+ The actions taken at any operation are described clearly by the
+ code for this actions.
+ Notes
+ [1] the bitfields are packed in target machine integers!
+ [2] op is either an assignment operator or an increment/
+ decrement operator
+ [3] atype: the type in which the bitfield arithmetic is done;
+ and in which bitfields are stored!
+*/
+eval_field(expr, code)
+ struct expr *expr;
+ int code;
+{
+ int op = expr->OP_OPER;
+ register struct expr *leftop = expr->OP_LEFT;
+ register struct expr *rightop = expr->OP_RIGHT;
+ register struct field *fd = leftop->ex_type->tp_field;
+ struct type *tp = leftop->ex_type->tp_up;
+ arith tmpvar;
+ struct type *atype = tp->tp_unsigned ? uword_type : word_type;
+ arith asize = atype->tp_size;
+
+ /* First some assertions to be sure that the rest is legal */
+ ASSERT(asize == word_size); /* make sure that C_loc() is legal */
+ ASSERT(leftop->ex_type->tp_fund == FIELD);
+ leftop->ex_type = atype; /* this is cheating but it works... */
+ if (op == '=') {
+ /* F = E: f = ((E & mask)<<shift) | (~(mask<<shift) & f) */
+ ASSERT(tp == rightop->ex_type);
+ EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
+ conversion(tp, atype);
+ C_loc(fd->fd_mask);
+ C_and(asize);
+ if (code == TRUE)
+ C_dup(asize);
+ C_loc((arith)fd->fd_shift);
+ if (atype->tp_unsigned)
+ C_slu(asize);
+ else
+ C_sli(asize);
+ C_loc(~((fd->fd_mask << fd->fd_shift) | (~0 << (8 * asize))));
+ if (leftop->ex_depth == 0) { /* simple case */
+ load_val(leftop, RVAL);
+ C_and(asize);
+ C_ior(asize);
+ store_val(&(leftop->EX_VALUE), atype);
+ }
+ else { /* complex case */
+ tmpvar = NewLocal(pointer_size, pointer_align,
+ reg_pointer, 0);
+ EVAL(leftop, LVAL, TRUE, NO_LABEL, NO_LABEL);
+ C_dup(pointer_size);
+ StoreLocal(tmpvar, pointer_size);
+ C_loi(asize);
+ C_and(asize);
+ C_ior(asize);
+ LoadLocal(tmpvar, pointer_size);
+ C_sti(asize);
+ FreeLocal(tmpvar);
+ }
+ }
+ else { /* treat ++F as F += 1 and --F as F -= 1 */
+ /* F op= e: f = (((((f>>shift)&mask) op e)&mask)<<shift)|
+ (f&~(mask<<shift))
+ */
+ if (leftop->ex_depth == 0) /* simple case */
+ load_val(leftop, RVAL);
+ else { /* complex case */
+ tmpvar = NewLocal(pointer_size, pointer_align,
+ reg_pointer, 0);
+ EVAL(leftop, LVAL, TRUE, NO_LABEL, NO_LABEL);
+ C_dup(pointer_size);
+ StoreLocal(tmpvar, pointer_size);
+ C_loi(asize);
+ }
+ if (atype->tp_unsigned) {
+ C_loc((arith)fd->fd_shift);
+ C_sru(asize);
+ C_loc(fd->fd_mask);
+ C_and(asize);
+ }
+ else {
+ arith bits_in_type = asize * 8;
+ C_loc(bits_in_type - (fd->fd_width + fd->fd_shift));
+ C_sli(asize);
+ C_loc(bits_in_type - fd->fd_width);
+ C_sri(asize);
+ }
+ if (code == TRUE && (op == POSTINCR || op == POSTDECR))
+ C_dup(asize);
+ conversion(atype, rightop->ex_type);
+ EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
+ /* the 'op' operation: */
+ if (op == PLUSPLUS || op == POSTINCR)
+ assop(rightop->ex_type, PLUSAB);
+ else
+ if (op == MINMIN || op == POSTDECR)
+ assop(rightop->ex_type, MINAB);
+ else
+ assop(rightop->ex_type, op);
+ conversion(rightop->ex_type, atype);
+ C_loc(fd->fd_mask);
+ C_and(asize);
+ if (code == TRUE && op != POSTINCR && op != POSTDECR)
+ C_dup(asize);
+ C_loc((arith)fd->fd_shift);
+ if (atype->tp_unsigned)
+ C_slu(asize);
+ else
+ C_sli(asize);
+ C_loc(~((fd->fd_mask << fd->fd_shift) | (~0 << (8 * asize))));
+ if (leftop->ex_depth == 0) {
+ load_val(leftop, RVAL);
+ C_and(asize);
+ C_ior(asize);
+ store_val(&(leftop->EX_VALUE), atype);
+ }
+ else {
+ LoadLocal(tmpvar, pointer_size);
+ C_loi(asize);
+ C_and(asize);
+ C_ior(asize);
+ LoadLocal(tmpvar, pointer_size);
+ C_sti(asize);
+ FreeLocal(tmpvar);
+ }
+ }
+ if (code == TRUE) {
+ /* Take care that the effective value stored in
+ the bit field (i.e. the value that is got on
+ retrieval) is on top of stack.
+ */
+ if (atype->tp_unsigned == 0) { /* sign extension */
+ register arith shift = asize * 8 - fd->fd_width;
+
+ C_loc(shift);
+ C_sli(asize);
+ C_loc(shift);
+ C_sri(asize);
+ }
+ conversion(atype, expr->ex_type);
+ }
+}
+#endif NOBITFIELD
+
+#endif LINT
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* FIELD DESCRIPTOR */
+
+struct field { /* for field specifiers */
+ struct field *next;
+ arith fd_mask;
+ int fd_shift;
+ int fd_width;
+ struct sdef *fd_sdef; /* upward pointer */
+};
+
+/* ALLOCDEF "field" 50 */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* F I L E I N F O R M A T I O N S T R U C T U R E */
+
+struct file_info {
+ unsigned int fil_lino;
+ int fil_nestlow;
+ char *fil_name;
+ char *fil_wdir;
+};
+
+#define nestlow finfo.fil_nestlow
+#define LineNumber finfo.fil_lino
+#define FileName finfo.fil_name
+#define WorkingDir finfo.fil_wdir
+
+extern struct file_info finfo; /* input.c */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* IDENTIFIER FIDDLING & SYMBOL TABLE HANDLING */
+
+#include "lint.h"
+#include <em_reg.h>
+#include "nofloat.h"
+#include "debug.h"
+#include "idfsize.h"
+#include "botch_free.h"
+#include "nopp.h"
+#include "nparams.h"
+#include <alloc.h>
+#include "arith.h"
+#include "align.h"
+#include "LLlex.h"
+#include "level.h"
+#include "stack.h"
+#include "idf.h"
+#include "label.h"
+#include "def.h"
+#include "type.h"
+#include "proto.h"
+#include "struct.h"
+#include "declar.h"
+#include "decspecs.h"
+#include "sizes.h"
+#include "Lpars.h"
+#include "assert.h"
+#include "specials.h" /* registration of special identifiers */
+#include "noRoption.h"
+
+int idfsize = IDFSIZE;
+extern char options[];
+extern arith NewLocal();
+
+char sp_occurred[SP_TOTAL+1]; /* indicate occurrence of special id */
+
+struct idf *idf_hashtable[HASHSIZE];
+ /* All identifiers can in principle be reached through
+ idf_hashtable; idf_hashtable[hc] is the start of a chain of
+ idf's whose tags all hash to hc. Each idf is the start of
+ a chain of def's for that idf, sorted according to level,
+ with the most recent one on top.
+ Any identifier occurring on a level is entered into this
+ list, regardless of the nature of its declaration
+ (variable, selector, structure tag, etc.).
+ */
+
+struct idf *
+idf_hashed(tg, size, hc)
+ char *tg;
+ int size; /* includes the '\0' character */
+ int hc;
+{
+ /* The tag tg with length size and known hash value hc is
+ looked up in the identifier table; if not found, it is
+ entered. A pointer to it is returned.
+ The identifier has already been truncated to idfsize
+ characters.
+ */
+ register struct idf **hook = &idf_hashtable[hc], *notch;
+
+ while ((notch = *hook)) {
+ register char *s1 = tg;
+ register char *cp = notch->id_text;
+ register int cmp;
+
+ while (!(cmp = (*s1 - *cp++))) {
+ if (*s1++ == '\0') {
+ break;
+ }
+ }
+
+ if (cmp < 0)
+ break;
+ if (cmp == 0) {
+ /* suppose that special identifiers, as
+ "setjmp", are already inserted
+ */
+ sp_occurred[notch->id_special] = 1;
+ return notch;
+ }
+ hook = ¬ch->next;
+ }
+ /* a new struct idf must be inserted at the hook */
+ notch = new_idf();
+ notch->next = *hook;
+ *hook = notch; /* hooked in */
+ notch->id_text = Salloc(tg, (unsigned) size);
+#ifndef NOPP
+ notch->id_resmac = 0;
+#endif NOPP
+ return notch;
+}
+
+#ifdef DEBUG
+hash_stat()
+{
+ if (options['h']) {
+ register int i;
+
+ print("Hash table tally:\n");
+ for (i = 0; i < HASHSIZE; i++) {
+ register struct idf *notch = idf_hashtable[i];
+ int cnt = 0;
+
+ while (notch) {
+ cnt++;
+ notch = notch->next;
+ }
+ print("%d %d\n", i, cnt);
+ }
+ print("End hash table tally\n");
+ }
+}
+#endif DEBUG
+
+struct idf *
+str2idf(tg)
+ char tg[];
+{
+ /* str2idf() returns an entry in the symbol table for the
+ identifier tg. If necessary, an entry is created.
+ It is used where the text of the identifier is available
+ but its hash value is not; otherwise idf_hashed() is to
+ be used.
+ */
+ register char *cp = tg;
+ register int hash;
+ register int pos = -1;
+ register int ch;
+ char ntg[IDFSIZE + 1];
+ register char *ncp = ntg;
+
+ hash = STARTHASH();
+ while (++pos < idfsize && (ch = *cp++)) {
+ *ncp++ = ch;
+ hash = ENHASH(hash, ch, pos);
+ }
+ hash = STOPHASH(hash);
+ *ncp++ = '\0';
+ return idf_hashed(ntg, ncp - ntg, hash);
+}
+
+struct idf *
+gen_idf()
+{
+ /* A new idf is created out of nowhere, to serve as an
+ anonymous name.
+ */
+ static int name_cnt;
+ char buff[100];
+
+ sprint(buff, "#%d in %s, line %u",
+ ++name_cnt, dot.tk_file, dot.tk_line);
+ return str2idf(buff);
+}
+
+int
+is_anon_idf(idf)
+ struct idf *idf;
+{
+ return idf->id_text[0] == '#';
+}
+
+declare_idf(ds, dc, lvl)
+ struct decspecs *ds;
+ struct declarator *dc;
+{
+ /* The identifier inside dc is declared on the level lvl, with
+ properties deduced from the decspecs ds and the declarator
+ dc.
+ The level is given explicitly to be able to insert, e.g.,
+ labels on the outermost level inside the function.
+ This routine implements the rich semantics of C
+ declarations.
+ */
+ register struct idf *idf = dc->dc_idf;
+ register int sc = ds->ds_sc;
+ /* This local copy is essential:
+ char b(), c;
+ makes b GLOBAL and c AUTO.
+ */
+ register struct def *def = idf->id_def; /* may be NULL */
+ register struct type *type;
+ struct stack_level *stl = stack_level_of(lvl);
+ char formal_array = 0;
+
+ /* determine the present type */
+ if (ds->ds_type == 0) {
+ /* at the L_FORMAL1 level there is no type specified yet
+ */
+ ASSERT(lvl == L_FORMAL1);
+ type = int_type; /* may change at L_FORMAL2 */
+ }
+ else {
+ /* combine the decspecs and the declarator into one type */
+ type = declare_type(ds->ds_type, dc);
+ if (type->tp_size <= (arith)0 &&
+ actual_declaration(sc, type)) {
+ if (type->tp_size == (arith) -1) {
+ /* the type is not yet known,
+ but it has to be:
+ */
+ extern char *symbol2str();
+ error("unknown %s-type",
+ symbol2str(type->tp_fund));
+ }
+ else if (type->tp_fund != LABEL) {
+ /* CJ */
+ warning("%s has size 0", idf->id_text);
+ }
+ }
+ }
+
+ /* some additional work for formal definitions */
+ if (lvl == L_FORMAL2) {
+ switch (type->tp_fund) {
+ case FUNCTION:
+ warning("%s is a function; cannot be formal",
+ idf->id_text);
+ type = construct_type(POINTER, type, 0, (arith)0,
+ NO_PROTO);
+ break;
+ case ARRAY: /* RM 10.1 */
+ type = construct_type(POINTER, type->tp_up, 0, (arith)0,
+ NO_PROTO);
+ formal_array = 1;
+ break;
+#ifndef NOFLOAT
+ case FLOAT: /* RM 10.1 */
+ type = double_type;
+ break;
+#endif NOFLOAT
+ case CHAR:
+ case SHORT:
+ /* The RM is not clear about this: we must
+ convert the parameter from int (they have
+ been pushed as ints) to the specified type.
+ The conversion to type int or uint is not
+ allowed.
+ */
+ break;
+ }
+ }
+ /* The tests on types, postponed from do_decspecs(), can now
+ be performed.
+ */
+ /* update the storage class */
+ if (type && type->tp_fund == FUNCTION) {
+ if (sc == 0 || (ds->ds_sc_given && sc == AUTO)) /* RM 8.1 */
+ sc = GLOBAL;
+ else
+ if (sc == REGISTER) {
+ error("function storage class cannot be register");
+ ds->ds_sc = sc = GLOBAL;
+ }
+ }
+ else /* non-FUNCTION */
+ if (sc == 0)
+ sc = lvl == L_GLOBAL ? GLOBAL
+ : lvl == L_FORMAL1 || lvl == L_FORMAL2 ? FORMAL
+ : AUTO;
+#ifndef NOROPTION
+ if (options['R']) { /* some special K & R tests */
+ /* is it also an enum? */
+ if (idf->id_enum && idf->id_enum->tg_level == level)
+ warning("%s is also an enum tag", idf->id_text);
+ /* is it a universal typedef? */
+ if (def && def->df_level == L_UNIVERSAL)
+ warning("redeclaring reserved word %s", idf->id_text);
+ }
+#endif
+
+#ifdef LINT
+ if ( def && def->df_level < lvl
+ && !( lvl == L_FORMAL2
+ || def->df_level == L_UNIVERSAL
+ || sc == GLOBAL
+ || sc == EXTERN
+ )
+ ) {
+ /* there is already a definition for this non-extern name
+ on a more global level
+ */
+ warning("%s is already defined as a %s",
+ idf->id_text,
+ def->df_level == L_GLOBAL ? "global" :
+ def->df_level == L_FORMAL2 ? "formal" :
+ "more global local"
+ );
+ }
+#endif LINT
+
+ if (def &&
+ ( def->df_level == lvl ||
+ ( lvl != L_GLOBAL && def->df_level > lvl )
+ )
+ ) {
+ /* There is already a declaration for idf on this
+ level, or even more inside.
+ The rules differ for different levels.
+ */
+ switch (lvl) {
+ case L_GLOBAL:
+ global_redecl(idf, sc, type);
+ def->df_file = idf->id_file;
+ def->df_line = idf->id_line;
+ break;
+ case L_FORMAL1: /* formal declaration */
+ error("formal %s redeclared", idf->id_text);
+ break;
+ case L_FORMAL2: /* formal definition */
+ default: /* local */
+ error("%s redeclared", idf->id_text);
+ break;
+ }
+ }
+ else /* the idf is unknown on this level */
+ if (lvl == L_FORMAL2 && sc != ENUM && good_formal(def, idf)) {
+ /* formal declaration, update only */
+ def->df_type = type;
+ def->df_formal_array = formal_array;
+ def->df_sc = sc;
+ def->df_level = L_FORMAL2; /* CJ */
+ def->df_file = idf->id_file;
+ def->df_line = idf->id_line;
+ }
+ else
+ if ( lvl >= L_LOCAL &&
+ (type->tp_fund == FUNCTION || sc == EXTERN)
+ ) {
+ /* extern declaration inside function is treated the
+ same way as global extern declaration
+ */
+#ifndef NOROPTION
+ if ( options['R'] &&
+ (sc == STATIC && type->tp_fund == FUNCTION)
+ )
+ if (!is_anon_idf(idf))
+ warning("non-global static function %s",
+ idf->id_text);
+#endif
+ declare_idf(ds, dc, L_GLOBAL);
+ }
+ else { /* fill in the def block */
+ register struct def *newdef = new_def();
+
+ newdef->next = def;
+ newdef->df_level = lvl;
+ newdef->df_type = type;
+ newdef->df_sc = sc;
+ newdef->df_file = idf->id_file;
+ newdef->df_line = idf->id_line;
+#ifdef LINT
+ newdef->df_set = (type->tp_fund == ARRAY);
+ newdef->df_firstbrace = 0;
+#endif LINT
+
+ /* link it into the name list in the proper place */
+ idf->id_def = newdef;
+ update_ahead(idf);
+ stack_idf(idf, stl);
+ /* We now calculate the address.
+ Globals have names and don't get addresses, they
+ get numbers instead (through data_label()).
+ Formals are handled by declare_formals().
+ So here we hand out local addresses only.
+ */
+ if (lvl >= L_LOCAL) {
+ ASSERT(sc);
+ switch (sc) {
+ case REGISTER:
+ case AUTO:
+ if (type->tp_size == (arith)-1) {
+ error("size of local %s unknown",
+ idf->id_text);
+ /** type = idf->id_def->df_type = int_type; **/
+ }
+ newdef->df_address =
+ NewLocal(type->tp_size,
+ type->tp_align,
+ regtype(type),
+ sc);
+ break;
+ case STATIC:
+ newdef->df_address = (arith) data_label();
+ break;
+ }
+ }
+ }
+}
+
+actual_declaration(sc, tp)
+ int sc;
+ struct type *tp;
+{
+ /* An actual_declaration needs space, right here and now.
+ */
+ register int fund = tp->tp_fund;
+
+ if (sc == ENUM || sc == TYPEDEF) /* virtual declarations */
+ return 0;
+ if (fund == FUNCTION || fund == ARRAY)
+ /* allocation solved in other ways */
+ return 0;
+ /* to be allocated */
+ return 1;
+}
+
+global_redecl(idf, new_sc, tp)
+ register struct idf *idf;
+ struct type *tp;
+{
+ /* A global identifier may be declared several times,
+ provided the declarations do not conflict; they might
+ conflict in type (or supplement each other in the case of
+ an array) or they might conflict or supplement each other
+ in storage class.
+ */
+ register struct def *def = idf->id_def;
+
+ if (!equal_type(tp, def->df_type))
+ error("redeclaration of %s with different type", idf->id_text);
+ update_proto(tp, def->df_type);
+ if (tp->tp_fund == ARRAY) {
+ /* Multiple array declaration; this may be interesting */
+ if (tp->tp_size < 0) { /* new decl has [] */
+ /* nothing new */
+ } else
+ if (def->df_type->tp_size < 0) { /* old decl has [] */
+ def->df_type = tp;
+ }
+ }
+
+ /* Now we may be able to update the storage class.
+ Clean out this mess as soon as we know all the possibilities
+ for new_sc.
+ For now we have:
+ EXTERN: we have seen the word "extern"
+ GLOBAL: the item was declared on the outer
+ level, without either "extern" or
+ "static".
+ STATIC: we have seen the word "static"
+ IMPLICIT: function declaration inferred from
+ call
+ */
+ if (new_sc == IMPLICIT)
+ return; /* no new information */
+ switch (def->df_sc) { /* the old storage class */
+ case EXTERN:
+ switch (new_sc) { /* the new storage class */
+ case EXTERN:
+ case GLOBAL:
+ break;
+ case STATIC:
+ if (def->df_initialized) {
+ error("cannot redeclare %s to static",
+ idf->id_text);
+ }
+ else {
+ warning("%s redeclared to static",
+ idf->id_text);
+ }
+ def->df_sc = new_sc;
+ break;
+ default:
+ crash("bad storage class");
+ /*NOTREACHED*/
+ }
+ break;
+ case GLOBAL:
+ switch (new_sc) { /* the new storage class */
+ case EXTERN:
+ def->df_sc = EXTERN;
+ break;
+ case GLOBAL:
+ break;
+ case STATIC:
+ if (def->df_initialized)
+ error("cannot redeclare %s to static",
+ idf->id_text);
+ else {
+#ifndef NOROPTION
+ if (options['R'])
+ warning("%s redeclared to static",
+ idf->id_text);
+#endif
+ def->df_sc = STATIC;
+ }
+ break;
+ default:
+ crash("bad storage class");
+ /*NOTREACHED*/
+ }
+ break;
+ case STATIC:
+ switch (new_sc) { /* the new storage class */
+ case EXTERN:
+ if (def->df_initialized)
+ error("cannot redeclare %s to extern",
+ idf->id_text);
+ else {
+ warning("%s redeclared to extern",
+ idf->id_text);
+ def->df_sc = EXTERN;
+ }
+ break;
+ case GLOBAL:
+ case STATIC:
+ if (def->df_type->tp_fund != FUNCTION)
+ warning("%s was already static",
+ idf->id_text);
+ break;
+ default:
+ crash("bad storage class");
+ /*NOTREACHED*/
+ }
+ break;
+ case IMPLICIT:
+ switch (new_sc) { /* the new storage class */
+ case EXTERN:
+ case GLOBAL:
+ def->df_sc = new_sc;
+ break;
+ case STATIC:
+#ifndef NOROPTION
+ if (options['R'])
+ warning("%s was implicitly declared as extern",
+ idf->id_text);
+#endif
+ def->df_sc = new_sc;
+ break;
+ default:
+ crash("bad storage class");
+ /*NOTREACHED*/
+ }
+ break;
+ case ENUM:
+ case TYPEDEF:
+ error("illegal redeclaration of %s", idf->id_text);
+ break;
+ default:
+ crash("bad storage class");
+ /*NOTREACHED*/
+ }
+}
+
+int
+good_formal(def, idf)
+ register struct def *def;
+ register struct idf *idf;
+{
+ /* Succeeds if def is a proper L_FORMAL1 definition and
+ gives an error message otherwise.
+ */
+ if (!def || def->df_level != L_FORMAL1) { /* not in parameter list */
+ if (!is_anon_idf(idf))
+ error("%s not in parameter list", idf->id_text);
+ return 0;
+ }
+ ASSERT(def->df_sc == FORMAL); /* CJ */
+ return 1;
+}
+
+declare_params(dc)
+ register struct declarator *dc;
+{
+ /* Declares the formal parameters if they exist.
+ */
+ register struct formal *fm = dc->dc_formal;
+
+ while (fm) {
+ declare_parameter(fm->fm_idf);
+ fm = fm->next;
+ }
+ free_formals(dc->dc_formal);
+ dc->dc_formal = 0;
+}
+
+init_idf(idf)
+ register struct idf *idf;
+{
+ /* The topmost definition of idf is set to initialized.
+ */
+ register struct def *def = idf->id_def; /* the topmost */
+
+ if (def->df_initialized)
+ error("multiple initialization of %s", idf->id_text);
+ if (def->df_sc == TYPEDEF) {
+ warning("typedef cannot be initialized");
+ def->df_sc = EXTERN; /* ??? *//* What else ? */
+ }
+ def->df_initialized = 1;
+}
+
+declare_parameter(idf)
+ struct idf *idf;
+{
+ /* idf is declared as a formal.
+ */
+ add_def(idf, FORMAL, int_type, level);
+}
+
+declare_enum(tp, idf, l)
+ struct type *tp;
+ struct idf *idf;
+ arith l;
+{
+ /* idf is declared as an enum constant with value l.
+ */
+ add_def(idf, ENUM, tp, level);
+ idf->id_def->df_address = l;
+}
+
+declare_formals(fp)
+ arith *fp;
+{
+ /* Declares those formals as int that haven't been declared
+ by the user.
+ An address is assigned to each formal parameter.
+ The total size of the formals is returned in *fp;
+ */
+ register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
+ arith f_offset = (arith)0;
+ register int nparams = 0;
+
+#ifdef DEBUG
+ if (options['t'])
+ dumpidftab("start declare_formals", 0);
+#endif DEBUG
+ while (se) {
+ register struct def *def = se->se_idf->id_def;
+
+ def->df_address = f_offset;
+ /* the alignment convention for parameters is: align on
+ word boundaries, i.e. take care that the following
+ parameter starts on a new word boundary.
+ */
+ f_offset = align(f_offset + def->df_type->tp_size, (int) word_size);
+ formal_cvt(def); /* cvt int to char or short, if necessary */
+ se = se->next;
+ def->df_level = L_FORMAL2; /* CJ */
+ RegisterAccount(def->df_address, def->df_type->tp_size,
+ regtype(def->df_type),
+ def->df_sc);
+ if (nparams++ >= STDC_NPARAMS)
+ strict("number of formal parameters exceeds ANSI limit");
+ }
+ *fp = f_offset;
+}
+
+int
+regtype(tp)
+ struct type *tp;
+{
+ switch(tp->tp_fund) {
+ case INT:
+ case LONG:
+ return reg_any;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ return reg_float;
+#endif NOFLOAT
+ case POINTER:
+ return reg_pointer;
+ }
+ return -1;
+}
+
+add_def(idf, sc, tp, lvl)
+ struct idf *idf;
+ struct type *tp;
+ int lvl;
+ int sc;
+{
+ /* The identifier idf is declared on level lvl with storage
+ class sc and type tp, through a faked C declaration.
+ This is probably the wrong way to structure the problem,
+ but it will have to do for the time being.
+ */
+ struct decspecs Ds; struct declarator Dc;
+
+ Ds = null_decspecs;
+ Ds.ds_type = tp;
+ Ds.ds_sc = sc;
+ Dc = null_declarator;
+ Dc.dc_idf = idf;
+ declare_idf(&Ds, &Dc, lvl);
+}
+
+update_ahead(idf)
+ register struct idf *idf;
+{
+ /* The tk_symb of the token ahead is updated in the light of new
+ information about the identifier idf.
+ */
+ register int tk_symb = AHEAD;
+
+ if ( (tk_symb == IDENTIFIER || tk_symb == TYPE_IDENTIFIER) &&
+ ahead.tk_idf == idf
+ )
+ AHEAD = idf->id_def && idf->id_def->df_sc == TYPEDEF ?
+ TYPE_IDENTIFIER : IDENTIFIER;
+}
+
+free_formals(fm)
+ register struct formal *fm;
+{
+ while (fm) {
+ struct formal *tmp = fm->next;
+
+ free_formal(fm);
+ fm = tmp;
+ }
+}
+
+char hmask[IDFSIZE];
+
+init_hmask()
+{
+ /* A simple congruence random number generator, as
+ described in Knuth, vol 2.
+ */
+ register int h, rnd = HASH_X;
+
+ for (h = 0; h < IDFSIZE; h++) {
+ hmask[h] = rnd;
+ rnd = (HASH_A * rnd + HASH_C) & HASHMASK;
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* IDENTIFIER DESCRIPTOR */
+
+#include "nopp.h"
+
+/* Since the % operation in the calculation of the hash function
+ turns out to be expensive, it is replaced by the cheaper XOR (^).
+ Each character of the identifier is xored with an 8-bit mask which
+ depends on the position of the character; the sum of these results
+ is the hash value. The random masks are obtained from a
+ congruence generator in idf.c.
+*/
+
+#define HASHSIZE 256 /* must be a power of 2 */
+#define HASH_X 0253 /* Knuth's X */
+#define HASH_A 77 /* Knuth's a */
+#define HASH_C 153 /* Knuth's c */
+
+extern char hmask[]; /* the random masks */
+#define HASHMASK (HASHSIZE-1) /* since it is a power of 2 */
+#define STARTHASH() (0)
+#define ENHASH(hs,ch,ps) (hs + (ch ^ hmask[ps]))
+#define STOPHASH(hs) (hs & HASHMASK)
+
+struct idf {
+ struct idf *next;
+ char *id_text;
+#ifndef NOPP
+ struct macro *id_macro;
+ int id_resmac; /* if nonzero: keyword of macroproc. */
+#endif NOPP
+ int id_reserved; /* non-zero for reserved words */
+ char *id_file; /* file containing the occurrence */
+ unsigned int id_line; /* line number of the occurrence */
+ struct def *id_def; /* variables, typedefs, enum-constants */
+ struct sdef *id_sdef; /* selector tags */
+ struct tag *id_struct; /* struct and union tags */
+ struct tag *id_enum; /* enum tags */
+ int id_proto; /* non-zero don't complain about proto */
+ int id_special; /* special action needed at occurrence */
+};
+
+/* ALLOCDEF "idf" 50 */
+
+extern struct idf *str2idf(), *idf_hashed();
+
+extern int level;
+extern struct idf *gen_idf();
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: INITIALIZATION ROUTINES */
+
+#include "nopp.h"
+
+#ifndef NOPP
+#include <system.h>
+#include <alloc.h>
+#include <time.h>
+#include "class.h"
+#include "macro.h"
+#include "idf.h"
+
+struct mkey {
+ char *mk_reserved;
+ int mk_key;
+} mkey[] = {
+ {"define", K_DEFINE},
+ {"elif", K_ELIF},
+ {"else", K_ELSE},
+ {"endif", K_ENDIF},
+ {"error", K_ERROR},
+ {"if", K_IF},
+ {"ifdef", K_IFDEF},
+ {"ifndef", K_IFNDEF},
+ {"include", K_INCLUDE},
+ {"line", K_LINE},
+ {"pragma", K_PRAGMA},
+ {"undef", K_UNDEF},
+ {0, K_UNKNOWN}
+};
+
+char *strcpy();
+
+init_pp()
+{
+ static char *months[12] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ long clock, sys_time();
+ static char dbuf[30];
+ static char tbuf[30];
+ struct tm *tp;
+
+ /* Initialise the control line keywords (if, include, define, etc)
+ Although the lexical analyzer treats them as identifiers, the
+ control line handler can recognize them as keywords by the
+ id_resmac field of the identifier.
+ */
+ {
+ register struct mkey *mk = &mkey[0];
+
+ while (mk->mk_reserved) {
+ register struct idf *idf = str2idf(mk->mk_reserved);
+
+ if (idf->id_resmac)
+ fatal("maximum identifier length insufficient");
+ idf->id_resmac = mk->mk_key;
+ mk++;
+ }
+ }
+
+ /* Initialize __LINE__, __FILE__, __DATE__, __TIME__,
+ and __STDC__ macro definitions.
+ */
+ clock = sys_time();
+ tp = localtime(&clock);
+
+ /* __DATE__ */
+ sprintf(dbuf, "\"%.3s %.2d %d\"", months[tp->tm_mon],
+ tp->tm_mday, tp->tm_year+1900);
+ macro_def(str2idf("__DATE__"), dbuf, -1, 12, NOFLAG);
+
+ /* __TIME__ */
+ sprintf(tbuf, "\"%.2d:%.2d:%.2d\"", tp->tm_hour, tp->tm_min, tp->tm_sec);
+ macro_def(str2idf("__TIME__"), tbuf, -1, 10, NOFLAG);
+
+ /* __LINE__ */
+ macro_def(str2idf("__LINE__"), "0", -1, 1, FUNC);
+
+ /* __FILE__ */
+ macro_def(str2idf("__FILE__"), "", -1, 1, FUNC);
+
+ /* __STDC__ */
+ macro_def(str2idf("__STDC__"), "1", -1, 1, NOFLAG);
+
+ /* defined(??) */
+ macro_def(str2idf("defined"), "", 1, 1, FUNC);
+}
+#endif NOPP
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+#include "inputtype.h"
+#include "file_info.h"
+#include "input.h"
+
+#define INP_PUSHBACK 3
+#define INP_TYPE struct file_info
+#define INP_VAR finfo
+struct file_info finfo;
+extern int nestlevel;
+#include "nopp.h"
+#include <inp_pkg.body>
+
+#ifndef NOPP
+char *
+getwdir(fn)
+ register char *fn;
+{
+ register char *p;
+ char *strrindex();
+
+ p = strrindex(fn, '/');
+ while (p && *(p + 1) == '\0') { /* remove trailing /'s */
+ *p = '\0';
+ p = strrindex(fn, '/');
+ }
+
+ if (fn[0] == '\0' || (fn[0] == '/' && p == &fn[0])) /* absolute path */
+ return "";
+ if (p) {
+ *p = '\0';
+ fn = Salloc(fn, p - &fn[0] + 1);
+ *p = '/';
+ return fn;
+ }
+ return ".";
+}
+#endif NOPP
+
+int NoUnstack;
+
+AtEoIT()
+{
+ unstackrepl();
+ return 0;
+}
+
+AtEoIF()
+{
+#ifndef NOPP
+ if (nestlevel != nestlow) lexwarning("missing #endif");
+ else
+#endif NOPP
+ if (NoUnstack) lexerror("unexpected EOF");
+#ifndef NOPP
+ nestlevel = nestlow;
+#endif
+ return 0;
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+#define INP_PUSHBACK 3
+
+#include <inp_pkg.spec>
+
+/* Note: The following macro only garuantees one PushBack.
+*/
+#define UnGetChar() ChPushBack(LexSave)
+
+extern int LexSave; /* last character read by GetChar */
+extern int GetChar(); /* character input, with trigraph parsing */
--- /dev/null
+/* $Header$ */
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+#define PRIVATE /*static /* or not */
+#define IMPORT extern
+#define EXPORT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */
+
+{
+#include "lint.h"
+#include "nofloat.h"
+#include <em.h>
+#include "debug.h"
+#include <alloc.h>
+#include <assert.h>
+#include "nobitfield.h"
+#include "arith.h"
+#include "label.h"
+#include "expr.h"
+#include "type.h"
+#include "proto.h"
+#include "struct.h"
+#include "field.h"
+#include "assert.h"
+#include "Lpars.h"
+#include "sizes.h"
+#include "idf.h"
+#include "level.h"
+#include "def.h"
+#include "LLlex.h"
+#include "noRoption.h"
+#include "estack.h"
+#ifdef LINT
+#include "l_lint.h"
+#endif LINT
+
+#define con_nullbyte() C_con_ucon("0", (arith)1)
+#define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT)
+
+char *long2str();
+char *strncpy();
+extern char options[];
+static int gen_error;
+struct type **gen_tphead(), **gen_tpmiddle();
+struct sdef *gen_align_to_next();
+struct e_stack *p_stack;
+}
+
+/* initial_value recursively guides the initialisation expression.
+ Upto now, the initialisation of a union is not allowed!
+*/
+/* 7 */
+initial_value(register struct type **tpp; register struct expr **expp;) :
+ { if (tpp) gen_tpcheck(tpp, 0); }
+[
+ assignment_expression(expp)
+ {
+#ifdef LINT
+ lint_expr(*expp, USED);
+#endif LINT
+ if ((*expp)->ex_type->tp_fund == ARRAY)
+ array2pointer(*expp);
+ if (tpp) {
+ gen_simple_exp(tpp, expp);
+ free_expression(*expp);
+ *expp = 0;
+ }
+ }
+|
+ initial_value_pack(tpp, expp)
+]
+;
+
+initial_value_pack(struct type **tpp; struct expr **expp;)
+ { static int pack_level; }
+:
+ '{'
+ { if (pack_level == 0) gen_error = 0; pack_level++; }
+ initial_value_list(tpp, expp)
+ { pack_level--;
+ if (!pack_level) {
+ while (p_stack) {
+ struct e_stack *p = p_stack->next;
+
+ free_e_stack(p_stack);
+ p_stack = p;
+ }
+ }
+ }
+ '}'
+;
+
+initial_value_list(register struct type **tpp; struct expr **expp;)
+ { struct expr *e1;
+ register struct type **tpp2 = 0;
+ }
+:
+ { if (tpp) tpp2 = gen_tphead(tpp, 0); }
+ initial_value(tpp2, &e1)
+ { if (!tpp) init_expression(&expp, e1); }
+ [%while (AHEAD != '}') /* >>> conflict on ',' */
+ ','
+ { if (tpp) tpp2 = gen_tpmiddle(); }
+ initial_value(tpp2, &e1)
+ { if (!tpp) init_expression(&expp, e1); }
+ ]*
+ { if (tpp) gen_tpend(); }
+ ','? /* optional trailing comma */
+;
+
+{
+gen_tpcheck(tpp, union_allowed)
+ struct type **tpp;
+{
+ register struct type *tp;
+
+ if (gen_error) return;
+ switch((tp = *tpp)->tp_fund) {
+ case ARRAY:
+ if (! valid_type(tp->tp_up, "array element"))
+ gen_error = 1;
+ break;
+ case STRUCT:
+ if (! valid_type(tp, "struct"))
+ gen_error = 1;
+ break;
+ case UNION:
+ if (! valid_type(tp, "union"))
+ gen_error = 1;
+ break;
+ }
+}
+
+gen_simple_exp(tpp, expp)
+ struct type **tpp;
+ struct expr **expp;
+{
+ register struct type *tp;
+
+ if (gen_error) return;
+ tp = *tpp;
+ switch(tp->tp_fund) {
+ case ARRAY:
+ if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) {
+ ch_array(tpp,*expp);
+ break;
+ }
+ /* Fall through */
+ case UNION:
+ case STRUCT:
+ check_and_pad(expp, tpp);
+ break;
+ case ERRONEOUS:
+ gen_error = 1;
+ break;
+ default:
+ check_ival(expp, tp);
+ break;
+ }
+}
+
+struct type **
+arr_elem(tpp, p)
+ struct type **tpp;
+ struct e_stack *p;
+{
+ register struct type *tp = *tpp;
+
+ if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) {
+ p->nelem = 1;
+ return tpp;
+ }
+ if (AHEAD == '{' || ! aggregate_type(tp->tp_up))
+ return &(tp->tp_up);
+ return gen_tphead(&(tp->tp_up), 1);
+}
+
+struct sdef *
+next_field(sd, p)
+ register struct sdef *sd;
+ register struct e_stack *p;
+{
+ if (sd->sd_sdef)
+ p->bytes_upto_here += zero_bytes(sd);
+ if (p->last_offset != sd->sd_offset) {
+ p->bytes_upto_here +=
+ size_of_type(sd->sd_type, "selector");
+ p->last_offset = sd->sd_offset;
+ }
+ return sd->sd_sdef;
+}
+
+struct type **
+gen_tphead(tpp, nest)
+ struct type **tpp;
+{
+ register struct type *tp = *tpp;
+ register struct e_stack *p;
+ register struct sdef *sd;
+
+ if (tpp && *tpp == error_type) {
+ gen_error = 1;
+ return 0;
+ }
+ if (gen_error) return tpp;
+ p = new_e_stack();
+ p->next = p_stack;
+ p_stack = p;
+ p->s_nested = nest;
+ p->s_tpp = tpp;
+ switch(tp->tp_fund) {
+ case ARRAY:
+ p->nelem = -1;
+ p->elem_count = 1;
+ if (tp->tp_size != (arith) -1) {
+ p->nelem = (tp->tp_size / tp->tp_up->tp_size);
+ }
+ return arr_elem(tpp, p);
+ case STRUCT:
+ p->s_def = sd = tp->tp_sdef;
+ p->bytes_upto_here = 0;
+ p->last_offset = -1;
+#ifndef NOBITFIELD
+ while (sd && is_anon_idf(sd->sd_idf)) {
+ put_bf(sd->sd_type, (arith) 0);
+ sd = next_field(sd, p);
+ }
+#endif
+ if (! sd) {
+ /* something wrong with this struct */
+ gen_error = 1;
+ p_stack = p->next;
+ free_e_stack(p);
+ return 0;
+ }
+ p->s_def = sd;
+ if (AHEAD != '{' && aggregate_type(sd->sd_type)) {
+ return gen_tphead(&(sd->sd_type), 1);
+ }
+ return &(sd->sd_type);
+ default:
+ p->nelem = 1;
+ p->elem_count = 1;
+ return tpp;
+ }
+}
+
+struct type **
+gen_tpmiddle()
+{
+ register struct type *tp;
+ register struct sdef *sd;
+ register struct e_stack *p = p_stack;
+
+ if (gen_error) {
+ if (p) return p->s_tpp;
+ return 0;
+ }
+again:
+ tp = *(p->s_tpp);
+ switch(tp->tp_fund) {
+ default:
+ if (p->elem_count == p->nelem && p->s_nested) {
+ p = p->next;
+ free_e_stack(p_stack);
+ p_stack = p;
+ goto again;
+ }
+ p->elem_count++;
+ if (p->nelem >= 0 && p->elem_count > p->nelem) {
+ too_many_initialisers();
+ return p->s_tpp;
+ }
+ if (tp->tp_fund == ARRAY) {
+ return arr_elem(p->s_tpp, p);
+ }
+ return p->s_tpp;
+ case STRUCT:
+ sd = gen_align_to_next(p);
+ if (! sd) {
+ while (p->bytes_upto_here++ < tp->tp_size)
+ con_nullbyte();
+ if (p->s_nested) {
+ p = p->next;
+ free_e_stack(p_stack);
+ p_stack = p;
+ goto again;
+ }
+ too_many_initialisers();
+ return p->s_tpp;
+ }
+ if (AHEAD != '{' && aggregate_type(sd->sd_type)) {
+ return gen_tphead(&(sd->sd_type), 1);
+ }
+ return &(sd->sd_type);
+ }
+}
+
+struct sdef *
+gen_align_to_next(p)
+ register struct e_stack *p;
+{
+ register struct sdef *sd = p->s_def;
+
+ if (! sd) return sd;
+#ifndef NOBITFIELD
+ do {
+ if (is_anon_idf(sd->sd_idf)) put_bf(sd->sd_type, (arith) 0);
+#endif
+ sd = next_field(sd, p);
+#ifndef NOBITFIELD
+ } while (sd && is_anon_idf(sd->sd_idf));
+#endif
+ p->s_def = sd;
+ return sd;
+}
+
+gen_tpend()
+{
+ register struct e_stack *p = p_stack;
+ register struct type *tp;
+ register struct sdef *sd;
+ int getout = 0;
+
+ while (!getout && p) {
+ if (!gen_error) {
+ tp = *(p->s_tpp);
+ switch(tp->tp_fund) {
+ case ARRAY:
+ if (tp->tp_size == -1) {
+ *(p->s_tpp) = construct_type(ARRAY, tp->tp_up,
+ 0, p->elem_count, NO_PROTO);
+ }
+ else {
+ while (p->nelem-- > p->elem_count) {
+ pad(tp->tp_up);
+ }
+ }
+ break;
+ case STRUCT:
+ sd = gen_align_to_next(p);
+ while (sd) {
+ pad(sd->sd_type);
+ if (sd->sd_sdef)
+ p->bytes_upto_here += zero_bytes(sd);
+ p->bytes_upto_here +=
+ size_of_type(sd->sd_type, "selector");
+ sd = sd->sd_sdef;
+ }
+ while (p->bytes_upto_here++ < tp->tp_size)
+ con_nullbyte();
+ break;
+ }
+ }
+ if (! p->s_nested) getout = 1;
+ p = p->next;
+ free_e_stack(p_stack);
+ p_stack = p;
+ }
+ gen_error = 0;
+}
+
+/* check_and_pad() is given a simple initialisation expression
+ where the type can be either a simple or an aggregate type.
+ In the latter case, only the first member is initialised and
+ the rest is zeroed.
+*/
+check_and_pad(expp, tpp)
+ struct type **tpp;
+ struct expr **expp;
+{
+ register struct type *tp = *tpp;
+
+ if (tp->tp_fund == ARRAY) {
+ check_and_pad(expp, &(tp->tp_up)); /* first member */
+ if (tp->tp_size == (arith)-1)
+ /* no size specified upto here: just
+ set it to the size of one member.
+ */
+ tp = *tpp = construct_type(ARRAY, tp->tp_up,
+ 0, (arith)1, NO_PROTO);
+ else {
+ register int dim = tp->tp_size / tp->tp_up->tp_size;
+ /* pad remaining members with zeroes */
+ while (--dim > 0)
+ pad(tp->tp_up);
+ }
+ }
+ else
+ if (tp->tp_fund == STRUCT) {
+ register struct sdef *sd = tp->tp_sdef;
+
+ check_and_pad(expp, &(sd->sd_type));
+ /* next selector is aligned by adding extra zeroes */
+ if (sd->sd_sdef)
+ zero_bytes(sd);
+ while (sd = sd->sd_sdef) { /* pad remaining selectors */
+ pad(sd->sd_type);
+ if (sd->sd_sdef)
+ zero_bytes(sd);
+ }
+ }
+ else if (tp->tp_fund == UNION) {
+ /* only the first selector can be initialized */
+ register struct sdef *sd = tp->tp_sdef;
+
+ check_and_pad(expp, &(sd->sd_type));
+ }
+ else /* simple type */
+ check_ival(expp, tp);
+}
+
+/* pad() fills an element of type tp with zeroes.
+ If the element is an aggregate, pad() is called recursively.
+*/
+pad(tpx)
+ struct type *tpx;
+{
+ register struct type *tp = tpx;
+ register arith sz = tp->tp_size;
+
+ gen_tpcheck(&tpx, 1);
+ if (gen_error) return;
+ switch (tp->tp_fund) {
+ case UNION:
+#ifndef NOROPTION
+ if (options['R']) {
+ warning("initialisation of unions not allowed");
+ }
+#endif
+ break;
+#ifndef NOBITFIELD
+ case FIELD:
+ put_bf(tp, (arith)0);
+ return;
+#endif NOBITFIELD
+ default:
+ break;
+ }
+
+ while (sz >= word_size) {
+ C_con_cst((arith) 0);
+ sz -= word_size;
+ }
+ while (sz) {
+ C_con_icon("0", (arith) 1);
+ sz--;
+ }
+}
+
+/* check_ival() checks whether the initialisation of an element
+ of a fundamental type is legal and, if so, performs the initialisation
+ by directly generating the necessary code.
+ No further comment is needed to explain the internal structure
+ of this straightforward function.
+*/
+check_ival(expp, tp)
+ register struct type *tp;
+ struct expr **expp;
+{
+ /* The philosophy here is that ch7cast puts an explicit
+ conversion node in front of the expression if the types
+ are not compatible. In this case, the initialisation
+ expression is no longer a constant.
+ */
+ register struct expr *expr = *expp;
+
+ switch (tp->tp_fund) {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case LONG:
+ case ENUM:
+ case POINTER:
+ ch7cast(expp, '=', tp);
+ expr = *expp;
+#ifdef DEBUG
+ print_expr("init-expr after cast", expr);
+#endif DEBUG
+ if (!is_ld_cst(expr))
+ illegal_init_cst(expr);
+ else
+ if (expr->VL_CLASS == Const)
+ con_int(expr);
+ else
+ if (expr->VL_CLASS == Name) {
+ register struct idf *idf = expr->VL_IDF;
+
+ if (idf->id_def->df_level >= L_LOCAL)
+ illegal_init_cst(expr);
+ else /* e.g., int f(); int p = f; */
+ if (idf->id_def->df_type->tp_fund == FUNCTION)
+ C_con_pnam(idf->id_text);
+ else /* e.g., int a; int *p = &a; */
+ C_con_dnam(idf->id_text, expr->VL_VALUE);
+ }
+ else {
+ ASSERT(expr->VL_CLASS == Label);
+ C_con_dlb(expr->VL_LBL, expr->VL_VALUE);
+ }
+ break;
+#ifndef NOFLOAT
+ case FLOAT:
+ case DOUBLE:
+ ch7cast(expp, '=', tp);
+ expr = *expp;
+#ifdef DEBUG
+ print_expr("init-expr after cast", expr);
+#endif DEBUG
+ if (expr->ex_class == Float)
+ C_con_fcon(expr->FL_VALUE, expr->ex_type->tp_size);
+#ifdef NOTDEF
+
+Coercion from int to float is now always done compile time.
+This, to accept declarations like
+double x = -(double)1;
+and also to prevent runtime coercions for compile-time constants.
+
+ else
+ if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) {
+ /* float f = 1; */
+ expr = expr->OP_RIGHT;
+ if (is_cp_cst(expr))
+ C_con_fcon(long2str((long)expr->VL_VALUE, 10),
+ tp->tp_size);
+ else
+ illegal_init_cst(expr);
+ }
+#endif NOTDEF
+ else
+ illegal_init_cst(expr);
+ break;
+#endif NOFLOAT
+
+#ifndef NOBITFIELD
+ case FIELD:
+ ch7cast(expp, '=', tp->tp_up);
+ expr = *expp;
+#ifdef DEBUG
+ print_expr("init-expr after cast", expr);
+#endif DEBUG
+ if (is_cp_cst(expr))
+ put_bf(tp, expr->VL_VALUE);
+ else
+ illegal_init_cst(expr);
+ break;
+#endif NOBITFIELD
+
+ case ERRONEOUS:
+ break;
+ default:
+ crash("check_ival");
+ /*NOTREACHED*/
+ }
+}
+
+/* ch_array() initialises an array of characters when given
+ a string constant.
+ Alignment is taken care of.
+*/
+ch_array(tpp, ex)
+ struct type **tpp; /* type tp = array of characters */
+ struct expr *ex;
+{
+ register struct type *tp = *tpp;
+ register arith length = ex->SG_LEN;
+ char *s;
+
+ ASSERT(ex->ex_class == String);
+ if (tp->tp_size == (arith)-1) {
+ /* set the dimension */
+ tp = *tpp = construct_type(ARRAY, tp->tp_up, 0, length, NO_PROTO);
+ }
+ else {
+ arith dim = tp->tp_size / tp->tp_up->tp_size;
+
+ if (length > dim) {
+ expr_warning(ex, "too many initialisers");
+ }
+ length = dim;
+ }
+ /* throw out the characters of the already prepared string */
+ s = Malloc((unsigned) (length));
+ clear(s, (int) (length));
+ strncpy(s, ex->SG_VALUE, (int) length);
+ free(ex->SG_VALUE);
+ str_cst(s, (int) (length));
+ free(s);
+}
+
+/* As long as some parts of the pipeline cannot handle very long string
+ constants, string constants are written out in chunks
+*/
+str_cst(str, len)
+ register char *str;
+ register int len;
+{
+ int chunksize = ((127 + (int) word_size) / (int) word_size) * (int) word_size;
+
+ while (len > chunksize) {
+ C_con_scon(str, (arith) chunksize);
+ len -= chunksize;
+ str += chunksize;
+ }
+ C_con_scon(str, (arith) len);
+}
+
+#ifndef NOBITFIELD
+/* put_bf() takes care of the initialisation of (bit-)field
+ selectors of a struct: each time such an initialisation takes place,
+ put_bf() is called instead of the normal code generating routines.
+ Put_bf() stores the given integral value into "field" and
+ "throws" the result of "field" out if the current selector
+ is the last of this number of fields stored at the same address.
+*/
+put_bf(tp, val)
+ struct type *tp;
+ arith val;
+{
+ static long field = (arith)0;
+ static arith offset = (arith)-1;
+ register struct field *fd = tp->tp_field;
+ register struct sdef *sd = fd->fd_sdef;
+ static struct expr exp;
+
+ ASSERT(sd);
+ if (offset == (arith)-1) {
+ /* first bitfield in this field */
+ offset = sd->sd_offset;
+ exp.ex_type = tp->tp_up;
+ exp.ex_class = Value;
+ exp.VL_CLASS = Const;
+ }
+ if (val != 0) /* insert the value into "field" */
+ field |= (val & fd->fd_mask) << fd->fd_shift;
+ if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) {
+ /* the selector was the last stored at this address */
+ exp.VL_VALUE = field;
+ con_int(&exp);
+ field = (arith)0;
+ offset = (arith)-1;
+ }
+}
+#endif NOBITFIELD
+
+int
+zero_bytes(sd)
+ register struct sdef *sd;
+{
+ /* fills the space between a selector of a struct
+ and the next selector of that struct with zero-bytes.
+ */
+ register int n = sd->sd_sdef->sd_offset - sd->sd_offset -
+ size_of_type(sd->sd_type, "struct member");
+ register int count = n;
+
+ while (n-- > 0)
+ con_nullbyte();
+ return count;
+}
+
+int
+valid_type(tp, str)
+ struct type *tp;
+ char *str;
+{
+ ASSERT(tp!=(struct type *)0);
+ if (tp->tp_size < 0) {
+ error("size of %s unknown", str);
+ return 0;
+ }
+ return 1;
+}
+
+con_int(ex)
+ register struct expr *ex;
+{
+ register struct type *tp = ex->ex_type;
+
+ ASSERT(is_cp_cst(ex));
+ if (tp->tp_unsigned)
+ C_con_ucon(long2str((long)ex->VL_VALUE, -10), tp->tp_size);
+ else if (tp->tp_size == word_size)
+ C_con_cst(ex->VL_VALUE);
+ else
+ C_con_icon(long2str((long)ex->VL_VALUE, 10), tp->tp_size);
+}
+
+illegal_init_cst(ex)
+ struct expr *ex;
+{
+ expr_error(ex, "illegal initialisation constant");
+ gen_error = 1;
+}
+
+too_many_initialisers()
+{
+ error("too many initialisers");
+ gen_error = 1;
+}
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+/* To determine the minimum scope of a local variable, all (braced)
+ scopes are numbered consecutively. Next we maintain an array which
+ maps the nesting depth (level) onto the scope number; we record
+ the scope number of the first application of a local variable
+ in its definition. Each further application requires that the
+ level of the variable be at least large enough to comprise both
+ the present scope and that of its first application. That level
+ number is determined by searching the array and is then recorded in
+ the definition (beacuse it is always equal to or smaller than the
+ level already there).
+
+ The array is implemented as a linked list of struct brace.
+*/
+
+struct brace {
+ struct brace *next;
+ int br_count;
+ int br_level;
+};
+
+/* ALLOCDEF "brace" 10 */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+/* Lint class constants */
+
+#define LFDF 'a' /* Library Function Definition */
+#define LVDF 'b' /* Library Variable Definition */
+#define EFDF 'c' /* External Function Definition */
+#define EVDF 'd' /* External Variable Definition */
+#define EFDC 'e' /* External Function Declaration */
+#define EVDC 'f' /* External Variable Declaration */
+#define IFDC 'g' /* Implicit Function Declaration */
+#define SFDF 'h' /* Static Function Definition */
+#define SVDF 'i' /* Static Variable Definition */
+#define FC 'j' /* Function Call */
+#define VU 'k' /* Variable Usage */
+#define XXDF 'l' /* Ignore Class */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint-specific comment handling */
+
+#include <ctype.h>
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h>
+#include "interface.h"
+#include "arith.h"
+#include "l_state.h"
+#include "l_comment.h"
+
+extern char loptions[];
+
+/* Since the lexical analyser does a one-token look-ahead, pseudo-
+ comments are read too soon. This is remedied by first storing them
+ in static variables and then moving them to the real variables
+ one token later.
+*/
+
+PRIVATE int notreached;
+PRIVATE int varargsN = -1;
+PRIVATE int argsused;
+PRIVATE int formatN;
+PRIVATE int formatVAR;
+PRIVATE char *format;
+PRIVATE char *prev_format;
+
+PRIVATE make_format();
+
+int LINTLIB; /* file is lint library */
+int s_NOTREACHED; /* statement not reached */
+int f_VARARGSn; /* function with variable # of args */
+int f_ARGSUSED; /* function does not use all args */
+int f_FORMATn; /* argument f_FORMATn is f_FORMAT */
+char *f_FORMAT;
+int f_FORMATvar; /* but the formal argument may be
+ absent because of varargs.h */
+
+lint_init_comment()
+{
+ LINTLIB = loptions['L'];
+}
+
+lint_comment_ahead()
+{
+ s_NOTREACHED = notreached;
+ notreached = 0;
+}
+
+lint_comment_function()
+{
+ f_ARGSUSED = argsused | loptions['v'];
+ argsused = 0;
+
+ f_VARARGSn = varargsN;
+ varargsN = -1;
+
+ f_FORMATn = formatN;
+ formatN = 0;
+ f_FORMAT = format;
+ if (format)
+ prev_format = format;
+ format = 0;
+
+ f_FORMATvar = formatVAR;
+ formatVAR = 0;
+}
+
+PRIVATE char buf[1000];
+PRIVATE char *bufpos; /* next free position in buf */
+
+lint_start_comment()
+{
+ bufpos = &buf[0];
+}
+
+lint_comment_char(c)
+ int c;
+{
+/* This function is called with every character between /_* and *_/ */
+ if (bufpos - &buf[0] < sizeof(buf)-1)
+ *bufpos++ = (char)c;
+}
+
+lint_end_comment()
+{
+ *bufpos++ = '\0';
+ bufpos = &buf[0];
+
+ /* skip initial blanks */
+ while (*bufpos && isspace(*bufpos)) {
+ bufpos++;
+ }
+
+ /* now test for one of the pseudo-comments */
+ if (strncmp(bufpos, "NOTREACHED", 10) == 0) {
+ notreached = 1;
+ }
+ else
+ if (strncmp(bufpos, "ARGSUSED", 8) == 0) {
+ argsused = 1;
+ }
+ else
+ if (strncmp(bufpos, "LINTLIBRARY", 11) == 0) {
+ LINTLIB = 1;
+ }
+ else
+ if (strncmp(bufpos, "VARARGS", 7) == 0) {
+ bufpos += 7;
+ varargsN = isdigit(*bufpos) ? atoi(bufpos) : 0;
+ }
+ else
+ if (strncmp(bufpos, "FORMAT", 6) == 0 && isdigit(bufpos[6])) {
+ register int argn;
+
+ bufpos += 6;
+ argn = *bufpos++ - '0';
+ varargsN = argn + 1;
+ if (*bufpos == 'v') {
+ /* something like FORMAT3v */
+ formatVAR = 1;
+ bufpos++;
+ }
+ make_format(argn, bufpos);
+
+ }
+}
+
+/* We use a small FSA to skip layout inside formats, but to preserve
+ a space between letters and digits.
+*/
+
+#define NONE 0
+#define LETGIT 1
+#define LETGITSPACE 2
+
+PRIVATE
+make_format(argn, oldf)
+ int argn;
+ char *oldf;
+{
+ register char *newf;
+ register int last_stat;
+
+ while (*oldf && *oldf != '$') {
+ oldf++;
+ }
+ if (!*oldf) {
+ /* no format given, repeat previous format */
+ if (!prev_format) {
+ warning("format missing and no previous format");
+ }
+ formatN = argn;
+ format = prev_format;
+ return;
+ }
+ if (*oldf++ != '$') {
+ warning("no format in FORMAT pseudo-comment");
+ format = 0;
+ return;
+ }
+
+ /* there is a new format to be composed */
+ newf = Malloc(strlen(oldf));
+ /* certainly enough and probably not overly too much */
+ formatN = argn;
+ format = newf;
+
+ last_stat = NONE;
+ while (*oldf && *oldf != '$') {
+ register char ch = *oldf++;
+
+ if (isspace(ch)) {
+ if (last_stat == LETGIT)
+ last_stat = LETGITSPACE;
+ }
+ else
+ if (isalnum(ch)) {
+ switch (last_stat) {
+ case NONE:
+ last_stat = LETGIT;
+ break;
+ case LETGITSPACE:
+ *newf++ = ' ';
+ last_stat = LETGIT;
+ break;
+ }
+ *newf++ = ch;
+ }
+ else {
+ last_stat = NONE;
+ *newf++ = ch;
+ }
+ }
+ if (*oldf != '$') {
+ warning("no end of format in FORMAT pseudo-comment");
+ format = 0;
+ return;
+ }
+ *newf++ = '\0';
+}
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+extern int LINTLIB; /* file is lint library */
+extern int s_NOTREACHED; /* statement not reached */
+extern int f_VARARGSn; /* function with variable # of args */
+extern int f_ARGSUSED; /* function does not use all args */
+extern int f_FORMATn; /* argument f_FORMATn is f_FORMAT */
+extern char *f_FORMAT;
+extern int f_FORMATvar; /* but the formal argument may be
+ absent because of varargs.h */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+/*
+ *The following functions are hacked to null-functions (i.e. they
+ * do nothing). This needs another solution in the future.
+ */
+#include "lint.h"
+
+#ifdef LINT
+
+#include "arith.h"
+#include "label.h"
+
+C_close(){}
+int C_busy(){return 0;}
+
+
+/* More routines */
+/* ARGSUSED */
+CC_bhcst(ps_xxx,n,w,i) arith n,w; {}
+/* ARGSUSED */
+CC_crcst(ps_xxx,v) arith v; {}
+/* ARGSUSED */
+CC_crdlb(ps_xxx,v,s) label v; arith s; {}
+/* ARGSUSED */
+CC_crdnam(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_crfcon(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_cricon(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_crilb(ps_xxx,v) label v; {}
+/* ARGSUSED */
+CC_crpnam(ps_xxx,v) char *v; {}
+/* ARGSUSED */
+CC_crscon(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_crucon(ps_xxx,v,s) char *v; arith s; {}
+/* ARGSUSED */
+CC_cst(l) {}
+/* ARGSUSED */
+CC_dfdlb(l) label l; {}
+/* ARGSUSED */
+CC_dfdnam(s) char *s; {}
+/* ARGSUSED */
+CC_dfilb(l) label l; {}
+/* ARGSUSED */
+CC_end(l) arith l; {}
+CC_msend() {}
+/* ARGSUSED */
+CC_msstart(ms) {}
+/* ARGSUSED */
+CC_opcst(op_xxx,c) arith c; {}
+/* ARGSUSED */
+CC_opdlb(op_xxx,g,o) label g; arith o; {}
+/* ARGSUSED */
+CC_opilb(op_xxx,b) label b; {}
+/* ARGSUSED */
+CC_oppnam(op_xxx,p) char *p; {}
+/* ARGSUSED */
+CC_pronarg(s) char *s; {}
+/* ARGSUSED */
+CC_psdlb(ps_xxx,l) label l; {}
+/* ARGSUSED */
+CC_psdnam(ps_xxx,s) char *s; {}
+/* ARGSUSED */
+CC_pspnam(ps_xxx,s) char *s; {}
+/* ARGSUSED */
+CC_scon(v,s) char *s; {}
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint evaluation order checking */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h> /* for st_free */
+#include "interface.h"
+#include "assert.h"
+#include "arith.h" /* definition arith */
+#include "label.h" /* definition label */
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+#include "code.h" /* RVAL etc */
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "type.h"
+#include "level.h"
+#include "nofloat.h"
+#include "l_lint.h"
+#include "l_state.h"
+
+extern char *symbol2str();
+
+PRIVATE check_ev_order();
+
+check_and_merge(expr, espp, esp)
+ struct expr *expr;
+ struct expr_state **espp, *esp;
+{
+/* Checks for undefined evaluation orders in case of a non-sequencing operator.
+ * In addition the sets of used and set variables of both expressions are
+ * united.
+ * *espp will be pointing to this new list. esp is used for this list.
+ */
+ register struct expr_state **pp, *p1, *p2;
+ int oper = expr->OP_OPER;
+ int is_sequencer =
+ (oper == '?' || oper == OR || oper == AND || oper ==',');
+
+ for (p1 = *espp; p1; p1 = p1->next) {
+ /* scan the list esp for the same variable */
+ p2 = esp;
+ pp = &esp;
+ while (p2) {
+ if ( /* p1 and p2 refer to the same location */
+ p1->es_idf == p2->es_idf
+ && p1->es_offset == p2->es_offset
+ ) {
+ /* check */
+ if (!is_sequencer)
+ check_ev_order(p1, p2, expr);
+
+ /* merge the info */
+ p1->es_used |= p2->es_used;
+ p1->es_referred |= p2->es_referred;
+ p1->es_set |= p2->es_set;
+
+ /* and remove the entry from esp */
+ *pp = p2->next;
+ free_expr_state(p2);
+ p2 = *pp;
+ }
+ else {
+ /* skip over the entry in esp */
+ pp = &p2->next;
+ p2 = p2->next;
+ }
+ }
+ }
+ /* If there is anything left in the list esp, this is put in
+ front of the list *espp is now pointing to, and *espp will be
+ left pointing to this new list.
+ */
+ if (!esp)
+ return;
+ p1 = *espp;
+ *espp = esp;
+ while (esp->next)
+ esp = esp->next;
+ esp->next = p1;
+}
+
+PRIVATE
+check_ev_order(esp1, esp2, expr)
+ struct expr_state *esp1, *esp2;
+ struct expr *expr;
+{
+ if ( (esp1->es_used && esp2->es_set)
+ || (esp1->es_set && esp2->es_used)
+ || (esp1->es_set && esp2->es_set)
+ ) {
+ expr_warning(expr,
+ "result of %s depends on evaluation order on %s",
+ symbol2str(expr->OP_OPER),
+ esp1->es_idf->id_text);
+ }
+}
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint main routines */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h> /* for st_free */
+#include "debug.h"
+#include "interface.h"
+#include "assert.h"
+#include "arith.h" /* definition arith */
+#include "label.h" /* definition label */
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+#include "code.h" /* RVAL etc */
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "type.h"
+#include "level.h"
+#include "nofloat.h"
+#include "l_lint.h"
+#include "l_state.h"
+#include "l_outdef.h"
+
+extern char options[128];
+extern char *symbol2str();
+
+PRIVATE struct expr_state *expr2state();
+PRIVATE struct expr_state *value2state();
+PRIVATE struct expr_state *oper2state();
+PRIVATE expr_ignored();
+PRIVATE add_expr_state();
+PRIVATE referred_esp();
+PRIVATE free_expr_states();
+
+lint_init()
+{
+ lint_init_comment();
+ lint_init_stack();
+}
+
+lint_expr(expr, used)
+ struct expr *expr;
+ int used; /* USED or IGNORED */
+{
+ register struct expr_state *esp;
+
+ esp = expr2state(expr, RVAL, used);
+ referred_esp(esp);
+ free_expr_states(esp);
+}
+
+PRIVATE struct expr_state *
+expr2state(expr, val, used)
+ register struct expr *expr;
+ int val; /* RVAL or LVAL */
+ int used; /* USED or IGNORED */
+{
+/* Main function to process an expression tree.
+ * It returns a structure containing information about which variables
+ * are set and which are used in the expression.
+ * In addition it sets 'used' and 'set' fields of the corresponding
+ * variables in the current state.
+ * If the value of an operation without side-effects is not used,
+ * a warning is given.
+ */
+ if (used == IGNORED) {
+ expr_ignored(expr);
+ }
+
+ switch (expr->ex_class) {
+ case Value:
+ return value2state(expr, val);
+
+ case Oper:
+ return oper2state(expr, val, used);
+
+ default: /* String, Float, Type */
+ return 0;
+ }
+}
+
+PRIVATE struct expr_state *
+value2state(expr, val)
+ struct expr *expr;
+ int val; /* RVAL or LVAL */
+{
+ switch (expr->VL_CLASS) {
+ case Const:
+ case Label:
+ return 0;
+
+ case Name:
+ {
+ register struct idf *idf = expr->VL_IDF;
+ struct expr_state *esp = 0;
+
+ if (!idf || !idf->id_def)
+ return 0;
+
+ if (val == RVAL && expr->ex_lvalue == 1) {
+ /* value of identifier used */
+ change_state(idf, USED);
+ add_expr_state(expr->EX_VALUE, USED, &esp);
+ }
+ if (val == RVAL && expr->ex_lvalue == 0) {
+ /* address of identifier used */
+ add_expr_state(expr->EX_VALUE, REFERRED, &esp);
+ }
+ return esp;
+ }
+
+ default:
+ NOTREACHED();
+ /* NOTREACHED */
+ }
+}
+
+/* Let's get this straight.
+ An assignment is performed by elaborating the LHS and the RHS
+ collaterally, to use the A68 terminology, and then serially do the
+ actual assignment. This means:
+ 1. evaluate the LHS as an LVAL,
+ 2. evaluate the RHS as an RVAL,
+ 3. merge them checking for interference,
+ 4. set the result of the LHS to SET, if it is a named variable
+*/
+
+PRIVATE struct expr_state *
+oper2state(expr, val, used)
+ struct expr *expr;
+ int val; /* RVAL or LVAL */
+ int used; /* USED or IGNORED */
+{
+ register int oper = expr->OP_OPER;
+ register struct expr *left = expr->OP_LEFT;
+ register struct expr *right = expr->OP_RIGHT;
+ struct expr_state *esp_l = 0;
+ struct expr_state *esp_r = 0;
+
+ switch (oper) {
+
+ /* assignments */
+ case '=':
+ case PLUSAB:
+ case MINAB:
+ case TIMESAB:
+ case DIVAB:
+ case MODAB:
+ case LEFTAB:
+ case RIGHTAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ /* evaluate the LHS, only once; see RM 7.14 */
+ esp_l = expr2state(left, (oper == '=' ? LVAL : RVAL), USED);
+
+ /* evaluate the RHS as an RVAL and merge */
+ esp_r = expr2state(right, RVAL, USED);
+ check_and_merge(expr, &esp_l, esp_r);
+
+ /* set resulting variable, if any */
+ if (ISNAME(left)) {
+ change_state(left->VL_IDF, SET);
+ add_expr_state(left->EX_VALUE, SET, &esp_l);
+ }
+
+ return esp_l;
+
+ case POSTINCR:
+ case POSTDECR:
+ case PLUSPLUS:
+ case MINMIN:
+ esp_l = expr2state(left, RVAL, USED);
+
+ /* set resulting variable, if any */
+ if (ISNAME(left)) {
+ change_state(left->VL_IDF, SET);
+ add_expr_state(left->EX_VALUE, SET, &esp_l);
+ }
+
+ return esp_l;
+
+ case '?':
+ esp_l = expr2state(left, RVAL, USED);
+ esp_r = expr2state(right->OP_LEFT, RVAL, USED);
+ check_and_merge(expr, &esp_l, esp_r);
+ esp_r = expr2state(right->OP_RIGHT, RVAL, USED);
+ check_and_merge(expr, &esp_l, esp_r);
+ return esp_l;
+
+ case '(':
+ if (right != 0) {
+ /* function call with parameters */
+ register struct expr *ex = right;
+
+ while ( ex->ex_class == Oper
+ && ex->OP_OPER == PARCOMMA
+ ) {
+ esp_r = expr2state(ex->OP_RIGHT, RVAL, USED);
+ check_and_merge(expr, &esp_l, esp_r);
+ ex = ex->OP_LEFT;
+ }
+ esp_r = expr2state(ex, RVAL, USED);
+ check_and_merge(expr, &esp_l, esp_r);
+ }
+
+ if (ISNAME(left)) {
+ fill_outcall(expr,
+ expr->ex_type->tp_fund == VOID ?
+ VOIDED : used
+ );
+ outcall();
+ left->VL_IDF->id_def->df_used = 1;
+ }
+ else {
+ esp_r = expr2state(left, RVAL, USED);
+ check_and_merge(expr, &esp_l, esp_r);
+ }
+ referred_esp(esp_l);
+ return esp_l;
+
+ case '.':
+ return expr2state(left, val, USED);
+
+ case ARROW:
+ return expr2state(left, RVAL, USED);
+
+ case INT2INT:
+ case INT2FLOAT:
+ case FLOAT2INT:
+ case FLOAT2FLOAT:
+ return expr2state(right, RVAL, USED);
+
+ /* monadic operators */
+ case '-':
+ case '*':
+ if (left)
+ goto dyadic;
+ case '~':
+ case '!':
+ return expr2state(right, RVAL, USED);
+
+ /* relational operators */
+ case '<':
+ case '>':
+ case LESSEQ:
+ case GREATEREQ:
+ case EQUAL:
+ case NOTEQUAL:
+ lint_relop(left, right, oper);
+ lint_relop(right, left,
+ oper == '<' ? '>' :
+ oper == '>' ? '<' :
+ oper == LESSEQ ? GREATEREQ :
+ oper == GREATEREQ ? LESSEQ :
+ oper
+ );
+ goto dyadic;
+
+ /* dyadic operators */
+ dyadic:
+ case '+':
+ case '/':
+ case '%':
+ case ',':
+ case LEFT:
+ case RIGHT:
+ case '&':
+ case '|':
+ case '^':
+ case OR:
+ case AND:
+ esp_l = expr2state(left, RVAL,
+ oper == ',' ? IGNORED : USED);
+ esp_r = expr2state(right, RVAL,
+ oper == ',' ? used : USED);
+ check_and_merge(expr, &esp_l, esp_r);
+
+ return esp_l;
+
+ default:
+ return 0; /* for initcomma */
+ }
+}
+
+PRIVATE
+expr_ignored(expr)
+ struct expr *expr;
+{
+ switch (expr->ex_class) {
+ case Oper:
+ switch (expr->OP_OPER) {
+ case '=':
+ case TIMESAB:
+ case DIVAB:
+ case MODAB:
+ case LEFTAB:
+ case RIGHTAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ case AND: /* doubtful but useful */
+ case OR: /* doubtful but useful */
+ case '(':
+ case '?':
+ case ',':
+ break;
+
+ case PLUSAB:
+ case MINAB:
+ case POSTINCR:
+ case POSTDECR:
+ case PLUSPLUS:
+ case MINMIN:
+ /* may hide the operator '*' */
+ if ( /* operation on a pointer */
+ expr->OP_TYPE->tp_fund == POINTER
+ && /* the result is dereferenced, e.g. *p++; */
+ expr->ex_type == expr->OP_TYPE->tp_up
+ ) {
+ hwarning("result of * ignored");
+ }
+ break;
+
+ default:
+ hwarning("result of %s ignored",
+ symbol2str(expr->OP_OPER));
+ break;
+ }
+ break;
+
+ case Value:
+ hwarning("value as statement");
+ break;
+
+ default: /* String Float */
+ hwarning("constant as statement");
+ break;
+ }
+}
+
+PRIVATE
+add_expr_state(value, to_state, espp)
+ struct value value;
+ struct expr_state **espp;
+{
+ register struct expr_state *esp = *espp;
+
+ ASSERT(value.vl_class == Name);
+
+ /* try to find the esp */
+ while ( esp
+ && !( esp->es_idf == value.vl_data.vl_idf
+ && esp->es_offset == value.vl_value
+ )
+ ) {
+ esp = esp->next;
+ }
+
+ /* if not found, add it */
+ if (!esp) {
+ esp = new_expr_state();
+ esp->es_idf = value.vl_data.vl_idf;
+ esp->es_offset = value.vl_value;
+ esp->next = *espp;
+ *espp = esp;
+ }
+
+ /* set state */
+ switch (to_state) {
+ case USED:
+ esp->es_used = 1;
+ break;
+ case REFERRED:
+ esp->es_referred = 1;
+ break;
+ case SET:
+ esp->es_set = 1;
+ break;
+ default:
+ NOTREACHED();
+ /* NOTREACHED */
+ }
+}
+
+PRIVATE
+referred_esp(esp)
+ struct expr_state *esp;
+{
+ /* raises all REFERRED items to SET and USED status */
+ while (esp) {
+ if (esp->es_referred) {
+ esp->es_set = 1;
+ change_state(esp->es_idf, SET);
+ esp->es_used = 1;
+ change_state(esp->es_idf, USED);
+ esp->es_referred = 0;
+ }
+ esp = esp->next;
+ }
+}
+
+PRIVATE
+free_expr_states(esp)
+ register struct expr_state *esp;
+{
+ while (esp) {
+ register struct expr_state *esp2 = esp;
+
+ esp = esp->next;
+ free_expr_state(esp2);
+ }
+}
+
+#ifdef DEBUG
+print_esp(msg, esp)
+ char *msg;
+ struct expr_state *esp;
+{
+ print("%s: <", msg);
+ while (esp) {
+ print(" %s[%d]%c%c%c ",
+ esp->es_idf->id_text, esp->es_offset,
+ (esp->es_used ? 'U' : ' '),
+ (esp->es_referred ? 'R' : ' '),
+ (esp->es_set ? 'S' : ' ')
+ );
+ esp = esp->next;
+ }
+ print(">\n");
+}
+#endif DEBUG
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* LINT FLAGS */
+
+#define USED 0
+#define IGNORED 1
+#define SET 2
+#define VOIDED 3
+#define REFERRED 4
+
+/* for od_valreturned */
+#define NOVALRETURNED 0
+#define VALRETURNED 1
+#define NORETURN 2 /* end of function NOTREACHED */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint miscellaneous routines */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h> /* for st_free */
+#include "interface.h"
+#include "arith.h" /* definition arith */
+#include "label.h" /* definition label */
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+#include "code.h" /* RVAL etc */
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "type.h"
+#include "level.h"
+#include "nofloat.h"
+#include "l_state.h"
+
+extern char *symbol2str();
+extern struct type *func_type;
+
+PRIVATE lint_enum_arith();
+PRIVATE lint_conversion();
+PRIVATE int numsize();
+
+lint_new_oper(expr)
+ struct expr *expr;
+{
+ /* Does additional checking on a newly constructed expr node
+ of class Oper.
+
+ Some code in this routine could be contracted, but since
+ I am not sure we have covered the entire ground, we'll
+ leave the contracting for some rainy day.
+ */
+ register struct expr *left = expr->OP_LEFT;
+ register struct expr *right = expr->OP_RIGHT;
+ register int oper = expr->OP_OPER;
+ register int l_fund =
+ left == 0 ? 0 : /* for monadics */
+ left->ex_type->tp_fund;
+ register int r_fund =
+ right == 0 ? 0 : /* for ( without parameters */
+ right->ex_type->tp_fund;
+
+ /* In ch7.c, in ch7asgn(), a combined operator/assignment
+ is hammered into correctness by repeated application of
+ ch7bin(), which calls new_oper(), which calls lint_new_oper().
+ These spurious calls understandably cause spurious error
+ messages, which we don't like. So we try to suppress these
+ wierd calls here. This refers to the code marked
+ this is really $#@&*%$# !
+ in ch7asgn().
+ */
+ switch (oper) {
+ case PLUSAB:
+ case MINAB:
+ case TIMESAB:
+ case DIVAB:
+ case MODAB:
+ case LEFTAB:
+ case RIGHTAB:
+ case ANDAB:
+ case XORAB:
+ case ORAB:
+ /* is the left operand wierd? */
+ if ( left->ex_class == Value
+ && left->VL_CLASS == Const
+ && left->VL_VALUE == 0
+ ) {
+ return;
+ }
+ }
+
+ switch (oper) {
+ case '=':
+ lint_conversion(right, l_fund);
+ break;
+
+ case PLUSAB:
+ lint_conversion(right, l_fund);
+ case '+':
+ lint_enum_arith(l_fund, oper, r_fund);
+ break;
+
+ case MINAB:
+ lint_conversion(right, l_fund);
+ case '-':
+ if (left == 0) {
+ /* unary */
+ if (r_fund == ENUM)
+ warning("negating an enum");
+ }
+ else {
+ /* binary */
+ if (l_fund == ENUM && r_fund == ENUM) {
+ if (!equal_type(left->ex_type, right->ex_type))
+ warning("subtracting enums of different type");
+ /* update the type, cem does not do it */
+ expr->ex_type = int_type;
+ }
+ lint_enum_arith(l_fund, oper, r_fund);
+ }
+ break;
+
+ case TIMESAB:
+ lint_conversion(right, l_fund);
+ case '*':
+ if (left == 0) {
+ /* unary */
+ }
+ else {
+ /* binary */
+ if (l_fund == ENUM || r_fund == ENUM)
+ warning("multiplying enum");
+ }
+ break;
+
+ case DIVAB:
+ lint_conversion(right, l_fund);
+ case '/':
+ if (l_fund == ENUM || r_fund == ENUM)
+ warning("division on enum");
+ break;
+
+ case MODAB:
+ lint_conversion(right, l_fund);
+ case '%':
+ if (l_fund == ENUM || r_fund == ENUM)
+ warning("modulo on enum");
+ break;
+
+ case '~':
+ if (r_fund == ENUM || r_fund == FLOAT || r_fund == DOUBLE)
+ warning("~ on %s", symbol2str(r_fund));
+ break;
+
+ case '!':
+ if (r_fund == ENUM)
+ warning("! on enum");
+ break;
+
+ case INT2INT:
+ case INT2FLOAT:
+ case FLOAT2INT:
+ case FLOAT2FLOAT:
+ lint_conversion(right, l_fund);
+ break;
+
+ case '<':
+ case '>':
+ case LESSEQ:
+ case GREATEREQ:
+ case EQUAL:
+ case NOTEQUAL:
+ if ( (l_fund == ENUM || r_fund == ENUM)
+ && !equal_type(left->ex_type, right->ex_type)
+ ) {
+ warning("comparing enum with non-enum");
+ }
+ lint_relop(left, right, oper);
+ lint_relop(right, left,
+ oper == '<' ? '>' :
+ oper == '>' ? '<' :
+ oper == LESSEQ ? GREATEREQ :
+ oper == GREATEREQ ? LESSEQ :
+ oper
+ );
+ break;
+
+ case LEFTAB:
+ case RIGHTAB:
+ lint_conversion(right, l_fund);
+ case LEFT:
+ case RIGHT:
+ if (l_fund == ENUM || r_fund == ENUM)
+ warning("shift on enum");
+ break;
+
+ case ANDAB:
+ case ORAB:
+ case XORAB:
+ lint_conversion(right, l_fund);
+ case '&':
+ case '|':
+ case '^':
+ if (l_fund == ENUM || r_fund == ENUM)
+ warning("bit operations on enum");
+ break;
+
+ case ',':
+ case '?':
+ case ':':
+ case AND:
+ case OR:
+ case POSTINCR:
+ case POSTDECR:
+ case PLUSPLUS:
+ case MINMIN:
+ case '(':
+ case '.':
+ case ARROW:
+ default:
+ /* OK with lint */
+ break;
+ }
+}
+
+PRIVATE
+lint_enum_arith(l_fund, oper, r_fund)
+ int l_fund, oper, r_fund;
+{
+ if ( l_fund == ENUM
+ && r_fund != CHAR
+ && r_fund != SHORT
+ && r_fund != INT
+ ) {
+ warning("%s on enum and %s",
+ symbol2str(oper), symbol2str(r_fund));
+ }
+ else
+ if ( r_fund == ENUM
+ && l_fund != CHAR
+ && l_fund != SHORT
+ && l_fund != INT
+ ) {
+ warning("%s on %s and enum",
+ symbol2str(oper), symbol2str(l_fund));
+ }
+}
+
+PRIVATE
+lint_conversion(from_expr, to_fund)
+ struct expr *from_expr;
+ int to_fund;
+{
+ register int from_fund = from_expr->ex_type->tp_fund;
+
+ /* was there an attempt to reduce the type of the from_expr
+ of the form
+ expr & 0377
+ or something like this?
+ */
+ if (from_expr->ex_class == Oper && from_expr->OP_OPER == INT2INT) {
+ from_expr = from_expr->OP_LEFT;
+ }
+ if (from_expr->ex_class == Oper && from_expr->OP_OPER == '&') {
+ struct expr *bits =
+ is_cp_cst(from_expr->OP_LEFT) ? from_expr->OP_LEFT :
+ is_cp_cst(from_expr->OP_RIGHT) ? from_expr->OP_RIGHT :
+ 0;
+
+ if (bits) {
+ arith val = bits->VL_VALUE;
+
+ if (val < 256)
+ from_fund = CHAR;
+ else if (val < 256)
+ from_fund = SHORT;
+ }
+ }
+ if (numsize(from_fund) > numsize(to_fund)) {
+ awarning("conversion from %s to %s may lose accuracy",
+ symbol2str(from_fund), symbol2str(to_fund));
+ }
+}
+
+PRIVATE int
+numsize(fund)
+{
+ switch (fund) {
+ case CHAR: return 1;
+ case SHORT: return 2;
+ case INT: return 3;
+ case ENUM: return 3;
+ case LONG: return 4;
+ case FLOAT: return 5;
+ case DOUBLE: return 6;
+ default: return 0;
+ }
+}
+
+lint_ret_conv(from_expr)
+ struct expr *from_expr;
+{
+ lint_conversion(from_expr, func_type->tp_fund);
+}
+
+lint_ptr_conv(from, to)
+ short from, to;
+{
+/* X -> X ok -- this includes struct -> struct, of any size
+ * X -> CHAR ok
+ * DOUBLE -> X ok
+ * FLOAT -> LONG -> INT -> SHORT ok
+ */
+ if (from == to)
+ return;
+
+ if (to == CHAR)
+ return;
+
+ if (from == DOUBLE)
+ return;
+
+ switch (from) {
+ case FLOAT:
+ switch (to) {
+ case LONG:
+ case INT:
+ case SHORT:
+ return;
+ }
+ break;
+ case LONG:
+ switch (to) {
+ case INT:
+ case SHORT:
+ return;
+ }
+ break;
+ case INT:
+ switch (to) {
+ case SHORT:
+ return;
+ }
+ break;
+ }
+
+ if (from == CHAR) {
+ hwarning("pointer to char may not align correctly for a %s",
+ symbol2str(to));
+ }
+ else {
+ warning("pointer to %s may not align correctly for a %s",
+ symbol2str(from), symbol2str(to));
+ }
+}
+
+lint_relop(left, right, oper)
+ struct expr *left, *right;
+ int oper; /* '<', '>', LESSEQ, GREATEREQ, EQUAL, NOTEQUAL */
+{
+ /* left operand may be converted */
+ if ( left->ex_class == Oper
+ && left->OP_OPER == INT2INT
+ ) {
+ left = left->OP_RIGHT;
+ }
+
+ /* <unsigned> <relop> <neg-const|0> is doubtful */
+ if ( left->ex_type->tp_unsigned
+ && right->ex_class == Value
+ && right->VL_CLASS == Const
+ ) {
+ if (right->VL_VALUE < 0) {
+ warning("unsigned compared to negative constant");
+ }
+ if (right->VL_VALUE == 0) {
+ switch (oper) {
+ case '<':
+ warning("unsigned < 0 will always fail");
+ break;
+
+ case LESSEQ:
+ warning("unsigned <= 0 is probably wrong");
+ break;
+
+ case GREATEREQ:
+ warning("unsigned >= 0 will always succeed");
+ break;
+ }
+ }
+ }
+
+ /* <char> <relop> <neg-const> is undefined */
+ if ( left->ex_type->tp_fund == CHAR
+ && right->ex_class == Value
+ && right->VL_CLASS == Const
+ && (right->VL_VALUE < 0 || right->VL_VALUE > 127)
+ ) {
+ warning("character compared to negative constant");
+ }
+}
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint outdef construction */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h>
+#include "interface.h"
+#include "arith.h"
+#include "assert.h"
+#include "type.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "def.h"
+#include "struct.h"
+#include "field.h"
+#include "idf.h"
+#include "level.h"
+#include "label.h"
+#include "code.h"
+#include "expr.h"
+#include "l_lint.h"
+#include "l_comment.h"
+#include "l_outdef.h"
+#include "l_class.h"
+
+extern char *bts2str();
+extern char *symbol2str();
+
+int stat_number = 9999; /* static scope number */
+struct outdef OutDef;
+
+PRIVATE struct outdef OutCall;
+
+PRIVATE local_EFDC();
+PRIVATE output_def();
+PRIVATE outargs();
+PRIVATE outarg();
+PRIVATE outargstring();
+PRIVATE outargtype();
+PRIVATE implicit_func_decl();
+PRIVATE fill_arg();
+
+lint_declare_idf(idf, sc)
+ struct idf *idf;
+ int sc;
+{
+ register struct def *def = idf->id_def;
+ register int is_function = def->df_type->tp_fund == FUNCTION;
+
+ if (level == L_GLOBAL) {
+ lint_ext_def(idf, sc);
+ if (is_function)
+ def2decl(sc);
+ if (sc != TYPEDEF)
+ outdef();
+ }
+ else
+ if (level >= L_LOCAL && sc != STATIC && is_function) {
+ local_EFDC(idf);
+ }
+}
+
+lint_ext_def(idf, sc)
+ struct idf *idf;
+{
+/* At this place the following fields of the outputdefinition can be
+ * filled:
+ * name, stat_number, class, file, line, type.
+ * For variable definitions and declarations this will be all.
+ * For functions the fields nrargs and argtps are filled after parsing
+ * the arguments.
+ * The returns-field is known at the end of the function definition.
+ * sc indicates the storage class defined by the declaration specifier.
+ */
+ register struct def *def = idf->id_def;
+ register struct type *type = def->df_type;
+
+ OutDef.od_name = idf->id_text;
+ OutDef.od_statnr = (sc == STATIC ? stat_number : 0);
+
+ switch (type->tp_fund) {
+ case ERRONEOUS:
+ OutDef.od_class = XXDF;
+ break;
+ case FUNCTION:
+ /* For the moment assume it will be a definition.
+ * If no compound_statement follows, it is a declaration,
+ * in which case the class will be adjusted by def2decl().
+ */
+ OutDef.od_class = (sc == STATIC ? SFDF : EFDF);
+ break;
+ default: /* a variable */
+ OutDef.od_class =
+ sc == EXTERN ? EVDC :
+ sc == STATIC ? SVDF : EVDF;
+ break;
+ }
+ OutDef.od_file = def->df_file;
+ OutDef.od_line = def->df_line;
+ OutDef.od_type = (type->tp_fund == FUNCTION ? type->tp_up : type);
+ OutDef.od_valreturned = NORETURN;
+}
+
+def2decl(sc)
+ int sc;
+{
+/* It was assumed we were parsing a function definition.
+ * There was no compound statement following, so actually it was a
+ * declaration. This function updates the class.
+ */
+ OutDef.od_class = (sc == STATIC ? XXDF : EFDC);
+}
+
+set_od_valreturned(n)
+{
+ OutDef.od_valreturned = n;
+}
+
+PRIVATE
+local_EFDC(idf)
+ struct idf *idf;
+{
+ struct outdef od;
+
+ od.od_class = EFDC;
+ od.od_statnr = 0;
+ od.od_name = idf->id_text;
+ od.od_file = idf->id_def->df_file;
+ od.od_line = idf->id_def->df_line;
+ od.od_type = idf->id_def->df_type->tp_up;
+ output_def(&od);
+ /* The other fields are not used for this class. */
+}
+
+lint_formals()
+{
+/* Make a list of tp_entries containing the types of the formal
+ * parameters of the function definition just parsed.
+ */
+ register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
+ register struct argument **hook = &OutDef.od_arg;
+ register int nrargs = 0;
+
+ while (se) {
+ register struct type *type = se->se_idf->id_def->df_type;
+ register struct argument *arg = new_argument();
+
+ /* Do the conversions on the formals that could not be
+ done in declare_idf().
+ It is, unfortunately, impossible not to do them,
+ since the corresponding actuals will have been
+ converted to generate proper code and we do not
+ want to duplicate the whole of expression handling
+ for lint.
+ */
+ switch (type->tp_fund) {
+ case CHAR:
+ case SHORT:
+ type = int_type;
+ break;
+ case FLOAT:
+ type = double_type;
+ break;
+ }
+
+ if (f_FORMAT && nrargs == f_FORMATn) {
+ if ( !f_FORMATvar
+ && ( type->tp_fund != POINTER
+ || type->tp_up->tp_fund != CHAR
+ )
+ ) {
+ warning("format parameter %d is not pointer to char",
+ nrargs);
+ }
+ arg->ar_type = string_type;
+ arg->ar_class = ArgString;
+ arg->CAS_VALUE = f_FORMAT;
+ arg->CAS_LEN = strlen(f_FORMAT);
+ f_FORMAT = 0;
+ }
+ else {
+ arg->ar_type = type;
+ arg->ar_class = ArgFormal;
+ }
+ *hook = arg;
+ hook = &arg->next;
+
+ nrargs++;
+ se = se->next;
+ }
+
+ if (f_FORMAT) {
+ /* f_FORMAT has not been consumed, perhaps due to
+ a varargs-like construction; add erroneous ArgFormals
+ until f_FORMATn, then an ArgString, if necessary.
+ */
+ if (!f_FORMATvar) {
+ warning("FORMAT%d function has only %d argument%s",
+ f_FORMATn, nrargs, nrargs == 1 ? "" : "s"
+ );
+ }
+
+ while (nrargs < f_FORMATn) {
+ register struct argument *arg = new_argument();
+
+ arg->ar_type = error_type;
+ arg->ar_class = ArgFormal;
+ *hook = arg;
+ hook = &arg->next;
+ nrargs++;
+ }
+ if (nrargs == f_FORMATn) {
+ register struct argument *arg = new_argument();
+
+ arg->ar_type = string_type;
+ arg->ar_class = ArgString;
+ arg->CAS_VALUE = f_FORMAT;
+ arg->CAS_LEN = strlen(f_FORMAT);
+ f_FORMAT = 0;
+ *hook = arg;
+ hook = &arg->next;
+ nrargs++;
+ }
+ /* life is full of duplicated code; this is no good */
+ }
+
+ if (f_VARARGSn > nrargs) {
+ warning("VARARGS%d function has only %d argument%s",
+ f_VARARGSn, nrargs, nrargs == 1 ? "" : "s"
+ );
+ f_VARARGSn = nrargs;
+ }
+ OutDef.od_nrargs = nrargs;
+}
+
+output_use(idf)
+ struct idf *idf;
+{
+/* Output the usage-definition of the variable described by idf.
+ */
+ OutDef.od_name = idf->id_text;
+ OutDef.od_statnr = (idf->id_def->df_sc == STATIC ? stat_number : 0);
+ OutDef.od_class = VU;
+ OutDef.od_file = FileName;
+ OutDef.od_line = LineNumber;
+ OutDef.od_type = idf->id_def->df_type;
+ outdef();
+}
+
+outdef()
+{
+ output_def(&OutDef);
+}
+
+outcall()
+{
+ output_def(&OutCall);
+}
+
+PRIVATE
+output_def(od)
+ struct outdef *od;
+{
+/* As the types are output the tp_entries are removed, because they
+ * are then not needed anymore.
+ */
+ if (od->od_class == XXDF)
+ return;
+
+ if (LINTLIB) {
+ switch (od->od_class) {
+ case EFDF:
+ od->od_class = LFDF;
+ break;
+ case EVDF:
+ od->od_class = LVDF;
+ break;
+ case SFDF:
+ /* remove tp_entries */
+ while (od->od_arg) {
+ register struct argument *tmp = od->od_arg;
+ od->od_arg = od->od_arg->next;
+ free_argument(tmp);
+ }
+ return;
+ default:
+ return;
+ }
+ }
+ printf("%s:%d:%c", od->od_name, od->od_statnr, od->od_class);
+ switch (od->od_class) {
+ case EFDF:
+ case SFDF:
+ case LFDF:
+ if (f_VARARGSn != -1) {
+ printf(":%d", -1 - f_VARARGSn);
+ outargs(od->od_arg, f_VARARGSn);
+ }
+ else {
+ printf(":%d", od->od_nrargs);
+ outargs(od->od_arg, od->od_nrargs);
+ }
+ od->od_arg = 0;
+ printf(":%d", od->od_valreturned);
+ break;
+ case FC:
+ printf(":%d", od->od_nrargs);
+ outargs(od->od_arg, od->od_nrargs);
+ od->od_arg = 0;
+ printf(":%d", od->od_valused);
+ break;
+ case EVDF:
+ case SVDF:
+ case LVDF:
+ case EFDC:
+ case EVDC:
+ case IFDC:
+ case VU:
+ break;
+ default:
+ NOTREACHED();
+ /*NOTREACHED*/
+ }
+ printf(":");
+ outargtype(od->od_type);
+ printf(":%u:%s\n", od->od_line, od->od_file);
+}
+
+PRIVATE
+outargs(arg, n)
+ struct argument *arg;
+{
+/* Output the n arguments in the argument list and remove them */
+
+ register struct argument *tmp;
+
+ while (n--) {
+ ASSERT(arg);
+ outarg(arg);
+ tmp = arg;
+ arg = arg->next;
+ free_argument(tmp);
+ }
+ /* remove the remaining entries */
+ while (arg) {
+ tmp = arg;
+ arg = arg->next;
+ free_argument(tmp);
+ }
+}
+
+PRIVATE
+outarg(arg)
+ struct argument *arg;
+{
+ printf(":");
+ switch (arg->ar_class) {
+ case ArgConst:
+ if (arg->CAA_VALUE >= 0) {
+ /* constant non-negative actual parameter */
+ printf("+");
+ }
+ outargtype(arg->ar_type);
+ break;
+
+ case ArgString:
+ outargstring(arg);
+ break;
+
+ case ArgFormal:
+ case ArgExpr:
+ outargtype(arg->ar_type);
+ if (arg->ar_type->tp_fund == FUNCTION) {
+ /* UGLY PATCH !!! ??? */
+ /* function names as operands are sometimes
+ FUNCTION and sometimes POINTER to FUNCTION,
+ depending on opaque circumstances. E.g., in
+ f(main, main);
+ the first main is PtF and the second is F.
+ */
+ printf("*");
+ }
+ break;
+
+ default:
+ NOTREACHED();
+ /*NOTREACHED*/
+ }
+}
+
+PRIVATE
+outargstring(arg)
+ struct argument *arg;
+{
+ char buff[1000];
+ register char *p;
+
+ bts2str(arg->CAS_VALUE, arg->CAS_LEN, buff);
+ for (p = &buff[0]; *p; p++) {
+ if (*p == '"' || *p == ':')
+ *p = ' ';
+ }
+ printf("\"%s\"", buff);
+}
+
+PRIVATE
+outargtype(tp)
+ struct type *tp;
+{
+ switch (tp->tp_fund) {
+ case POINTER:
+ outargtype(tp->tp_up);
+ printf("*");
+ break;
+
+ case ARRAY:
+ outargtype(tp->tp_up);
+ printf("*"); /* compatible with [] */
+ break;
+
+ case FUNCTION:
+ outargtype(tp->tp_up);
+ printf("()");
+ break;
+
+ case STRUCT:
+ case UNION:
+ case ENUM:
+ printf("%s %s", symbol2str(tp->tp_fund), tp->tp_idf->id_text);
+ break;
+
+ case CHAR:
+ case INT:
+ case SHORT:
+ case LONG:
+ case FLOAT:
+ case DOUBLE:
+ case VOID:
+ case ERRONEOUS:
+ if (tp->tp_unsigned)
+ printf("unsigned ");
+ printf("%s", symbol2str(tp->tp_fund));
+ break;
+ default:
+ NOTREACHED();
+ /*NOTREACHED*/
+ }
+}
+
+PRIVATE
+implicit_func_decl(idf, file, line)
+ struct idf *idf;
+ char *file;
+ unsigned int line;
+{
+ struct outdef od;
+
+ od.od_class = IFDC;
+ od.od_statnr = 0;
+ od.od_name = idf->id_text;
+ od.od_file = file;
+ od.od_line = line;
+ od.od_type = idf->id_def->df_type->tp_up;
+ output_def(&od);
+ /* The other fields are not used for this class. */
+}
+
+fill_outcall(ex, used)
+ struct expr *ex;
+ int used;
+{
+ register struct idf *idf = ex->OP_LEFT->VL_IDF;
+ register struct def *def = idf->id_def;
+
+ if (def->df_sc == IMPLICIT && !idf->id_def->df_used) {
+ /* IFDC, first time */
+ implicit_func_decl(idf, ex->ex_file, ex->ex_line);
+ }
+
+ OutCall.od_type = def->df_type->tp_up;
+ OutCall.od_statnr = (def->df_sc == STATIC ? stat_number : 0);
+ OutCall.od_class = FC;
+ OutCall.od_name = idf->id_text;
+ OutCall.od_file = ex->ex_file;
+ OutCall.od_line = ex->ex_line;
+ OutCall.od_arg = (struct argument *)0;
+ OutCall.od_nrargs = 0;
+
+ if ((ex = ex->OP_RIGHT) != 0) { /* function call with arguments */
+ /* store types of argument expressions in tp_entries */
+ while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
+ fill_arg(ex->OP_RIGHT);
+ ex = ex->OP_LEFT;
+ }
+ fill_arg(ex);
+ }
+ OutCall.od_valused = used; /* USED, IGNORED or VOIDED */
+}
+
+PRIVATE
+fill_arg(e)
+ struct expr *e;
+{
+ register struct argument *arg;
+
+ arg = new_argument();
+ arg->ar_type = e->ex_type;
+ if (is_cp_cst(e)) {
+ arg->ar_class = ArgConst;
+ arg->CAA_VALUE = e->VL_VALUE;
+ }
+ else if (e->ex_class == Value && e->VL_CLASS == Label) {
+ /* it may be a string; let's look it up */
+ register struct string_cst *sc = str_list;
+
+ while (sc) {
+ if (sc->sc_dlb == e->VL_LBL)
+ break;
+ sc = sc->next;
+ }
+ if (sc) {
+ /* it was a string */
+ arg->ar_class = ArgString;
+ arg->CAS_VALUE = sc->sc_value;
+ arg->CAS_LEN = sc->sc_len - 1; /* included the \0 */
+ }
+ else {
+ arg->ar_class = ArgExpr;
+ }
+ }
+ else {
+ arg->ar_class = ArgExpr;
+ }
+ arg->next = OutCall.od_arg;
+ OutCall.od_arg = arg;
+ OutCall.od_nrargs++;
+}
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint output definition */
+
+/* Values for ar_class */
+#define ArgFormal 0
+#define ArgExpr 1 /* actual */
+#define ArgConst 2 /* integer constant */
+#define ArgString 3 /* string */
+
+struct argument {
+ struct argument *next;
+ struct type *ar_type;
+ int ar_class; /* for constant parameters */
+ union const_arg {
+ arith ca_value;
+ struct {
+ char *cas_value;
+ int cas_len;
+ } ca_string;
+ } ar_object;
+};
+
+#define CAA_VALUE ar_object.ca_value
+#define CAS_VALUE ar_object.ca_string.cas_value
+#define CAS_LEN ar_object.ca_string.cas_len
+
+/* ALLOCDEF "argument" 10 */
+
+struct outdef {
+ char od_class;
+ int od_statnr;
+ char *od_name;
+ char *od_file;
+ unsigned int od_line;
+ int od_nrargs;
+ struct argument *od_arg; /* a list of the types of the
+ * formal parameters */
+ int od_valreturned;
+ /* NOVALRETURNED, VALRETURNED, NORETURN; see l_lint.h */
+ int od_valused;
+ /* USED, IGNORED, SET, VOIDED; see l_lint.h */
+ struct type *od_type;
+};
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint state stack */
+
+/* These datastructures are used to implement a stack on which the
+ * state of automatic variables (including register variables) is
+ * kept.
+ * In this way it is possible to account for the flow of
+ * control of the program.
+ */
+
+
+struct switch_states {
+ struct state *sws_case;
+ struct state *sws_break;
+ int sws_default_met;
+};
+
+struct lint_stack_entry {
+ struct lint_stack_entry *next;
+ struct lint_stack_entry *ls_previous;
+ short ls_class; /* IF, WHILE, DO, FOR, SWITCH, CASE */
+ int ls_level;
+ struct state *ls_current; /* used by all classes */
+ union {
+ struct state *u_if_state; /* used for IF-class */
+ struct state *u_end; /* used for loop-classes */
+ struct switch_states u_switch;
+ } ls_states; /* not used for CASE-class */
+};
+
+/* macros to access the union */
+#define LS_IF_STATE ls_states.u_if_state
+#define LS_END ls_states.u_end
+#define LS_CASE ls_states.u_switch.sws_case
+#define LS_BREAK ls_states.u_switch.sws_break
+#define LS_DEFAULT_MET ls_states.u_switch.sws_default_met
+
+/* ALLOCDEF "lint_stack_entry" 10 */
+
+struct state {
+ struct state *next; /* only used by memory allocator */
+ struct auto_def *st_auto_list;
+ int st_notreached; /* set if not reached */
+ int st_warned; /* set if warning issued */
+};
+
+/* ALLOCDEF "state" 15 */
+
+struct auto_def {
+ struct auto_def *next;
+ struct idf *ad_idf;
+ struct def *ad_def;
+ int ad_used;
+ int ad_set;
+ int ad_maybe_set;
+};
+
+/* ALLOCDEF "auto_def" 20 */
+
+struct expr_state {
+ struct expr_state *next;
+ struct idf *es_idf;
+ arith es_offset;
+ int es_used;
+ int es_referred;
+ int es_set;
+};
+
+/* ALLOCDEF "expr_state" 20 */
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* Lint status checking */
+
+#include "lint.h"
+
+#ifdef LINT
+
+#include <alloc.h> /* for st_free */
+#include "interface.h"
+#include "assert.h"
+#include "debug.h"
+#include "arith.h" /* definition arith */
+#include "label.h" /* definition label */
+#include "expr.h"
+#include "idf.h"
+#include "def.h"
+#include "code.h" /* RVAL etc */
+#include "LLlex.h"
+#include "Lpars.h"
+#include "stack.h"
+#include "type.h"
+#include "level.h"
+#include "nofloat.h"
+#include "l_lint.h"
+#include "l_brace.h"
+#include "l_state.h"
+#include "l_comment.h"
+#include "l_outdef.h"
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+extern char *symbol2str();
+extern char *func_name;
+extern struct type *func_type;
+extern int func_notypegiven;
+extern char loptions[];
+
+/* global variables for the lint_stack */
+PRIVATE struct lint_stack_entry stack_bottom;
+PRIVATE struct lint_stack_entry *top_ls = &stack_bottom;
+
+/* global variables for the brace stack */
+PRIVATE int brace_count;
+PRIVATE struct brace brace_bottom;
+PRIVATE struct brace *top_br = &brace_bottom;
+
+PRIVATE end_brace();
+PRIVATE lint_1_local();
+PRIVATE lint_1_global();
+PRIVATE check_autos();
+PRIVATE struct auto_def *copy_st_auto_list();
+PRIVATE free_st_auto_list();
+PRIVATE struct state *copy_state();
+PRIVATE Free_state();
+PRIVATE remove_settings();
+PRIVATE struct auto_def *merge_autos();
+PRIVATE merge_states();
+PRIVATE struct lint_stack_entry *find_wdf(), *find_wdfc(), *find_cs();
+PRIVATE cont_break_merge();
+PRIVATE lint_push();
+PRIVATE lint_pop();
+
+lint_init_stack()
+{
+/* Allocate some memory for the global stack_bottom
+ */
+ stack_bottom.ls_current = new_state();
+}
+
+lint_start_local()
+{
+ register struct brace *br = new_brace();
+
+ brace_count++;
+ br->br_count = brace_count;
+ br->br_level = level;
+ br->next = top_br;
+ top_br = br;
+}
+
+lint_local_level(stl)
+ struct stack_level *stl;
+{
+ if (s_NOTREACHED) {
+ top_ls->ls_current->st_notreached = 1;
+ s_NOTREACHED = 0;
+ }
+
+ if (top_ls->ls_class == CASE && level == top_ls->ls_level) {
+ lint_break_stmt();
+ /* To prevent a warning for the case
+ * switch (cond) {
+ * int i;
+ * case 0:
+ * i = 0;
+ * use(i);
+ * }
+ */
+ }
+
+ check_autos();
+ end_brace(stl);
+}
+
+PRIVATE
+end_brace(stl)
+ struct stack_level *stl;
+{
+ /* Check if static variables and labels are used and/or set.
+ */
+ register struct stack_entry *se = stl->sl_entry;
+ register struct brace *br;
+
+ while (se) {
+ register struct idf *idf = se->se_idf;
+ register struct def *def = idf->id_def;
+
+ if (def) {
+ lint_1_local(idf, def);
+ }
+ se = se->next;
+ }
+
+ br = top_br;
+ top_br = br->next;
+ free_brace(br);
+}
+
+PRIVATE
+lint_1_local(idf, def)
+ struct idf *idf;
+ struct def *def;
+{
+ register int sc = def->df_sc;
+
+ if ( (sc == STATIC || sc == LABEL)
+ && !def->df_used
+ ) {
+ def_warning(def, "%s %s declared but not used in function %s",
+ symbol2str(sc), idf->id_text, func_name);
+ }
+
+ if ( loptions['h']
+ && sc == AUTO
+ && !def->df_initialized
+ && def->df_firstbrace != 0
+ && def->df_minlevel != level
+ ) {
+ register int diff = def->df_minlevel - level;
+
+ def_warning(def,
+ "local %s could be declared %d level%s deeper",
+ idf->id_text, diff, (diff == 1 ? "" : "s")
+ );
+ }
+}
+
+lint_global_level(stl)
+ struct stack_level *stl;
+{
+ register struct stack_entry *se = stl->sl_entry;
+
+ ASSERT(level == L_GLOBAL);
+ while (se) {
+ register struct idf *idf = se->se_idf;
+ register struct def *def = idf->id_def;
+
+ if (def) {
+ lint_1_global(idf, def);
+ }
+ se = se->next;
+ }
+}
+
+PRIVATE
+lint_1_global(idf, def)
+ struct idf *idf;
+ struct def *def;
+{
+ register int sc = def->df_sc;
+ register int fund = def->df_type->tp_fund;
+
+ switch (sc) {
+ case STATIC:
+ case EXTERN:
+ case GLOBAL:
+ case IMPLICIT:
+ if (fund == ERRONEOUS)
+ break;
+
+ if (def->df_set || def->df_used) {
+ /* Output a line to the intermediate file for
+ * used external variables (including functions)
+ */
+ output_use(idf);
+ }
+ else {
+ if (sc == STATIC) {
+ if (def->df_set) {
+ def_warning(def,
+ "%s %s %s set but not used",
+ symbol2str(sc),
+ symbol2str(fund),
+ idf->id_text);
+ }
+ else {
+ def_warning(def,
+ "%s %s %s not used anywhere",
+ symbol2str(sc),
+ symbol2str(fund),
+ idf->id_text);
+ }
+ }
+ if (loptions['x']) {
+ register char *fn = def->df_file;
+
+ if ( (sc == EXTERN || sc == GLOBAL)
+ && def->df_alloc == 0
+ && !def->df_set
+ && !def->df_initialized
+ && strcmp(&fn[strlen(fn)-2], ".c") == 0
+ ) {
+ def_warning(def,
+ "%s %s %s not used anywhere",
+ symbol2str(sc),
+ symbol2str(fund),
+ idf->id_text);
+ }
+ }
+ }
+ break;
+ }
+}
+
+change_state(idf, to_state)
+ struct idf *idf;
+ int to_state; /* SET or USED */
+{
+/* Changes the state of the variable identified by idf in the current state
+ * on top of the stack.
+ * For non-automatic variables, the fields in the def-descriptor are set too.
+ */
+ register struct def *def = idf->id_def;
+ register struct auto_def *a = top_ls->ls_current->st_auto_list;
+
+ if (def) {
+ switch (to_state) {
+ case SET:
+ def->df_set = 1;
+ break;
+ case USED:
+ def->df_used = 1;
+ break;
+ }
+
+ if (def->df_firstbrace == 0) {
+ def->df_firstbrace = brace_count;
+ def->df_minlevel = level;
+ }
+ else {
+ register struct brace *br = top_br;
+
+ /* find the smallest brace range from which
+ firstbrace is visible
+ */
+ while (br && br->br_count > def->df_firstbrace) {
+ br = br->next;
+ }
+ ASSERT(br && def->df_minlevel >= br->br_level);
+ def->df_minlevel = br->br_level;
+ }
+ }
+
+ while(a && a->ad_idf != idf)
+ a = a->next;
+ if (a == 0) /* identifier not in list */
+ return;
+
+ switch (to_state) {
+ case SET:
+ a->ad_maybe_set = 0;
+ a->ad_set = 1;
+ break;
+ case USED:
+ if (!a->ad_set) {
+ warning("%s%s uninitialized", idf->id_text,
+ (a->ad_maybe_set ? " possibly" : "")
+ );
+ a->ad_maybe_set = 0;
+ a->ad_set = 1; /* one warning */
+ }
+ a->ad_used = 1;
+ break;
+ }
+}
+
+extern struct stack_level *local_level;
+
+add_auto(idf) /* to current state on top of lint_stack */
+ struct idf *idf;
+{
+/* Check if idf's definition is really an auto (or register).
+ * It could be a static or extern too.
+ * Watch out for register formal parameters.
+ */
+ register struct def *def = idf->id_def;
+ register struct auto_def *a;
+
+ if (!def)
+ return;
+ switch (def->df_sc) {
+ case AUTO:
+ case REGISTER:
+ if (def->df_level < L_LOCAL)
+ return; /* a register formal */
+ a = new_auto_def();
+ a->ad_idf = idf;
+ a->ad_def = idf->id_def;
+ a->ad_used = def->df_used;
+ a->ad_set = def->df_set;
+ a->next = top_ls->ls_current->st_auto_list;
+ top_ls->ls_current->st_auto_list = a;
+ }
+}
+
+PRIVATE
+check_autos()
+{
+/* Before leaving a block remove the auto_defs of the automatic
+ * variables on this level and check if they are used
+ */
+ register struct auto_def *a1 = top_ls->ls_current->st_auto_list;
+ register struct auto_def *a2;
+
+ ASSERT(!(a1 && a1->ad_def->df_level > level));
+ while (a1 && a1->ad_def->df_level == level) {
+ a2 = a1;
+ a1 = a1->next;
+ if (!a2->ad_used) {
+ if (a2->ad_set || a2->ad_maybe_set) {
+ def_warning(a2->ad_def,
+ "%s set but not used in function %s",
+ a2->ad_idf->id_text, func_name);
+ }
+ else {
+ def_warning(a2->ad_def,
+ "%s neither set nor used in function %s",
+ a2->ad_idf->id_text, func_name);
+ }
+ }
+ free_auto_def(a2);
+ }
+ top_ls->ls_current->st_auto_list = a1;
+}
+
+check_args_used()
+{
+ register struct stack_entry *se = local_level->sl_entry;
+
+ ASSERT(level == L_FORMAL1);
+ while (se) {
+ register struct def *def = se->se_idf->id_def;
+
+ if ( (def && !def->df_used)
+ && !(f_ARGSUSED || LINTLIB)
+ ) {
+ def_warning(def, "argument %s not used in function %s",
+ se->se_idf->id_text, func_name);
+ }
+ se = se->next;
+ }
+}
+
+PRIVATE struct auto_def *
+copy_st_auto_list(from_al, lvl)
+ struct auto_def *from_al;
+{
+ struct auto_def *start = 0;
+ register struct auto_def **hook = &start;
+
+ while (from_al && from_al->ad_def->df_level > lvl) {
+ from_al = from_al->next;
+ }
+ while (from_al) {
+ register struct auto_def *a = new_auto_def();
+
+ *hook = a;
+ *a = *from_al;
+ hook = &a->next;
+ from_al = from_al->next;
+ }
+
+ return start;
+}
+
+PRIVATE
+free_st_auto_list(au)
+ register struct auto_def *au;
+{
+ register struct auto_def *a;
+
+ while (au) {
+ a = au;
+ au = au->next;
+ free_auto_def(a);
+ }
+}
+
+PRIVATE struct state *
+copy_state(from_st, lvl)
+ struct state *from_st;
+{
+/* Memory for the struct state and the struct auto_defs is allocated
+ * by this function
+ */
+ register struct state *st = new_state();
+
+ st->st_auto_list = copy_st_auto_list(from_st->st_auto_list, lvl);
+ st->st_notreached = from_st->st_notreached;
+ st->st_warned = from_st->st_warned;
+ return st;
+}
+
+PRIVATE
+Free_state(stp)
+ struct state **stp;
+{
+/* This function also frees the list of auto_defs
+ */
+ free_st_auto_list((*stp)->st_auto_list);
+ free_state(*stp);
+ *stp = 0;
+}
+
+PRIVATE
+remove_settings(state, lvl)
+ struct state *state;
+{
+/* The state of all variables on this level are set to 'not set' and
+ * 'not maybe set'. (I think you have to read this twice.)
+ */
+ register struct auto_def *a = state->st_auto_list;
+
+ while (a && a->ad_def->df_level == lvl) {
+ a->ad_set = a->ad_maybe_set = 0;
+ a = a->next;
+ }
+}
+
+
+/******** M E R G E ********/
+
+/* modes for merging */
+#define NORMAL 0
+#define CASE_BREAK 1
+#define USE_ONLY 2
+
+PRIVATE struct auto_def *
+merge_autos(a1, a2, lvl, mode)
+ struct auto_def *a1, *a2;
+ int mode;
+{
+/* Returns a pointer to the result.
+ * a1 is left unchanged.
+ * a2 is used to create this result.
+ * The fields are set as follows:
+ * a1_set + a2_set -> set
+ * + a?_maybe_set -> maybe set
+ * ELSE -> NOT set && NOT maybe set
+ * * + a?_used -> used
+ *
+ * For mode == CASE_BREAK:
+ * First a2 is taken as the result, then
+ * variables NOT set in a2 and set or maybe set in a1 become 'maybe set'
+ *
+ * For mode == USE_ONLY:
+ * Start with a2 as the result.
+ * Variables used in a1 become used in a2.
+ * The rest of the result is not changed.
+ */
+ register struct auto_def *a;
+
+ while (a1 && a1->ad_def->df_level > lvl) {
+ a1 = a1->next;
+ }
+ while (a2 && a2->ad_def->df_level > lvl) {
+ a = a2;
+ a2 = a2->next;
+ free_auto_def(a);
+ }
+ a = a2; /* pointer to the result */
+ while (a1) {
+ ASSERT(a2);
+ ASSERT(a1->ad_idf == a2->ad_idf);
+ if (a1->ad_used)
+ a2->ad_used = 1;
+
+ if (mode != USE_ONLY) {
+ if ( ( !a2->ad_set
+ && (a1->ad_set || a1->ad_maybe_set)
+ )
+ || ( mode == NORMAL
+ && !a1->ad_set
+ && (a2->ad_set || a2->ad_maybe_set)
+ )
+ ) {
+ a2->ad_set = 0;
+ a2->ad_maybe_set = 1;
+ }
+ }
+
+ a1 = a1->next;
+ a2 = a2->next;
+ }
+ ASSERT(!a2);
+ return a;
+}
+
+PRIVATE
+merge_states(st1, st2, lvl, mode)
+ struct state *st1, *st2;
+ int mode;
+{
+/* st2 becomes the result.
+ * st1 is left unchanged.
+ * The resulting state is the state the program gets in if st1 OR st2
+ * becomes the state. (E.g. the states at the end of an if-part and an
+ * end-part are merged by this function.)
+ */
+ if (st1->st_notreached) {
+ if (mode == NORMAL || st2->st_notreached) {
+ st2->st_auto_list =
+ merge_autos(st1->st_auto_list,
+ st2->st_auto_list, lvl, USE_ONLY);
+ }
+ }
+ else if (st2->st_notreached) {
+ register struct auto_def *tmp = st2->st_auto_list;
+
+ st2->st_auto_list = copy_st_auto_list(st1->st_auto_list, lvl);
+ st2->st_notreached = 0;
+ st2->st_warned = 0;
+ st2->st_auto_list = merge_autos(tmp, st2->st_auto_list,
+ lvl, USE_ONLY);
+ free_st_auto_list(tmp);
+ }
+ else {
+ st2->st_auto_list =
+ merge_autos(st1->st_auto_list, st2->st_auto_list,
+ lvl, mode);
+ }
+}
+
+
+/******** L I N T S T A C K S E A R C H I N G ********/
+
+/* The next four find-functions search the lint_stack for an entry.
+ * The letters mean : w: WHILE; d: DO; f: FOR; s: SWITCH; c: CASE.
+ */
+
+PRIVATE struct lint_stack_entry *
+find_wdf()
+{
+ register struct lint_stack_entry *lse = top_ls;
+
+ while (lse != &stack_bottom) {
+ switch (lse->ls_class) {
+ case WHILE:
+ case DO:
+ case FOR:
+ return lse;
+ }
+ lse = lse->ls_previous;
+ }
+ return 0;
+}
+
+PRIVATE struct lint_stack_entry *
+find_wdfc()
+{
+ register struct lint_stack_entry *lse = top_ls;
+
+ while (lse != &stack_bottom) {
+ switch (lse->ls_class) {
+ case WHILE:
+ case DO:
+ case FOR:
+ case CASE:
+ return lse;
+ }
+ lse = lse->ls_previous;
+ }
+ return 0;
+}
+
+PRIVATE struct lint_stack_entry *
+find_cs()
+{
+ register struct lint_stack_entry *lse = top_ls;
+
+ while (lse != &stack_bottom) {
+ switch (lse->ls_class) {
+ case CASE:
+ case SWITCH:
+ return lse;
+ }
+ lse = lse->ls_previous;
+ }
+ return 0;
+}
+
+/******** A C T I O N S ********/
+
+start_if_part(const)
+{
+/* Push a new stack entry on the lint_stack with class == IF
+ * copy the ls_current to the top of this stack
+ */
+ register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+ if (const)
+ hwarning("condition in if statement is constant");
+
+ lse->ls_class = IF;
+ lse->ls_current = copy_state(top_ls->ls_current, level);
+ lse->ls_level = level;
+ lint_push(lse);
+}
+
+start_else_part()
+{
+/* Move ls_current to LS_IF_STATE
+ * ls_current of the stack entry one below is copied to ls_current.
+ */
+ if (s_NOTREACHED) {
+ top_ls->ls_current->st_notreached = 1;
+ s_NOTREACHED = 0;
+ }
+ top_ls->LS_IF_STATE = top_ls->ls_current;
+ /* this is the reason why ls_current is a pointer */
+ top_ls->ls_current = copy_state(top_ls->ls_previous->ls_current,
+ level);
+ top_ls->ls_level = level;
+}
+
+end_if_else_stmt()
+{
+ Free_state(&top_ls->ls_previous->ls_current);
+ merge_states(top_ls->LS_IF_STATE, top_ls->ls_current,
+ top_ls->ls_level, NORMAL);
+ Free_state(&top_ls->LS_IF_STATE);
+ top_ls->ls_previous->ls_current = top_ls->ls_current;
+ lint_pop();
+}
+
+end_if_stmt()
+{
+/* No else-part met; merge ls_current with ls_current of previous
+ * stack entry
+ */
+ merge_states(top_ls->ls_current, top_ls->ls_previous->ls_current,
+ top_ls->ls_level, NORMAL);
+ Free_state(&top_ls->ls_current);
+ lint_pop();
+}
+
+start_loop_stmt(looptype, const, cond)
+{
+/* If const, the condition is constant and given in cond */
+ register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+ lse->ls_class = looptype;
+ lse->ls_current = copy_state(top_ls->ls_current, level);
+ lse->ls_level = level;
+ if (const && !cond) {
+ /* while (0) | for (;0;) */
+ hwarning("condition in %s statement is constant",
+ symbol2str(looptype));
+ lse->ls_current->st_notreached = 1;
+ }
+ if (const && cond) {
+ /* while (1) | for (;;) | do */
+ /* omitting the copy for LS_END will force this loop
+ to be treated as a do loop
+ */
+ top_ls->ls_current->st_notreached = 1;
+ }
+ else {
+ lse->LS_END = copy_state(top_ls->ls_current, level);
+ }
+ lint_push(lse);
+}
+
+end_loop_stmt()
+{
+ register struct lint_stack_entry *prev_ls = top_ls->ls_previous;
+
+ lint_continue_stmt();
+ top_ls->LS_END->st_notreached = prev_ls->ls_current->st_notreached;
+ top_ls->LS_END->st_warned = prev_ls->ls_current->st_warned;
+ Free_state(&top_ls->ls_current);
+ Free_state(&prev_ls->ls_current);
+ prev_ls->ls_current = top_ls->LS_END;
+ lint_pop();
+}
+
+end_do_stmt(const, cond)
+{
+ end_loop_stmt();
+ if (const)
+ hwarning("condition in do-while statement is constant");
+ if (const && cond && top_ls->ls_current->st_notreached) {
+ /* no break met; this is really an endless loop */
+ }
+ else {
+ top_ls->ls_current->st_notreached = 0;
+ }
+}
+
+PRIVATE
+cont_break_merge(lse)
+ struct lint_stack_entry *lse;
+{
+ /* merge for continue and break statements */
+ if (lse->LS_END) {
+ merge_states(top_ls->ls_current, lse->LS_END,
+ lse->ls_level, NORMAL);
+ }
+ else {
+ lse->LS_END = copy_state(top_ls->ls_current, lse->ls_level);
+ }
+}
+
+lint_continue_stmt()
+{
+ register struct lint_stack_entry *lse = find_wdf();
+
+ if (!lse)
+ return; /* not inside a loop statement */
+
+ cont_break_merge(lse);
+ top_ls->ls_current->st_notreached = 1;
+}
+
+start_switch_part(expr)
+ struct expr *expr;
+{
+/* ls_current of a SWITCH entry has different meaning from ls_current of
+ * other entries. It keeps track of which variables are used in all
+ * following case parts. (Needed for variables declared in a compound
+ * switch-block.)
+ */
+ register struct lint_stack_entry *lse = new_lint_stack_entry();
+
+ if (is_cp_cst(expr))
+ hwarning("value in switch statement is constant");
+
+ lse->ls_class = SWITCH;
+ lse->ls_current = copy_state(top_ls->ls_current, level);
+ lse->ls_level = level;
+ lse->LS_CASE = copy_state(top_ls->ls_current, level);
+ lse->ls_current->st_notreached = 1;
+ top_ls->ls_current->st_notreached = 1;
+ lint_push(lse);
+}
+
+end_switch_stmt()
+{
+ if (top_ls->ls_class == CASE) {
+ /* no break after last case or default */
+ lint_break_stmt(); /* introduce break */
+ }
+
+ if (!top_ls->LS_DEFAULT_MET) {
+ top_ls->ls_current->st_notreached = 0;
+ if (top_ls->LS_BREAK) {
+ merge_states(top_ls->ls_current, top_ls->LS_BREAK,
+ top_ls->ls_level, NORMAL);
+ Free_state(&top_ls->ls_current);
+ }
+ else {
+ top_ls->LS_BREAK = top_ls->ls_current;
+ }
+ }
+ else {
+ Free_state(&top_ls->ls_current);
+ }
+
+ if (top_ls->LS_BREAK) {
+ merge_states(top_ls->LS_CASE, top_ls->LS_BREAK,
+ top_ls->ls_level, CASE_BREAK);
+ Free_state(&top_ls->LS_CASE);
+ }
+ else {
+ top_ls->LS_BREAK = top_ls->LS_CASE;
+ }
+
+ top_ls->LS_BREAK->st_notreached =
+ top_ls->ls_previous->ls_current->st_notreached;
+ /* yack */
+ Free_state(&top_ls->ls_previous->ls_current);
+
+ if (!top_ls->LS_DEFAULT_MET)
+ top_ls->LS_BREAK->st_notreached = 0;
+ top_ls->ls_previous->ls_current = top_ls->LS_BREAK;
+
+ lint_pop();
+}
+
+lint_case_stmt(dflt)
+{
+/* A default statement is just a special case statement */
+
+ register struct lint_stack_entry *lse;
+ register struct lint_stack_entry *cs_entry = find_cs();
+
+ if (!cs_entry)
+ return; /* not inside switch */
+ if (cs_entry != top_ls) {
+ warning("%s statement in strange context",
+ dflt ? "default" : "case");
+ return;
+ }
+ if (cs_entry->ls_class == SWITCH) {
+ if (dflt) {
+ cs_entry->LS_DEFAULT_MET = 1;
+ }
+ lse = new_lint_stack_entry();
+ lse->ls_class = CASE;
+ lse->ls_current = copy_state(top_ls->ls_current, level);
+ remove_settings(lse->ls_current, level);
+ lse->ls_level = level;
+ lint_push(lse);
+ }
+ else {
+ ASSERT(cs_entry->ls_class == CASE);
+ if (dflt) {
+ cs_entry->ls_previous->LS_DEFAULT_MET = 1;
+ }
+ merge_states(top_ls->ls_current, top_ls->ls_previous->LS_CASE,
+ top_ls->ls_previous->ls_level, NORMAL);
+ merge_states(top_ls->ls_current,
+ top_ls->ls_previous->ls_current,
+ top_ls->ls_previous->ls_level, NORMAL);
+ Free_state(&top_ls->ls_current);
+ top_ls->ls_current =
+ copy_state(top_ls->ls_previous->ls_current,
+ top_ls->ls_previous->ls_level);
+ remove_settings(top_ls->ls_current, top_ls->ls_level);
+ }
+}
+
+lint_break_stmt()
+{
+ register struct lint_stack_entry *lse = find_wdfc();
+
+ if (!lse)
+ return;
+
+ switch (lse->ls_class) {
+ case WHILE:
+ case FOR:
+ case DO:
+ /* loop break */
+ lse->ls_previous->ls_current->st_notreached = 0;
+ cont_break_merge(lse);
+ break;
+
+ case CASE:
+ /* case break */
+ if (!top_ls->ls_current->st_notreached) {
+ lse->ls_previous->ls_previous->ls_current->st_notreached = 0;
+ }
+ merge_states(lse->ls_current, lse->ls_previous->ls_current,
+ lse->ls_previous->ls_level, NORMAL);
+ if (lse->ls_previous->LS_BREAK) {
+ merge_states(top_ls->ls_current, lse->ls_previous->LS_BREAK,
+ lse->ls_previous->ls_level, NORMAL);
+ }
+ else {
+ lse->ls_previous->LS_BREAK = copy_state(top_ls->ls_current,
+ lse->ls_previous->ls_level);
+ }
+ if (lse == top_ls) {
+ Free_state(&lse->ls_current);
+ lint_pop();
+ }
+ break;
+ default:
+ NOTREACHED();
+ /*NOTREACHED*/
+ }
+ top_ls->ls_current->st_notreached = 1;
+}
+
+lint_start_function()
+{
+ lint_return_stmt(-1); /* initialization */
+ lint_comment_function();
+}
+
+lint_end_function()
+{
+ extern struct outdef OutDef;
+ register int fund = func_type->tp_fund;
+
+ if ( OutDef.od_valreturned == NOVALRETURNED
+ && !func_notypegiven
+ && fund != VOID
+ ) {
+ warning("function %s declared %s%s but no value returned",
+ func_name,
+ (func_type->tp_unsigned && fund != POINTER) ?
+ "unsigned " : "",
+ symbol2str(fund)
+ );
+ }
+ /* write the function definition record */
+ outdef();
+
+ /* At this stage it is possible that stack_bottom.ls_current is
+ * pointing to a state with a list of auto_defs.
+ * These auto_defs must be freed and the state must be filled
+ * with zeros.
+ */
+ ASSERT(top_ls == &stack_bottom);
+ if (top_ls->ls_current->st_auto_list != 0)
+ free_st_auto_list(top_ls->ls_current->st_auto_list);
+ top_ls->ls_current->st_auto_list = 0;
+ top_ls->ls_current->st_notreached = 0;
+ top_ls->ls_current->st_warned = 0;
+}
+
+lint_return_stmt(e)
+ int e;
+{
+/* The statics of this function are initialized by calling it with e = -1. */
+
+ static int ret_e;
+ /*-1 no return met yet
+ * 0 return; met
+ * 1 return with expression met
+ */
+ static int warned;
+
+ switch (e) {
+ case -1:
+ ret_e = -1;
+ warned = 0;
+ return;
+ case 0:
+ if (top_ls->ls_current->st_notreached)
+ break;
+ if (ret_e == 1 && !warned) {
+ warning("function %s does not always return a value",
+ func_name);
+ warned = 1;
+ }
+ else
+ ret_e = 0;
+ break;
+ case 1:
+ if (top_ls->ls_current->st_notreached)
+ break;
+ if (ret_e == 0 && !warned) {
+ warning("function %s does not always return a value",
+ func_name);
+ warned = 1;
+ }
+ else
+ ret_e = 1;
+ break;
+ }
+ if (!top_ls->ls_current->st_notreached)
+ set_od_valreturned(e);
+ top_ls->ls_current->st_notreached = 1;
+}
+
+lint_jump_stmt(idf)
+ struct idf *idf;
+{
+ top_ls->ls_current->st_notreached = 1;
+ if (!idf->id_def)
+ return;
+ idf->id_def->df_used = 1;
+}
+
+lint_label()
+{
+/* When meeting a label, we should take the intersection of all
+ settings at all goto's leading this way, but this cannot reasonably
+ be done. So we assume that the user knows what he is doing and set
+ all automatic variables to set.
+*/
+ register struct auto_def *a = top_ls->ls_current->st_auto_list;
+
+ while (a) {
+ a->ad_maybe_set = 0;
+ a->ad_set = 1;
+ a = a->next;
+ }
+}
+
+lint_statement()
+{
+/* Check if this statement can be reached
+ */
+ if (s_NOTREACHED) {
+ top_ls->ls_current->st_notreached = 1;
+ s_NOTREACHED = 0;
+ }
+ if (DOT == '{' || DOT == ';')
+ return;
+ if (top_ls->ls_current->st_warned)
+ return;
+ if (top_ls->ls_current->st_notreached) {
+ if (DOT != CASE && DOT != DEFAULT && AHEAD != ':') {
+ if (DOT != BREAK || loptions['b'])
+ warning("statement cannot be reached");
+ top_ls->ls_current->st_warned = 1;
+ }
+ else {
+ top_ls->ls_current->st_notreached = 0;
+ top_ls->ls_current->st_warned = 0;
+ }
+ }
+}
+
+PRIVATE
+lint_push(lse)
+ struct lint_stack_entry *lse;
+{
+ lse->ls_previous = top_ls;
+ top_ls->next = lse;
+ top_ls = lse;
+}
+
+PRIVATE
+lint_pop()
+{
+ top_ls = top_ls->ls_previous;
+ free_lint_stack_entry(top_ls->next);
+}
+
+#ifdef DEBUG
+/* FOR DEBUGGING */
+
+print_lint_stack()
+{
+ register struct lint_stack_entry *lse = top_ls;
+
+ while (lse) {
+ print(" |-------------- level %d ------------\n",
+ lse->ls_level);
+ print(" |cur: ");
+ if (lse->ls_current) {
+ print_autos(lse->ls_current->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->ls_current->st_notreached);
+ }
+ else
+ print("\n");
+ print(" |class == %s\n",
+ lse->ls_class ? symbol2str(lse->ls_class) : "{");
+ switch (lse->ls_class) {
+ case SWITCH:
+ print(" |LS_BREAK: ");
+ if (lse->LS_BREAK) {
+ print_autos(lse->LS_BREAK->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->LS_BREAK->st_notreached);
+ }
+ else
+ print("\n");
+ print(" |LS_CASE: ");
+ if (lse->LS_CASE) {
+ print_autos(lse->LS_CASE->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->LS_CASE->st_notreached);
+ }
+ else
+ print("\n");
+ break;
+ case DO:
+ case WHILE:
+ case FOR:
+ print(" |LS_END: ");
+ if (lse->LS_END) {
+ print_autos(lse->LS_END->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->LS_END->st_notreached);
+ }
+ else
+ print("\n");
+ break;
+ case IF:
+ print(" |LS_IF_STATE: ");
+ if (lse->LS_IF_STATE) {
+ print_autos(lse->LS_IF_STATE->st_auto_list);
+ print(" |st_notreached == %d\n",
+ lse->LS_IF_STATE->st_notreached);
+ }
+ else
+ print("\n");
+ break;
+ default:
+ break;
+ }
+ lse = lse->ls_previous;
+ }
+ print(" |--------------\n\n");
+}
+
+print_autos(a)
+ register struct auto_def *a;
+{
+ while (a) {
+ print("%s", a->ad_idf->id_text);
+ print("(l=%d)", a->ad_def->df_level);
+ print("(U%dS%dM%d) ", a->ad_used, a->ad_set, a->ad_maybe_set);
+ a = a->next;
+ }
+ print("\n");
+}
+#endif DEBUG
+
+#endif LINT
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* L A B E L H A N D L I N G */
+
+#include "Lpars.h"
+#include "level.h"
+#include "idf.h"
+#include "label.h"
+#include "arith.h"
+#include "def.h"
+#include "type.h"
+#include "noRoption.h"
+
+extern char options[];
+
+enter_label(idf, defining)
+ register struct idf *idf;
+{
+ /* The identifier idf is entered as a label. If it is new,
+ it is entered into the idf list with the largest possible
+ scope, i.e., on the lowest possible level.
+ If defining, the label comes from a label statement.
+ */
+ if (idf->id_def) {
+ register struct def *def = idf->id_def;
+
+ if (def->df_sc == LABEL) {
+ if (defining && def->df_initialized)
+ error("redeclaration of label %s",
+ idf->id_text);
+ }
+ else { /* there may still be room for it */
+#ifndef NOROPTION
+ if (options['R'] && def->df_sc == TYPEDEF)
+ warning("label %s is also a typedef",
+ idf->id_text);
+#endif
+
+ if (def->df_level == level) /* but alas, no */
+ error("%s is not a label", idf->id_text);
+ else {
+ register int lvl = def->df_level + 1;
+
+#ifndef NOROPTION
+ if (options['R'] && def->df_level > L_LOCAL)
+ warning("label %s is not function-wide",
+ idf->id_text);
+#endif
+ if (lvl < L_LOCAL)
+ lvl = L_LOCAL;
+ add_def(idf, LABEL, label_type, lvl);
+ }
+ }
+ }
+ else {
+ add_def(idf, LABEL, label_type, L_LOCAL);
+ }
+ if (idf->id_def->df_address == 0)
+ idf->id_def->df_address = (arith) text_label();
+ if (defining)
+ idf->id_def->df_initialized = 1;
+}
+
+unstack_label(idf)
+ register struct idf *idf;
+{
+ /* The scope in which the label idf occurred is left.
+ */
+ if (!idf->id_def->df_initialized && !is_anon_idf(idf))
+ error("label %s not defined", idf->id_text);
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* L A B E L D E F I N I T I O N */
+
+#include <em_label.h> /* obtain definition of "label" */
+
+#define NO_LABEL (label) 0
+
+extern label lab_count;
+#define text_label() (lab_count++) /* returns a new text label */
+
+extern label datlab_count;
+#define data_label() (datlab_count++) /* returns a new data label */
+
+#define define_label(idf) enter_label(idf, 1);
+ /* The identifier idf is defined as a label. If it is new,
+ it is entered into the idf list with the largest possible
+ scope, i.e., on the lowest possible level.
+ */
+
+#define apply_label(idf) enter_label(idf, 0);
+ /* The identifier idf is applied as a label. It may or may
+ not be there, and if it is there, it may be from a
+ declaration or another application.
+ */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* LEVEL DEFINITIONS */
+
+/* The level of the top-most stack_level is kept in a global variable
+ with the obvious name 'level'. Although this variable is consulted
+ by a variety of routines, it turns out that its actual value is of
+ importance in only a very few files. Therefore the names of the
+ values are put in a separate include-file.
+ The L_PROTO level is a dummy level, which only occurs within
+ prototype declarations. When the declaration is really declared
+ the level is turned into L_FORMAL2.
+*/
+
+#define L_PROTO (-1) /* prototype declaration */
+#define L_UNIVERSAL 0
+#define L_GLOBAL 1
+#define L_FORMAL1 2 /* formal declaration */
+#define L_FORMAL2 3 /* formal definition */
+#define L_LOCAL 4 /* and up */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: DEFINITION OF MACRO DESCRIPTOR */
+
+#include "nopp.h"
+
+#ifndef NOPP
+/* The flags of the mc_flag field of the macro structure. Note that
+ these flags can be set simultaneously.
+*/
+#define NOFLAG 0 /* no special flags */
+#define FUNC 01 /* function attached */
+#define NOREPLACE 02 /* don't replace */
+
+#define FORMALP 0200 /* mask for creating macro formal parameter */
+
+/* The macro descriptor is very simple, except the fact that the
+ mc_text, which points to the replacement text, contains the
+ non-ascii characters \201, \202, etc, indicating the position of a
+ formal parameter in this text.
+*/
+struct macro {
+ struct macro *next;
+ char * mc_text; /* the replacement text */
+ int mc_nps; /* number of formal parameters */
+ int mc_length; /* length of replacement text */
+ int mc_count; /* # of "concurrent" invocations*/
+ char mc_flag; /* marking this macro */
+};
+
+/* ALLOCDEF "macro" 20 */
+
+struct mlist {
+ struct mlist *next;
+ struct macro *m_mac;
+ char *m_repl;
+ char m_unstack;
+};
+
+/* ALLOCDEF "mlist" 20 */
+
+/* `token' numbers of keywords of command-line processor
+*/
+#define K_UNKNOWN 0
+#define K_DEFINE 1
+#define K_ELIF 2
+#define K_ELSE 3
+#define K_ENDIF 4
+#define K_ERROR 5
+#define K_IF 6
+#define K_IFDEF 7
+#define K_IFNDEF 8
+#define K_INCLUDE 9
+#define K_LINE 10
+#define K_PRAGMA 11
+#define K_UNDEF 12
+#endif NOPP
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* MAIN PROGRAM */
+
+#include "lint.h"
+#include "nofloat.h"
+#include <system.h>
+#include "nopp.h"
+#include "target_sizes.h"
+#include "debug.h"
+#include "use_tmp.h"
+#include "inputtype.h"
+#include "input.h"
+#include "level.h"
+#include "idf.h"
+#include "arith.h"
+#include "type.h"
+#include "proto.h"
+#include "declar.h"
+#include "tokenname.h"
+#include "Lpars.h"
+#include "LLlex.h"
+#include <alloc.h>
+#include "specials.h"
+#include "noRoption.h"
+#include "nocross.h"
+#include "sizes.h"
+#include "align.h"
+
+extern struct tokenname tkidf[];
+extern char *symbol2str();
+extern char options[128];
+
+#ifndef NOPP
+int inc_pos = 1; /* place where next -I goes */
+int inc_total = 0;
+int inc_max;
+char **inctable;
+
+extern char *getwdir();
+#endif NOPP
+
+struct sp_id special_ids[] = {
+ {"setjmp", SP_SETJMP}, /* non-local goto's are registered */
+ {0, 0}
+};
+
+#ifndef NOCROSS
+arith
+ short_size = SZ_SHORT,
+ word_size = SZ_WORD,
+ dword_size = (2 * SZ_WORD),
+ int_size = SZ_INT,
+ long_size = SZ_LONG,
+#ifndef NOFLOAT
+ float_size = SZ_FLOAT,
+ double_size = SZ_DOUBLE,
+ lngdbl_size = SZ_LNGDBL,
+#endif NOFLOAT
+ pointer_size = SZ_POINTER;
+
+int
+ short_align = AL_SHORT,
+ word_align = AL_WORD,
+ int_align = AL_INT,
+ long_align = AL_LONG,
+#ifndef NOFLOAT
+ float_align = AL_FLOAT,
+ double_align = AL_DOUBLE,
+ lngdbl_align = AL_LNGDBL,
+#endif NOFLOAT
+ pointer_align = AL_POINTER,
+ struct_align = AL_STRUCT,
+ union_align = AL_UNION;
+#endif NOCROSS
+
+#ifndef NOPP
+arith ifval; /* ifval will contain the result of the #if expression */
+#endif NOPP
+
+char *prog_name;
+
+main(argc, argv)
+ char *argv[];
+{
+ /* parse and interpret the command line options */
+ prog_name = argv[0];
+
+ init_hmask();
+#ifndef NOPP
+ inctable = (char **) Malloc(10 * sizeof(char *));
+ inctable[0] = ".";
+ inctable[1] = "/usr/include";
+ inctable[2] = 0;
+ inc_total = 2;
+ inc_max = 10;
+
+ init_pp(); /* initialise the preprocessor macros */
+#endif NOPP
+
+ /* Note: source file "-" indicates that the source is supplied
+ as standard input. This is only allowed if INP_READ_IN_ONE is
+ not defined!
+ */
+#ifdef INP_READ_IN_ONE
+ while (argc > 1 && *argv[1] == '-')
+#else INP_READ_IN_ONE
+ while (argc > 1 && *argv[1] == '-' && argv[1][1] != '\0')
+#endif INP_READ_IN_ONE
+ {
+ char *par = &argv[1][1];
+
+ do_option(par, 1);
+ argc--, argv++;
+ }
+#ifdef LINT
+ lint_init();
+#endif LINT
+ compile(argc - 1, &argv[1]);
+
+#ifdef DEBUG
+ hash_stat();
+#endif DEBUG
+
+ sys_stop(err_occurred ? S_EXIT : S_END);
+ /*NOTREACHED*/
+}
+
+char *source = 0;
+
+char *nmlist = 0;
+
+compile(argc, argv)
+ char *argv[];
+{
+ char *result;
+#ifndef LINT
+ register char *destination = 0;
+#endif LINT
+
+#ifdef DEBUG
+#ifndef NOPP
+ int pp_only = options['E'] || options['P'] || options['C'];
+#endif NOPP
+#endif
+
+ switch (argc) {
+ case 1:
+#ifndef LINT
+#ifdef DEBUG
+#ifndef NOPP
+ if (!pp_only)
+#endif NOPP
+#endif
+ fatal("%s: destination file not specified", prog_name);
+#endif LINT
+ break;
+
+#ifndef LINT
+ case 2:
+ destination = argv[1];
+ break;
+ case 3:
+ nmlist = argv[2];
+ destination = argv[1];
+ break;
+#endif LINT
+
+ default:
+#ifndef LINT
+ fatal("use: %s source destination [namelist]", prog_name);
+#else LINT
+ fatal("use: %s source", prog_name);
+#endif LINT
+ break;
+ }
+
+ if (strcmp(argv[0], "-"))
+ FileName = source = argv[0];
+ else {
+ source = 0;
+ FileName = "standard input";
+ }
+
+ if (!InsertFile(source, (char **) 0, &result)) /* read the source file */
+ fatal("%s: no source file %s\n", prog_name, FileName);
+ File_Inserted = 1;
+ init();
+ LineNumber = 0;
+ nestlow = -1;
+#ifndef NOPP
+ WorkingDir = getwdir(source);
+#endif NOPP
+ PushLex(); /* initialize lex machine */
+
+#ifdef DEBUG
+#ifndef NOPP
+ if (pp_only) /* run the preprocessor as if it is stand-alone */
+ preprocess();
+ else
+#endif NOPP
+#endif DEBUG
+ {
+#ifndef LINT
+ init_code(destination && strcmp(destination, "-") != 0 ?
+ destination : 0);
+#endif LINT
+
+ /* compile the source text */
+ C_program();
+
+#ifdef PREPEND_SCOPES
+ prepend_scopes();
+#endif PREPEND_SCOPES
+ end_code();
+
+#ifdef DEBUG
+ if (options['u']) {
+ unstack_level(); /* unstack L_GLOBAL */
+ }
+ if (options['f'] || options['t'])
+ dumpidftab("end of main", options['f'] ? 7 : 0);
+#endif DEBUG
+ }
+ PopLex();
+}
+
+init()
+{
+ init_cst(); /* initialize variables of "cstoper.c" */
+ reserve(tkidf); /* mark the C reserved words as such */
+ init_specials(special_ids); /* mark special ids as such */
+
+ /* Treat the type generic as int, having the same size and
+ alignment requirements.
+ This type is used as top type for void pointers, and is
+ transparent to the user.
+ */
+ gen_type = standard_type(GENERIC, 0, 1, (arith)1);
+ char_type = standard_type(CHAR, 0, 1, (arith)1);
+ uchar_type = standard_type(CHAR, UNSIGNED, 1, (arith)1);
+
+ short_type = standard_type(SHORT, 0, short_align, short_size);
+ ushort_type = standard_type(SHORT, UNSIGNED, short_align, short_size);
+
+ /* Treat type `word' as `int', having its own size and
+ alignment requirements.
+ This type is transparent to the user.
+ */
+ word_type = standard_type(INT, 0, word_align, word_size);
+ uword_type = standard_type(INT, UNSIGNED, word_align, word_size);
+
+ int_type = standard_type(INT, 0, int_align, int_size);
+ uint_type = standard_type(INT, UNSIGNED, int_align, int_size);
+
+ long_type = standard_type(LONG, 0, long_align, long_size);
+ ulong_type = standard_type(LONG, UNSIGNED, long_align, long_size);
+
+#ifndef NOFLOAT
+ float_type = standard_type(FLOAT, 0, float_align, float_size);
+ double_type = standard_type(DOUBLE, 0, double_align, double_size);
+ lngdbl_type = standard_type(LNGDBL, 0, lngdbl_align, lngdbl_size);
+#endif NOFLOAT
+ void_type = standard_type(VOID, 0, 1, (arith)0);
+ label_type = standard_type(LABEL, 0, 0, (arith)0);
+ error_type = standard_type(ERRONEOUS, 0, 1, (arith)1);
+
+ /* Pointer Arithmetic type: all arithmetics concerning
+ pointers is supposed to be performed in the
+ pointer arithmetic type which is equal to either
+ int_type or long_type, depending on the pointer_size
+ */
+ if ((int)pointer_size == (int)word_size)
+ pa_type = word_type;
+ else
+ if ((int)pointer_size == (int)short_size)
+ pa_type = short_type;
+ else
+ if ((int)pointer_size == (int)int_size)
+ pa_type = int_type;
+ else
+ if ((int)pointer_size == (int)long_size)
+ pa_type = long_type;
+ else
+ fatal("pointer size incompatible with any integral size");
+
+ if ((int)int_size != (int)word_size)
+ fatal("int_size and word_size are not equal");
+ if ((int)short_size > (int)int_size || (int)int_size > (int)long_size)
+ fatal("sizes of short/int/long decreasing");
+
+ /* Build a type for function returning int, RM 13 */
+ funint_type = construct_type(FUNCTION, int_type, 0, (arith)0, NO_PROTO);
+ string_type = construct_type(POINTER, char_type, 0, (arith)0, NO_PROTO);
+
+ /* Define the standard type identifiers. */
+ add_def(str2idf("char"), TYPEDEF, char_type, L_UNIVERSAL);
+ add_def(str2idf("int"), TYPEDEF, int_type, L_UNIVERSAL);
+#ifndef NOFLOAT
+ add_def(str2idf("float"), TYPEDEF, float_type, L_UNIVERSAL);
+ add_def(str2idf("double"), TYPEDEF, double_type, L_UNIVERSAL);
+#endif NOFLOAT
+ add_def(str2idf("void"), TYPEDEF, void_type, L_UNIVERSAL);
+ stack_level();
+}
+
+init_specials(si)
+ register struct sp_id *si;
+{
+ while (si->si_identifier) {
+ struct idf *idf = str2idf(si->si_identifier);
+
+ if (idf->id_special)
+ fatal("maximum identifier length insufficient");
+ idf->id_special = si->si_flag;
+ si++;
+ }
+}
+
+#ifdef DEBUG
+#ifndef NOPP
+preprocess()
+{
+ /* preprocess() is the "stand-alone" preprocessor which
+ consecutively calls the lexical analyzer LLlex() to get
+ the tokens and prints them in a suitable way.
+ */
+ static unsigned int lastlineno = 0;
+ static char *lastfilenm = "";
+
+ while (LLlex() != EOI) {
+ if (lastlineno != dot.tk_line) {
+ if (strcmp(lastfilenm, dot.tk_file) == 0) {
+ if (dot.tk_line - lastlineno <= 1) {
+ lastlineno++;
+ print("\n");
+ }
+ else {
+ lastlineno = dot.tk_line;
+ if (!options['P'])
+ print("\n#line %ld \"%s\"\n",
+ lastlineno,
+ lastfilenm
+ );
+ }
+ }
+ else {
+ lastfilenm = dot.tk_file;
+ lastlineno = dot.tk_line;
+ if (!options['P'])
+ print("\n#line %ld \"%s\"\n",
+ lastlineno, lastfilenm);
+ }
+ }
+ else
+ if (strcmp(lastfilenm, dot.tk_file) != 0) {
+ lastfilenm = dot.tk_file;
+ if (!options['P'])
+ print("\n#line %ld \"%s\"\n",
+ lastlineno, lastfilenm);
+ }
+ switch (DOT) {
+ case IDENTIFIER:
+ case TYPE_IDENTIFIER:
+ print("%s ", dot.tk_idf->id_text);
+ break;
+ case STRING:
+ {
+ char sbuf[1024]; /* a transient buffer */
+ char *bts2str();
+
+ print("\"%s\" ", bts2str(dot.tk_bts, dot.tk_len, sbuf));
+ break;
+ }
+ case INTEGER:
+ print("%ld ", dot.tk_ival);
+ break;
+#ifndef NOFLOAT
+ case FLOATING:
+ print("%s ", dot.tk_fval);
+ break;
+#endif NOFLOAT
+ case EOI:
+ case EOF:
+ return;
+ default: /* very expensive... */
+ print("%s ", symbol2str(DOT));
+ }
+ }
+}
+#endif NOPP
+#endif DEBUG
+
+No_Mem() /* called by alloc package */
+{
+ fatal("out of memory");
+}
+
+C_failed() /* called by EM_code module */
+{
+ fatal("write failed");
+}
+
--- /dev/null
+sed -e '
+s:^.*[ ]ALLOCDEF[ ].*"\(.*\)"[ ]*\([0-9][0-9]*\).*$:\
+/* allocation definitions of struct \1 */\
+extern char *st_alloc();\
+extern struct \1 *h_\1;\
+#define new_\1() ((struct \1 *) st_alloc((char **)\&h_\1, sizeof(struct \1), \2))\
+#define free_\1(p) st_free(p, \&h_\1, sizeof(struct \1))\
+:'
--- /dev/null
+: Update Files from database
+
+PATH=/bin:/usr/bin
+
+case $# in
+1) ;;
+*) echo use: $0 file >&2
+ exit 1
+esac
+
+(
+IFCOMMAND="if (<\$FN) 2>/dev/null;\
+ then if cmp -s \$FN \$TMP;\
+ then rm \$TMP;\
+ else mv \$TMP \$FN;\
+ echo update \$FN;\
+ fi;\
+ else mv \$TMP \$FN;\
+ echo create \$FN;\
+ fi"
+echo 'TMP=.uf$$'
+echo 'FN=$TMP'
+echo 'cat >$TMP <<\!EOF!'
+sed -n '/^!File:/,${
+/^$/d
+/^!File:[ ]*\(.*\)$/s@@!EOF!\
+'"$IFCOMMAND"'\
+FN=\1\
+cat >$TMP <<\\!EOF!@
+p
+}' $1
+echo '!EOF!'
+echo $IFCOMMAND
+) |
+sh
--- /dev/null
+sed -n '
+s:^.*ALLOCDEF.*"\(.*\)".*$:struct \1 *h_\1 = 0;:p
+' $*
--- /dev/null
+cat <<'--EOT--'
+/* Generated by make.tokcase */
+/* $Header: */
+#include "Lpars.h"
+
+char *
+symbol2str(tok)
+ int tok;
+{
+ static char buf[2] = { '\0', '\0' };
+
+ if (040 <= tok && tok < 0177) {
+ buf[0] = tok;
+ buf[1] = '\0';
+ return buf;
+ }
+ switch (tok) {
+--EOT--
+
+sed '
+/{[A-Z]/!d
+s/.*{\(.*\),.*\(".*"\).*$/ case \1 :\
+ return \2;/
+'
+
+cat <<'--EOT--'
+ case '\n':
+ case '\f':
+ case '\v':
+ case '\r':
+ case '\t':
+ buf[0] = tok;
+ return buf;
+ default:
+ return "bad token";
+ }
+}
+--EOT--
--- /dev/null
+cat <<'--EOT--'
+/* Generated by make.tokfile */
+/* $Header: */
+--EOT--
+
+sed '
+/{[A-Z]/!d
+s/.*{//
+s/,.*//
+s/.*/%token &;/
+'
--- /dev/null
+/* $Header$ */
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* mcomm.c -- change ".lcomm name" into ".comm name" where "name"
+ is specified in a list.
+*/
+#include <stdio.h>
+
+#define IDFSIZE 4096
+
+char *readfile();
+
+struct node {
+ char *name;
+ struct node *left, *right;
+};
+
+char *
+Malloc(n)
+ unsigned n;
+{
+ char *space;
+ char *malloc();
+
+ if ((space = malloc(n)) == 0) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ return space;
+}
+
+struct node *make_tree();
+
+#define new_node() ((struct node *) Malloc(sizeof (struct node)))
+
+main(argc, argv)
+ char *argv[];
+{
+ char *nl_file, *as_file;
+ char *nl_text, *as_text;
+ struct node *nl_tree = 0;
+ int nl_siz, as_siz;
+
+ if (argc != 3) {
+ fprintf(stderr, "use: %s namelist assembler_file\n", argv[0]);
+ exit(1);
+ }
+ nl_file = argv[1];
+ as_file = argv[2];
+
+ if ((nl_text = readfile(nl_file, &nl_siz)) == 0) {
+ fprintf(stderr, "%s: cannot read namelist %s\n",
+ argv[0], nl_file);
+ exit(1);
+ }
+
+ if ((as_text = readfile(as_file, &as_siz)) == 0) {
+ fprintf(stderr, "%s: cannot read assembler file %s\n",
+ argv[0], as_file);
+ exit(1);
+ }
+
+ nl_tree = make_tree(nl_text);
+ edit(as_text, nl_tree);
+
+ if (writefile(as_file, as_text, as_siz) == 0) {
+ fprintf(stderr, "%s: cannot write to %s\n", argv[0], as_file);
+ exit(1);
+ }
+ return 0;
+}
+
+#include <sys/types.h>
+#include <stat.h>
+
+char *
+readfile(filename, psiz)
+ char *filename;
+ int *psiz;
+{
+ struct stat stbuf; /* for `stat' to get filesize */
+ register int fd; /* filedescriptor for `filename' */
+ register char *cbuf; /* pointer to buffer to be returned */
+
+ if (((fd = open(filename, 0)) < 0) || (fstat(fd, &stbuf) != 0))
+ return 0;
+ cbuf = Malloc(stbuf.st_size + 1);
+ if (read(fd, cbuf, stbuf.st_size) != stbuf.st_size)
+ return 0;
+ cbuf[stbuf.st_size] = '\0';
+ close(fd); /* filedes no longer needed */
+ *psiz = stbuf.st_size;
+ return cbuf;
+}
+
+int
+writefile(filename, text, size)
+ char *filename, *text;
+{
+ register fd;
+
+ if ((fd = open(filename, 1)) < 0)
+ return 0;
+ if (write(fd, text, size) != size)
+ return 0;
+ close(fd);
+ return 1;
+}
+
+struct node *
+make_tree(nl)
+ char *nl;
+{
+ char *id = nl;
+ struct node *tree = 0;
+
+ while (*nl) {
+ if (*nl == '\n') {
+ *nl = '\0';
+ insert(&tree, id);
+ id = ++nl;
+ }
+ else {
+ ++nl;
+ }
+ }
+ return tree;
+}
+
+insert(ptree, id)
+ struct node **ptree;
+ char *id;
+{
+ register cmp;
+
+ if (*ptree == 0) {
+ register struct node *nnode = new_node();
+
+ nnode->name = id;
+ nnode->left = nnode->right = 0;
+ *ptree = nnode;
+ }
+ else
+ if ((cmp = strcmp((*ptree)->name, id)) < 0)
+ insert(&((*ptree)->right), id);
+ else
+ if (cmp > 0)
+ insert(&((*ptree)->left), id);
+}
+
+struct node *
+find(tree, id)
+ struct node *tree;
+ char *id;
+{
+ register cmp;
+
+ if (tree == 0)
+ return 0;
+ if ((cmp = strcmp(tree->name, id)) < 0)
+ return find(tree->right, id);
+ if (cmp > 0)
+ return find(tree->left, id);
+ return tree;
+}
+
+edit(text, tree)
+ char *text;
+ struct node *tree;
+{
+ register char *ptr = text;
+ char idbuf[IDFSIZE];
+ register char *id;
+ register char *save_ptr;
+
+ while (*ptr) {
+ if (
+ *ptr == '.' &&
+ *++ptr == 'l' &&
+ *++ptr == 'c' &&
+ *++ptr == 'o' &&
+ *++ptr == 'm' &&
+ *++ptr == 'm' &&
+ (*++ptr == ' ' || *ptr == '\t')
+ )
+ {
+ save_ptr = ptr - 6;
+ while (*++ptr == ' ' || *ptr == '\t')
+ ;
+ if (*ptr == '_')
+ ++ptr;
+ if (InId(*ptr)) {
+ id = &idbuf[0];
+ *id++ = *ptr++;
+ while (InId(*ptr))
+ *id++ = *ptr++;
+ *id = '\0';
+ if (find(tree, idbuf) != 0) {
+ *save_ptr++ = ' ';
+ *save_ptr++ = '.';
+ }
+ }
+ }
+ while (*ptr && *ptr++ != '\n')
+ ;
+ }
+}
+
+InId(c)
+{
+ switch (c) {
+
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y':
+ case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z':
+ case '_':
+ case '.':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+puttree(nd)
+ struct node *nd;
+{
+ if (nd) {
+ puttree(nd->left);
+ printf("%s\n", nd->name);
+ puttree(nd->right);
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* MESSAGE ADMINISTRATION */
+
+extern int fp_used; /* code.c */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* Accepted if many characters of long names are significant */
+/* $Header$ */
+abcdefghijklmnopr() { }
+abcdefghijklmnopq() { }
+main() { }
--- /dev/null
+User options:
+C while running preprocessor, copy comment
+D see identifier following as a macro
+E run preprocessor only
+I expand include table with directory name following
+M set identifier length
+n don't generate register messages
+p generate linenumbers and filename indications
+ while generating EM code
+P in running the preprocessor do not output '# line' lines
+R restricted C
+T take path following as directory for storing temporary file(s)
+U undefine predefined name
+V set objectsize and alignment requirements
+w suppress warning diagnostics
+
+
+Debug options:
+
+d perform a small dataflow analysis
+f dump whole identifier table, including macros and reserved words
+h supply hash table statistics
+i print name of include files
+m supply memory allocation statistics
+r right-adjust bitfield
+t dump table of identifiers
+u unstack L_UNIVERSAL
+x dump expressions
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* U S E R O P T I O N - H A N D L I N G */
+
+#include "lint.h"
+#include "botch_free.h"
+#include <alloc.h>
+#include "nofloat.h"
+#include "nopp.h"
+#include "idfsize.h"
+#include "nobitfield.h"
+#include "class.h"
+#include "macro.h"
+#include "idf.h"
+#include "arith.h"
+#include "sizes.h"
+#include "align.h"
+#include "use_tmp.h"
+#include "dataflow.h"
+#include "noRoption.h"
+
+#ifndef NOPP
+extern char **inctable;
+extern int inc_pos;
+extern int inc_max;
+extern int inc_total;
+#endif NOPP
+
+char options[128]; /* one for every char */
+#ifdef LINT
+char loptions[128]; /* one for every char */
+#endif LINT
+
+extern int idfsize;
+
+static int txt2int();
+
+do_option(text)
+ char *text;
+{
+ register char opt;
+
+next_option: /* to allow combined one-char options */
+ switch (opt = *text++) {
+
+ case 0: /* to end the goto next_option loop */
+ break;
+
+ default:
+#ifndef LINT
+ fatal("illegal option: %c", opt);
+#else LINT
+ warning("illegal option: %c", opt);
+#endif LINT
+ break;
+
+ case '-':
+ options[*text++] = 1; /* flags, debug options etc. */
+ goto next_option;
+
+#ifndef LINT
+#ifdef DATAFLOW
+ case 'd':
+#endif DATAFLOW
+ case 'p': /* procentry/procexit */
+ case 'L' : /* no fil/lin */
+ case 'n': /* use no registers */
+ case 'w': /* no warnings will be given */
+ case 's': /* no stricts will be given */
+ options[opt] = 1;
+ goto next_option;
+#endif LINT
+
+#ifdef LINT
+ case 'h': /* heuristic tests */
+ case 'v': /* no complaints about unused arguments */
+ case 'a': /* check long->int int->long conversions */
+ case 'b': /* don't report unreachable break-statements */
+ case 'x': /* complain about unused extern declared variables */
+ case 'u': /* no "used but not defined"; for pass 2 */
+ case 'L': /* lintlibrary */
+ loptions[opt] = 1;
+ goto next_option;
+#endif LINT
+
+ case 'R': /* strict version */
+#ifndef NOROPTION
+ options[opt] = 1;
+#else NOROPTION
+ warning("-R option not implemented");
+#endif NOROPTION
+ goto next_option;
+
+#ifdef ___XXX___
+deleted, is now a debug-flag
+ case 'C' : /* E option + comment output */
+#ifndef NOPP
+ options['E'] = 1;
+ warning("-C: comment is not output");
+#else NOPP
+ warning("-C option ignored");
+#endif NOPP
+ break;
+#endif ___XXX___
+
+ case 'D' : { /* -Dname : predefine name */
+#ifndef NOPP
+ register char *cp = text, *name, *mactext;
+
+ if (class(*cp) != STIDF && class(*cp) != STELL) {
+ error("identifier missing in -D%s", text);
+ break;
+ }
+
+ name = cp;
+
+ while (*cp && in_idf(*cp)) {
+ ++cp;
+ }
+
+ if (!*cp) { /* -Dname */
+ mactext = "1";
+ }
+ else
+ if (*cp == '=') { /* -Dname=text */
+ *cp++ = '\0'; /* end of name */
+ mactext = cp;
+ }
+ else { /* -Dname?? */
+ error("malformed option -D%s", text);
+ break;
+ }
+
+ macro_def(str2idf(name), mactext, -1, strlen(mactext),
+ NOFLAG);
+#else NOPP
+ warning("-D option ignored");
+#endif NOPP
+ break;
+ }
+
+#ifdef ___XXX___
+deleted, is now a debug-flag
+ case 'E' : /* run preprocessor only, with #<int> */
+#ifndef NOPP
+ options['E'] = 1;
+#else NOPP
+ warning("-E option ignored");
+#endif NOPP
+ break;
+#endif ___XXX___
+
+ case 'I' : /* -Ipath : insert "path" into include list */
+#ifndef NOPP
+ if (*text) {
+ int i;
+ register char *new = text;
+
+ if (++inc_total > inc_max) {
+ char **n = (char **)
+ Malloc((10+inc_max)*sizeof(char *));
+ for (i = 0; i < inc_max; i++) {
+ n[i] = inctable[i];
+ }
+ free((char *) inctable);
+ inctable = n;
+ inc_max += 10;
+ }
+
+ i = inc_pos++;
+ while (new) {
+ char *tmp = inctable[i];
+
+ inctable[i++] = new;
+ new = tmp;
+ }
+ }
+ else inctable[inc_pos] = 0;
+#else NOPP
+ warning("-I option ignored");
+#endif NOPP
+ break;
+
+ case 'M': /* maximum identifier length */
+ idfsize = txt2int(&text);
+ if (*text || idfsize <= 0)
+ fatal("malformed -M option");
+ if (idfsize > IDFSIZE)
+ fatal("maximum identifier length is %d", IDFSIZE);
+ break;
+
+#ifdef ___XXX___
+deleted, is now a debug-flag
+ case 'P' : /* run preprocessor stand-alone, without #'s */
+#ifndef NOPP
+ options['E'] = 1;
+ options['P'] = 1;
+#else NOPP
+ warning("-P option ignored");
+#endif NOPP
+ break;
+#endif ___XXX___
+
+#ifdef LINT
+ case 'S' : { /* -Sint : static scope number for lint */
+ extern int stat_number;
+ stat_number = txt2int(&text);
+ break;
+ }
+#endif LINT
+
+ case 'T' : {
+#ifdef USE_TMP
+ extern char *C_tmpdir;
+ if (*text)
+ C_tmpdir = text;
+ else
+ C_tmpdir = ".";
+#else USE_TMP
+ warning("-T option ignored");
+#endif USE_TMP
+ break;
+ }
+
+ case 'U' : { /* -Uname : undefine predefined */
+#ifndef NOPP
+ register struct idf *idef;
+
+ if (*text) {
+ if ((idef = str2idf(text))->id_macro) {
+ free_macro(idef->id_macro);
+ idef->id_macro = (struct macro *) 0;
+ }
+ }
+#else NOPP
+ warning("-U option ignored");
+#endif NOPP
+ break;
+ }
+
+#ifndef LINT
+ case 'V' : /* set object sizes and alignment requirements */
+#ifdef NOCROSS
+ warning("-V option ignored");
+ break;
+#else NOCROSS
+ {
+ register arith sz, algn;
+ char c;
+
+ while (c = *text++) {
+ sz = txt2int(&text);
+ algn = 0;
+ if (*text == '.') {
+ text++;
+ algn = txt2int(&text);
+ }
+ switch (c) {
+ case 's': /* short */
+ if (sz != (arith)0)
+ short_size = sz;
+ if (algn != 0)
+ short_align = algn;
+ break;
+ case 'w': /* word */
+ if (sz != (arith)0)
+ dword_size = (word_size = sz) << 1;
+ if (algn != 0)
+ word_align = algn;
+ break;
+ case 'i': /* int */
+ if (sz != (arith)0)
+ int_size = sz;
+ if (algn != 0)
+ int_align = algn;
+ break;
+ case 'l': /* long */
+ if (sz != (arith)0)
+ long_size = sz;
+ if (algn != 0)
+ long_align = algn;
+ break;
+ case 'f': /* float */
+#ifndef NOFLOAT
+ if (sz != (arith)0)
+ float_size = sz;
+ if (algn != 0)
+ float_align = algn;
+#endif NOFLOAT
+ break;
+ case 'd': /* double */
+#ifndef NOFLOAT
+ if (sz != (arith)0)
+ double_size = sz;
+ if (algn != 0)
+ double_align = algn;
+#endif NOFLOAT
+ break;
+ case 'x': /* long double */
+#ifndef NOFLOAT
+ if (sz != (arith)0)
+ lngdbl_size = sz;
+ if (algn != 0)
+ lngdbl_align = algn;
+#endif NOFLOAT
+ break;
+ case 'p': /* pointer */
+ if (sz != (arith)0)
+ pointer_size = sz;
+ if (algn != 0)
+ pointer_align = algn;
+ break;
+ case 'r': /* adjust bitfields right */
+#ifndef NOBITFIELD
+ options['r'] = 1;
+#else NOBITFIELD
+ warning("bitfields are not implemented");
+#endif NOBITFIELD
+ break;
+ case 'S': /* initial struct alignment */
+ if (sz != (arith)0)
+ struct_align = sz;
+ break;
+ case 'U': /* initial union alignment */
+ if (sz != (arith)0)
+ union_align = sz;
+ break;
+ default:
+ error("-V: bad type indicator %c\n", c);
+ }
+ }
+ break;
+ }
+#endif NOCROSS
+#endif LINT
+ }
+}
+
+static int
+txt2int(tp)
+ register char **tp;
+{
+ /* the integer pointed to by *tp is read, while increasing
+ *tp; the resulting value is yielded.
+ */
+ register int val = 0, ch;
+
+ while (ch = **tp, ch >= '0' && ch <= '9') {
+ val = val * 10 + ch - '0';
+ (*tp)++;
+ }
+ return val;
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: PRAGMA INTERPRETER */
+
+#include "arith.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "debug.h"
+#include "idf.h"
+#include "input.h"
+#include "nopp.h"
+
+#ifndef NOPP
+#include "ifdepth.h"
+#include "botch_free.h"
+#include "nparams.h"
+#include "parbufsize.h"
+#include "textsize.h"
+#include "idfsize.h"
+#include "assert.h"
+#include <alloc.h>
+#include "class.h"
+#include "macro.h"
+
+#define P_UNKNOWN 0
+#define P_FLAGS 1
+
+struct pkey {
+ char *pk_name;
+ int pk_key;
+} pragmas[] = {
+ {"flags", P_FLAGS},
+ {0, P_UNKNOWN}
+};
+
+extern struct idf *GetIdentifier();
+
+
+do_pragma()
+{
+ register struct pkey *pkp;
+ register struct idf *id;
+ struct token tk;
+ int flag;
+
+ if ((id = GetIdentifier()) != (struct idf *)0) {
+ /* Lineair search - why bother ?
+ */
+ for (pkp = &pragmas[0]; pkp->pk_key != P_UNKNOWN; pkp++)
+ if (strcmp(pkp->pk_name, id->id_text) == 0)
+ break;
+
+ switch (pkp->pk_key) {
+ case P_FLAGS:
+ if (GetToken(&tk) == STRING)
+ do_option(tk.tk_bts);
+ break;
+
+ case P_UNKNOWN:
+ strict("unknown pragma directive %s", id->id_text);
+ break;
+
+ default:
+ strict("unimplemented pragma directive");
+ break;
+ }
+ }
+ SkipToNewLine(0);
+
+}
+#endif
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PROGRAM PARSER */
+
+/* The presence of typedef declarations renders it impossible to
+ make a context-free grammar of C. Consequently we need
+ context-sensitive parsing techniques, the simplest one being
+ a subtle cooperation between the parser and the lexical scanner.
+ The lexical scanner has to know whether to return IDENTIFIER
+ or TYPE_IDENTIFIER for a given tag, and it obtains this information
+ from the definition list, as constructed by the parser.
+ The present grammar is essentially LL(2), and is processed by
+ a parser generator which accepts LL(1) with tie breaking rules
+ in C, of the form %if(cond) and %while(cond). To solve the LL(1)
+ ambiguities, the lexical scanner does a one symbol look-ahead.
+ This symbol, however, cannot always be correctly assessed, since
+ the present symbol may cause a change in the definition list
+ which causes the identification of the look-ahead symbol to be
+ invalidated.
+ The lexical scanner relies on the parser (or its routines) to
+ detect this situation and then update the look-ahead symbol.
+ An alternative approach would be to reassess the look-ahead symbol
+ in the lexical scanner when it is promoted to dot symbol. This
+ would be more beautiful but less correct, since then for a short
+ while there would be a discrepancy between the look-ahead symbol
+ and the definition list; I think it would nevertheless work in
+ correct programs.
+ A third solution would be to enter the identifier as soon as it
+ is found; its storage class is then known, although its full type
+ isn't. We would have to fill that in afterwards.
+
+ At block exit the situation is even worse. Upon reading the
+ closing brace, the names declared inside the function are cleared
+ from the name list. This action may expose a type identifier that
+ is the same as the identifier in the look-ahead symbol. This
+ situation certainly invalidates the third solution, and casts
+ doubts upon the second.
+*/
+
+%lexical LLlex;
+%start C_program, program;
+%start If_expr, control_if_expression;
+
+{
+#include "lint.h"
+#include "nopp.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "idf.h"
+#include "label.h"
+#include "type.h"
+#include "declar.h"
+#include "decspecs.h"
+#include "code.h"
+#include "expr.h"
+#include "def.h"
+#ifdef LINT
+#include "l_state.h"
+#endif LINT
+
+#ifndef NOPP
+extern arith ifval;
+#endif NOPP
+
+extern error();
+}
+
+control_if_expression
+ {
+ struct expr *exprX;
+ }
+:
+ constant_expression(&exprX)
+ {
+#ifndef NOPP
+ register struct expr *expr = exprX;
+ if (expr->ex_flags & EX_SIZEOF)
+ expr_error(expr,
+ "sizeof not allowed in preprocessor");
+ ifval = expr->VL_VALUE;
+ free_expression(expr);
+#endif NOPP
+ }
+;
+
+/* 10 */
+program:
+ [%persistent external_definition]*
+ {unstack_world();}
+;
+
+/* A C identifier definition is remarkable in that it formulates
+ the declaration in a way different from most other languages:
+ e.g., rather than defining x as a pointer-to-integer, it defines
+ *x as an integer and lets the compiler deduce that x is actually
+ pointer-to-integer. This has profound consequences, both for the
+ structure of an identifier definition and for the compiler.
+
+ A definition starts with a decl_specifiers, which contains things
+ like
+ typedef int
+ which is implicitly repeated for every definition in the list, and
+ then for each identifier a declarator is given, of the form
+ *a()
+ or so. The decl_specifiers is kept in a struct decspecs, to be
+ used again and again, while the declarator is stored in a struct
+ declarator, only to be passed to declare_idf together with the
+ struct decspecs.
+*/
+
+external_definition
+ { struct decspecs Ds;
+ struct declarator Dc;
+ }
+:
+ { Ds = null_decspecs;
+ Dc = null_declarator;
+ }
+ [ %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER)
+ decl_specifiers(&Ds)
+ [
+ declarator(&Dc)
+ {
+ declare_idf(&Ds, &Dc, level);
+#ifdef LINT
+ lint_ext_def(Dc.dc_idf, Ds.ds_sc);
+#endif LINT
+ }
+ [
+ function(&Ds, &Dc)
+ |
+ non_function(&Ds, &Dc)
+ ]
+ |
+ ';'
+ ]
+ |
+ empty
+ {do_decspecs(&Ds);}
+ declarator(&Dc)
+ {
+ declare_idf(&Ds, &Dc, level);
+#ifdef LINT
+ lint_ext_def(Dc.dc_idf, Ds.ds_sc);
+#endif LINT
+ }
+ function(&Ds, &Dc)
+ ]
+ {remove_declarator(&Dc);}
+;
+
+non_function(register struct decspecs *ds; register struct declarator *dc;)
+:
+ { reject_params(dc);
+ def_proto(dc);
+ }
+ [
+ initializer(dc->dc_idf, ds->ds_sc)
+ |
+ { code_declaration(dc->dc_idf, (struct expr *) 0, level, ds->ds_sc); }
+ ]
+ {
+#ifdef LINT
+ if (dc->dc_idf->id_def->df_type->tp_fund == FUNCTION)
+ def2decl(ds->ds_sc);
+ if (dc->dc_idf->id_def->df_sc != TYPEDEF)
+ outdef();
+#endif LINT
+ }
+ [
+ ','
+ init_declarator(ds)
+ ]*
+ ';'
+;
+
+/* 10.1 */
+function(struct decspecs *ds; struct declarator *dc;)
+ {
+ arith fbytes;
+ }
+:
+ { register struct idf *idf = dc->dc_idf;
+#ifdef LINT
+ lint_start_function();
+#endif LINT
+ init_idf(idf);
+ stack_level(); /* L_FORMAL1 declarations */
+ if (dc->dc_formal)
+ strict("'%s' old-fashioned function declaration",
+ idf->id_text);
+ declare_params(dc);
+ begin_proc(ds, idf); /* sets global function info */
+ stack_level(); /* L_FORMAL2 declarations */
+ declare_protos(idf, dc);
+ }
+ declaration*
+ {
+ declare_formals(&fbytes);
+#ifdef LINT
+ lint_formals();
+#endif LINT
+ }
+ compound_statement
+ {
+ end_proc(fbytes);
+#ifdef LINT
+ lint_return_stmt(0); /* implicit return at end of function */
+#endif LINT
+ unstack_level(); /* L_FORMAL2 declarations */
+#ifdef LINT
+ check_args_used();
+#endif LINT
+ unstack_level(); /* L_FORMAL1 declarations */
+#ifdef LINT
+ lint_end_function();
+#endif LINT
+ }
+;
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* P R O T O T Y P E F I D D L I N G */
+
+#include "lint.h"
+#include "debug.h"
+#include "idfsize.h"
+#include "nparams.h"
+#include "botch_free.h"
+#include <alloc.h>
+#include "Lpars.h"
+#include "level.h"
+#include "arith.h"
+#include "align.h"
+#include "stack.h"
+#include "idf.h"
+#include "def.h"
+#include "type.h"
+#include "struct.h"
+#include "label.h"
+#include "expr.h"
+#include "declar.h"
+#include "decspecs.h"
+#include "proto.h"
+#include "assert.h"
+
+extern char options[];
+
+add_proto(pl, ds, dc, level)
+ struct proto *pl;
+ struct decspecs *ds;
+ struct declarator *dc;
+ int level;
+{
+ /* The full typed identifier or abstract type, described
+ by the structures decspecs and declarator are turned
+ a into parameter type list structure.
+ The parameters will be declared at level L_FORMAL2,
+ later on it's decided whether they were prototypes
+ or actual declarations.
+ */
+ register struct idf *idf;
+ register struct def *def = (struct def *)0;
+ register int sc = ds->ds_sc;
+ register struct type *type;
+ char formal_array = 0;
+
+ ASSERT(ds->ds_type != (struct type *)0);
+
+ pl->pl_flag = FORMAL;
+ if ((idf = dc->dc_idf) != (struct idf *)0)
+ def = idf->id_def;
+ type = declare_type(ds->ds_type, dc);
+ if (type->tp_size < (arith)0 && actual_declaration(sc, type)) {
+ extern char *symbol2str();
+ error("unknown %s-type", symbol2str(type->tp_fund));
+ } else if (type->tp_size == 0) {
+ pl->pl_flag = VOID;
+ if (idf != (struct idf *)0)
+ strict("illegal use of void in argument list");
+ }
+
+ /* Perform some special conversions for parameters.
+ */
+ if (type->tp_fund == FUNCTION) {
+ if (type->tp_proto)
+ remove_proto_idfs(type->tp_proto);
+ type = construct_type(POINTER, type, 0, (arith) 0, NO_PROTO);
+ } else if (type->tp_fund == ARRAY) {
+ type = construct_type(POINTER, type, 0, (arith) 0, NO_PROTO);
+ formal_array = 1;
+ }
+
+ /* According to the standard we should ignore the storage
+ class of a parameter, unless it's part of a function
+ definition.
+ However, in the routine declare_protos we don't know decspecs,
+ and therefore we can't complain up there. So we build up the
+ storage class, and keep quiet until we reach declare_protos.
+ */
+ sc = (ds->ds_sc_given && ds->ds_sc != REGISTER) ?
+ 0 : sc == 0 ? FORMAL : REGISTER;
+
+ if (def && (def->df_level == level || def->df_level < L_PROTO)) {
+ /* redeclaration at the same level */
+ error("parameter %s redeclared", idf->id_text);
+ } else if (idf != (struct idf *)0) {
+ /* New definition, redefinition hides earlier one
+ */
+ register struct def *newdef = new_def();
+
+ newdef->next = def;
+ newdef->df_level = level;
+ newdef->df_sc = sc;
+ newdef->df_type = type;
+ newdef->df_formal_array = formal_array;
+ newdef->df_file = idf->id_file;
+ newdef->df_line = idf->id_line;
+#ifdef LINT
+ newdef->df_set = (type->tp_fund == ARRAY);
+ newdef->df_firstbrace = 0;
+#endif
+ /* We can't put the idf onto the stack, since these kinds
+ of declaration may occurs at any level, and the idf
+ does not necessarily go at this level. E.g.
+
+ f() {
+ ...
+ { int func(int a, int b);
+ ...
+
+ The idf's a and b declared in the prototype declaration
+ do not go at any level, they are simply ignored.
+ However, in
+
+ f(int a, int b) {
+ ...
+
+ They should go at level L_FORMAL2. But at this stage
+ we don't know whether we have a prototype or function
+ definition. So, this process is postponed.
+ */
+ idf->id_def = newdef;
+ update_ahead(idf);
+ }
+
+ pl->pl_idf = idf;
+ pl->pl_type = type;
+}
+
+declare_protos(idf, dc)
+ register struct idf *idf;
+ register struct declarator *dc;
+{
+ /* At this points we know that the idf's in protolist are formal
+ parameters. So it's time to declare them at level L_FORMAL2.
+ */
+ struct stack_level *stl = stack_level_of(L_FORMAL1);
+ register struct decl_unary *du;
+ register struct type *type;
+ register struct proto *pl;
+ register struct def *def;
+
+#ifdef DEBUG
+ if (options['t'])
+ dumpidftab("start declare_protos", 0);
+#endif DEBUG
+ du = dc->dc_decl_unary;
+ while (du && du->du_fund != FUNCTION)
+ du = du->next;
+ pl = du ? du->du_proto : NO_PROTO;
+ if (pl) {
+ idf->id_proto = 0;
+ do {
+ type = pl->pl_type;
+
+ /* `...' only for type checking */
+ if (pl->pl_flag == ELLIPSIS) {
+ pl = pl->next;
+ continue;
+ }
+
+ /* special case: int f(void) { ; } */
+ if (type->tp_fund == VOID)
+ break;
+
+ if (!pl->pl_idf || !(def = pl->pl_idf->id_def)) {
+ error("no parameter supplied");
+ pl = pl->next;
+ continue;
+ }
+
+ /* Postponed storage class checking.
+ */
+ if (def->df_sc == 0)
+ error("illegal storage class in parameter declaration");
+
+ def->df_level = L_FORMAL2;
+ stack_idf(pl->pl_idf, stl);
+ pl = pl->next;
+ } while (pl);
+ }
+#ifdef DEBUG
+ if (options['t'])
+ dumpidftab("end declare_protos", 0);
+#endif DEBUG
+}
+
+
+def_proto(dc)
+ register struct declarator *dc;
+{
+ /* Prototype declarations may have arguments, but the idf's
+ in the parameter type list can be ignored.
+ */
+ register struct decl_unary *du = dc->dc_decl_unary;
+
+ while (du) {
+ if (du->du_fund == FUNCTION)
+ remove_proto_idfs(du->du_proto);
+ du = du->next;
+ }
+}
+
+update_proto(tp, otp)
+ register struct type *tp, *otp;
+{
+ /* This routine performs the proto type updates.
+ Consider the following code:
+
+ int f(double g());
+ int f(double g(int f(), int));
+ int f(double g(int f(long double), int));
+
+ The most accurate definition is the third line.
+ This routine will silently update all lists,
+ and removes the redundant occupied space.
+ */
+ register struct proto *pl, *opl;
+
+#if 0
+ /* THE FOLLOWING APPROACH IS PRESUMABLY WRONG.
+ THE ONLY THING THIS CODE IS SUPPOSED TO DO
+ IS TO UPDATE THE PROTOTYPELISTS, I HAVEN'T
+ EVEN CONSIDERED THE DISPOSAL OF REDUNDANT
+ SPACE !!.
+ THIS ROUTINE DUMPS CORE. SORRY, BUT IT'S 10
+ P.M. AND I'M SICK AN TIRED OF THIS PROBLEM.
+ */
+ print("Entering\n");
+ if (tp == otp) {
+ print("OOPS - they are equal\n");
+ return;
+ }
+ if (!tp || !otp) {
+ print("OOPS - Nil pointers tp=@%o otp=@%o\n", tp, otp);
+ return;
+ }
+
+ print("Search function\n");
+ while (tp && tp->tp_fund != FUNCTION) {
+ if (!(tp->tp_up)) {
+ print("TP is NIL\n");
+ return;
+ }
+ tp = tp->tp_up;
+ if (!(otp->tp_up)) {
+ print("OTP is NIL\n");
+ return;
+ }
+ otp = otp->tp_up;
+ if (!tp) return;
+ }
+
+ print("Do it\n");
+ pl = tp->tp_proto;
+ opl = otp->tp_proto;
+ if (pl && opl) {
+ /* both have prototypes */
+ print("Both have proto type\n");
+ print("New proto type list\n");
+ dump_proto(pl);
+ print("Old proto type list\n");
+ dump_proto(opl);
+ while (pl && opl) {
+ update_proto(pl->pl_type, opl->pl_type);
+ pl = pl->next;
+ opl = pl->next;
+ }
+ /*free_proto_list(tp->tp_proto);*/
+ tp->tp_proto = otp->tp_proto;
+ } else if (opl) {
+ /* old decl has type */
+ print("Old decl has type\n");
+ print("Old proto type list\n");
+ dump_proto(opl);
+ tp->tp_proto = opl;
+ } else if (pl) {
+ /* new decl has type */
+ print("New decl has type\n");
+ print("New proto type list\n");
+ dump_proto(pl);
+ print("otp = @%o\n", otp);
+ otp->tp_proto = pl;
+ print("after assign\n");
+ } else
+ print("none has prototype\n");
+
+ print("Going for another top type\n");
+ update_proto(tp->tp_up, otp->tp_up);
+# endif
+}
+
+free_proto_list(pl)
+ register struct proto *pl;
+{
+ while (pl) {
+ register struct proto *tmp = pl->next;
+ free_proto(pl);
+ pl = tmp;
+ }
+}
+
+remove_proto_idfs(pl)
+ register struct proto *pl;
+{
+ /* Remove all the identifier definitions from the
+ prototype list. Keep in account the recursive
+ function definitions.
+ */
+ register struct def *def;
+
+ while (pl) {
+ if (pl->pl_idf) {
+#ifdef DEBUG
+ if (options['t'])
+ print("Removing idf %s from list\n",
+ pl->pl_idf->id_text);
+#endif
+ /* Remove all the definitions made within
+ a prototype.
+ */
+ if (pl->pl_flag == FORMAL) {
+ register struct type *tp = pl->pl_type;
+
+ while (tp && tp->tp_fund != FUNCTION)
+ tp = tp->tp_up;
+ if (tp)
+ remove_proto_idfs(tp->tp_proto);
+ }
+ def = pl->pl_idf->id_def;
+ if (def && def->df_level <= L_PROTO){
+ pl->pl_idf->id_def = def->next;
+ free_def(def);
+ }
+ pl->pl_idf = (struct idf *) 0;
+ }
+ pl = pl->next;
+ }
+}
+
+call_proto(expp)
+ register struct expr **expp;
+{
+ /* If the function specified by (*expp)->OP_LEFT has a prototype,
+ the parameters are converted according the rules specified in
+ par. 3.3.2.2. E.i. the parameters are converted to the prototype
+ counter parts as if by assignment. For the parameters falling
+ under ellipsis clause the old parameters conversion stuff
+ applies.
+ */
+ register struct expr *left = (*expp)->OP_LEFT;
+ register struct expr *right = (*expp)->OP_RIGHT;
+ register struct proto *pl = NO_PROTO;
+
+ if (left != NILEXPR) { /* in case of an error */
+ register struct type *tp = left->ex_type;
+
+ while (tp && tp->tp_fund != FUNCTION)
+ tp = tp->tp_up;
+ pl = (tp && tp->tp_proto) ? tp->tp_proto : NO_PROTO;
+ }
+
+ if (right != NILEXPR) { /* function call with parameters */
+ register struct expr *ex = right;
+ register struct expr **ep = &((*expp)->OP_RIGHT);
+ register int ecnt = 0, pcnt = 0;
+ struct expr **estack[NPARAMS];
+ struct proto *pstack[NPARAMS];
+
+ if (pl == NO_PROTO) {
+ register struct idf *idf;
+
+ if (left->ex_class != Value || left->VL_CLASS != Name) {
+ strict("no prototype supplied");
+ return;
+ }
+ if ((idf = left->VL_IDF)->id_proto)
+ return;
+ strict("'%s' no prototype supplied", idf->id_text);
+ idf->id_proto++;
+ return;
+ }
+
+ /* stack up the parameter expressions */
+ while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
+ if (ecnt == STDC_NPARAMS)
+ strict("number of parameters exceeds ANSI limit");
+ if (ecnt >= NPARAMS-1) {
+ error("too many parameters");
+ return;
+ }
+ estack[ecnt++] = &(ex->OP_RIGHT);
+ ep = &(ex->OP_LEFT);
+ ex = ex->OP_LEFT;
+ }
+ estack[ecnt++] = ep;
+
+ /* Declarations like int f(void) do not expect any
+ parameters.
+ */
+ if (pl && pl->pl_flag == VOID) {
+ strict("no parameters expected");
+ return;
+ }
+
+ /* stack up the prototypes */
+ while (pl) {
+ /* stack prototypes */
+ pstack[pcnt++] = pl;
+ pl = pl->next;
+ }
+ pcnt--;
+
+ for (--ecnt; ecnt >= 0; ecnt--) {
+ /* Only the parameters specified in the prototype
+ are checked and converted. The parameters that
+ fall under the ellipsis clause are neither
+ checked nor converted !
+ */
+ if (pcnt < 0) {
+ error("more parameters than specified in prototype");
+ break;
+ }
+ if (pstack[pcnt]->pl_flag != ELLIPSIS) {
+ ch7cast(estack[ecnt],CASTAB,pstack[pcnt]->pl_type);
+ pcnt--;
+ } else
+ break; /* against unnecessary looping */
+ }
+ if (pcnt >= 0 && pstack[0]->pl_flag != ELLIPSIS)
+ error("less parameters than specified in prototype");
+
+ } else {
+ if (pl && pl->pl_flag != VOID)
+ error("less parameters than specified in prototype");
+ }
+}
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PARAMETER TYPE LIST DEFINITION */
+
+struct proto {
+ struct proto *next;
+ struct type *pl_type; /* parameter type */
+ struct idf *pl_idf; /* parameter identifier */
+ short pl_flag; /* ELLIPSIS or FORMAL */
+};
+
+#define NO_PROTO ((struct proto *)0)
+
+/* ALLOCDEF "proto" 10 */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* M A C R O R E P L A C E M E N T */
+#include "nopp.h"
+
+#ifndef NOPP
+
+#include "debug.h"
+#include "pathlength.h"
+#include "strsize.h"
+#include "nparams.h"
+#include "idfsize.h"
+#include "numsize.h"
+#include <alloc.h>
+#include "idf.h"
+#include "input.h"
+#include "macro.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "class.h"
+#include "assert.h"
+#include "static.h"
+#include "lapbuf.h"
+#include "argbuf.h"
+#include "replace.h"
+
+struct repl *ReplaceList; /* list of currently active macros */
+
+int
+replace(idf)
+ register struct idf *idf;
+{
+ /* replace is called by the lexical analyzer to perform
+ macro replacement. The routine actualy functions as a
+ higher interface to the real thing: expand_macro().
+ */
+ struct repl *repl;
+ int size;
+
+ repl = new_repl();
+ repl->r_ptr = repl->r_text;
+ repl->r_args = new_args();
+ if (!expand_macro(repl, idf, (struct idf *)0))
+ return 0;
+ free_args(repl->r_args);
+ InsertText(repl->r_text, repl->r_ptr - repl->r_text);
+ repl->next = ReplaceList;
+ ReplaceList = repl;
+ return 1;
+}
+
+unstackrepl()
+{
+ struct repl *repl = ReplaceList;
+
+#ifdef PERSONAL_TOUCH
+ if (repl == NO_REPL) {
+ print("Leendert, you don't understand the principle yet\n");
+ return;
+ }
+#else
+ ASSERT(repl != NO_REPL);
+#endif
+ ReplaceList = repl->next;
+ free_repl(repl);
+}
+
+expand_macro(repl, idf, previdf)
+ register struct repl *repl;
+ register struct idf *idf;
+ struct idf *previdf;
+{
+ /* expand_macro() does the actual macro replacement.
+ "idf" is a description of the identifier which
+ caused the replacement.
+ If the identifier represents a function-like macro
+ call, the number of actual parameters is checked
+ against the number of formal parameters. Note that
+ in ANSI C the parameters are expanded first;
+ this is done by calling getactuals().
+ When the possible parameters are expanded, the replace-
+ ment list associated with "idf" is expanded.
+ expand_macro() returns 1 if the replacement succeeded
+ and 0 if some error occurred.
+ */
+ register struct macro *mac = idf->id_macro;
+ struct args *args = repl->r_args;
+ register int ch;
+
+ if (mac->mc_nps != -1) { /* with parameter list */
+ if (mac->mc_flag & FUNC) {
+ /* the following assertion won't compile:
+ ASSERT(!strcmp("defined", idf->id_text));
+ */
+ if (!AccDefined) return 0;
+ }
+
+ ch = GetChar();
+ ch = skipspaces(ch,1);
+ if (ch != '(') { /* no replacement if no () */
+ /* This is obscure. See the examples for the replace
+ algorithm in section 3`.8.3.5.
+ lexwarning("macro %s needs arguments", idf->id_text);
+ */
+ UnGetChar();
+ return 0;
+ } else
+ getactuals(args, idf);
+
+ if (mac->mc_flag & FUNC) {
+ struct idf *param = str2idf(args->a_rawbuf);
+
+ *repl->r_ptr++ = param->id_macro ? '1' : '0';
+ *repl->r_ptr = '\0';
+ return 1;
+ }
+ }
+
+ if (mac->mc_flag & FUNC) /* this macro leads to special action */
+ macro_func(idf);
+
+ if (mac->mc_nps == -1) {
+ register int size = mac->mc_length;
+ register char *text = mac->mc_text;
+
+ ASSERT((repl->r_ptr+size) < &(repl->r_text[LAPBUF]));
+ while (size-- > 0)
+ *repl->r_ptr++ = *text++;
+ *repl->r_ptr = '\0';
+ } else
+ macro2buffer(repl, idf, args);
+
+ /* According to the ANSI definition:
+
+ #define a +
+ a+b; --> + + b ;
+
+ 'a' must be substituded, but the result should be
+ three tokens: + + ID. Because this preprocessor is
+ character based, we have a problem.
+ For now: just insert a space after all tokens,
+ until ANSI fixes this flaw.
+ */
+ *repl->r_ptr++ = ' ';
+ *repl->r_ptr = '\0';
+
+ if (idf != previdf)
+ maccount(repl, idf);
+ return 1;
+}
+
+getactuals(args, idf)
+ register struct args *args;
+ register struct idf *idf;
+{
+ /* Get the actual parameters from the input stream.
+ The hard part is done by actual(), only comma's and
+ other syntactic trivialities are checked here.
+ */
+ register int nps = idf->id_macro->mc_nps;
+ register int argcnt;
+ register int ch;
+
+ argcnt = 0;
+ args->a_expvec[0] = args->a_expptr = &args->a_expbuf[0];
+ args->a_rawvec[0] = args->a_rawptr = &args->a_rawbuf[0];
+ if ((ch = GetChar()) != ')') {
+ PushBack();
+ while ((ch = actual(args, idf)) != ')' ) {
+ if (ch != ',') {
+ lexerror("illegal macro call");
+ return;
+ }
+ stash(args, '\0');
+ ++argcnt;
+ args->a_expvec[argcnt] = args->a_expptr;
+ args->a_rawvec[argcnt] = args->a_rawptr;
+ if (argcnt == STDC_NPARAMS)
+ strict("number of parameters exceeds ANSI standard");
+ if (argcnt >= NPARAMS)
+ fatal("argument vector overflow");
+ }
+ stash(args, '\0');
+ ++argcnt;
+ }
+ if (argcnt < nps)
+ lexerror("too few macro arguments");
+ if (argcnt > nps)
+ lexerror("too many macro arguments");
+}
+
+int
+actual(args, idf)
+ register struct args *args;
+ register struct idf *idf;
+{
+ /* This routine deals with the scanning of an actual parameter.
+ It keeps in account the openning and clossing brackets,
+ preprocessor numbers, strings and character constants.
+ */
+ register int ch;
+ register int level = 0;
+
+ while (1) {
+ ch = GetChar();
+
+ if (class(ch) == STIDF || class(ch) == STELL) {
+ /* Scan a preprocessor identifier token. If the
+ token is a macro, it is expanded first.
+ */
+ char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
+ register char *p = buf;
+ register struct idf *idef;
+ register int pos = -1;
+ register int hash;
+ extern int idfsize;
+ int size;
+
+ hash = STARTHASH();
+ do {
+ if (++pos < idfsize) {
+ *p++ = ch;
+ hash = ENHASH(hash, ch, pos);
+ }
+ ch = GetChar();
+ } while (in_idf(ch));
+ hash = STOPHASH(hash);
+ *p++ = '\0';
+ UnGetChar();
+
+ /* When the identifier has an associated macro
+ replacement list, it's expanded.
+ */
+ idef = idf_hashed(buf, p - buf, hash);
+ if (idef->id_macro) /* expand macro identifier */
+ expand_actual(args, idef, idf);
+ else
+ for (p = buf; *p != '\0'; p++)
+ stash(args, *p);
+ } else if (class(ch) == STNUM || class(ch) == '.') {
+ /* preprocessor number token. No this is no joke,
+ the commitee decided (in all it's wisdom) that
+ a preprocessing number has the following regular
+ expression:
+ [0-9"."]{[0-9"."a-zA-Z_]|{[Ee][+-]}}*
+ */
+ do {
+ stash(args, ch);
+ if ((ch = GetChar()) == 'e' || ch == 'E') {
+ ch = GetChar();
+ if (ch == '+' || ch == '-') {
+ stash(args, ch);
+ ch = GetChar();
+ }
+ }
+ } while (class(ch) == STNUM || class(ch) == STIDF ||
+ class(ch) == STELL || ch == '.');
+ UnGetChar();
+ } else if (ch == '(' || ch == '[' || ch == '{') {
+ /* a comma may occur within these constructions */
+ level++;
+ stash(args, ch);
+ } else if (ch == ')' || ch == ']' || ch == '}') {
+ level--;
+ /* clossing parenthesis of macro call */
+ if (ch == ')' && level < 0)
+ return ')';
+ stash(args, ch);
+ } else if (ch == ',') {
+ if (level <= 0) { /* comma separator for next argument */
+ if (level)
+ lexerror("unbalanced parenthesis");
+ return ',';
+ }
+ stash(args, ch);
+ } else if (ch == '\n') {
+ /* newlines are accepted as white spaces */
+ LineNumber++;
+ while ((ch = GetChar()), class(ch) == STSKIP)
+ /* VOID */;
+
+ /* This piece of code needs some explanation:
+ consider the call of a macro defined as:
+ #define sum(a,b) (a+b)
+ in the following form:
+ sum(
+ #include phone_number
+ ,2);
+ in which case the include must be handled
+ interpreted as such.
+ */
+ if (ch == '#')
+ domacro();
+ UnGetChar();
+ stash(args, ' ');
+ } else if (ch == '/') {
+ /* comments are treated as one white space token */
+ if ((ch = GetChar()) == '*') {
+ skipcomment();
+ stash(args, ' ');
+ } else {
+ UnGetChar();
+ stash(args, '/');
+ }
+ } else if (ch == '\'' || ch == '"') {
+ /* Strings are considered as ONE token, thus no
+ replacement within strings.
+ */
+ register int match = ch;
+
+ stash(args, ch);
+ while ((ch = GetChar()) != EOI) {
+ if (ch == match)
+ break;
+ if (ch == '\\') {
+ stash(args, ch);
+ ch = GetChar();
+ } else if (ch == '\n') {
+ lexerror("newline in string");
+ LineNumber++;
+ stash(args, match);
+ break;
+ }
+ stash(args, ch);
+ }
+ if (ch != match) {
+ lexerror("unterminated macro call");
+ return ')';
+ }
+ stash(args, ch);
+ } else
+ stash(args, ch);
+ }
+}
+
+expand_actual(args, idef, idf)
+ register struct args *args;
+ register struct idf *idf, *idef;
+{
+ struct repl *nrepl = new_repl();
+ register char *p;
+
+ nrepl->r_args = new_args();
+ nrepl->r_ptr = nrepl->r_text;
+ if (expand_macro(nrepl, idef, idf)) {
+ register struct args *ap = nrepl->r_args;
+
+ for (p = nrepl->r_text; p < nrepl->r_ptr; p++)
+ *args->a_expptr++ = *p;
+
+ /* stash idef name */
+ for (p = idef->id_text; *p != '\0'; p++)
+ *args->a_rawptr++ = *p;
+
+ /* The following code deals with expanded function
+ like macro calls. It makes the following code
+ work:
+
+ #define def(a,b) x(a,b)
+ #define glue(a,b) a ## b
+
+ glue(abc,def(a,b))
+
+ Results in:
+
+ abcdef(a,b);
+ */
+ if (ap->a_rawvec[0]) {
+ /* stash arguments */
+ register int i;
+
+ *args->a_rawptr++ = '(';
+ for (i = 0; ap->a_rawvec[i] != (char *)0; i++) {
+ for (p = ap->a_rawvec[i]; *p != '\0'; p++)
+ *args->a_rawptr++ = *p;
+ *args->a_rawptr++ = ',';
+ }
+ *--args->a_rawptr = ')';
+ ++args->a_rawptr; /* one too far */
+ }
+ } else /* something happened during the macro expansion */
+ for (p = idef->id_text; *p != '\0'; p++)
+ stash(args, *p);
+ free_args(nrepl->r_args);
+ free_repl(nrepl);
+}
+
+maccount(repl, idf)
+ register struct repl *repl;
+ register struct idf *idf;
+{
+ /* To prevent re-expansion of already expanded macro's we count
+ the occurrences of the currently expanded macro name in the
+ replacement list. This is mainly to prevent recursion as in:
+
+ #define f(a) f(2 * (a))
+ f(y+1);
+
+ This results in:
+
+ f(2*(y+1));
+
+ When reading the inserted text we decrement the count of a
+ macro name until it's zero. Then we start expanding it again.
+ */
+ register char *text = repl->r_text;
+ register int pos = -1;
+ extern int idfsize;
+
+ while (*text != '\0') {
+ if (*text == '\'' || *text == '"') {
+ register int delim;
+
+ for (delim = *text++; *text != delim; text++)
+ if (*text == '\\')
+ text++;
+ text++;
+ } else
+ if (class(*text) == STIDF || class(*text) == STELL) {
+ char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
+ register char *p = buf;
+
+ do {
+ if (++pos < idfsize)
+ *p++ = *text;
+ text++;
+ } while (in_idf(*text));
+ *p++ = '\0';
+
+ if (!strcmp(idf->id_text, buf))
+ idf->id_macro->mc_count++;
+ } else
+ text++;
+ }
+}
+
+macro_func(idef)
+ register struct idf *idef;
+{
+ /* macro_func() performs the special actions needed with some
+ macros. These macros are __FILE__ and __LINE__ which
+ replacement texts must be evaluated at the time they are
+ used.
+ */
+ register struct macro *mac = idef->id_macro;
+ static char FilNamBuf[PATHLENGTH];
+ char *long2str();
+
+ switch (idef->id_text[2]) {
+ case 'F': /* __FILE__ */
+ FilNamBuf[0] = '"';
+ strcpy(&FilNamBuf[1], FileName);
+ strcat(FilNamBuf, "\"");
+ mac->mc_text = FilNamBuf;
+ mac->mc_length = strlen(FilNamBuf);
+ break;
+ case 'L': /* __LINE__ */
+ mac->mc_text = long2str((long)LineNumber, 10);
+ mac->mc_length = 1;
+ break;
+ default:
+ crash("(macro_func)");
+ /*NOTREACHED*/
+ }
+}
+
+macro2buffer(repl, idf, args)
+ register struct repl *repl;
+ register struct idf *idf;
+ register struct args *args;
+{
+ /* macro2buffer expands the replacement list and places the
+ result onto the replacement buffer. It deals with the #
+ and ## operators, and inserts the actual parameters.
+ The argument buffer contains the raw argument (needed
+ for the ## operator), and the expanded argument (for
+ all other parameter substitutions).
+
+ The grammar of the replacement list is:
+
+ repl_list: TOKEN repl_list
+ | PARAMETER repl_list
+ | '#' PARAMETER
+ | TOKEN '##' TOKEN
+ | PARAMETER '##' TOKEN
+ | TOKEN '##' PARAMETER
+ | PARAMETER '##' PARAMETER
+ ;
+
+ As the grammar indicates, we could make a DFA and
+ use this finite state machine for the replacement
+ list parsing (inserting the arguments, etc.).
+
+ Currently we go through the replacement list in a
+ linear fashion. This is VERY expensive, something
+ smarter should be done (but even a DFA is O(|s|)).
+ */
+ register char *ptr = idf->id_macro->mc_text;
+ char *stringify();
+
+ while (*ptr) {
+ ASSERT(repl->r_ptr < &(repl->r_text[LAPBUF]));
+ if (*ptr == '\'' || *ptr == '"') {
+ register int delim = *ptr;
+
+ do {
+ *repl->r_ptr++ = *ptr;
+ if (*ptr == '\\')
+ *repl->r_ptr++ = *++ptr;
+ if (*ptr == '\0') {
+ lexerror("unterminated string");
+ *repl->r_ptr = '\0';
+ return;
+ }
+ ptr++;
+ } while (*ptr != delim || *ptr == '\0');
+ *repl->r_ptr++ = *ptr++;
+ } else if (*ptr == '#') {
+ if (*++ptr == '#') {
+ /* ## - paste operator */
+ ptr++;
+
+ /* trim the actual replacement list */
+ --repl->r_ptr;
+ while (is_wsp(*repl->r_ptr) &&
+ repl->r_ptr >= repl->r_text)
+ --repl->r_ptr;
+
+ /* ## occurred at the beginning of the
+ replacement list.
+ */
+ if (repl->r_ptr == repl->r_text)
+ goto paste;
+ ++repl->r_ptr;
+
+ /* skip space in macro replacement list */
+ while ((*ptr & FORMALP) == 0 && is_wsp(*ptr))
+ ptr++;
+
+ /* ## occurred at the end of the
+ replacement list.
+ */
+ if (*ptr & FORMALP) {
+ register int n = *ptr++ & 0177;
+ register char *p;
+
+ ASSERT(n != 0);
+ p = args->a_rawvec[n-1];
+ while (is_wsp(*p))
+ p++;
+ while (*p)
+ *repl->r_ptr++ = *p++;
+ } else if (*ptr == '\0')
+ goto paste;
+ } else
+ ptr = stringify(repl, ptr, args);
+ } else if (*ptr & FORMALP) {
+ /* insert actual parameter */
+ register int n = *ptr++ & 0177;
+ register char *p, *q;
+
+ ASSERT(n != 0);
+
+ /* This is VERY dirty, we look ahead for the
+ ## operater. If it's found we use the raw
+ argument buffer instead of the expanded
+ one.
+ */
+ for (p = ptr; (*p & FORMALP) == 0 && is_wsp(*p); p++)
+ /* VOID */;
+ if (*p == '#' && p[1] == '#')
+ q = args->a_rawvec[n-1];
+ else
+ q = args->a_expvec[n-1];
+
+ while (*q)
+ *repl->r_ptr++ = *q++;
+
+ *repl->r_ptr++ = ' ';
+ } else
+ *repl->r_ptr++ = *ptr++;
+ }
+ *repl->r_ptr = '\0';
+ return;
+
+paste:
+ /* Sorry, i know this looks a bit like
+ a unix device driver code.
+ */
+ lexerror("illegal use of the ## operator");
+ return;
+}
+
+char *
+stringify(repl, ptr, args)
+ register struct repl *repl;
+ register char *ptr;
+ register struct args *args;
+{
+ /* If a parameter is immediately preceded by a # token
+ both are replaced by a single string literal that
+ contains the spelling of the token sequence for the
+ corresponding argument.
+ Each occurrence of white space between the argument's
+ tokens become a single space character in the string
+ literal. White spaces before the first token and after
+ the last token comprising the argument are deleted.
+ To retain the original spelling we insert backslashes
+ as appropriate. We only escape backslashes if they
+ occure within string tokens.
+ */
+ register int space = 1; /* skip leading spaces */
+ register int delim = 0; /* string or character constant delim */
+ register int backslash = 0; /* last character was a \ */
+
+ /* skip spaces macro replacement list */
+ while ((*ptr & FORMALP) == 0 && is_wsp(*ptr))
+ ptr++;
+
+ if (*ptr & FORMALP) {
+ register int n = *ptr++ & 0177;
+ register char *p;
+
+ ASSERT(n != 0);
+ p = args->a_expvec[n-1];
+ *repl->r_ptr++ = '"';
+ while (*p) {
+ if (is_wsp(*p)) {
+ if (!space) {
+ space = 1;
+ *repl->r_ptr++ = ' ';
+ }
+ p++;
+ continue;
+ }
+ space = 0;
+
+ if (!delim && (*p == '"' || *p == '\''))
+ delim = *p;
+ else if (*p == delim && !backslash)
+ delim = 0;
+ backslash = *p == '\\';
+ if (*p == '"' || (delim && *p == '\\'))
+ *repl->r_ptr++ = '\\';
+ *repl->r_ptr++ = *p++;
+ }
+
+ /* trim spaces in the replacement list */
+ for (--repl->r_ptr; is_wsp(*repl->r_ptr); repl->r_ptr--)
+ /* VOID */;
+ *++repl->r_ptr = '"';
+ ++repl->r_ptr; /* oops, one to far */
+ } else
+ error("illegal use of # operator");
+ return ptr;
+}
+
+stash(args, ch)
+ register struct args *args;
+ register int ch;
+{
+ /* Stash characters into the macro expansion buffer.
+ */
+ if (args->a_expptr >= &(args->a_expbuf[ARGBUF]))
+ fatal("macro argument buffer overflow");
+ *args->a_expptr++ = ch;
+
+ if (args->a_rawptr >= &(args->a_rawbuf[ARGBUF]))
+ fatal("raw macro argument buffer overflow");
+ *args->a_rawptr++ = ch;
+
+
+}
+#endif NOPP
--- /dev/null
+struct repl {
+ struct repl *next;
+ struct args *r_args; /* replacement parameters */
+ char r_text[LAPBUF]; /* replacement text */
+ char *r_ptr; /* replacement text pointer */
+};
+
+/* ALLOCDEF "repl" 4 */
+
+#define NO_REPL (struct repl *)0
+
+/* The implementation of the ## operator is currently very clumsy.
+ When the the ## operator is used the arguments are taken from
+ the raw buffer; this buffer contains a precise copy of the
+ original argument. The fully expanded copy is in the arg buffer.
+ The two copies are here explicitely because:
+
+ #define ABC f()
+ #define ABCD 2
+ #define g(x, y) x ## y + h(x)
+
+ g(ABC, D);
+
+ In this case we need two copies: one raw copy for the pasting
+ operator, and an expanded one as argument for h().
+*/
+struct args {
+ char *a_expptr; /* expanded argument pointer */
+ char *a_expvec[NPARAMS]; /* expanded argument vector */
+ char a_expbuf[ARGBUF]; /* expanded argument buffer space */
+ char *a_rawptr; /* raw argument pointer */
+ char *a_rawvec[NPARAMS]; /* raw argument vector */
+ char a_rawbuf[ARGBUF]; /* raw argument buffer space */
+};
+
+/* ALLOCDEF "args" 2 */
+
+#define NO_ARGS (struct args *)0
+
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: SCANNER FOR THE ACTUAL PARAMETERS OF MACROS */
+
+#include "nopp.h"
+
+#ifndef NOPP
+/* This file contains the function getactuals() which scans an actual
+ parameter list and splits it up into a list of strings, each one
+ representing an actual parameter.
+*/
+
+#include "lapbuf.h" /* UF */
+#include "nparams.h" /* UF */
+
+#include "input.h"
+#include "class.h"
+#include "idf.h"
+#include "macro.h"
+#include "interface.h"
+#include "file_info.h"
+
+#define EOS '\0'
+#define overflow() (fatal("actual parameter buffer overflow"))
+
+PRIVATE char apbuf[LAPBUF]; /* temporary storage for actual parameters */
+PRIVATE char *actparams[NPARAMS]; /* pointers to the text of the actuals */
+PRIVATE char *aptr; /* pointer to last inserted character in apbuf */
+
+#define copy(ch) ((aptr < &apbuf[LAPBUF]) ? (*aptr++ = ch) : overflow())
+
+PRIVATE int nr_of_params; /* number of actuals read until now */
+
+PRIVATE char **
+getactuals(idef)
+ register struct idf *idef;
+{
+ /* getactuals() collects the actual parameters and turns them
+ into a list of strings, a pointer to which is returned.
+ */
+ register acnt = idef->id_macro->mc_nps;
+
+ nr_of_params = 0;
+ actparams[0] = aptr = &apbuf[0];
+ copyact('(', ')', 0); /* read the actual parameters */
+ copy(EOS); /* mark the end of it all */
+
+ if (!nr_of_params++) { /* 0 or 1 parameter */
+ /* there could be a ( <spaces, comment, ...> )
+ */
+ register char *p = actparams[0];
+
+ while ((class(*p) == STSKIP) || (*p == '\n')) {
+ ++p;
+ }
+
+ if (!*p) { /* the case () : 0 parameters */
+ nr_of_params--;
+ }
+ }
+
+ if (nr_of_params != acnt) {
+ /* argument mismatch: too many or too few
+ actual parameters.
+ */
+ lexwarning("argument mismatch, %s", idef->id_text);
+
+ while (nr_of_params < acnt) {
+ /* too few paraeters: remaining actuals are ""
+ */
+ actparams[nr_of_params] = "";
+ nr_of_params++;
+ }
+ }
+
+ return actparams;
+}
+
+PRIVATE
+copyact(ch1, ch2, lvl)
+ char ch1, ch2;
+ int lvl;
+{
+ /* copyact() is taken from Ceriel Jacobs' LLgen, with
+ permission. Its task is to build a list of actuals
+ parameters, which list is surrounded by '(' and ')' and in
+ which the parameters are separated by ',' if there are
+ more than 1. The balancing of '(',')' and '[',']' and
+ '{','}' is taken care of by calling this function
+ recursively. At each level lvl, copyact() reads the input,
+ upto the corresponding closing bracket.
+
+ Opening bracket is ch1, closing bracket is ch2. If
+ lvl != 0, copy opening and closing parameters too.
+ */
+ register int ch; /* Current char */
+ register int match; /* used to read strings */
+
+ if (lvl) {
+ copy(ch1);
+ }
+
+ for (;;) {
+ LoadChar(ch);
+
+ if (ch == ch2) {
+ if (lvl) {
+ copy(ch);
+ }
+ return;
+ }
+
+ switch(ch) {
+
+#ifdef __MATCHING_PAR__
+ case ')':
+ case '}':
+ case ']':
+ lexerror("unbalanced parenthesis");
+ break;
+#endif __MATCHING_PAR__
+
+ case '(':
+ copyact('(', ')', lvl+1);
+ break;
+
+#ifdef __MATCHING_PAR__
+ case '{':
+ /* example:
+ #define declare(v, t) t v
+ declare(v, union{int i, j; float r;});
+ */
+ copyact('{', '}', lvl+1);
+ break;
+
+ case '[':
+ copyact('[', ']', lvl+1);
+ break;
+#endif __MATCHING_PAR__
+
+ case '\n':
+ LineNumber++;
+ while (LoadChar(ch), ch == '#') {
+ /* This piece of code needs some
+ explanation: consider the call of
+ the macro defined as:
+ #define sum(b,c) (b + c)
+ in the following form:
+ sum(
+ #include my_phone_number
+ ,2)
+ in which case the include must be
+ interpreted as such.
+ */
+ domacro(); /* has read nl, vt or ff */
+ /* Loop, for another control line */
+ }
+
+ PushBack();
+ copy(' ');
+ break;
+
+ case '/':
+ LoadChar(ch);
+
+ if (ch == '*') { /* skip comment */
+ skipcomment();
+ continue;
+ }
+
+ PushBack();
+ copy('/');
+ break;
+
+ case ',':
+ if (!lvl) {
+ /* next parameter encountered */
+ copy(EOS);
+
+ if (++nr_of_params >= NPARAMS) {
+ fatal("too many actual parameters");
+ }
+
+ actparams[nr_of_params] = aptr;
+ }
+ else {
+ copy(ch);
+ }
+ break;
+
+ case '\'':
+ case '"' :
+ /* watch out for brackets in strings, they do
+ not count !
+ */
+ match = ch;
+ copy(ch);
+ while (LoadChar(ch), ch != EOI) {
+ if (ch == match) {
+ break;
+ }
+
+ if (ch == '\\') {
+ copy(ch);
+ LoadChar(ch);
+ }
+ else
+ if (ch == '\n') {
+ lexerror("newline in string");
+ LineNumber++;
+ copy(match);
+ break;
+ }
+
+ copy(ch);
+ }
+
+ if (ch == match) {
+ copy(ch);
+ break;
+ }
+ /* Fall through */
+
+ case EOI :
+ lexerror("unterminated macro call");
+ return;
+
+ default:
+ copy(ch);
+ break;
+ }
+ }
+}
+#endif NOPP
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* VARIOUS TARGET MACHINE SIZE DESCRIPTORS */
+
+#include "nofloat.h"
+#include "nocross.h"
+#include "target_sizes.h"
+
+#ifndef NOCROSS
+extern arith
+ short_size, word_size, dword_size, int_size, long_size,
+#ifndef NOFLOAT
+ float_size, double_size, lngdbl_size,
+#endif NOFLOAT
+ pointer_size;
+#else NOCROSS
+#define short_size (SZ_SHORT)
+#define word_size (SZ_WORD)
+#define dword_size (2*SZ_WORD)
+#define int_size (SZ_INT)
+#define long_size (SZ_LONG)
+#ifndef NOFLOAT
+#define float_size (SZ_FLOAT)
+#define double_size (SZ_DOUBLE)
+#define lngdbl_size (SZ_LNGDBL)
+#endif NOFLOAT
+#define pointer_size (SZ_POINTER)
+#endif NOCROSS
+
+extern arith max_int, max_unsigned; /* cstoper.c */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* PREPROCESSOR: INPUT SKIP FUNCTIONS */
+
+#include "nopp.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "class.h"
+#include "input.h"
+
+#ifndef NOPP
+int
+skipspaces(ch, skipnl)
+ register int ch;
+{
+ /* skipspaces() skips any white space and returns the first
+ non-space character.
+ */
+ for (;;) {
+ while (class(ch) == STSKIP)
+ ch = GetChar();
+ if (skipnl && class(ch) == STNL) {
+ ch = GetChar();
+ ++LineNumber;
+ continue;
+ }
+
+ /* \\\n are handled by trigraph */
+
+ if (ch == '/') {
+ ch = GetChar();
+ if (ch == '*') {
+ skipcomment();
+ ch = GetChar();
+ }
+ else {
+ UnGetChar();
+ return '/';
+ }
+ }
+ else
+ return ch;
+ }
+}
+#endif NOPP
+
+SkipToNewLine(garbage)
+ int garbage;
+{
+ register int ch;
+ register int pstrict = 0;
+
+ UnGetChar();
+ while ((ch = GetChar()) != '\n') {
+ if (ch == '/') {
+ if ((ch = GetChar()) == '*') {
+ skipcomment();
+ continue;
+ }
+ }
+ if (garbage && !is_wsp(ch))
+ pstrict = 1;
+ }
+ ++LineNumber;
+ return pstrict;
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* OCCURANCES OF SPECIAL IDENTIFIERS */
+
+#define SP_SETJMP 1
+
+#define SP_TOTAL 1
+
+struct sp_id {
+ char *si_identifier; /* its name */
+ int si_flag; /* index into sp_occurred array */
+};
+
+extern char sp_occurred[]; /* idf.c */
+extern struct sp_id special_ids[]; /* main.c */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* S T A C K / U N S T A C K R O U T I N E S */
+
+#include "lint.h"
+#include "nofloat.h"
+#include <system.h>
+#include <em.h>
+#include "debug.h"
+#include "botch_free.h"
+#include <alloc.h>
+#include "Lpars.h"
+#include "arith.h"
+#include "stack.h"
+#include "type.h"
+#include "idf.h"
+#include "def.h"
+#include "struct.h"
+#include "level.h"
+#include "mes.h"
+#include "noRoption.h"
+
+/* #include <em_reg.h> */
+
+extern char options[];
+
+static struct stack_level UniversalLevel;
+struct stack_level *local_level = &UniversalLevel;
+/* The main reason for having this secondary stacking
+ mechanism besides the linked lists pointed to by the idf's
+ is efficiency.
+ To remove the idf's of a given level, one could scan the
+ hash table and chase down the idf chains; with a hash
+ table size of 100 this is feasible, but with a size of say
+ 100000 this becomes painful. Therefore all idf's are also
+ kept in a stack of sets, one set for each level.
+*/
+
+int level; /* Always equal to local_level->sl_level. */
+
+stack_level() {
+ /* A new level is added on top of the identifier stack.
+ */
+ register struct stack_level *stl = new_stack_level();
+ register struct stack_level *loclev = local_level;
+
+ loclev->sl_next = stl;
+ stl->sl_previous = loclev;
+ stl->sl_level = ++level;
+ stl->sl_max_block = loclev->sl_max_block;
+ local_level = stl;
+#ifdef LINT
+ lint_start_local();
+#endif LINT
+}
+
+stack_idf(idf, stl)
+ struct idf *idf;
+ register struct stack_level *stl;
+{
+ /* The identifier idf is inserted in the stack on level stl.
+ */
+ register struct stack_entry *se = new_stack_entry();
+
+ /* link it into the stack level */
+ se->next = stl->sl_entry;
+ se->se_idf = idf;
+ stl->sl_entry = se;
+}
+
+struct stack_level *
+stack_level_of(lvl)
+{
+ /* The stack_level corresponding to level lvl is returned.
+ The stack should probably be an array, to be extended with
+ realloc where needed.
+ */
+ register struct stack_level *stl;
+
+ if (lvl == level)
+ return local_level;
+ stl = &UniversalLevel;
+
+ while (stl->sl_level != lvl)
+ stl = stl->sl_next;
+ return stl;
+}
+
+unstack_level()
+{
+ /* The top level of the identifier stack is removed.
+ */
+ struct stack_level *lastlvl;
+
+#ifdef DEBUG
+ if (options['t'])
+ dumpidftab("before unstackidfs", 0);
+#endif DEBUG
+
+#ifdef LINT
+ lint_local_level(local_level);
+#endif LINT
+
+ /* The implementation below is more careful than strictly
+ necessary. Optimists may optimize it afterwards.
+ */
+ while (local_level->sl_entry) {
+ register struct stack_entry *se = local_level->sl_entry;
+ register struct idf *idf = se->se_idf;
+ register struct def *def;
+ register struct sdef *sdef;
+ register struct tag *tag;
+
+ /* unlink it from the local stack level */
+ local_level->sl_entry = se->next;
+ free_stack_entry(se);
+
+ while ((def = idf->id_def) && def->df_level >= level) {
+ /* unlink it from the def list under the idf block */
+ if (def->df_sc == LABEL)
+ unstack_label(idf);
+ else if (def->df_sc == REGISTER || def->df_sc == AUTO)
+ FreeLocal(def->df_address);
+ idf->id_def = def->next;
+ free_def(def);
+ update_ahead(idf);
+ }
+ while ( (sdef = idf->id_sdef)
+ && sdef->sd_level >= level
+ ) {
+ /* unlink it from the sdef list under the idf block */
+ idf->id_sdef = sdef->next;
+ free_sdef(sdef);
+ }
+ while ( (tag = idf->id_struct)
+ && tag->tg_level >= level
+ ) {
+ /* unlink it from the struct list under the idf block */
+ idf->id_struct = tag->next;
+ free_tag(tag);
+ }
+ while ((tag = idf->id_enum) && tag->tg_level >= level) {
+ /* unlink it from the enum list under the idf block */
+ idf->id_enum = tag->next;
+ free_tag(tag);
+ }
+ }
+ /* Unlink the local stack level from the stack.
+ */
+ lastlvl = local_level;
+ local_level = local_level->sl_previous;
+ if (level >= L_LOCAL) {
+ local_level->sl_max_block = lastlvl->sl_max_block;
+ }
+ free_stack_level(lastlvl);
+ local_level->sl_next = (struct stack_level *) 0;
+ level = local_level->sl_level;
+
+#ifdef DEBUG
+ if (options['t'])
+ dumpidftab("after unstackidfs", 0);
+#endif DEBUG
+}
+
+unstack_world()
+{
+ /* The global level of identifiers is scanned, and final
+ decisions are taken about such issues as
+ extern/static/global and un/initialized.
+ Effects on the code generator: initialised variables
+ have already been encoded while the uninitialised ones
+ are not and have to be encoded at this moment.
+ */
+ register struct stack_entry *se = local_level->sl_entry;
+
+#ifdef LINT
+ lint_global_level(local_level);
+#endif LINT
+
+ open_name_list();
+
+ while (se) {
+ register struct idf *idf = se->se_idf;
+ register struct def *def = idf->id_def;
+
+ if (!def) {
+ /* global selectors, etc. */
+ se = se->next;
+ continue;
+ }
+
+#ifdef DEBUG
+ if (options['a']) {
+ char *symbol2str();
+
+ print("\"%s\", %s, %s, %s, %s\n",
+ idf->id_text,
+ (def->df_alloc == 0) ? "no alloc" :
+ (def->df_alloc == ALLOC_SEEN) ? "alloc seen" :
+ (def->df_alloc == ALLOC_DONE) ? "alloc done" :
+ "illegal alloc info",
+ symbol2str(def->df_sc),
+ def->df_initialized ? "init" : "no init",
+ def->df_used ? "used" : "not used");
+ }
+#endif DEBUG
+ /*
+ /_* find final storage class *_/
+ if (def->df_sc == GLOBAL || def->df_sc == IMPLICIT)
+ /_* even now we still don't know *_/
+ def->df_sc = EXTERN;
+ */
+
+ if ( def->df_sc == STATIC
+ && def->df_type->tp_fund == FUNCTION
+ && !def->df_initialized
+ ) {
+ /* orphaned static function */
+#ifndef NOROPTION
+ if (options['R'])
+ warning("static function %s never defined, %s",
+ idf->id_text,
+ "changed to extern"
+ );
+#endif
+ def->df_sc = EXTERN;
+ }
+
+ if (
+ def->df_alloc == ALLOC_SEEN &&
+ !def->df_initialized
+ ) {
+ /* space must be allocated */
+ bss(idf);
+ if (def->df_sc != STATIC)
+ namelist(idf->id_text); /* may be common */
+ def->df_alloc = ALLOC_DONE; /* see Note below */
+ }
+ se = se->next;
+ }
+ /* Note:
+ df_alloc must be set to ALLOC_DONE because the idf entry
+ may occur several times in the list.
+ The reason for this is that the same name may be used
+ for different purposes on the same level, e.g.
+ struct s {int s;} s;
+ is a legal definition and contains 3 defining occurrences
+ of s.
+ Each definition has been entered into the identifier stack.
+ Although only one of them concerns a variable, we meet the
+ s 3 times when scanning the identifier stack.
+ */
+}
+
+/* A list of potential common names is kept, to be fed to
+ an understanding loader. The list is written to a file
+ the name of which is nmlist. If nmlist == NULL, no name
+ list is generated.
+*/
+extern char *nmlist; /* BAH! -- main.c */
+static File *nfp = 0;
+
+open_name_list()
+{
+ if (nmlist && sys_open(nmlist, OP_WRITE, &nfp) == 0)
+ fatal("cannot create namelist %s", nmlist);
+}
+
+namelist(nm)
+ char *nm;
+{
+ if (nmlist) {
+ sys_write(nfp, nm, strlen(nm));
+ sys_write(nfp, "\n", 1);
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* IDENTIFIER STACK DEFINITIONS */
+
+/* The identifier stack is implemented as a stack of sets.
+ The stack is implemented by a doubly linked list,
+ the sets by singly linked lists.
+*/
+
+struct stack_level {
+ struct stack_level *next;
+ struct stack_level *sl_next; /* upward link */
+ struct stack_level *sl_previous; /* downward link */
+ struct stack_entry *sl_entry; /* sideward link */
+ arith sl_local_offset; /* @ for first coming object */
+ arith sl_max_block; /* maximum size of sub-block */
+ int sl_level;
+};
+
+/* ALLOCDEF "stack_level" 5 */
+
+struct stack_entry {
+ struct stack_entry *next;
+ struct idf *se_idf;
+};
+
+/* ALLOCDEF "stack_entry" 5 */
+
+extern struct stack_level *local_level;
+extern struct stack_level *stack_level_of();
+extern int level;
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* STATEMENT SYNTAX PARSER */
+
+{
+#include <em.h>
+
+#include "lint.h"
+#include "debug.h"
+#include "botch_free.h"
+
+#include "arith.h"
+#include "LLlex.h"
+#include "type.h"
+#include "idf.h"
+#include "label.h"
+#include "expr.h"
+#include "code.h"
+#include "stack.h"
+#include "def.h"
+#ifdef LINT
+#include "l_lint.h"
+#include "l_state.h"
+#endif LINT
+
+extern int level;
+}
+
+/* Each statement construction is stacked in order to trace a
+ statement to such a construction. Example: a case statement should
+ be recognized as a piece of the most enclosing switch statement.
+*/
+
+/* 9 */
+statement
+ {
+#ifdef LINT
+ lint_statement();
+#endif LINT
+ }
+:
+%if (AHEAD != ':')
+ expression_statement
+|
+ label ':' statement
+|
+ compound_statement
+|
+ if_statement
+|
+ while_statement
+|
+ do_statement
+|
+ for_statement
+|
+ switch_statement
+|
+ case_statement
+|
+ default_statement
+|
+ BREAK
+ {
+ code_break();
+#ifdef LINT
+ lint_break_stmt();
+#endif LINT
+ }
+ ';'
+|
+ CONTINUE
+ {
+ code_continue();
+#ifdef LINT
+ lint_continue_stmt();
+#endif LINT
+ }
+ ';'
+|
+ return_statement
+|
+ jump
+|
+ ';'
+;
+
+
+expression_statement
+ { struct expr *expr;
+ }
+:
+ expression(&expr)
+ ';'
+ {
+#ifdef DEBUG
+ print_expr("expression_statement", expr);
+#endif DEBUG
+ code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL);
+ free_expression(expr);
+ }
+;
+
+label
+ { struct idf *idf;
+ }
+:
+ identifier(&idf)
+ {
+ /* This allows the following absurd case:
+
+ typedef int grz;
+ main() {
+ grz: printf("A labelled statement\n");
+ }
+ */
+#ifdef LINT
+ lint_label();
+#endif LINT
+ define_label(idf);
+ C_df_ilb((label)idf->id_def->df_address);
+ }
+;
+
+if_statement
+ {
+ struct expr *expr;
+ label l_true = text_label();
+ label l_false = text_label();
+ label l_end = text_label();
+ }
+:
+ IF
+ '('
+ expression(&expr)
+ {
+ opnd2test(&expr, IF);
+ if (is_cp_cst(expr)) {
+ /* The comparison has been optimized
+ to a 0 or 1.
+ */
+ if (expr->VL_VALUE == (arith)0) {
+ C_bra(l_false);
+ }
+ /* else fall through */
+#ifdef LINT
+ start_if_part(1);
+#endif LINT
+ }
+ else {
+ code_expr(expr, RVAL, TRUE, l_true, l_false);
+ C_df_ilb(l_true);
+#ifdef LINT
+ start_if_part(0);
+#endif LINT
+ }
+ free_expression(expr);
+ }
+ ')'
+ statement
+ [%prefer
+ ELSE
+ {
+#ifdef LINT
+ start_else_part();
+#endif LINT
+ C_bra(l_end);
+ C_df_ilb(l_false);
+ }
+ statement
+ { C_df_ilb(l_end);
+#ifdef LINT
+ end_if_else_stmt();
+#endif LINT
+ }
+ |
+ empty
+ { C_df_ilb(l_false);
+#ifdef LINT
+ end_if_stmt();
+#endif LINT
+ }
+ ]
+;
+
+while_statement
+ {
+ struct expr *expr;
+ label l_break = text_label();
+ label l_continue = text_label();
+ label l_body = text_label();
+ }
+:
+ WHILE
+ {
+ stack_stmt(l_break, l_continue);
+ C_df_ilb(l_continue);
+ }
+ '('
+ expression(&expr)
+ {
+ opnd2test(&expr, WHILE);
+ if (is_cp_cst(expr)) {
+ if (expr->VL_VALUE == (arith)0) {
+ C_bra(l_break);
+ }
+#ifdef LINT
+ start_loop_stmt(WHILE, 1,
+ expr->VL_VALUE != (arith)0);
+#endif LINT
+ }
+ else {
+ code_expr(expr, RVAL, TRUE, l_body, l_break);
+ C_df_ilb(l_body);
+#ifdef LINT
+ start_loop_stmt(WHILE, 0, 0);
+#endif LINT
+ }
+ }
+ ')'
+ statement
+ {
+ C_bra(l_continue);
+ C_df_ilb(l_break);
+ unstack_stmt();
+ free_expression(expr);
+#ifdef LINT
+ end_loop_stmt();
+#endif LINT
+ }
+;
+
+do_statement
+ { struct expr *expr;
+ label l_break = text_label();
+ label l_continue = text_label();
+ label l_body = text_label();
+ }
+:
+ DO
+ { C_df_ilb(l_body);
+ stack_stmt(l_break, l_continue);
+#ifdef LINT
+ start_loop_stmt(DO, 1, 1);
+#endif LINT
+ }
+ statement
+ WHILE
+ '('
+ { C_df_ilb(l_continue);
+ }
+ expression(&expr)
+ {
+ opnd2test(&expr, WHILE);
+ if (is_cp_cst(expr)) {
+ if (expr->VL_VALUE == (arith)1) {
+ C_bra(l_body);
+ }
+#ifdef LINT
+ end_do_stmt(1, expr->VL_VALUE != (arith)0);
+#endif LINT
+ }
+ else {
+ code_expr(expr, RVAL, TRUE, l_body, l_break);
+#ifdef LINT
+ end_do_stmt(0, 0);
+#endif LINT
+ }
+ C_df_ilb(l_break);
+ }
+ ')'
+ ';'
+ {
+ unstack_stmt();
+ free_expression(expr);
+ }
+;
+
+for_statement
+ { struct expr *e_init = 0, *e_test = 0, *e_incr = 0;
+ label l_break = text_label();
+ label l_continue = text_label();
+ label l_body = text_label();
+ label l_test = text_label();
+#ifdef LINT
+ int const = 1, cond = 1; /* the default case */
+#endif LINT
+ }
+:
+ FOR
+ { stack_stmt(l_break, l_continue);
+ }
+ '('
+ [
+ expression(&e_init)
+ { code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL);
+ }
+ ]?
+ ';'
+ { C_df_ilb(l_test);
+ }
+ [
+ expression(&e_test)
+ {
+ opnd2test(&e_test, FOR);
+ if (is_cp_cst(e_test)) {
+ if (e_test->VL_VALUE == (arith)0) {
+ C_bra(l_break);
+ }
+#ifdef LINT
+ const = 1,
+ cond = e_test->VL_VALUE != (arith)0;
+#endif LINT
+ }
+ else {
+ code_expr(e_test, RVAL, TRUE, l_body, l_break);
+ C_df_ilb(l_body);
+#ifdef LINT
+ const = 0, cond = 0;
+#endif LINT
+ }
+ }
+ ]?
+ ';'
+ expression(&e_incr)?
+ ')'
+ {
+#ifdef LINT
+ start_loop_stmt(FOR, const, cond);
+#endif LINT
+ }
+ statement
+ {
+#ifdef LINT
+ end_loop_stmt();
+#endif LINT
+ C_df_ilb(l_continue);
+ if (e_incr)
+ code_expr(e_incr, RVAL, FALSE,
+ NO_LABEL, NO_LABEL);
+ C_bra(l_test);
+ C_df_ilb(l_break);
+ unstack_stmt();
+ free_expression(e_init);
+ free_expression(e_test);
+ free_expression(e_incr);
+ }
+;
+
+switch_statement
+ {
+ struct expr *expr;
+ }
+:
+ SWITCH
+ '('
+ expression(&expr)
+ {
+ code_startswitch(&expr);
+#ifdef LINT
+ start_switch_part(expr);
+#endif LINT
+ }
+ ')'
+ statement
+ {
+#ifdef LINT
+ end_switch_stmt();
+#endif LINT
+ code_endswitch();
+ free_expression(expr);
+ }
+;
+
+case_statement
+ {
+ struct expr *expr;
+ }
+:
+ CASE
+ constant_expression(&expr)
+ {
+#ifdef LINT
+ lint_case_stmt(0);
+#endif LINT
+ code_case(expr);
+ free_expression(expr);
+ }
+ ':'
+ statement
+;
+
+default_statement
+:
+ DEFAULT
+ {
+#ifdef LINT
+ lint_case_stmt(1);
+#endif LINT
+ code_default();
+ }
+ ':'
+ statement
+;
+
+return_statement
+ { struct expr *expr = 0;
+ }
+:
+ RETURN
+ [
+ expression(&expr)
+ {
+#ifdef LINT
+ lint_ret_conv(expr);
+#endif LINT
+
+ do_return_expr(expr);
+ free_expression(expr);
+#ifdef LINT
+ lint_return_stmt(1);
+#endif LINT
+ }
+ |
+ empty
+ {
+ do_return();
+#ifdef LINT
+ lint_return_stmt(0);
+#endif LINT
+ }
+ ]
+ ';'
+;
+
+jump
+ { struct idf *idf;
+ }
+:
+ GOTO
+ identifier(&idf)
+ ';'
+ {
+ apply_label(idf);
+ C_bra((label)idf->id_def->df_address);
+#ifdef LINT
+ lint_jump_stmt(idf);
+#endif LINT
+ }
+;
+
+compound_statement:
+ '{'
+ {
+ stack_level();
+ }
+ [%while ((DOT != IDENTIFIER && AHEAD != ':') ||
+ (DOT == IDENTIFIER && AHEAD == IDENTIFIER))
+ /* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */
+ declaration
+ ]*
+ [%persistent
+ statement
+ ]*
+ '}'
+ {
+ unstack_level();
+ }
+;
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* library routine for copying structs */
+
+__stb(n, f, t)
+ register char *f, *t; register n;
+{
+ if (n > 0)
+ do
+ *t++ = *f++;
+ while (--n);
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* S T A T E M E N T - B L O C K D E F I N I T I O N S */
+
+struct stmt_block {
+ struct stmt_block *next;
+ label st_break;
+ label st_continue;
+};
+
+/* ALLOCDEF "stmt_block" 5 */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* ADMINISTRATION OF STRUCT AND UNION DECLARATIONS */
+
+#include "nobitfield.h"
+#include "debug.h"
+#include "botch_free.h"
+#include <alloc.h>
+#include "arith.h"
+#include "stack.h"
+#include "idf.h"
+#include "def.h"
+#include "type.h"
+#include "proto.h"
+#include "struct.h"
+#include "field.h"
+#include "LLlex.h"
+#include "Lpars.h"
+#include "align.h"
+#include "level.h"
+#include "assert.h"
+#include "sizes.h"
+#include "noRoption.h"
+
+/* Type of previous selector declared with a field width specified,
+ if any. If a selector is declared with no field with it is set to 0.
+*/
+static field_busy = 0;
+
+extern char options[];
+int lcm();
+
+/* The semantics of the identification of structure/union tags is
+ obscure. Some highly regarded compilers are found out to accept,
+ e.g.:
+ f(xp) struct aap *xp; {
+ struct aap {char *za;};
+ xp->za;
+ }
+ Equally highly regarded software uses this feature, so we shall
+ humbly oblige.
+ The rules we use are:
+ 1. A structure definition applies at the level where it is
+ found, unless there is a structure declaration without a
+ definition on an outer level, in which case the definition
+ is applied at that level.
+ 2. A selector is applied on the same level as on which its
+ structure is being defined.
+
+ If below struct is mentioned, union is implied (and sometimes enum
+ as well).
+*/
+
+add_sel(stp, tp, idf, sdefpp, szp, fd) /* this is horrible */
+ register struct type *stp; /* type of the structure */
+ struct type *tp; /* type of the selector */
+ register struct idf *idf; /* idf of the selector */
+ struct sdef ***sdefpp; /* address of hook to selector definition */
+ arith *szp; /* pointer to struct size upto here */
+ struct field *fd;
+{
+ /* The selector idf with type tp is added to two chains: the
+ selector identification chain starting at idf->id_sdef,
+ and to the end of the member list starting at stp->tp_sdef.
+ The address of the hook in the latest member (sdef) is
+ given in sdefpp; the hook itself must still be empty.
+ */
+ arith offset;
+#ifndef NOBITFIELD
+ extern arith add_field();
+#endif NOBITFIELD
+
+ struct tag *tg = stp->tp_idf->id_struct; /* or union */
+ struct sdef *sdef = idf->id_sdef;
+ register struct sdef *newsdef;
+ int lvl = tg->tg_level;
+
+#ifndef NOROPTION
+ if (options['R'] && !is_anon_idf(idf)) {
+ /* a K & R test */
+ if (idf->id_struct && idf->id_struct->tg_level == level)
+ warning("%s is also a struct/union tag", idf->id_text);
+ }
+#endif
+
+ if (stp->tp_fund == STRUCT) {
+#ifndef NOBITFIELD
+ if (fd == 0) { /* no field width specified */
+ offset = align(*szp, tp->tp_align);
+ field_busy = 0;
+ }
+ else {
+ /* if something is wrong, the type of the
+ specified selector remains unchanged; its
+ bitfield specifier, however, is thrown away.
+ */
+ offset = add_field(szp, fd, &tp, idf, stp);
+ }
+#else NOBITFIELD
+ offset = align(*szp, tp->tp_align);
+ field_busy = 0;
+#endif NOBITFIELD
+ }
+ else { /* (stp->tp_fund == UNION) */
+ if (fd) {
+ error("fields not allowed in unions");
+ free_field(fd);
+ fd = 0;
+ }
+ offset = (arith)0;
+ }
+
+ check_selector(idf, stp);
+#ifndef NOROPTION
+ if (options['R']) {
+ if ( sdef && sdef->sd_level == lvl &&
+ ( sdef->sd_offset != offset ||
+ !equal_type(sdef->sd_type, tp))
+ ) /* RM 8.5 */
+ warning("selector %s redeclared", idf->id_text);
+ }
+#endif
+
+ newsdef = new_sdef();
+ newsdef->sd_sdef = (struct sdef *) 0;
+
+ /* link into selector descriptor list of this id
+ */
+ newsdef->next = sdef;
+ idf->id_sdef = newsdef;
+
+ newsdef->sd_level = lvl;
+ newsdef->sd_idf = idf;
+ newsdef->sd_stype = stp;
+ newsdef->sd_type = tp;
+ newsdef->sd_offset = offset;
+
+#ifndef NOBITFIELD
+ if (tp->tp_fund == FIELD)
+ tp->tp_field->fd_sdef = newsdef;
+#endif NOBITFIELD
+
+ stack_idf(idf, stack_level_of(lvl));
+
+ /* link into selector definition list of the struct/union
+ */
+ **sdefpp = newsdef;
+ *sdefpp = &newsdef->sd_sdef;
+
+ /* update the size of the struct/union upward */
+ if (stp->tp_fund == STRUCT && fd == 0) {
+ /* Note: the case that a bitfield is declared is
+ handled by add_field() !
+ */
+ *szp = offset + size_of_type(tp, "member");
+ stp->tp_align = lcm(stp->tp_align, tp->tp_align);
+ }
+ else
+ if (stp->tp_fund == UNION) {
+ arith sel_size = size_of_type(tp, "member");
+
+ if (*szp < sel_size)
+ *szp = sel_size;
+ stp->tp_align = lcm(stp->tp_align, tp->tp_align);
+ }
+}
+
+check_selector(idf, stp)
+ register struct idf *idf;
+ struct type *stp; /* the type of the struct */
+{
+ /* checks if idf occurs already as a selector in
+ struct or union *stp.
+ */
+ register struct sdef *sdef = stp->tp_sdef;
+
+ while (sdef) {
+ if (sdef->sd_idf == idf)
+ error("multiple selector %s", idf->id_text);
+ sdef = sdef->sd_sdef;
+ }
+}
+
+declare_struct(fund, idf, tpp)
+ register struct idf *idf;
+ struct type **tpp;
+{
+ /* A struct, union or enum (depending on fund) with tag (!)
+ idf is declared, and its type (incomplete as it may be) is
+ returned in *tpp.
+ The idf may be missing (i.e. idf == 0), in which case an
+ anonymous struct etc. is defined.
+ */
+ extern char *symbol2str();
+ register struct tag **tgp;
+ register struct tag *tg;
+
+ if (!idf)
+ idf = gen_idf();
+ tgp = (fund == ENUM ? &idf->id_enum : &idf->id_struct);
+
+#ifndef NOROPTION
+ if (options['R'] && !is_anon_idf(idf)) {
+ /* a K & R test */
+ if ( fund != ENUM &&
+ idf->id_sdef && idf->id_sdef->sd_level == level
+ ) {
+ warning("%s is also a selector", idf->id_text);
+ }
+ if ( fund == ENUM &&
+ idf->id_def && idf->id_def->df_level == level
+ ) {
+ warning("%s is also a variable", idf->id_text);
+ }
+ }
+#endif
+
+ tg = *tgp;
+ if (tg && tg->tg_type->tp_size < 0 && tg->tg_type->tp_fund == fund) {
+ /* An unfinished declaration has preceded it, possibly on
+ an earlier level. We just fill in the answer.
+ */
+ if (tg->tg_busy) {
+ error("recursive declaration of struct/union %s",
+ idf->id_text);
+ declare_struct(fund, gen_idf(), tpp);
+ }
+ else {
+#ifndef NOROPTION
+ if (options['R'] && tg->tg_level != level)
+ warning("%s declares %s in different range",
+ idf->id_text, symbol2str(fund));
+#endif
+ *tpp = tg->tg_type;
+ }
+ }
+ else
+ if (tg && tg->tg_level == level) {
+ /* There is an already defined struct/union of this name
+ on our level!
+ */
+ error("redeclaration of struct/union %s", idf->id_text);
+ declare_struct(fund, gen_idf(), tpp);
+ /* to allow a second struct_declaration_pack */
+ }
+ else {
+ /* The struct is new. */
+ /* Hook in a new struct tag */
+ tg = new_tag();
+ tg->next = *tgp;
+ *tgp = tg;
+ tg->tg_level = level;
+ /* and supply room for a type */
+ tg->tg_type = create_type(fund);
+ tg->tg_type->tp_align =
+ fund == ENUM ? int_align :
+ fund == STRUCT ? struct_align :
+ /* fund == UNION */ union_align;
+ tg->tg_type->tp_idf = idf;
+ *tpp = tg->tg_type;
+ stack_idf(idf, local_level);
+ }
+}
+
+apply_struct(fund, idf, tpp)
+ register struct idf *idf;
+ struct type **tpp;
+{
+ /* The occurrence of a struct, union or enum (depending on
+ fund) with tag idf is noted. It may or may not have been
+ declared before. Its type (complete or incomplete) is
+ returned in *tpp.
+ */
+ register struct tag **tgp;
+
+ tgp = (is_struct_or_union(fund) ? &idf->id_struct : &idf->id_enum);
+
+ if (*tgp)
+ *tpp = (*tgp)->tg_type;
+ else
+ declare_struct(fund, idf, tpp);
+}
+
+struct sdef *
+idf2sdef(idf, tp)
+ register struct idf *idf;
+ struct type *tp;
+{
+ /* The identifier idf is identified as a selector, preferably
+ in the struct tp, but we will settle for any unique
+ identification.
+ If the attempt fails, a selector of type error_type is
+ created.
+ */
+ register struct sdef **sdefp = &idf->id_sdef, *sdef;
+
+ /* Follow chain from idf, to meet tp. */
+ while ((sdef = *sdefp)) {
+ if (equal_type(sdef->sd_stype, tp))
+ return sdef;
+ sdefp = &(*sdefp)->next;
+ }
+
+ /* Tp not met; any unique identification will do. */
+ if (sdef = idf->id_sdef) {
+ /* There is an identification */
+ if (uniq_selector(sdef)) {
+ /* and it is unique, so we accept */
+ warning("selector %s applied to alien type",
+ idf->id_text);
+ }
+ else {
+ /* it is ambiguous */
+ error("ambiguous use of selector %s", idf->id_text);
+ }
+ return sdef;
+ }
+
+ /* No luck; create an error entry. */
+ if (!is_anon_idf(idf))
+ error("unknown selector %s", idf->id_text);
+ *sdefp = sdef = new_sdef();
+ sdef->sd_idf = idf;
+ sdef->sd_stype = sdef->sd_type = error_type;
+ return sdef;
+}
+
+int
+uniq_selector(idf_sdef)
+ register struct sdef *idf_sdef;
+{
+ /* Returns true if idf_sdef (which is guaranteed to exist)
+ is unique for this level, i.e there is no other selector
+ on this level with the same name or the other selectors
+ with the same name have the same offset.
+ See /usr/src/cmd/sed/sed.h for an example of this absurd
+ case!
+ */
+
+ register struct sdef *sdef = idf_sdef->next;
+
+ while (sdef && sdef->sd_level == idf_sdef->sd_level) {
+ if ( sdef->sd_type != idf_sdef->sd_type
+ || sdef->sd_offset != idf_sdef->sd_offset
+ ) {
+ return 0; /* ambiguity found */
+ }
+ sdef = sdef->next;
+ }
+ return 1;
+}
+
+#ifndef NOBITFIELD
+arith
+add_field(szp, fd, fdtpp, idf, stp)
+ arith *szp; /* size of struct upto here */
+ register struct field *fd; /* bitfield, containing width */
+ register struct type **fdtpp; /* type of selector */
+ struct idf *idf; /* name of selector */
+ register struct type *stp; /* current struct descriptor */
+{
+ /* The address where this selector is put is returned. If the
+ selector with specified width does not fit in the word, or
+ an explicit alignment is given, a new address is needed.
+ Note that the fields are packed into machine words (according
+ to the RM.)
+ */
+ long bits_in_type = word_size * 8;
+ static int field_offset = (arith)0;
+ static struct type *current_struct = 0;
+ static long bits_declared; /* nr of bits used in *field_offset */
+
+ if (current_struct != stp) {
+ /* This struct differs from the last one
+ */
+ field_busy = 0;
+ current_struct = stp;
+ }
+
+ if ( fd->fd_width < 0 ||
+ (fd->fd_width == 0 && !is_anon_idf(idf)) ||
+ fd->fd_width > bits_in_type
+ ) {
+ error("illegal field-width specified");
+ *fdtpp = error_type;
+ return field_offset;
+ }
+
+ switch ((*fdtpp)->tp_fund) {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case ENUM:
+ case LONG:
+ /* right type; size OK? */
+ if ((*fdtpp)->tp_size > word_size) {
+ error("bit field type %s does not fit in a word",
+ symbol2str((*fdtpp)->tp_fund));
+ *fdtpp = error_type;
+ return field_offset;
+ }
+ break;
+
+ default:
+ /* wrong type altogether */
+ error("field type cannot be %s",
+ symbol2str((*fdtpp)->tp_fund));
+ *fdtpp = error_type;
+ return field_offset;
+ }
+
+ if (field_busy == 0) {
+ /* align this selector on the next boundary :
+ the previous selector wasn't a bitfield.
+ */
+ field_offset = align(*szp, int_align);
+ *szp = field_offset + int_size;
+ stp->tp_align = lcm(stp->tp_align, int_align);
+ bits_declared = (arith)0;
+ field_busy = 1;
+ }
+
+ if (fd->fd_width > bits_in_type - bits_declared) {
+ /* field overflow: fetch next memory unit
+ */
+ field_offset = align(*szp, int_align);
+ *szp = field_offset + int_size;
+ stp->tp_align = lcm(stp->tp_align, int_align);
+ bits_declared = fd->fd_width;
+ }
+ else
+ if (fd->fd_width == 0)
+ /* next field should be aligned on the next boundary.
+ This will take care that no field will fit in the
+ space allocated upto here.
+ */
+ bits_declared = bits_in_type + 1;
+ else /* the bitfield fits in the current field */
+ bits_declared += fd->fd_width;
+
+ /* Arrived here, the place where the selector is stored in the
+ struct is computed.
+ Now we need a mask to use its value in expressions.
+ */
+ *fdtpp = construct_type(FIELD, *fdtpp, 0, (arith)0, NO_PROTO);
+ (*fdtpp)->tp_field = fd;
+
+ /* Set the mask right shifted. This solution avoids the
+ problem of having sign extension when using the mask for
+ extracting the value from the field-int.
+ Sign extension could occur on some machines when shifting
+ the mask to the left.
+ */
+ fd->fd_mask = (1 << fd->fd_width) - 1;
+
+ if (options['r']) /* adjust the field at the right */
+ fd->fd_shift = bits_declared - fd->fd_width;
+ else /* adjust the field at the left */
+ fd->fd_shift = bits_in_type - bits_declared;
+
+ return field_offset;
+}
+#endif NOBITFIELD
+
+/* some utilities */
+int
+is_struct_or_union(fund)
+ register int fund;
+{
+ return fund == STRUCT || fund == UNION;
+}
+
+/* Greatest Common Divisor
+ */
+int
+gcd(m, n)
+ register int m, n;
+{
+ register int r;
+
+ while (n) {
+ r = m % n;
+ m = n;
+ n = r;
+ }
+ return m;
+}
+
+/* Least Common Multiple
+ */
+int
+lcm(m, n)
+ register int m, n;
+{
+ return m * (n / gcd(m, n));
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* SELECTOR DESCRIPTOR */
+
+struct sdef { /* for selectors */
+ struct sdef *next;
+ int sd_level;
+ struct idf *sd_idf; /* its name */
+ struct sdef *sd_sdef; /* the next selector */
+ struct type *sd_stype; /* the struct it belongs to */
+ struct type *sd_type; /* its type */
+ arith sd_offset;
+};
+
+/* ALLOCDEF "sdef" 50 */
+
+struct tag { /* for struct-, union- and enum tags */
+ struct tag *next;
+ int tg_level;
+ int tg_busy; /* non-zero during declaration of struct/union pack */
+ struct type *tg_type;
+};
+
+
+/* ALLOCDEF "tag" 50 */
+
+struct sdef *idf2sdef();
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* S W I T C H - S T A T E M E N T A D M I N I S T R A T I O N */
+
+#include "nofloat.h"
+#include <em.h>
+#include "debug.h"
+#include "botch_free.h"
+#include <alloc.h>
+#include "density.h"
+#include "Lpars.h"
+#include "idf.h"
+#include "label.h"
+#include "arith.h"
+#include "switch.h"
+#include "code.h"
+#include "assert.h"
+#include "expr.h"
+#include "type.h"
+#include "noRoption.h"
+
+extern char options[];
+
+compact(nr, low, up)
+ arith low, up;
+{
+ /* Careful! up - low might not fit in an arith. And then,
+ the test "up-low < 0" might also not work to detect this
+ situation! Or is this just a bug in the M68020/M68000?
+ */
+ arith diff = up - low;
+
+ return (nr == 0 || (diff >= 0 && diff / nr <= (DENSITY - 1)));
+}
+
+static struct switch_hdr *switch_stack = 0;
+
+/* (EB 86.05.20) The following rules hold for switch statements:
+ - the expression E in "switch(E)" is cast to 'int' (RM 9.7)
+ - the expression E in "case E:" must be 'int' (RM 9.7)
+ - the values in the CSA/CSB tables are words (EM 7.4)
+ For simplicity, we suppose int_size == word_size.
+*/
+
+code_startswitch(expp)
+ struct expr **expp;
+{
+ /* Check the expression, stack a new case header and
+ fill in the necessary fields.
+ */
+ register label l_table = text_label();
+ register label l_break = text_label();
+ register struct switch_hdr *sh = new_switch_hdr();
+ int fund = any2arith(expp, SWITCH); /* INT, LONG or DOUBLE */
+
+ switch (fund) {
+ case LONG:
+#ifndef NOROPTION
+ if (options['R'])
+ warning("long in switch (cast to int)");
+#endif
+ int2int(expp, int_type);
+ break;
+#ifndef NOFLOAT
+ case DOUBLE:
+ error("float/double in switch");
+ erroneous2int(expp);
+ break;
+#endif NOFLOAT
+ }
+ stack_stmt(l_break, NO_LABEL);
+ sh->sh_break = l_break;
+ sh->sh_default = 0;
+ sh->sh_table = l_table;
+ sh->sh_nrofentries = 0;
+ sh->sh_type = (*expp)->ex_type; /* the expression switched */
+ sh->sh_lowerbd = sh->sh_upperbd = (arith)0; /* immaterial ??? */
+ sh->sh_entries = (struct case_entry *) 0; /* case-entry list */
+ sh->sh_expr = *expp;
+ sh->next = switch_stack; /* push onto switch-stack */
+ switch_stack = sh;
+ C_bra(l_table); /* goto start of switch_table */
+}
+
+code_endswitch()
+{
+ register struct switch_hdr *sh = switch_stack;
+ register label tablabel;
+ register struct case_entry *ce;
+
+ if (sh->sh_default == 0) /* no default occurred yet */
+ sh->sh_default = sh->sh_break;
+ C_bra(sh->sh_break); /* skip the switch table now */
+ C_df_ilb(sh->sh_table); /* switch table entry */
+ /* evaluate the switch expr. */
+ code_expr(sh->sh_expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
+ tablabel = data_label(); /* the rom must have a label */
+ C_df_dlb(tablabel);
+ C_rom_ilb(sh->sh_default);
+ if (compact(sh->sh_nrofentries, sh->sh_lowerbd, sh->sh_upperbd)) {
+ /* CSA */
+ register arith val;
+
+ C_rom_cst(sh->sh_lowerbd);
+ C_rom_cst(sh->sh_upperbd - sh->sh_lowerbd);
+ ce = sh->sh_entries;
+ if (sh->sh_nrofentries)
+ for (val = sh->sh_lowerbd; val <= sh->sh_upperbd; val++) {
+ ASSERT(ce);
+ if (val == ce->ce_value) {
+ C_rom_ilb(ce->ce_label);
+ ce = ce->next;
+ }
+ else
+ C_rom_ilb(sh->sh_default);
+ }
+ C_lae_dlb(tablabel, (arith)0); /* perform the switch */
+ C_csa(sh->sh_type->tp_size);
+ }
+ else { /* CSB */
+ C_rom_cst((arith)sh->sh_nrofentries);
+ for (ce = sh->sh_entries; ce; ce = ce->next) {
+ /* generate the entries: value + prog.label */
+ C_rom_cst(ce->ce_value);
+ C_rom_ilb(ce->ce_label);
+ }
+ C_lae_dlb(tablabel, (arith)0); /* perform the switch */
+ C_csb(sh->sh_type->tp_size);
+ }
+ C_df_ilb(sh->sh_break);
+ switch_stack = sh->next; /* unstack the switch descriptor */
+ for (ce = sh->sh_entries; ce;) { /* free allocated switch structure */
+ register struct case_entry *tmp = ce->next;
+
+ free_case_entry(ce);
+ ce = tmp;
+ }
+ free_switch_hdr(sh);
+ unstack_stmt();
+}
+
+code_case(expr)
+ struct expr *expr;
+{
+ register arith val;
+ register struct case_entry *ce;
+ register struct switch_hdr *sh = switch_stack;
+
+ ASSERT(is_cp_cst(expr));
+ if (sh == 0) {
+ error("case statement not in switch");
+ return;
+ }
+ if (expr->ex_flags & EX_ERROR) /* is probably 0 anyway */
+ return;
+ ch7cast(&expr, CASE, sh->sh_type);
+ ce = new_case_entry();
+ C_df_ilb(ce->ce_label = text_label());
+ ce->ce_value = val = expr->VL_VALUE;
+ if (sh->sh_entries == 0) { /* first case entry */
+ ce->next = (struct case_entry *) 0;
+ sh->sh_entries = ce;
+ sh->sh_lowerbd = sh->sh_upperbd = val;
+ sh->sh_nrofentries = 1;
+ }
+ else { /* second etc. case entry; put ce into proper place */
+ register struct case_entry *c1 = sh->sh_entries, *c2 = 0;
+
+ if (val < sh->sh_lowerbd)
+ sh->sh_lowerbd = val;
+ else
+ if (val > sh->sh_upperbd)
+ sh->sh_upperbd = val;
+ while (c1 && c1->ce_value < ce->ce_value) {
+ c2 = c1;
+ c1 = c1->next;
+ }
+ /* At this point three cases are possible:
+ 1: c1 != 0 && c2 != 0: insert ce somewhere in the middle
+ 2: c1 != 0 && c2 == 0: insert ce right after the head
+ 3: c1 == 0 && c2 != 0: append ce to last element
+ The case c1 == 0 && c2 == 0 cannot occur, since
+ the list is guaranteed to be non-empty.
+ */
+ if (c1) {
+ if (c1->ce_value == ce->ce_value) {
+ error("multiple case entry for value %ld",
+ ce->ce_value);
+ free_case_entry(ce);
+ return;
+ }
+ if (c2) {
+ ce->next = c2->next;
+ c2->next = ce;
+ }
+ else {
+ ce->next = sh->sh_entries;
+ sh->sh_entries = ce;
+ }
+ }
+ else {
+ ASSERT(c2);
+ ce->next = (struct case_entry *) 0;
+ c2->next = ce;
+ }
+ (sh->sh_nrofentries)++;
+ }
+}
+
+code_default()
+{
+ register struct switch_hdr *sh = switch_stack;
+
+ if (sh == 0) {
+ error("default statement not in switch");
+ return;
+ }
+ if (sh->sh_default != 0) {
+ error("multiple entry for default in switch");
+ return;
+ }
+
+ C_df_ilb(sh->sh_default = text_label());
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* S W I T C H - T A B L E - S T R U C T U R E */
+
+struct switch_hdr {
+ struct switch_hdr *next;
+ label sh_break;
+ label sh_default;
+ label sh_table;
+ int sh_nrofentries;
+ struct type *sh_type;
+ struct expr *sh_expr;
+ arith sh_lowerbd;
+ arith sh_upperbd;
+ struct case_entry *sh_entries;
+};
+
+/* ALLOCDEF "switch_hdr" 2 */
+
+struct case_entry {
+ struct case_entry *next;
+ label ce_label;
+ arith ce_value;
+};
+
+/* ALLOCDEF "case_entry" 20 */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* TOKEN NAME DEFINITIONS */
+
+#include "idf.h"
+#include "arith.h"
+#include "LLlex.h"
+#include "tokenname.h"
+#include "Lpars.h"
+
+/* To centralize the declaration of %tokens, their presence in this
+ file is taken as their declaration. The Makefile will produce
+ a grammar file (tokenfile.g) from this file.
+ Moreover, rather than looking up a symbol in all these lists
+ to find its printable name, a fast version of symbol2str() is
+ generated from these tables.
+ Consequenty some of these tables are not referenced explicitly
+ in the C text any more. To save space and to avoid lint confusion,
+ these have been made pseudo-invisible by #ifdefs.
+*/
+
+#ifdef ____
+struct tokenname tkspec[] = { /* the names of the special tokens */
+ {IDENTIFIER, "identifier"},
+ {TYPE_IDENTIFIER, "type_identifier"},
+ {STRING, "string"},
+ {WCHAR, "wchar"},
+ {FILESPECIFIER, "filespecifier"},
+ {INTEGER, "integer"},
+ {FLOATING, "floating"},
+ {0, ""}
+};
+#endif ____
+
+#ifdef ____
+struct tokenname tkcomp[] = { /* names of the composite tokens */
+ {NOTEQUAL, "!="},
+ {AND, "&&"},
+ {PLUSPLUS, "++"},
+ {MINMIN, "--"},
+ {ARROW, "->"},
+ {LEFT, "<<"},
+ {LESSEQ, "<="},
+ {EQUAL, "=="},
+ {GREATEREQ, ">="},
+ {RIGHT, ">>"},
+ {OR, "||"},
+ {ELLIPSIS, "..."},
+ {0, ""}
+};
+#endif ____
+
+struct tokenname tkidf[] = { /* names of the identifier tokens */
+ {AUTO, "auto"},
+ {BREAK, "break"},
+ {CASE, "case"},
+ {CONST, "const"},
+ {CONTINUE, "continue"},
+ {DEFAULT, "default"},
+ {DO, "do"},
+ {ELSE, "else"},
+ {ENUM, "enum"},
+ {EXTERN, "extern"},
+ {FOR, "for"},
+ {GOTO, "goto"},
+ {IF, "if"},
+ {LONG, "long"},
+ {REGISTER, "register"},
+ {RETURN, "return"},
+ {SHORT, "short"},
+ {SIGNED, "signed"},
+ {SIZEOF, "sizeof"},
+ {STATIC, "static"},
+ {STRUCT, "struct"},
+ {SWITCH, "switch"},
+ {TYPEDEF, "typedef"},
+ {UNION, "union"},
+ {UNSIGNED, "unsigned"},
+ {VOLATILE, "volatile"},
+ {WHILE, "while"},
+ {0, ""}
+};
+
+#ifdef ____
+struct tokenname tkfunny[] = { /* internal keywords */
+ {CHAR, "char"},
+ {INT, "int"},
+ {FLOAT, "float"},
+ {DOUBLE, "double"},
+ {LNGDBL, "long double"},
+ {ULONG, "unsigned long"},
+ {VOID, "void"},
+ {GENERIC, "generic"},
+
+ {ARRAY, "array"},
+ {FUNCTION, "function"},
+ {POINTER, "pointer"},
+ {FIELD, "field"},
+ {NEWLINE, "newline"},
+
+ {GLOBAL, "global"},
+ {IMPLICIT, "implicit"},
+ {FORMAL, "formal"},
+ {LABEL, "label"},
+ {ERRONEOUS, "erroneous"},
+
+ {PARCOMMA, "parcomma"},
+ {INITCOMMA, "initcomma"},
+ {CAST, "cast"},
+ {CASTAB, "castab"},
+ {POSTINCR, "postfix ++"},
+ {POSTDECR, "postfix --"},
+ {PLUSAB, "+="},
+ {MINAB, "-="},
+ {TIMESAB, "*="},
+ {DIVAB, "/="},
+ {MODAB, "%="},
+ {LEFTAB, "<<="},
+ {RIGHTAB, ">>="},
+ {ANDAB, "&="},
+ {XORAB, "^="},
+ {ORAB, "|="},
+
+ {INT2INT, "int2int"},
+ {INT2FLOAT, "int2float"},
+ {FLOAT2INT, "float2int"},
+ {FLOAT2FLOAT, "float2float"},
+ {0, ""}
+};
+#endif ____
+
+reserve(resv)
+ register struct tokenname resv[];
+{
+ /* The names of the tokens described in resv are entered
+ as reserved words.
+ */
+ while (resv->tn_symbol) {
+ struct idf *idf = str2idf(resv->tn_name);
+
+ if (idf->id_reserved)
+ fatal("maximum identifier length insufficient");
+ idf->id_reserved = resv->tn_symbol;
+ resv++;
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* TOKENNAME DEFINITION */
+
+struct tokenname { /* Used for defining the name of a
+ token as identified by its symbol
+ */
+ int tn_symbol;
+ char *tn_name;
+};
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* T Y P E D E F I N I T I O N M E C H A N I S M */
+
+#include "nofloat.h"
+#include "nobitfield.h"
+#include "botch_free.h"
+#include <alloc.h>
+#include "Lpars.h"
+#include "arith.h"
+#include "type.h"
+#include "idf.h"
+#include "def.h"
+#include "proto.h"
+#include "sizes.h"
+#include "align.h"
+#include "decspecs.h"
+
+extern struct type *function_of(), *array_of();
+#ifndef NOBITFIELD
+extern struct type *field_of();
+#endif NOBITFIELD
+
+/* To be created dynamically in main() from defaults or from command
+ line parameters.
+*/
+struct type
+ *char_type, *uchar_type,
+ *short_type, *ushort_type,
+ *word_type, *uword_type,
+ *int_type, *uint_type,
+ *long_type, *ulong_type,
+#ifndef NOFLOAT
+ *float_type, *double_type, *lngdbl_type,
+#endif NOFLOAT
+ *void_type, *gen_type, *label_type,
+ *string_type, *funint_type, *error_type;
+
+struct type *pa_type; /* Pointer-Arithmetic type */
+
+struct type *
+create_type(fund)
+ int fund;
+{
+ /* A brand new struct type is created, and its tp_fund set
+ to fund.
+ */
+ register struct type *ntp = new_type();
+
+ ntp->tp_fund = fund;
+ ntp->tp_size = (arith)-1;
+
+ return ntp;
+}
+
+struct type *
+construct_type(fund, tp, qual, count, pl)
+ register struct type *tp;
+ register struct proto *pl;
+ arith count; /* for fund == ARRAY only */
+ int qual;
+{
+ /* fund must be a type constructor: FIELD, FUNCTION, POINTER or
+ ARRAY. The pointer to the constructed type is returned.
+ */
+ register struct type *dtp;
+
+ switch (fund) {
+#ifndef NOBITFIELD
+ case FIELD:
+ dtp = field_of(tp, qual);
+ break;
+#endif NOBITFIELD
+
+ case FUNCTION:
+ if (tp->tp_fund == FUNCTION) {
+ error("function cannot yield function");
+ return error_type;
+ }
+ if (tp->tp_fund == ARRAY) {
+ error("function cannot yield array");
+ return error_type;
+ }
+
+ dtp = function_of(tp, pl, qual);
+ break;
+ case POINTER:
+ if (tp->tp_fund == VOID) {
+ /* A void pointer has the same characteristics as a
+ character pointer. I can't make them equal, because
+ i would like to have the type information around */
+ tp = qualifier_type(gen_type, tp->tp_typequal);
+ }
+ dtp = pointer_to(tp, qual);
+ break;
+ case ARRAY:
+ if (count >= 0 && tp->tp_size < 0) {
+ error("cannot construct array of unknown type");
+ count = (arith)-1;
+ }
+ else if (tp->tp_size == 0) /* CJ */
+ warning("array elements have size 0");
+ if (count >= (arith)0)
+ count *= tp->tp_size;
+ dtp = array_of(tp, count, qual);
+ break;
+ default:
+ crash("bad constructor in construct_type");
+ /*NOTREACHED*/
+ }
+ return dtp;
+}
+
+struct type *
+function_of(tp, pl, qual)
+ register struct type *tp;
+ register struct proto *pl;
+ int qual;
+{
+ register struct type *dtp = tp->tp_function;
+
+ /* look for a type with the right qualifier */
+ while (dtp && (dtp->tp_typequal != qual || dtp->tp_proto != pl))
+ dtp = dtp->next;
+
+ if (!dtp) {
+ dtp = create_type(FUNCTION);
+ dtp->tp_up = tp;
+ dtp->tp_size = pointer_size;
+ dtp->tp_align = pointer_align;
+ dtp->tp_typequal = qual;
+ dtp->tp_proto = pl;
+ dtp->next = tp->tp_function;
+ tp->tp_function = dtp;
+ }
+ return dtp;
+}
+
+struct type *
+pointer_to(tp, qual)
+ register struct type *tp;
+ int qual;
+{
+ register struct type *dtp = tp->tp_pointer;
+
+ /* look for a type with the right qualifier */
+ while (dtp && dtp->tp_typequal != qual)
+ dtp = dtp->next;
+
+ if (!dtp) {
+ dtp = create_type(POINTER);
+ dtp->tp_unsigned = 1;
+ dtp->tp_up = tp;
+ dtp->tp_size = pointer_size;
+ dtp->tp_align = pointer_align;
+ dtp->tp_typequal = qual;
+ dtp->next = tp->tp_pointer;
+ tp->tp_pointer = dtp;
+ }
+ return dtp;
+}
+
+struct type *
+array_of(tp, count, qual)
+ register struct type *tp;
+ arith count;
+ int qual;
+{
+ register struct type *dtp = tp->tp_array;
+
+ /* look for a type with the right size */
+ while (dtp && (dtp->tp_size != count || dtp->tp_typequal != qual))
+ dtp = dtp->next;
+
+ if (!dtp) {
+ dtp = create_type(ARRAY);
+ dtp->tp_up = tp;
+ dtp->tp_size = count;
+ dtp->tp_align = tp->tp_align;
+ dtp->tp_typequal = qual;
+ dtp->next = tp->tp_array;
+ tp->tp_array = dtp;
+ }
+ return dtp;
+}
+
+#ifndef NOBITFIELD
+struct type *
+field_of(tp, qual)
+ register struct type *tp;
+ int qual;
+{
+ register struct type *dtp = create_type(FIELD);
+
+ dtp->tp_up = tp;
+ dtp->tp_align = tp->tp_align;
+ dtp->tp_size = tp->tp_size;
+ dtp->tp_typequal = qual;
+ return dtp;
+}
+#endif NOBITFIELD
+
+arith
+size_of_type(tp, nm)
+ struct type *tp;
+ char nm[];
+{
+ arith sz = tp->tp_size;
+
+ if (sz < 0) {
+ error("size of %s unknown", nm);
+ return (arith)1;
+ }
+ return sz;
+}
+
+idf2type(idf, tpp)
+ struct idf *idf;
+ struct type **tpp;
+{
+ /* Decoding a typedef-ed identifier: if the size is yet
+ unknown we have to make copy of the type descriptor to
+ prevent garbage at the initialisation of arrays with
+ unknown size.
+ */
+ register struct type *tp = idf->id_def->df_type;
+
+ if ( tp->tp_size < (arith)0 && tp->tp_fund == ARRAY) {
+ *tpp = new_type();
+ **tpp = *tp;
+ /* this is really a structure assignment, AAGH!!! */
+ }
+ else {
+ *tpp = tp;
+ }
+}
+
+arith
+align(pos, al)
+ arith pos;
+ int al;
+{
+ return ((pos + al - 1) / al) * al;
+}
+
+struct type *
+standard_type(fund, sgn, algn, sz)
+ int algn; arith sz;
+{
+ register struct type *tp = create_type(fund);
+
+ tp->tp_unsigned = sgn;
+ tp->tp_align = algn;
+ tp->tp_size = sz;
+
+ return tp;
+}
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+/* TYPE DESCRIPTOR */
+
+#include "nofloat.h"
+#include "nobitfield.h"
+
+struct type {
+ struct type *next; /* used only with ARRAY */
+ short tp_fund; /* fundamental type */
+ char tp_unsigned;
+ int tp_align;
+ int tp_typequal; /* type qualifier */
+ arith tp_size; /* -1 if declared but not defined */
+ struct idf *tp_idf; /* name of STRUCT, UNION or ENUM */
+ struct sdef *tp_sdef; /* to first selector */
+ struct type *tp_up; /* from FIELD, POINTER, ARRAY
+ or FUNCTION to fund. */
+ struct field *tp_field; /* field descriptor if fund == FIELD */
+ struct type *tp_pointer;/* to POINTER */
+ struct type *tp_array; /* to ARRAY */
+ struct proto *tp_proto; /* prototype list */
+ struct type *tp_function;/* to FUNCTION */
+};
+
+
+/* Type qualifiers. Note: TQ_VOLATILE and TQ_CONST can be
+ 'ored' to specify: extern const volatile int a;
+*/
+#define TQ_VOLATILE 01
+#define TQ_CONST 02
+
+extern struct type
+ *create_type(), *standard_type(), *construct_type(), *pointer_to(),
+ *array_of(), *function_of();
+
+#ifndef NOBITFIELD
+extern struct type *field_of();
+#endif NOBITFIELD
+
+extern struct type
+ *char_type, *uchar_type,
+ *short_type, *ushort_type,
+ *word_type, *uword_type,
+ *int_type, *uint_type,
+ *long_type, *ulong_type,
+#ifndef NOFLOAT
+ *float_type, *double_type, *lngdbl_type,
+#endif NOFLOAT
+ *void_type, *gen_type, *label_type,
+ *string_type, *funint_type, *error_type;
+
+extern struct type *pa_type; /* type.c */
+
+extern arith size_of_type(), align();
+
+/* ALLOCDEF "type" 20 */
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+
+/* M I S C E L L A N E O U S U T I L I T I E S */
+
+/* $Header$ */
+
+/* Code for the allocation and de-allocation of temporary variables,
+ allowing re-use.
+*/
+
+#include <em.h>
+#include <em_reg.h>
+#include <alloc.h>
+#include <em_mes.h>
+
+#include "lint.h"
+#include "util.h"
+#include "use_tmp.h"
+#include "regcount.h"
+#include "sizes.h"
+#include "align.h"
+#include "stack.h"
+#include "Lpars.h"
+#include "def.h"
+
+static struct localvar *FreeTmps;
+#ifdef USE_TMP
+static int loc_id;
+#endif USE_TMP
+
+#ifdef PEEPHOLE
+#undef REGCOUNT
+#define REGCOUNT 1
+#endif
+
+extern char options[];
+
+LocalInit()
+{
+#ifdef USE_TMP
+ C_insertpart(loc_id = C_getid());
+#endif USE_TMP
+}
+
+arith
+LocalSpace(sz, al)
+ arith sz;
+{
+ register struct stack_level *stl = local_level;
+
+ stl->sl_max_block = - align(sz - stl->sl_max_block, al);
+ return stl->sl_max_block;
+}
+
+#define TABSIZ 32
+static struct localvar *regs[TABSIZ];
+
+arith
+NewLocal(sz, al, regtype, sc)
+ arith sz;
+{
+ register struct localvar *tmp = FreeTmps;
+ struct localvar *prev = 0;
+ register int index;
+
+ while (tmp) {
+ if (tmp->t_align >= al &&
+ tmp->t_size >= sz &&
+ tmp->t_sc == sc &&
+ tmp->t_regtype == regtype) {
+ if (prev) {
+ prev->next = tmp->next;
+ }
+ else FreeTmps = tmp->next;
+ break;
+ }
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ if (! tmp) {
+ tmp = new_localvar();
+ tmp->t_offset = LocalSpace(sz, al);
+ tmp->t_align = al;
+ tmp->t_size = sz;
+ tmp->t_sc = sc;
+ tmp->t_regtype = regtype;
+ tmp->t_count = REG_DEFAULT;
+ }
+ index = (int) (tmp->t_offset >> 2) & (TABSIZ - 1);
+ tmp->next = regs[index];
+ regs[index] = tmp;
+ return tmp->t_offset;
+}
+
+FreeLocal(off)
+ arith off;
+{
+ int index = (int) (off >> 2) & (TABSIZ - 1);
+ register struct localvar *tmp = regs[index];
+ struct localvar *prev = 0;
+
+ while (tmp && tmp->t_offset != off) {
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ if (tmp) {
+ if (prev) prev->next = tmp->next;
+ else regs[index] = tmp->next;
+ tmp->next = FreeTmps;
+ FreeTmps = tmp;
+ }
+}
+
+LocalFinish()
+{
+ register struct localvar *tmp, *tmp1;
+ register int i;
+
+#ifdef USE_TMP
+ C_beginpart(loc_id);
+#endif
+ tmp = FreeTmps;
+ while (tmp) {
+ tmp1 = tmp;
+ if (tmp->t_sc == REGISTER) tmp->t_count += REG_BONUS;
+ if (! options['n'] && tmp->t_regtype >= 0) {
+ C_ms_reg(tmp->t_offset, tmp->t_size, tmp->t_regtype, tmp->t_count);
+ }
+ tmp = tmp->next;
+ free_localvar(tmp1);
+ }
+ FreeTmps = 0;
+ for (i = 0; i < TABSIZ; i++) {
+ tmp = regs[i];
+ while (tmp) {
+ if (tmp->t_sc == REGISTER) tmp->t_count += REG_BONUS;
+ tmp1 = tmp;
+ if (! options['n'] && tmp->t_regtype >= 0) {
+ C_ms_reg(tmp->t_offset,
+ tmp->t_size,
+ tmp->t_regtype,
+ tmp->t_count);
+ }
+ tmp = tmp->next;
+ free_localvar(tmp1);
+ }
+ regs[i] = 0;
+ }
+ if (! options['n']) {
+ C_mes_begin(ms_reg);
+ C_mes_end();
+ }
+#ifdef USE_TMP
+ C_endpart(loc_id);
+#endif
+}
+
+RegisterAccount(offset, size, regtype, sc)
+ arith offset, size;
+{
+ register struct localvar *p;
+ int index;
+
+ if (regtype < 0) return;
+
+ p = new_localvar();
+ index = (int) (offset >> 2) & (TABSIZ - 1);
+ p->t_offset = offset;
+ p->t_regtype = regtype;
+ p->t_count = REG_DEFAULT;
+ p->t_sc = sc;
+ p->t_size = size;
+ p->next = regs[index];
+ regs[index] = p;
+}
+
+static struct localvar *
+find_reg(off)
+ arith off;
+{
+ register struct localvar *p = regs[(int)(off >> 2) & (TABSIZ - 1)];
+
+ while (p && p->t_offset != off) p = p->next;
+ return p;
+}
+
+LoadLocal(off, sz)
+ arith off, sz;
+{
+ register struct localvar *p = find_reg(off);
+
+#ifdef USE_TMP
+#ifdef REGCOUNT
+ if (p) p->t_count++;
+#endif
+#endif
+ if (sz == word_size) C_lol(off);
+ else if (sz == dword_size) C_ldl(off);
+ else {
+ if (p) p->t_regtype = -1;
+ C_lal(off);
+ C_loi(sz);
+ }
+}
+
+StoreLocal(off, sz)
+ arith off, sz;
+{
+ register struct localvar *p = find_reg(off);
+
+#ifdef USE_TMP
+#ifdef REGCOUNT
+ if (p) p->t_count++;
+#endif
+#endif
+ if (sz == word_size) C_stl(off);
+ else if (sz == dword_size) C_sdl(off);
+ else {
+ if (p) p->t_regtype = -1;
+ C_lal(off);
+ C_sti(sz);
+ }
+}
+
+#ifndef LINT
+AddrLocal(off)
+ arith off;
+{
+ register struct localvar *p = find_reg(off);
+
+ if (p) p->t_regtype = -1;
+ C_lal(off);
+}
+#endif LINT
--- /dev/null
+struct localvar {
+ struct localvar *next;
+ arith t_offset; /* offset from LocalBase */
+ arith t_size;
+ int t_align;
+ int t_regtype;
+ int t_count;
+ int t_sc; /* storage class */
+};
+
+/* ALLOCDEF "localvar" 10 */