From: ceriel Date: Tue, 7 Feb 1989 11:04:05 +0000 (+0000) Subject: Initial revision X-Git-Tag: release-5-5~2620 X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=926da49d391f4aade3caff54a310a1f519d88ad3;p=ack.git Initial revision --- diff --git a/lang/cem/cemcom.ansi/.distr b/lang/cem/cemcom.ansi/.distr new file mode 100644 index 000000000..b5565509f --- /dev/null +++ b/lang/cem/cemcom.ansi/.distr @@ -0,0 +1,101 @@ +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 diff --git a/lang/cem/cemcom.ansi/BigPars b/lang/cem/cemcom.ansi/BigPars new file mode 100644 index 000000000..08aaa58b3 --- /dev/null +++ b/lang/cem/cemcom.ansi/BigPars @@ -0,0 +1,145 @@ +!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 */ + + diff --git a/lang/cem/cemcom.ansi/LLlex.c b/lang/cem/cemcom.ansi/LLlex.c new file mode 100644 index 000000000..592bf0475 --- /dev/null +++ b/lang/cem/cemcom.ansi/LLlex.c @@ -0,0 +1,777 @@ +/* + * (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 +#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 + .. 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('?'); +} diff --git a/lang/cem/cemcom.ansi/LLlex.h b/lang/cem/cemcom.ansi/LLlex.h new file mode 100644 index 000000000..fb1318ce1 --- /dev/null +++ b/lang/cem/cemcom.ansi/LLlex.h @@ -0,0 +1,69 @@ +/* + * (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) diff --git a/lang/cem/cemcom.ansi/LLmessage.c b/lang/cem/cemcom.ansi/LLmessage.c new file mode 100644 index 000000000..23005c910 --- /dev/null +++ b/lang/cem/cemcom.ansi/LLmessage.c @@ -0,0 +1,59 @@ +/* + * (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 +#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 + } +} diff --git a/lang/cem/cemcom.ansi/LintPars b/lang/cem/cemcom.ansi/LintPars new file mode 100644 index 000000000..37266f8d3 --- /dev/null +++ b/lang/cem/cemcom.ansi/LintPars @@ -0,0 +1,145 @@ +!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 */ + + diff --git a/lang/cem/cemcom.ansi/Makefile b/lang/cem/cemcom.ansi/Makefile new file mode 100644 index 000000000..5c131d135 --- /dev/null +++ b/lang/cem/cemcom.ansi/Makefile @@ -0,0 +1,1091 @@ +# $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 + tokenfile.g + +symbol2str.c: 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 diff --git a/lang/cem/cemcom.ansi/Makefile.erik b/lang/cem/cemcom.ansi/Makefile.erik new file mode 100644 index 000000000..195e07fca --- /dev/null +++ b/lang/cem/cemcom.ansi/Makefile.erik @@ -0,0 +1,718 @@ +# $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 + tokenfile.g + +symbol2str.c: 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 diff --git a/lang/cem/cemcom.ansi/Resolve b/lang/cem/cemcom.ansi/Resolve new file mode 100755 index 000000000..5e1558107 --- /dev/null +++ b/lang/cem/cemcom.ansi/Resolve @@ -0,0 +1,67 @@ +: 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 < $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 diff --git a/lang/cem/cemcom.ansi/SmallPars b/lang/cem/cemcom.ansi/SmallPars new file mode 100644 index 000000000..fb0bf2a5d --- /dev/null +++ b/lang/cem/cemcom.ansi/SmallPars @@ -0,0 +1,145 @@ +!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 */ + + diff --git a/lang/cem/cemcom.ansi/Version.c b/lang/cem/cemcom.ansi/Version.c new file mode 100644 index 000000000..c10d537ea --- /dev/null +++ b/lang/cem/cemcom.ansi/Version.c @@ -0,0 +1,8 @@ +/* $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 diff --git a/lang/cem/cemcom.ansi/align.h b/lang/cem/cemcom.ansi/align.h new file mode 100644 index 000000000..470c1414c --- /dev/null +++ b/lang/cem/cemcom.ansi/align.h @@ -0,0 +1,35 @@ +/* + * (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(); diff --git a/lang/cem/cemcom.ansi/arith.c b/lang/cem/cemcom.ansi/arith.c new file mode 100644 index 000000000..470aa203e --- /dev/null +++ b/lang/cem/cemcom.ansi/arith.c @@ -0,0 +1,575 @@ +/* + * (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 +#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) /* 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 diff --git a/lang/cem/cemcom.ansi/arith.h b/lang/cem/cemcom.ansi/arith.h new file mode 100644 index 000000000..5ffea6c57 --- /dev/null +++ b/lang/cem/cemcom.ansi/arith.h @@ -0,0 +1,28 @@ +/* + * (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 /* obtain definition of "arith" */ + +#else SPECIAL_ARITHMETICS + +/* All preprocessor arithmetic should be done in longs. +*/ +#define arith long /* dummy */ + +#endif SPECIAL_ARITHMETICS diff --git a/lang/cem/cemcom.ansi/asm.c b/lang/cem/cemcom.ansi/asm.c new file mode 100644 index 000000000..4900ea909 --- /dev/null +++ b/lang/cem/cemcom.ansi/asm.c @@ -0,0 +1,16 @@ +/* + * (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"); +} diff --git a/lang/cem/cemcom.ansi/assert.h b/lang/cem/cemcom.ansi/assert.h new file mode 100644 index 000000000..8e3bc2e7d --- /dev/null +++ b/lang/cem/cemcom.ansi/assert.h @@ -0,0 +1,24 @@ +/* + * (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 diff --git a/lang/cem/cemcom.ansi/atw.h b/lang/cem/cemcom.ansi/atw.h new file mode 100644 index 000000000..ed2b2dcf4 --- /dev/null +++ b/lang/cem/cemcom.ansi/atw.h @@ -0,0 +1,10 @@ +/* + * (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) diff --git a/lang/cem/cemcom.ansi/blocks.c b/lang/cem/cemcom.ansi/blocks.c new file mode 100644 index 000000000..1684995d4 --- /dev/null +++ b/lang/cem/cemcom.ansi/blocks.c @@ -0,0 +1,168 @@ +/* + * (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 +#include +#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) + + 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 + diff --git a/lang/cem/cemcom.ansi/cem.1 b/lang/cem/cemcom.ansi/cem.1 new file mode 100644 index 000000000..ea79f3aa6 --- /dev/null +++ b/lang/cem/cemcom.ansi/cem.1 @@ -0,0 +1,230 @@ +.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 diff --git a/lang/cem/cemcom.ansi/cem.c b/lang/cem/cemcom.ansi/cem.c new file mode 100644 index 000000000..220953018 --- /dev/null +++ b/lang/cem/cemcom.ansi/cem.c @@ -0,0 +1,764 @@ +/* + * (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 +#include +#include +#include +#include + +#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; +} diff --git a/lang/cem/cemcom.ansi/cemcom.1 b/lang/cem/cemcom.ansi/cemcom.1 new file mode 100644 index 000000000..03e9d4aac --- /dev/null +++ b/lang/cem/cemcom.ansi/cemcom.1 @@ -0,0 +1,79 @@ +.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 diff --git a/lang/cem/cemcom.ansi/ch7.c b/lang/cem/cemcom.ansi/ch7.c new file mode 100644 index 000000000..cc664ff77 --- /dev/null +++ b/lang/cem/cemcom.ansi/ch7.c @@ -0,0 +1,540 @@ +/* + * (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; + } +} diff --git a/lang/cem/cemcom.ansi/ch7bin.c b/lang/cem/cemcom.ansi/ch7bin.c new file mode 100644 index 000000000..e43f1592a --- /dev/null +++ b/lang/cem/cemcom.ansi/ch7bin.c @@ -0,0 +1,350 @@ +/* + * (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 +#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); +} diff --git a/lang/cem/cemcom.ansi/ch7mon.c b/lang/cem/cemcom.ansi/ch7mon.c new file mode 100644 index 000000000..9e1be20d6 --- /dev/null +++ b/lang/cem/cemcom.ansi/ch7mon.c @@ -0,0 +1,166 @@ +/* + * (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 +#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; + + /* & indicates that + 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; + } +} diff --git a/lang/cem/cemcom.ansi/char.tab b/lang/cem/cemcom.ansi/char.tab new file mode 100644 index 000000000..682d10abb --- /dev/null +++ b/lang/cem/cemcom.ansi/char.tab @@ -0,0 +1,74 @@ +% +% 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}; diff --git a/lang/cem/cemcom.ansi/class.h b/lang/cem/cemcom.ansi/class.h new file mode 100644 index 000000000..d57ce26d3 --- /dev/null +++ b/lang/cem/cemcom.ansi/class.h @@ -0,0 +1,44 @@ +/* + * (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[]; diff --git a/lang/cem/cemcom.ansi/code.c b/lang/cem/cemcom.ansi/code.c new file mode 100644 index 000000000..5717399c8 --- /dev/null +++ b/lang/cem/cemcom.ansi/code.c @@ -0,0 +1,657 @@ +/* + * (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 +#include "botch_free.h" +#include +#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 + 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); + } +} diff --git a/lang/cem/cemcom.ansi/code.str b/lang/cem/cemcom.ansi/code.str new file mode 100644 index 000000000..6fa088c95 --- /dev/null +++ b/lang/cem/cemcom.ansi/code.str @@ -0,0 +1,22 @@ +/* + * (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 diff --git a/lang/cem/cemcom.ansi/conversion.c b/lang/cem/cemcom.ansi/conversion.c new file mode 100644 index 000000000..536d887e9 --- /dev/null +++ b/lang/cem/cemcom.ansi/conversion.c @@ -0,0 +1,158 @@ +/* + * (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 +#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 + diff --git a/lang/cem/cemcom.ansi/cstoper.c b/lang/cem/cemcom.ansi/cstoper.c new file mode 100644 index 000000000..d613edb14 --- /dev/null +++ b/lang/cem/cemcom.ansi/cstoper.c @@ -0,0 +1,237 @@ +/* + * (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]; +} diff --git a/lang/cem/cemcom.ansi/dataflow.c b/lang/cem/cemcom.ansi/dataflow.c new file mode 100644 index 000000000..0056121de --- /dev/null +++ b/lang/cem/cemcom.ansi/dataflow.c @@ -0,0 +1,37 @@ +/* + * (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 diff --git a/lang/cem/cemcom.ansi/declar.g b/lang/cem/cemcom.ansi/declar.g new file mode 100644 index 000000000..9af9c957a --- /dev/null +++ b/lang/cem/cemcom.ansi/declar.g @@ -0,0 +1,696 @@ +/* + * (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 +#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 */ diff --git a/lang/cem/cemcom.ansi/declar.str b/lang/cem/cemcom.ansi/declar.str new file mode 100644 index 000000000..640fc3ad7 --- /dev/null +++ b/lang/cem/cemcom.ansi/declar.str @@ -0,0 +1,44 @@ +/* + * (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; diff --git a/lang/cem/cemcom.ansi/declarator.c b/lang/cem/cemcom.ansi/declarator.c new file mode 100644 index 000000000..d8992357a --- /dev/null +++ b/lang/cem/cemcom.ansi/declarator.c @@ -0,0 +1,126 @@ +/* + * (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 +#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; + } +} diff --git a/lang/cem/cemcom.ansi/decspecs.c b/lang/cem/cemcom.ansi/decspecs.c new file mode 100644 index 000000000..c01b66154 --- /dev/null +++ b/lang/cem/cemcom.ansi/decspecs.c @@ -0,0 +1,197 @@ +/* + * (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); +} + diff --git a/lang/cem/cemcom.ansi/decspecs.str b/lang/cem/cemcom.ansi/decspecs.str new file mode 100644 index 000000000..59bc24fd3 --- /dev/null +++ b/lang/cem/cemcom.ansi/decspecs.str @@ -0,0 +1,20 @@ +/* + * (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; diff --git a/lang/cem/cemcom.ansi/def.str b/lang/cem/cemcom.ansi/def.str new file mode 100644 index 000000000..8d719f2c8 --- /dev/null +++ b/lang/cem/cemcom.ansi/def.str @@ -0,0 +1,40 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/domacro.c b/lang/cem/cemcom.ansi/domacro.c new file mode 100644 index 000000000..33be29399 --- /dev/null +++ b/lang/cem/cemcom.ansi/domacro.c @@ -0,0 +1,688 @@ +/* + * (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 +#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: /* # []? */ + 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); +} diff --git a/lang/cem/cemcom.ansi/dumpidf.c b/lang/cem/cemcom.ansi/dumpidf.c new file mode 100644 index 000000000..cd11ff4ce --- /dev/null +++ b/lang/cem/cemcom.ansi/dumpidf.c @@ -0,0 +1,512 @@ +/* + * (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" : "", + 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(""); + 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, ""); + 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 diff --git a/lang/cem/cemcom.ansi/error.c b/lang/cem/cemcom.ansi/error.c new file mode 100644 index 000000000..89517f422 --- /dev/null +++ b/lang/cem/cemcom.ansi/error.c @@ -0,0 +1,355 @@ +/* + * (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 +#include +#include + +#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"); +} diff --git a/lang/cem/cemcom.ansi/estack.str b/lang/cem/cemcom.ansi/estack.str new file mode 100644 index 000000000..b71bdb304 --- /dev/null +++ b/lang/cem/cemcom.ansi/estack.str @@ -0,0 +1,21 @@ +/* + * (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 diff --git a/lang/cem/cemcom.ansi/eval.c b/lang/cem/cemcom.ansi/eval.c new file mode 100644 index 000000000..a34cb77b0 --- /dev/null +++ b/lang/cem/cemcom.ansi/eval.c @@ -0,0 +1,994 @@ +/* + * (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 +#include +#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 + diff --git a/lang/cem/cemcom.ansi/expr.c b/lang/cem/cemcom.ansi/expr.c new file mode 100644 index 000000000..3e26e168b --- /dev/null +++ b/lang/cem/cemcom.ansi/expr.c @@ -0,0 +1,536 @@ +/* + * (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 +#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 + +/- or . + */ +#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); + } +} diff --git a/lang/cem/cemcom.ansi/expr.str b/lang/cem/cemcom.ansi/expr.str new file mode 100644 index 000000000..16648e072 --- /dev/null +++ b/lang/cem/cemcom.ansi/expr.str @@ -0,0 +1,116 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom.ansi/expression.g b/lang/cem/cemcom.ansi/expression.g new file mode 100644 index 000000000..e341ed667 --- /dev/null +++ b/lang/cem/cemcom.ansi/expression.g @@ -0,0 +1,375 @@ +/* + * (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 +#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; + } +; diff --git a/lang/cem/cemcom.ansi/field.c b/lang/cem/cemcom.ansi/field.c new file mode 100644 index 000000000..3b944310b --- /dev/null +++ b/lang/cem/cemcom.ansi/field.c @@ -0,0 +1,181 @@ +/* + * (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 +#include +#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)<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)<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 + diff --git a/lang/cem/cemcom.ansi/field.str b/lang/cem/cemcom.ansi/field.str new file mode 100644 index 000000000..520c9abc6 --- /dev/null +++ b/lang/cem/cemcom.ansi/field.str @@ -0,0 +1,16 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/file_info.h b/lang/cem/cemcom.ansi/file_info.h new file mode 100644 index 000000000..ef2892b4a --- /dev/null +++ b/lang/cem/cemcom.ansi/file_info.h @@ -0,0 +1,20 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/idf.c b/lang/cem/cemcom.ansi/idf.c new file mode 100644 index 000000000..49537a869 --- /dev/null +++ b/lang/cem/cemcom.ansi/idf.c @@ -0,0 +1,736 @@ +/* + * (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 +#include "nofloat.h" +#include "debug.h" +#include "idfsize.h" +#include "botch_free.h" +#include "nopp.h" +#include "nparams.h" +#include +#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; + } +} diff --git a/lang/cem/cemcom.ansi/idf.str b/lang/cem/cemcom.ansi/idf.str new file mode 100644 index 000000000..f6f110651 --- /dev/null +++ b/lang/cem/cemcom.ansi/idf.str @@ -0,0 +1,52 @@ +/* + * (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(); diff --git a/lang/cem/cemcom.ansi/init.c b/lang/cem/cemcom.ansi/init.c new file mode 100644 index 000000000..2e77ca154 --- /dev/null +++ b/lang/cem/cemcom.ansi/init.c @@ -0,0 +1,95 @@ +/* + * (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 +#include +#include +#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 diff --git a/lang/cem/cemcom.ansi/input.c b/lang/cem/cemcom.ansi/input.c new file mode 100644 index 000000000..dcabc8517 --- /dev/null +++ b/lang/cem/cemcom.ansi/input.c @@ -0,0 +1,64 @@ +/* + * (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 + +#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; +} diff --git a/lang/cem/cemcom.ansi/input.h b/lang/cem/cemcom.ansi/input.h new file mode 100644 index 000000000..43e11d4fb --- /dev/null +++ b/lang/cem/cemcom.ansi/input.h @@ -0,0 +1,15 @@ +/* + * (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 + +/* 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 */ diff --git a/lang/cem/cemcom.ansi/interface.h b/lang/cem/cemcom.ansi/interface.h new file mode 100644 index 000000000..e75dd7749 --- /dev/null +++ b/lang/cem/cemcom.ansi/interface.h @@ -0,0 +1,8 @@ +/* $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 diff --git a/lang/cem/cemcom.ansi/ival.g b/lang/cem/cemcom.ansi/ival.g new file mode 100644 index 000000000..b385db245 --- /dev/null +++ b/lang/cem/cemcom.ansi/ival.g @@ -0,0 +1,700 @@ +/* + * (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 +#include "debug.h" +#include +#include +#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; +} +} diff --git a/lang/cem/cemcom.ansi/l_brace.str b/lang/cem/cemcom.ansi/l_brace.str new file mode 100644 index 000000000..2e7b71da3 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_brace.str @@ -0,0 +1,28 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom.ansi/l_class.h b/lang/cem/cemcom.ansi/l_class.h new file mode 100644 index 000000000..2a77e546f --- /dev/null +++ b/lang/cem/cemcom.ansi/l_class.h @@ -0,0 +1,21 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom.ansi/l_comment.c b/lang/cem/cemcom.ansi/l_comment.c new file mode 100644 index 000000000..a2a74afc4 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_comment.c @@ -0,0 +1,211 @@ +/* + * (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 + +#include "lint.h" + +#ifdef LINT + +#include +#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 diff --git a/lang/cem/cemcom.ansi/l_comment.h b/lang/cem/cemcom.ansi/l_comment.h new file mode 100644 index 000000000..9340b0820 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_comment.h @@ -0,0 +1,15 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom.ansi/l_dummy.c b/lang/cem/cemcom.ansi/l_dummy.c new file mode 100644 index 000000000..f0633a615 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_dummy.c @@ -0,0 +1,74 @@ +/* + * (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 diff --git a/lang/cem/cemcom.ansi/l_ev_ord.c b/lang/cem/cemcom.ansi/l_ev_ord.c new file mode 100644 index 000000000..c0cfe4c49 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_ev_ord.c @@ -0,0 +1,107 @@ +/* + * (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 /* 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 diff --git a/lang/cem/cemcom.ansi/l_lint.c b/lang/cem/cemcom.ansi/l_lint.c new file mode 100644 index 000000000..b591e11f3 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_lint.c @@ -0,0 +1,442 @@ +/* + * (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 /* 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 diff --git a/lang/cem/cemcom.ansi/l_lint.h b/lang/cem/cemcom.ansi/l_lint.h new file mode 100644 index 000000000..0bdffde22 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_lint.h @@ -0,0 +1,18 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom.ansi/l_misc.c b/lang/cem/cemcom.ansi/l_misc.c new file mode 100644 index 000000000..1384c5fd9 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_misc.c @@ -0,0 +1,395 @@ +/* + * (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 /* 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; + } + + /* 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; + } + } + } + + /* 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 diff --git a/lang/cem/cemcom.ansi/l_outdef.c b/lang/cem/cemcom.ansi/l_outdef.c new file mode 100644 index 000000000..ef31a1a89 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_outdef.c @@ -0,0 +1,546 @@ +/* + * (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 +#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 diff --git a/lang/cem/cemcom.ansi/l_outdef.str b/lang/cem/cemcom.ansi/l_outdef.str new file mode 100644 index 000000000..541fbcd68 --- /dev/null +++ b/lang/cem/cemcom.ansi/l_outdef.str @@ -0,0 +1,47 @@ +/* + * (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; +}; diff --git a/lang/cem/cemcom.ansi/l_state.str b/lang/cem/cemcom.ansi/l_state.str new file mode 100644 index 000000000..2ef91912b --- /dev/null +++ b/lang/cem/cemcom.ansi/l_state.str @@ -0,0 +1,74 @@ +/* + * (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 */ + diff --git a/lang/cem/cemcom.ansi/l_states.c b/lang/cem/cemcom.ansi/l_states.c new file mode 100644 index 000000000..ad47b97fa --- /dev/null +++ b/lang/cem/cemcom.ansi/l_states.c @@ -0,0 +1,1131 @@ +/* + * (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 /* 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 diff --git a/lang/cem/cemcom.ansi/label.c b/lang/cem/cemcom.ansi/label.c new file mode 100644 index 000000000..984a43328 --- /dev/null +++ b/lang/cem/cemcom.ansi/label.c @@ -0,0 +1,74 @@ +/* + * (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); +} diff --git a/lang/cem/cemcom.ansi/label.h b/lang/cem/cemcom.ansi/label.h new file mode 100644 index 000000000..16e1bf720 --- /dev/null +++ b/lang/cem/cemcom.ansi/label.h @@ -0,0 +1,28 @@ +/* + * (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 /* 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. + */ diff --git a/lang/cem/cemcom.ansi/level.h b/lang/cem/cemcom.ansi/level.h new file mode 100644 index 000000000..9cf119e14 --- /dev/null +++ b/lang/cem/cemcom.ansi/level.h @@ -0,0 +1,23 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/macro.str b/lang/cem/cemcom.ansi/macro.str new file mode 100644 index 000000000..39476d6ed --- /dev/null +++ b/lang/cem/cemcom.ansi/macro.str @@ -0,0 +1,60 @@ +/* + * (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 diff --git a/lang/cem/cemcom.ansi/main.c b/lang/cem/cemcom.ansi/main.c new file mode 100644 index 000000000..9757ac000 --- /dev/null +++ b/lang/cem/cemcom.ansi/main.c @@ -0,0 +1,406 @@ +/* + * (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 +#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 +#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"); +} + diff --git a/lang/cem/cemcom.ansi/make.allocd b/lang/cem/cemcom.ansi/make.allocd new file mode 100755 index 000000000..08492fad1 --- /dev/null +++ b/lang/cem/cemcom.ansi/make.allocd @@ -0,0 +1,8 @@ +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))\ +:' diff --git a/lang/cem/cemcom.ansi/make.hfiles b/lang/cem/cemcom.ansi/make.hfiles new file mode 100755 index 000000000..2132dd618 --- /dev/null +++ b/lang/cem/cemcom.ansi/make.hfiles @@ -0,0 +1,35 @@ +: 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 diff --git a/lang/cem/cemcom.ansi/make.next b/lang/cem/cemcom.ansi/make.next new file mode 100755 index 000000000..be69d8d69 --- /dev/null +++ b/lang/cem/cemcom.ansi/make.next @@ -0,0 +1,3 @@ +sed -n ' +s:^.*ALLOCDEF.*"\(.*\)".*$:struct \1 *h_\1 = 0;:p +' $* diff --git a/lang/cem/cemcom.ansi/make.tokcase b/lang/cem/cemcom.ansi/make.tokcase new file mode 100755 index 000000000..90205c691 --- /dev/null +++ b/lang/cem/cemcom.ansi/make.tokcase @@ -0,0 +1,38 @@ +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-- diff --git a/lang/cem/cemcom.ansi/make.tokfile b/lang/cem/cemcom.ansi/make.tokfile new file mode 100755 index 000000000..74a7c44d9 --- /dev/null +++ b/lang/cem/cemcom.ansi/make.tokfile @@ -0,0 +1,11 @@ +cat <<'--EOT--' +/* Generated by make.tokfile */ +/* $Header: */ +--EOT-- + +sed ' +/{[A-Z]/!d +s/.*{// +s/,.*// +s/.*/%token &;/ +' diff --git a/lang/cem/cemcom.ansi/mcomm.c b/lang/cem/cemcom.ansi/mcomm.c new file mode 100644 index 000000000..c811685c4 --- /dev/null +++ b/lang/cem/cemcom.ansi/mcomm.c @@ -0,0 +1,246 @@ +/* $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 + +#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 +#include + +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); + } +} diff --git a/lang/cem/cemcom.ansi/mes.h b/lang/cem/cemcom.ansi/mes.h new file mode 100644 index 000000000..49b856b3a --- /dev/null +++ b/lang/cem/cemcom.ansi/mes.h @@ -0,0 +1,8 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/nmclash.c b/lang/cem/cemcom.ansi/nmclash.c new file mode 100644 index 000000000..e820442de --- /dev/null +++ b/lang/cem/cemcom.ansi/nmclash.c @@ -0,0 +1,9 @@ +/* + * (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() { } diff --git a/lang/cem/cemcom.ansi/options b/lang/cem/cemcom.ansi/options new file mode 100644 index 000000000..0dce7fa7a --- /dev/null +++ b/lang/cem/cemcom.ansi/options @@ -0,0 +1,28 @@ +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 diff --git a/lang/cem/cemcom.ansi/options.c b/lang/cem/cemcom.ansi/options.c new file mode 100644 index 000000000..c96cef6d7 --- /dev/null +++ b/lang/cem/cemcom.ansi/options.c @@ -0,0 +1,356 @@ +/* + * (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 +#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 # */ +#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; +} diff --git a/lang/cem/cemcom.ansi/pragma.c b/lang/cem/cemcom.ansi/pragma.c new file mode 100644 index 000000000..83edebb17 --- /dev/null +++ b/lang/cem/cemcom.ansi/pragma.c @@ -0,0 +1,74 @@ +/* + * (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 +#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 diff --git a/lang/cem/cemcom.ansi/program.g b/lang/cem/cemcom.ansi/program.g new file mode 100644 index 000000000..658af3943 --- /dev/null +++ b/lang/cem/cemcom.ansi/program.g @@ -0,0 +1,222 @@ +/* + * (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 + } +; diff --git a/lang/cem/cemcom.ansi/proto.c b/lang/cem/cemcom.ansi/proto.c new file mode 100644 index 000000000..a99bf3ba3 --- /dev/null +++ b/lang/cem/cemcom.ansi/proto.c @@ -0,0 +1,442 @@ +/* + * (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 +#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"); + } +} + diff --git a/lang/cem/cemcom.ansi/proto.str b/lang/cem/cemcom.ansi/proto.str new file mode 100644 index 000000000..614a5c914 --- /dev/null +++ b/lang/cem/cemcom.ansi/proto.str @@ -0,0 +1,17 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/replace.c b/lang/cem/cemcom.ansi/replace.c new file mode 100644 index 000000000..f907db765 --- /dev/null +++ b/lang/cem/cemcom.ansi/replace.c @@ -0,0 +1,677 @@ +/* + * (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 +#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 diff --git a/lang/cem/cemcom.ansi/replace.str b/lang/cem/cemcom.ansi/replace.str new file mode 100644 index 000000000..f4eccaea8 --- /dev/null +++ b/lang/cem/cemcom.ansi/replace.str @@ -0,0 +1,39 @@ +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 + diff --git a/lang/cem/cemcom.ansi/scan.c b/lang/cem/cemcom.ansi/scan.c new file mode 100644 index 000000000..6e89228ee --- /dev/null +++ b/lang/cem/cemcom.ansi/scan.c @@ -0,0 +1,237 @@ +/* + * (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 ( ) + */ + 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 diff --git a/lang/cem/cemcom.ansi/sizes.h b/lang/cem/cemcom.ansi/sizes.h new file mode 100644 index 000000000..7508a279e --- /dev/null +++ b/lang/cem/cemcom.ansi/sizes.h @@ -0,0 +1,33 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/skip.c b/lang/cem/cemcom.ansi/skip.c new file mode 100644 index 000000000..36ca38c48 --- /dev/null +++ b/lang/cem/cemcom.ansi/skip.c @@ -0,0 +1,69 @@ +/* + * (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; +} diff --git a/lang/cem/cemcom.ansi/specials.h b/lang/cem/cemcom.ansi/specials.h new file mode 100644 index 000000000..f086845bd --- /dev/null +++ b/lang/cem/cemcom.ansi/specials.h @@ -0,0 +1,18 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/stack.c b/lang/cem/cemcom.ansi/stack.c new file mode 100644 index 000000000..3be2dece2 --- /dev/null +++ b/lang/cem/cemcom.ansi/stack.c @@ -0,0 +1,279 @@ +/* + * (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 +#include +#include "debug.h" +#include "botch_free.h" +#include +#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 */ + +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); + } +} diff --git a/lang/cem/cemcom.ansi/stack.str b/lang/cem/cemcom.ansi/stack.str new file mode 100644 index 000000000..fc32c8726 --- /dev/null +++ b/lang/cem/cemcom.ansi/stack.str @@ -0,0 +1,34 @@ +/* + * (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; diff --git a/lang/cem/cemcom.ansi/statement.g b/lang/cem/cemcom.ansi/statement.g new file mode 100644 index 000000000..b10526066 --- /dev/null +++ b/lang/cem/cemcom.ansi/statement.g @@ -0,0 +1,472 @@ +/* + * (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 + +#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(); + } +; diff --git a/lang/cem/cemcom.ansi/stb.c b/lang/cem/cemcom.ansi/stb.c new file mode 100644 index 000000000..ca20cfd76 --- /dev/null +++ b/lang/cem/cemcom.ansi/stb.c @@ -0,0 +1,15 @@ +/* + * (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); +} diff --git a/lang/cem/cemcom.ansi/stmt.str b/lang/cem/cemcom.ansi/stmt.str new file mode 100644 index 000000000..a5f47680e --- /dev/null +++ b/lang/cem/cemcom.ansi/stmt.str @@ -0,0 +1,14 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/struct.c b/lang/cem/cemcom.ansi/struct.c new file mode 100644 index 000000000..ad0cc422e --- /dev/null +++ b/lang/cem/cemcom.ansi/struct.c @@ -0,0 +1,499 @@ +/* + * (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 +#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)); +} diff --git a/lang/cem/cemcom.ansi/struct.str b/lang/cem/cemcom.ansi/struct.str new file mode 100644 index 000000000..7a9c0e4ee --- /dev/null +++ b/lang/cem/cemcom.ansi/struct.str @@ -0,0 +1,30 @@ +/* + * (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(); diff --git a/lang/cem/cemcom.ansi/switch.c b/lang/cem/cemcom.ansi/switch.c new file mode 100644 index 000000000..859766ce0 --- /dev/null +++ b/lang/cem/cemcom.ansi/switch.c @@ -0,0 +1,227 @@ +/* + * (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 +#include "debug.h" +#include "botch_free.h" +#include +#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()); +} diff --git a/lang/cem/cemcom.ansi/switch.str b/lang/cem/cemcom.ansi/switch.str new file mode 100644 index 000000000..a8c118f2c --- /dev/null +++ b/lang/cem/cemcom.ansi/switch.str @@ -0,0 +1,29 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/tokenname.c b/lang/cem/cemcom.ansi/tokenname.c new file mode 100644 index 000000000..b7ea1a1bb --- /dev/null +++ b/lang/cem/cemcom.ansi/tokenname.c @@ -0,0 +1,149 @@ +/* + * (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++; + } +} diff --git a/lang/cem/cemcom.ansi/tokenname.h b/lang/cem/cemcom.ansi/tokenname.h new file mode 100644 index 000000000..bd883f1bc --- /dev/null +++ b/lang/cem/cemcom.ansi/tokenname.h @@ -0,0 +1,13 @@ +/* + * (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; +}; diff --git a/lang/cem/cemcom.ansi/type.c b/lang/cem/cemcom.ansi/type.c new file mode 100644 index 000000000..7d39783e5 --- /dev/null +++ b/lang/cem/cemcom.ansi/type.c @@ -0,0 +1,260 @@ +/* + * (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 +#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; +} diff --git a/lang/cem/cemcom.ansi/type.str b/lang/cem/cemcom.ansi/type.str new file mode 100644 index 000000000..b4379010f --- /dev/null +++ b/lang/cem/cemcom.ansi/type.str @@ -0,0 +1,60 @@ +/* + * (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 */ diff --git a/lang/cem/cemcom.ansi/util.c b/lang/cem/cemcom.ansi/util.c new file mode 100644 index 000000000..b51cf68d6 --- /dev/null +++ b/lang/cem/cemcom.ansi/util.c @@ -0,0 +1,237 @@ +/* + * (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 +#include +#include +#include + +#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 diff --git a/lang/cem/cemcom.ansi/util.str b/lang/cem/cemcom.ansi/util.str new file mode 100644 index 000000000..886432343 --- /dev/null +++ b/lang/cem/cemcom.ansi/util.str @@ -0,0 +1,11 @@ +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 */