Initial revision

This commit is contained in:
ceriel 1989-02-07 11:04:05 +00:00
parent e2fe3fec2c
commit 926da49d39
108 changed files with 22745 additions and 0 deletions

101
lang/cem/cemcom.ansi/.distr Normal file
View File

@ -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

View File

@ -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 */

View File

@ -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 <alloc.h>
#include "nofloat.h"
#include "idfsize.h"
#include "numsize.h"
#include "debug.h"
#include "strsize.h"
#include "nopp.h"
#include "input.h"
#include "arith.h"
#include "def.h"
#include "macro.h"
#include "idf.h"
#include "LLlex.h"
#include "Lpars.h"
#include "class.h"
#include "assert.h"
#include "sizes.h"
/* Data about the token yielded */
struct token dot, ahead, aside;
#ifndef NOPP
int ReplaceMacros = 1; /* replacing macros */
int AccDefined = 0; /* accept "defined(...)" */
int UnknownIdIsZero = 0; /* interpret unknown id as integer 0 */
int Unstacked = 0; /* an unstack is done */
#endif
int AccFileSpecifier = 0; /* return filespecifier <...> */
int EoiForNewline = 0; /* return EOI upon encountering newline */
int File_Inserted = 0; /* a file has just been inserted */
int LexSave = 0; /* last character read by GetChar */
#define MAX_LL_DEPTH 2
static struct token LexStack[MAX_LL_DEPTH];
static LexSP = 0;
/* In PushLex() the actions are taken in order to initialise or
re-initialise the lexical scanner.
E.g. at the invocation of a sub-parser that uses LLlex(), the
state of the current parser should be saved.
*/
PushLex()
{
ASSERT(LexSP < 2);
ASSERT(ASIDE == 0); /* ASIDE = 0; */
GetToken(&ahead);
LexStack[LexSP++] = dot;
}
PopLex()
{
ASSERT(LexSP > 0);
dot = LexStack[--LexSP];
}
int
LLlex()
{
/* LLlex() plays the role of Lexical Analyzer for the C parser.
The look-ahead and putting aside of tokens are taken into
account.
*/
if (ASIDE) { /* a token is put aside */
dot = aside;
ASIDE = 0;
}
else { /* read ahead and return the old one */
#ifdef LINT
lint_comment_ahead();
#endif LINT
dot = ahead;
/* the following test is performed due to the dual
task of LLlex(): it is also called for parsing the
restricted constant expression following a #if or
#elif. The newline character causes EOF to be
returned in this case to stop the LLgen parsing task.
*/
if (DOT != EOI)
GetToken(&ahead);
else
DOT = EOF;
}
return DOT;
}
char *string_token();
arith char_constant();
int
GetToken(ptok)
register struct token *ptok;
{
/* LexToken() is the actual token recognizer. It calls the
control line interpreter if it encounters a "\n{w}*#"
combination. Macro replacement is also performed if it is
needed.
*/
char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
register int ch, nch;
if (File_Inserted) {
File_Inserted = 0;
goto firstline;
}
again: /* rescan the input after an error or replacement */
ch = GetChar();
go_on: /* rescan, the following character has been read */
if ((ch & 0200) && ch != EOI) /* stop on non-ascii character */
fatal("non-ascii '\\%03o' read", ch & 0377);
/* keep track of the place of the token in the file */
ptok->tk_file = FileName;
ptok->tk_line = LineNumber;
switch (class(ch)) { /* detect character class */
case STNL: /* newline, vertical space or formfeed */
firstline:
LineNumber++; /* also at vs and ff */
ptok->tk_file = FileName;
ptok->tk_line = LineNumber;
if (EoiForNewline) /* called in control line */
/* a newline in a control line indicates the
end-of-information of the line.
*/
return ptok->tk_symb = EOI;
while ((ch = GetChar()), (ch == '#' || class(ch) == STSKIP)) {
/* blanks are allowed before hashes */
if (ch == '#') {
/* a control line follows */
domacro();
if (File_Inserted) {
File_Inserted = 0;
goto firstline;
}
}
}
/* We have to loop here, because in
`domacro' the nl, vt or ff is read. The
character following it may again be a `#'.
*/
goto go_on;
case STSKIP: /* just skip the skip characters */
goto again;
case STGARB: /* garbage character */
if (040 < ch && ch < 0177)
lexerror("garbage char %c", ch);
else
lexerror("garbage char \\%03o", ch);
goto again;
case STSIMP: /* a simple character, no part of compound token*/
if (ch == '/') { /* probably the start of comment */
ch = GetChar();
if (ch == '*') { /* start of comment */
skipcomment();
goto again;
}
else {
UnGetChar();
ch = '/'; /* restore ch */
}
}
return ptok->tk_symb = ch;
case STCOMP: /* maybe the start of a compound token */
nch = GetChar(); /* character lookahead */
switch (ch) {
case '!':
if (nch == '=')
return ptok->tk_symb = NOTEQUAL;
UnGetChar();
return ptok->tk_symb = ch;
case '&':
if (nch == '&')
return ptok->tk_symb = AND;
UnGetChar();
return ptok->tk_symb = ch;
case '+':
if (nch == '+')
return ptok->tk_symb = PLUSPLUS;
UnGetChar();
return ptok->tk_symb = ch;
case '-':
if (nch == '-')
return ptok->tk_symb = MINMIN;
if (nch == '>')
return ptok->tk_symb = ARROW;
UnGetChar();
return ptok->tk_symb = ch;
case '<':
if (AccFileSpecifier) {
UnGetChar(); /* pushback nch */
ptok->tk_bts = string_token("file specifier",
'>', &(ptok->tk_len));
return ptok->tk_symb = FILESPECIFIER;
}
if (nch == '<')
return ptok->tk_symb = LEFT;
if (nch == '=')
return ptok->tk_symb = LESSEQ;
UnGetChar();
return ptok->tk_symb = ch;
case '=':
if (nch == '=')
return ptok->tk_symb = EQUAL;
/* The following piece of code tries to recognise
old-fashioned assignment operators `=op'
Note however, that these are removed from the
ANSI C standard.
*/
switch (nch) {
case '+':
ptok->tk_symb = PLUSAB;
goto warn;
case '-':
ptok->tk_symb = MINAB;
goto warn;
case '*':
ptok->tk_symb = TIMESAB;
goto warn;
case '/':
ptok->tk_symb = DIVAB;
goto warn;
case '%':
ptok->tk_symb = MODAB;
goto warn;
case '>':
case '<':
GetChar(ch);
if (ch != nch) {
UnGetChar();
lexerror("illegal combination '=%c'",
nch);
}
ptok->tk_symb = nch == '<' ? LEFTAB : RIGHTAB;
goto warn;
case '&':
ptok->tk_symb = ANDAB;
goto warn;
case '^':
ptok->tk_symb = XORAB;
goto warn;
case '|':
ptok->tk_symb = ORAB;
warn:
warning("Old-fashioned assignment operator");
return ptok->tk_symb;
}
UnGetChar();
return ptok->tk_symb = ch;
case '>':
if (nch == '=')
return ptok->tk_symb = GREATEREQ;
if (nch == '>')
return ptok->tk_symb = RIGHT;
UnGetChar();
return ptok->tk_symb = ch;
case '|':
if (nch == '|')
return ptok->tk_symb = OR;
UnGetChar();
return ptok->tk_symb = ch;
}
case STCHAR: /* character constant */
ptok->tk_ival = char_constant("character");
ptok->tk_fund = INT;
return ptok->tk_symb = INTEGER;
case STSTR: /* string */
ptok->tk_bts = string_token("string", '"', &(ptok->tk_len));
ptok->tk_fund = CHAR; /* string of characters */
return ptok->tk_symb = STRING;
case STELL: /* wide character constant/string prefix */
nch = GetChar();
if (nch == '"') {
ptok->tk_bts = string_token("wide character string",
'"', &(ptok->tk_len));
ptok->tk_fund = WCHAR; /* string of wide characters */
return ptok->tk_symb = STRING;
} else if (nch == '\'') {
ptok->tk_ival = char_constant("wide character");
ptok->tk_fund = INT;
return ptok->tk_symb = INTEGER;
}
UnGetChar();
case STIDF:
{
register char *tg = &buf[0];
register int pos = -1;
register int hash;
register struct idf *idef;
extern int idfsize; /* ??? */
hash = STARTHASH();
do { /* read the identifier */
if (++pos < idfsize) {
*tg++ = ch;
hash = ENHASH(hash, ch, pos);
}
ch = GetChar();
} while (in_idf(ch));
hash = STOPHASH(hash);
if (ch != EOI)
UnGetChar();
*tg++ = '\0'; /* mark the end of the identifier */
idef = ptok->tk_idf = idf_hashed(buf, tg - buf, hash);
idef->id_file = ptok->tk_file;
idef->id_line = ptok->tk_line;
#ifndef NOPP
if (idef->id_macro && ReplaceMacros) {
if (idef->id_macro->mc_count > 0)
idef->id_macro->mc_count--;
else if (replace(idef))
goto again;
}
if (UnknownIdIsZero && idef->id_reserved != SIZEOF) {
ptok->tk_ival = (arith)0;
ptok->tk_fund = INT;
return ptok->tk_symb = INTEGER;
}
#endif NOPP
ptok->tk_symb = (
idef->id_reserved ? idef->id_reserved
: idef->id_def && idef->id_def->df_sc == TYPEDEF ?
TYPE_IDENTIFIER
: IDENTIFIER
);
return IDENTIFIER;
}
case STNUM: /* a numeric constant */
{
register char *np = &buf[1];
register int base = 10;
register int vch;
register arith val = 0;
if (ch == '.') {
#ifndef NOFLOAT
/* A very embarrasing ambiguity. We have either a
floating point number or field operator or
ELLIPSIS.
*/
ch = GetChar();
if (!is_dig(ch)) { /* . or ... */
if (ch == '.') {
if ((ch = GetChar()) == '.')
return ptok->tk_symb = ELLIPSIS;
/* This is funny: we can't push the
second dot back. But then again
..<ch> is already an error in C,
so why bother ?
*/
UnGetChar();
lexerror("illegal combination '..'");
}
UnGetChar();
return ptok->tk_symb = '.';
} else
*np++ = '0';
UnGetChar();
#else
if ((ch = GetChar()) == '.') {
if ((ch = GetChar()) == '.')
return ptok->tk_symb = ELLIPSIS;
UnGetChar();
lexerror("illegal combination '..'");
}
UnGetChar();
return ptok->tk_symb = '.';
#endif
}
if (ch == '0') {
*np++ = ch;
ch = GetChar();
if (ch == 'x' || ch == 'X') {
base = 16;
ch = GetChar();
}
else
base = 8;
}
while (vch = val_in_base(ch, base), vch >= 0) {
val = val*base + vch;
if (np < &buf[NUMSIZE])
*np++ = ch;
ch = GetChar();
}
if (is_suf(ch)) {
register int suf_long = 0;
register int suf_unsigned = 0;
/* The type of the integal constant is
based on its suffix.
*/
do {
switch (ch) {
case 'l':
case 'L':
suf_long++;
break;
case 'u':
case 'U':
suf_unsigned++;
break;
}
ch = GetChar();
} while (is_suf(ch));
UnGetChar();
if (suf_long > 1)
lexerror("only one long suffix allowed");
if (suf_unsigned > 1)
lexerror("only one unsigned suffix allowed");
ptok->tk_fund = (suf_long && suf_unsigned) ? ULONG :
(suf_long) ? LONG : UNSIGNED;
ptok->tk_ival = val;
return ptok->tk_symb = INTEGER;
}
#ifndef NOFLOAT
if (base == 16 || !(ch == '.' || ch == 'e' || ch == 'E'))
#endif NOFLOAT
{
UnGetChar();
ptok->tk_ival = val;
/* The semantic analyser must know if the
integral constant is given in octal/hexa-
decimal form, in which case its type is
UNSIGNED, or in decimal form, in which case
its type is signed, indicated by
the fund INTEGER.
*/
ptok->tk_fund =
(base == 10 || (base == 8 && val == (arith)0))
? INTEGER : UNSIGNED;
return ptok->tk_symb = INTEGER;
}
/* where's the test for the length of the integral ??? */
#ifndef NOFLOAT
if (ch == '.'){
if (np < &buf[NUMSIZE])
*np++ = ch;
ch = GetChar();
}
while (is_dig(ch)){
if (np < &buf[NUMSIZE])
*np++ = ch;
ch = GetChar();
}
if (ch == 'e' || ch == 'E') {
if (np < &buf[NUMSIZE])
*np++ = ch;
ch = GetChar();
if (ch == '+' || ch == '-') {
if (np < &buf[NUMSIZE])
*np++ = ch;
ch = GetChar();
}
if (!is_dig(ch)) {
lexerror("malformed floating constant");
if (np < &buf[NUMSIZE])
*np++ = ch;
}
while (is_dig(ch)) {
if (np < &buf[NUMSIZE])
*np++ = ch;
ch = GetChar();
}
}
/* The type of an integral floating point
constant may be given by the float (f)
or long double (l) suffix.
*/
if (ch == 'f' || ch == 'F')
ptok->tk_fund = FLOAT;
else if (ch == 'l' || ch == 'L')
ptok->tk_fund = LNGDBL;
else {
ptok->tk_fund = DOUBLE;
UnGetChar();
}
*np++ = '\0';
buf[0] = '-'; /* good heavens... */
if (np == &buf[NUMSIZE+1]) {
lexerror("floating constant too long");
ptok->tk_fval = Salloc("0.0",(unsigned) 5) + 1;
}
else
ptok->tk_fval = Salloc(buf,(unsigned) (np - buf)) + 1;
return ptok->tk_symb = FLOATING;
#endif NOFLOAT
}
case STEOI: /* end of text on source file */
return ptok->tk_symb = EOI;
default: /* this cannot happen */
crash("bad class for char 0%o", ch);
}
/*NOTREACHED*/
}
skipcomment()
{
/* The last character read has been the '*' of '/_*'. The
characters, except NL and EOI, between '/_*' and the first
occurring '*_/' are not interpreted.
NL only affects the LineNumber. EOI is not legal.
Important note: it is not possible to stop skipping comment
beyond the end-of-file of an included file.
EOI is returned by LoadChar only on encountering EOF of the
top-level file...
*/
register int c;
NoUnstack++;
c = GetChar();
#ifdef LINT
lint_start_comment();
lint_comment_char(c);
#endif LINT
do {
while (c != '*') {
if (class(c) == STNL) {
++LineNumber;
} else
if (c == EOI) {
NoUnstack--;
#ifdef LINT
lint_end_comment();
#endif LINT
return;
}
if (c == '/' && (c = GetChar()) == '*')
strict("extra comment delimiter found");
c = GetChar();
#ifdef LINT
lint_comment_char(c);
#endif LINT
} /* last Character seen was '*' */
c = GetChar();
#ifdef LINT
lint_comment_char(c);
#endif LINT
} while (c != '/');
#ifdef LINT
lint_end_comment();
#endif LINT
NoUnstack--;
}
arith
char_constant(nm)
char *nm;
{
register arith val = 0;
register int ch;
int size = 0;
ch = GetChar();
if (ch == '\'')
lexerror("%s constant too short", nm);
else
while (ch != '\'') {
if (ch == '\n') {
lexerror("newline in %s constant", nm);
LineNumber++;
break;
}
if (ch == '\\')
ch = quoted(GetChar());
if (ch >= 128) ch -= 256;
val = val*256 + ch;
size++;
ch = GetChar();
}
if (size > 1)
strict("%s constant includes more than one character", nm);
if (size > (int)int_size)
lexerror("%s constant too long", nm);
return val;
}
char *
string_token(nm, stop_char, plen)
char *nm;
int *plen;
{
register int ch;
register int str_size;
register char *str = Malloc((unsigned) (str_size = ISTRSIZE));
register int pos = 0;
ch = GetChar();
while (ch != stop_char) {
if (ch == '\n') {
lexerror("newline in %s", nm);
LineNumber++;
break;
}
if (ch == EOI) {
lexerror("end-of-file inside %s", nm);
break;
}
if (ch == '\\')
ch = quoted(GetChar());
str[pos++] = ch;
if (pos == str_size)
str = Srealloc(str, (unsigned) (str_size += RSTRSIZE));
ch = GetChar();
}
str[pos++] = '\0'; /* for filenames etc. */
*plen = pos;
return str;
}
int
quoted(ch)
register int ch;
{
/* quoted() replaces an escaped character sequence by the
character meant.
*/
/* first char after backslash already in ch */
if (!is_oct(ch)) { /* a quoted char */
switch (ch) {
case 'n':
ch = '\n';
break;
case 't':
ch = '\t';
break;
case 'b':
ch = '\b';
break;
case 'r':
ch = '\r';
break;
case 'f':
ch = '\f';
break;
case 'a': /* alert */
ch = '\007';
break;
case 'v': /* vertical tab */
ch = '\013';
break;
case 'x': /* quoted hex */
{
register int hex = 0;
register int vch;
for (;;) {
ch = GetChar();
if (vch = val_in_base(ch, 16), vch == -1)
break;
hex = hex * 16 + vch;
}
UnGetChar();
ch = hex;
}
}
}
else { /* a quoted octal */
register int oct = 0, cnt = 0;
do {
oct = oct*8 + (ch-'0');
ch = GetChar();
} while (is_oct(ch) && ++cnt < 3);
UnGetChar();
ch = oct;
}
return ch&0377;
}
int
val_in_base(ch, base)
register int ch;
{
switch (base) {
case 8:
return (is_dig(ch) && ch < '9') ? ch - '0' : -1;
case 10:
case 16:
return is_dig(ch) ? ch - '0'
: is_hex(ch) ? (ch - 'a' + 10) & 017
: -1;
default:
fatal("(val_in_base) illegal base value %d", base);
/* NOTREACHED */
}
}
int
GetChar()
{
/* The routines GetChar and trigraph parses the trigraph
sequences and removes occurences of \\\n.
*/
register int ch;
again:
LoadChar(ch);
/* possible trigraph sequence */
if (ch == '?')
ch = trigraph();
/* \\\n are removed from the input stream */
if (ch == '\\') {
LoadChar(ch);
if (ch == '\n') {
++LineNumber;
goto again;
}
PushBack();
ch = '\\';
}
return(LexSave = ch);
}
int
trigraph()
{
register int ch;
LoadChar(ch);
if (ch == '?') {
LoadChar(ch);
switch (ch) { /* its a trigraph */
case '=':
ch = '#';
return(ch);
case '(':
ch = '[';
return(ch);
case '/':
ch = '\\';
return(ch);
case ')':
ch = ']';
return(ch);
case '\'':
ch = '^';
return(ch);
case '<':
ch = '{';
return(ch);
case '!':
ch = '|';
return(ch);
case '>':
ch = '}';
return(ch);
case '-':
ch = '~';
return(ch);
}
PushBack();
}
PushBack();
return('?');
}

View File

@ -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)

View File

@ -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 <alloc.h>
#include "nofloat.h"
#include "idf.h"
#include "arith.h"
#include "LLlex.h"
#include "Lpars.h"
extern char *symbol2str();
LLmessage(tk) {
err_occurred = 1;
if (tk < 0) {
error("end of file expected");
}
else if (tk) {
error("%s missing", symbol2str(tk));
insert_token(tk);
}
else
error("%s deleted", symbol2str(DOT));
}
insert_token(tk)
int tk;
{
aside = dot;
DOT = tk;
switch (tk) {
/* The operands need some body */
case IDENTIFIER:
dot.tk_idf = gen_idf();
break;
case TYPE_IDENTIFIER:
dot.tk_idf = str2idf("int");
break;
case STRING:
dot.tk_bts = Salloc("", 1);
dot.tk_len = 1;
break;
case INTEGER:
dot.tk_fund = INT;
dot.tk_ival = 1;
break;
#ifndef NOFLOAT
case FLOATING:
dot.tk_fval = Salloc("0.0", 4);
break;
#endif NOFLOAT
}
}

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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
<tokenname.c ./make.tokfile >tokenfile.g
symbol2str.c: tokenname.c make.tokcase
<tokenname.c ./make.tokcase >symbol2str.c
char.c: char.tab
$(EMHOME)/bin/tabgen -fchar.tab >char.c
next.c: make.next $(NEXTFILES)
./make.next $(NEXTFILES) >next.c
code.h: make.allocd
declar.h: make.allocd
decspecs.h: make.allocd
def.h: make.allocd
estack.h: make.allocd
expr.h: make.allocd
field.h: make.allocd
idf.h: make.allocd
macro.h: make.allocd
stack.h: make.allocd
stmt.h: make.allocd
struct.h: make.allocd
switch.h: make.allocd
type.h: make.allocd
util.h: make.allocd
# Objects needed for 'main'
OBJ = $(COBJ) $(LOBJ) $(GOBJ)
SRC = $(CSRC) $(LCSRC) $(GCSRC)
main: $(OBJ) Makefile.erik
$(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(LIBS) -o main
size main
emain: $(OBJ) Makefile.erik
$(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(ELIBS) -o emain
size emain
cfiles: hfiles LLfiles $(GSRC)
@touch cfiles
install: main cem
cp main $(CEMCOM)
cp cem $(DRIVER)
print: files
pr `cat files` > print
tags: cfiles
ctags $(SRC)
shar: files
shar `cat files`
listcfiles:
@echo $(SRC)
listobjects:
@echo $(OBJ)
depend: cfiles
sed '/^#AUTOAUTO/,$$d' Makefile.erik >Makefile.erik.new
echo '#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO' >>Makefile.erik.new
$(MKDEP) $(SRC) | sed 's/\.c:/.o:/' >>Makefile.erik.new
mv Makefile.erik Makefile.erik.old
mv Makefile.erik.new Makefile.erik
xref:
ctags -x `grep "\.[ch]" files`|sed "s/).*/)/">Xref
lxref:
lxref $(OBJ) -lc >lxref
lint: lint.main lint.cem
lint.main: cfiles
$(LINT) -bx $(CDEFS) $(SRC) $(LINTLIBS) >lint.out
cchk:
cchk $(SRC)
clean:
rm -f $(LCSRC) $(OBJ) $(GENERATED) $(GSRC) $(GHSRC)
sim: cfiles
$(SIM) $(SIMFLAGS) $(CSRC) $(GSRC) $(LSRC)
#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
main.o: LLlex.h
main.o: Lpars.h
main.o: align.h
main.o: arith.h
main.o: debug.h
main.o: declar.h
main.o: file_info.h
main.o: idf.h
main.o: input.h
main.o: inputtype.h
main.o: level.h
main.o: noRoption.h
main.o: nobitfield.h
main.o: nocross.h
main.o: nofloat.h
main.o: nopp.h
main.o: sizes.h
main.o: spec_arith.h
main.o: specials.h
main.o: target_sizes.h
main.o: tokenname.h
main.o: type.h
main.o: use_tmp.h
idf.o: LLlex.h
idf.o: Lpars.h
idf.o: align.h
idf.o: arith.h
idf.o: assert.h
idf.o: botch_free.h
idf.o: debug.h
idf.o: declar.h
idf.o: decspecs.h
idf.o: def.h
idf.o: file_info.h
idf.o: idf.h
idf.o: idfsize.h
idf.o: label.h
idf.o: level.h
idf.o: noRoption.h
idf.o: nobitfield.h
idf.o: nocross.h
idf.o: nofloat.h
idf.o: nopp.h
idf.o: sizes.h
idf.o: spec_arith.h
idf.o: specials.h
idf.o: stack.h
idf.o: struct.h
idf.o: target_sizes.h
idf.o: type.h
declarator.o: Lpars.h
declarator.o: arith.h
declarator.o: botch_free.h
declarator.o: declar.h
declarator.o: expr.h
declarator.o: idf.h
declarator.o: label.h
declarator.o: nobitfield.h
declarator.o: nocross.h
declarator.o: nofloat.h
declarator.o: nopp.h
declarator.o: sizes.h
declarator.o: spec_arith.h
declarator.o: target_sizes.h
declarator.o: type.h
decspecs.o: Lpars.h
decspecs.o: arith.h
decspecs.o: decspecs.h
decspecs.o: def.h
decspecs.o: level.h
decspecs.o: noRoption.h
decspecs.o: nobitfield.h
decspecs.o: nofloat.h
decspecs.o: spec_arith.h
decspecs.o: type.h
struct.o: LLlex.h
struct.o: Lpars.h
struct.o: align.h
struct.o: arith.h
struct.o: assert.h
struct.o: botch_free.h
struct.o: debug.h
struct.o: def.h
struct.o: field.h
struct.o: file_info.h
struct.o: idf.h
struct.o: level.h
struct.o: noRoption.h
struct.o: nobitfield.h
struct.o: nocross.h
struct.o: nofloat.h
struct.o: nopp.h
struct.o: sizes.h
struct.o: spec_arith.h
struct.o: stack.h
struct.o: struct.h
struct.o: target_sizes.h
struct.o: type.h
expr.o: LLlex.h
expr.o: Lpars.h
expr.o: arith.h
expr.o: botch_free.h
expr.o: declar.h
expr.o: decspecs.h
expr.o: def.h
expr.o: expr.h
expr.o: file_info.h
expr.o: idf.h
expr.o: label.h
expr.o: level.h
expr.o: noRoption.h
expr.o: nobitfield.h
expr.o: nocross.h
expr.o: nofloat.h
expr.o: nopp.h
expr.o: sizes.h
expr.o: spec_arith.h
expr.o: target_sizes.h
expr.o: type.h
ch7.o: Lpars.h
ch7.o: arith.h
ch7.o: assert.h
ch7.o: debug.h
ch7.o: def.h
ch7.o: expr.h
ch7.o: idf.h
ch7.o: label.h
ch7.o: nobitfield.h
ch7.o: nofloat.h
ch7.o: nopp.h
ch7.o: spec_arith.h
ch7.o: struct.h
ch7.o: type.h
ch7bin.o: Lpars.h
ch7bin.o: arith.h
ch7bin.o: botch_free.h
ch7bin.o: expr.h
ch7bin.o: idf.h
ch7bin.o: label.h
ch7bin.o: noRoption.h
ch7bin.o: nobitfield.h
ch7bin.o: nofloat.h
ch7bin.o: nopp.h
ch7bin.o: spec_arith.h
ch7bin.o: struct.h
ch7bin.o: type.h
cstoper.o: Lpars.h
cstoper.o: arith.h
cstoper.o: assert.h
cstoper.o: debug.h
cstoper.o: expr.h
cstoper.o: idf.h
cstoper.o: label.h
cstoper.o: nobitfield.h
cstoper.o: nocross.h
cstoper.o: nofloat.h
cstoper.o: nopp.h
cstoper.o: sizes.h
cstoper.o: spec_arith.h
cstoper.o: target_sizes.h
cstoper.o: type.h
arith.o: Lpars.h
arith.o: arith.h
arith.o: botch_free.h
arith.o: expr.h
arith.o: field.h
arith.o: idf.h
arith.o: label.h
arith.o: mes.h
arith.o: noRoption.h
arith.o: nobitfield.h
arith.o: nofloat.h
arith.o: nopp.h
arith.o: spec_arith.h
arith.o: type.h
code.o: Lpars.h
code.o: arith.h
code.o: assert.h
code.o: atw.h
code.o: botch_free.h
code.o: code.h
code.o: dataflow.h
code.o: debug.h
code.o: declar.h
code.o: decspecs.h
code.o: def.h
code.o: expr.h
code.o: file_info.h
code.o: idf.h
code.o: label.h
code.o: level.h
code.o: noRoption.h
code.o: nobitfield.h
code.o: nocross.h
code.o: nofloat.h
code.o: nopp.h
code.o: sizes.h
code.o: spec_arith.h
code.o: specials.h
code.o: stack.h
code.o: stmt.h
code.o: target_sizes.h
code.o: type.h
code.o: use_tmp.h
dumpidf.o: Lpars.h
dumpidf.o: arith.h
dumpidf.o: debug.h
dumpidf.o: def.h
dumpidf.o: expr.h
dumpidf.o: field.h
dumpidf.o: idf.h
dumpidf.o: label.h
dumpidf.o: nobitfield.h
dumpidf.o: nofloat.h
dumpidf.o: nopp.h
dumpidf.o: spec_arith.h
dumpidf.o: stack.h
dumpidf.o: static.h
dumpidf.o: struct.h
dumpidf.o: type.h
error.o: LLlex.h
error.o: arith.h
error.o: debug.h
error.o: errout.h
error.o: expr.h
error.o: file_info.h
error.o: label.h
error.o: nofloat.h
error.o: nopp.h
error.o: spec_arith.h
error.o: tokenname.h
field.o: Lpars.h
field.o: align.h
field.o: arith.h
field.o: assert.h
field.o: code.h
field.o: debug.h
field.o: expr.h
field.o: field.h
field.o: idf.h
field.o: label.h
field.o: nobitfield.h
field.o: nocross.h
field.o: nofloat.h
field.o: nopp.h
field.o: sizes.h
field.o: spec_arith.h
field.o: target_sizes.h
field.o: type.h
tokenname.o: LLlex.h
tokenname.o: Lpars.h
tokenname.o: arith.h
tokenname.o: file_info.h
tokenname.o: idf.h
tokenname.o: nofloat.h
tokenname.o: nopp.h
tokenname.o: spec_arith.h
tokenname.o: tokenname.h
LLlex.o: LLlex.h
LLlex.o: Lpars.h
LLlex.o: arith.h
LLlex.o: assert.h
LLlex.o: class.h
LLlex.o: debug.h
LLlex.o: def.h
LLlex.o: file_info.h
LLlex.o: idf.h
LLlex.o: idfsize.h
LLlex.o: input.h
LLlex.o: nocross.h
LLlex.o: nofloat.h
LLlex.o: nopp.h
LLlex.o: numsize.h
LLlex.o: sizes.h
LLlex.o: spec_arith.h
LLlex.o: strsize.h
LLlex.o: target_sizes.h
LLmessage.o: LLlex.h
LLmessage.o: Lpars.h
LLmessage.o: arith.h
LLmessage.o: file_info.h
LLmessage.o: idf.h
LLmessage.o: nofloat.h
LLmessage.o: nopp.h
LLmessage.o: spec_arith.h
input.o: file_info.h
input.o: input.h
input.o: inputtype.h
input.o: nopp.h
domacro.o: LLlex.h
domacro.o: Lpars.h
domacro.o: arith.h
domacro.o: assert.h
domacro.o: botch_free.h
domacro.o: class.h
domacro.o: debug.h
domacro.o: file_info.h
domacro.o: idf.h
domacro.o: idfsize.h
domacro.o: ifdepth.h
domacro.o: input.h
domacro.o: interface.h
domacro.o: macro.h
domacro.o: nofloat.h
domacro.o: nopp.h
domacro.o: nparams.h
domacro.o: parbufsize.h
domacro.o: spec_arith.h
domacro.o: textsize.h
replace.o: LLlex.h
replace.o: arith.h
replace.o: assert.h
replace.o: class.h
replace.o: debug.h
replace.o: file_info.h
replace.o: idf.h
replace.o: input.h
replace.o: interface.h
replace.o: macro.h
replace.o: nofloat.h
replace.o: nopp.h
replace.o: pathlength.h
replace.o: spec_arith.h
replace.o: static.h
replace.o: strsize.h
init.o: class.h
init.o: idf.h
init.o: interface.h
init.o: macro.h
init.o: nopp.h
options.o: align.h
options.o: arith.h
options.o: botch_free.h
options.o: class.h
options.o: dataflow.h
options.o: idf.h
options.o: idfsize.h
options.o: macro.h
options.o: noRoption.h
options.o: nobitfield.h
options.o: nocross.h
options.o: nofloat.h
options.o: nopp.h
options.o: sizes.h
options.o: spec_arith.h
options.o: target_sizes.h
options.o: use_tmp.h
scan.o: class.h
scan.o: idf.h
scan.o: input.h
scan.o: interface.h
scan.o: lapbuf.h
scan.o: macro.h
scan.o: nopp.h
scan.o: nparams.h
skip.o: LLlex.h
skip.o: arith.h
skip.o: class.h
skip.o: file_info.h
skip.o: input.h
skip.o: interface.h
skip.o: nofloat.h
skip.o: nopp.h
skip.o: spec_arith.h
stack.o: Lpars.h
stack.o: arith.h
stack.o: botch_free.h
stack.o: debug.h
stack.o: def.h
stack.o: idf.h
stack.o: level.h
stack.o: mes.h
stack.o: noRoption.h
stack.o: nobitfield.h
stack.o: nofloat.h
stack.o: nopp.h
stack.o: spec_arith.h
stack.o: stack.h
stack.o: struct.h
stack.o: type.h
type.o: Lpars.h
type.o: align.h
type.o: arith.h
type.o: botch_free.h
type.o: def.h
type.o: idf.h
type.o: nobitfield.h
type.o: nocross.h
type.o: nofloat.h
type.o: nopp.h
type.o: sizes.h
type.o: spec_arith.h
type.o: target_sizes.h
type.o: type.h
ch7mon.o: Lpars.h
ch7mon.o: arith.h
ch7mon.o: botch_free.h
ch7mon.o: def.h
ch7mon.o: expr.h
ch7mon.o: idf.h
ch7mon.o: label.h
ch7mon.o: nobitfield.h
ch7mon.o: nofloat.h
ch7mon.o: nopp.h
ch7mon.o: spec_arith.h
ch7mon.o: type.h
label.o: Lpars.h
label.o: arith.h
label.o: def.h
label.o: idf.h
label.o: label.h
label.o: level.h
label.o: noRoption.h
label.o: nobitfield.h
label.o: nofloat.h
label.o: nopp.h
label.o: spec_arith.h
label.o: type.h
eval.o: Lpars.h
eval.o: align.h
eval.o: arith.h
eval.o: assert.h
eval.o: atw.h
eval.o: code.h
eval.o: dataflow.h
eval.o: debug.h
eval.o: def.h
eval.o: expr.h
eval.o: idf.h
eval.o: label.h
eval.o: level.h
eval.o: mes.h
eval.o: nobitfield.h
eval.o: nocross.h
eval.o: nofloat.h
eval.o: nopp.h
eval.o: sizes.h
eval.o: spec_arith.h
eval.o: specials.h
eval.o: stack.h
eval.o: target_sizes.h
eval.o: type.h
switch.o: Lpars.h
switch.o: arith.h
switch.o: assert.h
switch.o: botch_free.h
switch.o: code.h
switch.o: debug.h
switch.o: density.h
switch.o: expr.h
switch.o: idf.h
switch.o: label.h
switch.o: noRoption.h
switch.o: nobitfield.h
switch.o: nofloat.h
switch.o: nopp.h
switch.o: spec_arith.h
switch.o: switch.h
switch.o: type.h
conversion.o: Lpars.h
conversion.o: arith.h
conversion.o: nobitfield.h
conversion.o: nocross.h
conversion.o: nofloat.h
conversion.o: sizes.h
conversion.o: spec_arith.h
conversion.o: target_sizes.h
conversion.o: type.h
util.o: Lpars.h
util.o: align.h
util.o: def.h
util.o: nocross.h
util.o: nofloat.h
util.o: regcount.h
util.o: sizes.h
util.o: stack.h
util.o: target_sizes.h
util.o: use_tmp.h
util.o: util.h
blocks.o: Lpars.h
blocks.o: align.h
blocks.o: arith.h
blocks.o: atw.h
blocks.o: label.h
blocks.o: nocross.h
blocks.o: nofloat.h
blocks.o: sizes.h
blocks.o: spec_arith.h
blocks.o: stack.h
blocks.o: target_sizes.h
dataflow.o: dataflow.h
char.o: class.h
symbol2str.o: Lpars.h

67
lang/cem/cemcom.ansi/Resolve Executable file
View File

@ -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 <<EOF
$i: clashes $PW/$i
cid -Fclashes < $PW/$i > $i
EOF
done
make EMHOME=$EMHOME `cat $PW/Cfiles`
rm -f Makefile
ed - $PW/Makefile <<'EOF'
/^#EXCLEXCL/,/^#INCLINCL/d
w Makefile
q
EOF
make EMHOME=$EMHOME COPTIONS=$options CURRDIR=$PW/ $target

View File

@ -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 */

View File

@ -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

View File

@ -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();

View File

@ -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 <alloc.h>
#include "lint.h"
#include "nofloat.h"
#include "nobitfield.h"
#include "idf.h"
#include "arith.h"
#include "sizes.h"
#include "type.h"
#include "proto.h"
#include "label.h"
#include "expr.h"
#include "Lpars.h"
#include "field.h"
#include "mes.h"
#include "noRoption.h"
extern char *symbol2str();
extern char options[];
arithbalance(e1p, oper, e2p) /* RM 6.6 */
register struct expr **e1p, **e2p;
int oper;
{
/* The expressions *e1p and *e2p are balanced to be operands
of the arithmetic operator oper.
*/
register int t1, t2, u1, u2;
t1 = any2arith(e1p, oper);
t2 = any2arith(e2p, oper);
/* Now t1 and t2 are either INT, LONG, FLOAT, DOUBLE, or LNGDBL */
#ifndef NOFLOAT
/* If any operand has the type long double, the other operand
is converted to long double.
*/
if (t1 == LNGDBL) {
if (t2 != LNGDBL)
int2float(e2p, lngdbl_type);
return;
} else if (t2 == LNGDBL) {
if (t1 != LNGDBL)
int2float(e1p, lngdbl_type);
return;
}
/* If any operand has the type double, the other operand
is converted to double.
*/
if (t1 == DOUBLE) {
if (t2 != DOUBLE)
int2float(e2p, double_type);
return;
} else if (t2 == DOUBLE) {
if (t1 != DOUBLE)
int2float(e1p, double_type);
return;
}
/* If any operand has the type float, the other operand
is converted to float.
*/
if (t1 == FLOAT) {
if (t2 != FLOAT)
int2float(e2p, float_type);
return;
} else if (t2 == FLOAT) {
if (t1 != FLOAT)
int2float(e1p, float_type);
return;
}
#endif NOFLOAT
/* Now they are INT or LONG */
u1 = (*e1p)->ex_type->tp_unsigned;
u2 = (*e2p)->ex_type->tp_unsigned;
/* If either operand has type unsigned long int, the other
operand is converted to unsigned long int.
*/
if (t1 == LONG && u1 && (t2 != LONG || !u2))
t2 = int2int(e2p, ulong_type);
else if (t2 == LONG && u2 && (t1 != LONG || !u1))
t1 = int2int(e1p, ulong_type);
/* If one operand has type long int and the other has type unsigned
int, if a long int can represent all values of an unsigned int,
the operand of type unsigned int is converted to long int; if
a long int cannot represent all values of an unsigned int,
both operands are converted to unsigned long int.
*/
if (t1 == LONG && t2 == INT && u2)
t2 = int2int(e2p, (int_size<long_size)? long_type : ulong_type);
else if (t2 == LONG && t1 == INT && u1)
t1 = int2int(e1p, (int_size<long_size)? long_type : ulong_type);
if (int_size > long_size) /* sanity check */
crash("size of int exceeds size of long");
/* If either operand has type long int, the other operand is con-
verted to long int.
*/
if (t1 == LONG && t2 != LONG)
t2 = int2int(e2p, long_type);
else
if (t2 == LONG && t1 != LONG)
t1 = int2int(e1p, long_type);
/* If either operand has type unsigned int, the other operand
is converted to unsigned int.
Otherwise, both operands have type int.
*/
if (u1 && !u2)
t2 = int2int(e2p, (t1 == LONG) ? ulong_type : uint_type);
else
if (!u1 && u2)
t1 = int2int(e1p, (t2 == LONG) ? ulong_type : uint_type);
}
relbalance(e1p, oper, e2p)
register struct expr **e1p, **e2p;
{
/* The expressions *e1p and *e2p are balanced to be operands
of the relational operator oper.
*/
if ((*e1p)->ex_type->tp_fund == FUNCTION)
function2pointer(*e1p);
if ((*e2p)->ex_type->tp_fund == FUNCTION)
function2pointer(*e2p);
if ((*e1p)->ex_type->tp_fund == POINTER)
ch76pointer(e2p, oper, (*e1p)->ex_type);
else
if ((*e2p)->ex_type->tp_fund == POINTER)
ch76pointer(e1p, oper, (*e2p)->ex_type);
else
if ( (*e1p)->ex_type == (*e2p)->ex_type &&
(*e1p)->ex_type->tp_fund == ENUM
)
{}
else
arithbalance(e1p, oper, e2p);
}
ch76pointer(expp, oper, tp)
struct expr **expp;
register struct type *tp;
{
/* Checks whether *expp may be compared to tp using oper,
as described in chapter 7.6 and 7.7.
tp is known to be a pointer.
*/
register struct expr *exp = *expp;
if (exp->ex_type->tp_fund == POINTER) {
if (exp->ex_type != tp)
ch7cast(expp, oper, tp);
}
else
if ( is_integral_type(exp->ex_type)
#ifndef NOROPTION
&&
( !options['R'] /* we don't care */ ||
(oper == EQUAL || oper == NOTEQUAL || oper == ':')
)
#endif NOROPTION
) /* ch 7.7 */
ch7cast(expp, CAST, tp);
else {
expr_error(exp, "%s on %s and pointer",
symbol2str(oper),
symbol2str(exp->ex_type->tp_fund)
);
ch7cast(expp, oper, tp);
}
}
int
any2arith(expp, oper)
register struct expr **expp;
register int oper;
{
/* Turns any expression into int_type, long_type or
double_type.
*/
int fund;
switch (fund = (*expp)->ex_type->tp_fund) {
case CHAR:
case SHORT:
case GENERIC:
int2int(expp,
(*expp)->ex_type->tp_unsigned ? uint_type : int_type);
break;
case INT:
case LONG:
break;
case ENUM:
/* test the admissibility of the operator */
if ( is_test_op(oper) || oper == '=' || oper == PARCOMMA ||
oper == ',' || oper == ':'
) {
/* allowed by K & R */
}
else
#ifndef NOROPTION
if (!options['R']) {
/* allowed by us */
}
else
expr_warning(*expp, "%s on enum", symbol2str(oper));
#endif NOROPTION
#ifndef LINT
int2int(expp, int_type);
#endif LINT
break;
#ifndef NOFLOAT
case FLOAT:
/*
float2float(expp, double_type);
break;
*/
case DOUBLE:
case LNGDBL:
break;
#endif NOFLOAT
#ifndef NOBITFIELD
case FIELD:
field2arith(expp);
break;
#endif NOBITFIELD
default:
expr_error(*expp, "operator %s on non-numerical operand (%s)",
symbol2str(oper), symbol2str(fund));
case ERRONEOUS:
erroneous2int(expp);
break;
}
return (*expp)->ex_type->tp_fund;
}
erroneous2int(expp)
struct expr **expp;
{
/* the (erroneous) expression *expp is replaced by an
int expression
*/
register struct expr *exp = *expp;
int flags = exp->ex_flags;
free_expression(exp);
exp = intexpr((arith)0, INT);
exp->ex_flags = (flags | EX_ERROR);
*expp = exp;
}
struct expr *
arith2arith(tp, oper, expr)
struct type *tp;
int oper;
register struct expr *expr;
{
/* arith2arith constructs a new expression containing a
run-time conversion between some arithmetic types.
*/
register struct expr *new = new_expr();
new->ex_file = expr->ex_file;
new->ex_line = expr->ex_line;
new->ex_type = tp;
new->ex_class = Type;
return new_oper(tp, new, oper, expr);
}
int
int2int(expp, tp)
struct expr **expp;
register struct type *tp;
{
/* The expression *expp, which is of some integral type, is
converted to the integral type tp.
*/
register struct expr *exp = *expp;
if (is_cp_cst(exp)) {
register struct type *tp1 = exp->ex_type;
exp->ex_type = tp;
if (! tp1->tp_unsigned && tp->tp_unsigned) {
/* Avoid "unreal" overflow warnings, such as
caused by f.i.:
unsigned int x = ~0;
unsigned int y = -1;
*/
extern long full_mask[];
long remainder = exp->VL_VALUE &
~full_mask[(int)(tp->tp_size)];
if (remainder == 0 ||
remainder == ~full_mask[(int)(tp->tp_size)]) {
exp->VL_VALUE &= ~remainder;
}
}
cut_size(exp);
}
else {
exp = arith2arith(tp, INT2INT, exp);
}
*expp = exp;
return exp->ex_type->tp_fund;
}
#ifndef NOFLOAT
int2float(expp, tp)
register struct expr **expp;
struct type *tp;
{
/* The expression *expp, which is of some integral type, is
converted to the floating type tp.
*/
register struct expr *exp = *expp;
char buf[32];
fp_used = 1;
if (is_cp_cst(exp)) {
*expp = new_expr();
**expp = *exp;
sprint(buf+1, "%ld", (long)(exp->VL_VALUE));
buf[0] = '-';
exp = *expp;
exp->ex_type = tp;
exp->ex_class = Float;
exp->FL_VALUE = Salloc(buf, (unsigned)strlen(buf)+2) + 1;
exp->FL_DATLAB = 0;
}
else *expp = arith2arith(tp, INT2FLOAT, *expp);
}
float2int(expp, tp)
struct expr **expp;
struct type *tp;
{
/* The expression *expp, which is of some floating type, is
converted to the integral type tp.
*/
fp_used = 1;
*expp = arith2arith(tp, FLOAT2INT, *expp);
}
float2float(expp, tp)
register struct expr **expp;
struct type *tp;
{
/* The expression *expp, which is of some floating type, is
converted to the floating type tp.
There is no need for an explicit conversion operator
if the expression is a constant.
*/
fp_used = 1;
if (is_fp_cst(*expp))
(*expp)->ex_type = tp;
else
*expp = arith2arith(tp, FLOAT2FLOAT, *expp);
}
#endif NOFLOAT
array2pointer(exp)
register struct expr *exp;
{
/* The expression, which must be an array, is converted
to a pointer.
*/
exp->ex_type = construct_type(POINTER, exp->ex_type->tp_up, 0,
(arith)0, NO_PROTO);
}
function2pointer(exp)
register struct expr *exp;
{
/* The expression, which must be a function, is converted
to a pointer to the function.
*/
exp->ex_type = construct_type(POINTER, exp->ex_type, 0,
(arith)0, NO_PROTO);
}
string2pointer(ex)
register struct expr *ex;
{
/* The expression, which must be a string constant, is converted
to a pointer to the string-containing area.
*/
label lbl = data_label();
code_string(ex->SG_VALUE, ex->SG_LEN, lbl);
ex->ex_class = Value;
ex->VL_CLASS = Label;
ex->VL_LBL = lbl;
ex->VL_VALUE = (arith)0;
}
opnd2integral(expp, oper)
register struct expr **expp;
int oper;
{
register int fund = (*expp)->ex_type->tp_fund;
if (fund != INT && fund != LONG) {
expr_error(*expp, "%s operand to %s",
symbol2str(fund), symbol2str(oper));
erroneous2int(expp);
/* fund = INT; */
}
}
opnd2logical(expp, oper)
register struct expr **expp;
int oper;
{
int fund = (*expp)->ex_type->tp_fund;
if (fund == FUNCTION || fund == ARRAY) {
expr_warning(*expp, "%s operand to %s",
symbol2str(fund),
symbol2str(oper));
if (fund == FUNCTION) {
function2pointer(*expp);
}
else array2pointer(*expp);
}
#ifndef NOBITFIELD
else
if (fund == FIELD)
field2arith(expp);
#endif NOBITFIELD
switch (fund = (*expp)->ex_type->tp_fund) {
case CHAR:
case SHORT:
case INT:
case LONG:
case ENUM:
case POINTER:
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
#endif NOFLOAT
break;
default:
expr_error(*expp, "%s operand to %s",
symbol2str(fund), symbol2str(oper));
case ERRONEOUS:
erroneous2int(expp);
break;
}
}
opnd2test(expp, oper)
register struct expr **expp;
{
opnd2logical(expp, oper);
if ((*expp)->ex_class == Oper && is_test_op((*expp)->OP_OPER))
{ /* It is already a test */ }
else
ch7bin(expp, NOTEQUAL, intexpr((arith)0, INT));
}
int
is_test_op(oper)
{
switch (oper) {
case '<':
case '>':
case LESSEQ:
case GREATEREQ:
case EQUAL:
case NOTEQUAL:
case '!':
case AND:
case OR: /* && and || also impose a test */
return 1;
default:
return 0;
}
/*NOTREACHED*/
}
any2opnd(expp, oper)
register struct expr **expp;
{
if (!*expp)
return;
switch ((*expp)->ex_type->tp_fund) { /* RM 7.1 */
case CHAR:
case SHORT:
case ENUM:
#ifndef NOFLOAT
case FLOAT:
#endif NOFLOAT
any2arith(expp, oper);
break;
case ARRAY:
array2pointer(*expp);
break;
case POINTER:
if ((*expp)->ex_class == String)
string2pointer(*expp);
break;
#ifndef NOBITFIELD
case FIELD:
field2arith(expp);
break;
#endif NOBITFIELD
}
}
#ifndef NOBITFIELD
field2arith(expp)
register struct expr **expp;
{
/* The expression to extract the bitfield value from the
memory word is put in the tree.
*/
register struct type *tp = (*expp)->ex_type->tp_up;
register struct field *fd = (*expp)->ex_type->tp_field;
register struct type *atype = tp->tp_unsigned ? uword_type : word_type;
(*expp)->ex_type = atype;
if (atype->tp_unsigned) { /* don't worry about the sign bit */
ch7bin(expp, RIGHT, intexpr((arith)fd->fd_shift, INT));
ch7bin(expp, '&', intexpr(fd->fd_mask, INT));
}
else { /* take care of the sign bit: sign extend if needed */
arith bits_in_type = atype->tp_size * 8;
ch7bin(expp, LEFT,
intexpr(bits_in_type - fd->fd_width - fd->fd_shift,
INT)
);
ch7bin(expp, RIGHT, intexpr(bits_in_type - fd->fd_width, INT));
}
ch7cast(expp, CAST, tp); /* restore its original type */
}
#endif NOBITFIELD
#ifndef NOFLOAT
/* switch_sign_fp() negates the given floating constant expression
The lexical analyser has reserved an extra byte of space in front
of the string containing the representation of the floating
constant. This byte contains the '-' character and we have to
take care of the first byte the fl_value pointer points to.
*/
switch_sign_fp(expr)
register struct expr *expr;
{
if (*(expr->FL_VALUE) == '-')
++(expr->FL_VALUE);
else
--(expr->FL_VALUE);
}
#endif NOFLOAT

View File

@ -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 <em_arith.h> /* obtain definition of "arith" */
#else SPECIAL_ARITHMETICS
/* All preprocessor arithmetic should be done in longs.
*/
#define arith long /* dummy */
#endif SPECIAL_ARITHMETICS

View File

@ -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");
}

View File

@ -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

View File

@ -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)

View File

@ -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 <em.h>
#include <em_reg.h>
#include "arith.h"
#include "sizes.h"
#include "atw.h"
#include "align.h"
#ifndef STB
#include "label.h"
#include "stack.h"
#include "Lpars.h"
extern arith NewLocal();
#define LocalPtrVar() NewLocal(pointer_size, pointer_align, reg_pointer, REGISTER)
#endif STB
/* Because EM does not support the loading and storing of
objects having other sizes than word fragment and multiple,
we need to have a way of transferring these objects, whereby
we simulate "loi" and "sti": the address of the source resp.
destination is located on top of stack and a call is done
to load_block() resp. store_block().
===============================================================
# Loadblock() works on the stack as follows: ([ ] indicates the
# position of the stackpointer)
# lower address--->
# 1) | &object
# 2) | ... ATW(sz) bytes ... | sz | &stack_block | &object
# 3) | ... ATW(sz) bytes ...
===============================================================
Loadblock() pushes ATW(sz) bytes directly onto the stack!
Store_block() works on the stack as follows:
lower address--->
1) | ... ATW(sz) bytes ... | &object
2) | ... ATW(sz) bytes ... | &object | &stack_block | sz
3) <empty>
If sz is a legal argument for "loi" or "sti", just one EM
instruction is generated.
In the other cases, the notion of alignment is taken into account:
we only push an object of the size accepted by EM onto the stack,
while we need a loop to store the stack block into a memory object.
*/
store_block(sz, al)
arith sz;
int al;
{
if (
((sz == al) && (word_align % al == 0)) ||
(
(sz % word_size == 0 || word_size % sz == 0) &&
(al % word_align == 0)
)
) /* Lots of Irritating Stupid Parentheses */
C_sti(sz);
else {
#ifndef STB
arith src, dst;
/* allocate two pointer temporaries */
src = LocalPtrVar();
dst = LocalPtrVar();
/* load the addresses */
StoreLocal(dst, pointer_size);
C_lor((arith)1); /* push current sp */
StoreLocal(src, pointer_size);
copy_loop(sz, src, dst);
C_asp(ATW(sz));
FreeLocal(dst);
FreeLocal(src);
#else STB
/* address of destination lies on the stack */
/* push address of first byte of block on stack onto
the stack by computing it from the current stack
pointer position
*/
C_lor((arith)1); /* push current sp */
C_adp(pointer_size); /* set & to 1st byte of block */
C_loc(sz); /* number of bytes to transfer */
C_cal("__stb"); /* call transfer routine */
C_asp(pointer_size + pointer_size + int_size + ATW(sz));
#endif STB
}
}
load_block(sz, al)
arith sz;
int al;
{
arith esz = ATW(sz); /* effective size == actual # pushed bytes */
if (
((sz == al) && (word_align % al == 0)) ||
(
(sz % word_size == 0 || word_size % sz == 0) &&
(al % word_align == 0)
)
) /* Lots of Irritating Stupid Parentheses */
C_loi(sz);
else {
#ifndef STB
arith src, dst;
/* allocate two pointer temporaries */
src = LocalPtrVar();
dst = LocalPtrVar();
StoreLocal(src, pointer_size);
C_asp(-esz); /* allocate stack block */
C_lor((arith)1); /* push & of stack block as dst */
StoreLocal(dst, pointer_size);
copy_loop(sz, src, dst);
FreeLocal(dst);
FreeLocal(src);
#else STB
C_asp(-(esz - pointer_size)); /* allocate stack block */
C_lor((arith)1); /* push & of stack block as dst */
C_dup(pointer_size); /* fetch source address */
C_adp(esz - pointer_size);
C_loi(pointer_size);
C_loc(sz); /* # bytes to copy */
C_cal("__stb"); /* library copy routine */
C_asp(int_size + pointer_size + pointer_size);
#endif STB
}
}
#ifndef STB
copy_loop(sz, src, dst)
arith sz, src, dst;
{
/* generate inline byte-copy loop */
label l_cont = text_label(), l_stop = text_label();
C_loc(sz); /* amount of bytes */
C_df_ilb(l_cont);
C_dup(word_size);
C_zle(l_stop);
C_dec();
LoadLocal(src, pointer_size);
C_dup(pointer_size);
C_adp((arith)1);
StoreLocal(src, pointer_size);
C_loi((arith)1);
LoadLocal(dst, pointer_size);
C_dup(pointer_size);
C_adp((arith)1);
StoreLocal(dst, pointer_size);
C_sti((arith)1);
C_bra(l_cont);
C_df_ilb(l_stop);
C_asp(word_size);
}
#endif STB
#endif LINT

230
lang/cem/cemcom.ansi/cem.1 Normal file
View File

@ -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

764
lang/cem/cemcom.ansi/cem.c Normal file
View File

@ -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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#define MAXARGC 256 /* maximum number of arguments allowed in a list */
#define USTR_SIZE 1024 /* maximum length of string variable */
struct arglist {
int al_argc;
char *al_argv[MAXARGC];
};
/* some system-dependent variables */
char *PP = "/lib/cpp";
char *CEM = "/usr/em/lib/em_cemcom";
char *ENCODE = "/usr/em/lib/em_encode";
char *DECODE = "/usr/em/lib/em_decode";
char *OPT = "/usr/em/lib/em_opt";
char *SHELL = "/bin/sh";
#ifndef MANTRA
char *CG = "/usr/em/lib/vax4/cg";
char *AS = "/bin/as";
char *AS_FIX = "/user1/erikb/bin/mcomm";
char *LD = "/bin/ld";
char *LIBDIR = "/user1/cem/lib";
char *V_FLAG = "-Vs2.2w4.4i4.4l4.4f4.4d8.4p4.4";
#else MANTRA
char *CG = "/usr/em/lib/m68k2/cg";
char *AS = "/usr/em/lib/m68k2/as";
char *LD = "/usr/em/lib/em_led";
char *CV = "/usr/em/lib/m68k2/cv";
char *LIBDIR = "/usr/em/lib/m68k2";
char *V_FLAG = "-Vs2.2w2.2i2.2l4.2f4.2d8.2p4.2";
#endif MANTRA
struct arglist LD_HEAD = {
2,
{
#ifndef MANTRA
"/usr/em/lib/vax4/head_em",
"/usr/em/lib/vax4/head_cc"
#else MANTRA
"/usr/em/lib/m68k2/head_em",
"/usr/em/lib/m68k2/head_cc"
#endif MANTRA
}
};
struct arglist LD_TAIL = {
#ifndef MANTRA
4,
{
"/user1/cem/lib/libc.a",
"/user1/cem/lib/stb.o",
"/usr/em/lib/vax4/tail_mon",
"/usr/em/lib/vax4/tail_em"
}
#else MANTRA
7,
{
"/usr/em/lib/m68k2/tail_cc.1s",
"/usr/em/lib/m68k2/tail_cc.2g",
"/usr/em/lib/m68k2/tail_cem",
"/usr/em/lib/m68k2/tail_fp.a",
"/usr/em/lib/m68k2/tail_em.rt",
"/usr/em/lib/m68k2/tail_mon",
"/usr/em/lib/m68k2/end_em"
}
#endif MANTRA
};
char *o_FILE = "a.out";
#ifdef MANTRA
char *cv_FILE = "cv.out";
#endif MANTRA
#define remove(str) (((FLAG(t) == 0) && unlink(str)), (str)[0] = '\0')
#define cleanup(str) (str && remove(str))
#define mkname(dst, s1, s2) mkstr(dst, (s1), (s2), 0)
#define init(al) (al)->al_argc = 1
#define library(nm) \
mkstr(alloc((unsigned int)strlen(nm) + strlen(LIBDIR) + 7), \
LIBDIR, "/lib", nm, ".a", 0)
struct arglist SRCFILES, LDFILES, GEN_LDFILES, PP_FLAGS, CEM_FLAGS,
OPT_FLAGS, DECODE_FLAGS, ENCODE_FLAGS, CG_FLAGS, AS_FLAGS,
O_FLAGS, DEBUG_FLAGS, CALL_VEC;
#ifndef MANTRA
struct arglist LD_FLAGS;
#else MANTRA
struct arglist LD_FLAGS = {
5,
{
"-b0:0x80000",
"-a0:2",
"-a1:2",
"-a2:2",
"-a3:2"
}
};
struct arglist CV_FLAGS;
int Nc_flag = 0;
#endif MANTRA
/* option naming */
#define NAME(chr) chr
#define FLAG(chr) NAME(chr)_flag
int E_flag, P_flag, S_flag, c_flag, e_flag, k_flag,
m_flag, o_flag, t_flag, v_flag;
/* various passes */
struct prog {
char *p_name;
char **p_task;
struct arglist *p_flags;
} ProgParts[] = {
{ "cpp", &PP, &PP_FLAGS },
{ "cem", &CEM, &CEM_FLAGS },
{ "opt", &OPT, &OPT_FLAGS },
{ "decode", &DECODE, &DECODE_FLAGS },
{ "encode", &ENCODE, &ENCODE_FLAGS },
{ "be", &CG, &CG_FLAGS },
{ "cg", &CG, &CG_FLAGS },
{ "as", &AS, &AS_FLAGS },
{ "ld", &LD, &LD_FLAGS },
#ifdef MANTRA
{ "cv", &CV, &CV_FLAGS },
#endif MANTRA
{ 0, 0, 0 }
};
/* various forward declarations */
int trap();
char *mkstr();
char *alloc();
long sizeof_file();
/* various globals */
char *ProgCall = 0;
int debug = 0;
int exec = 1;
int RET_CODE = 0;
main(argc, argv)
char *argv[];
{
char *str, **argvec, *file, *ldfile = 0;
int count, ext;
char Nfile[USTR_SIZE], kfile[USTR_SIZE], sfile[USTR_SIZE],
mfile[USTR_SIZE], ofile[USTR_SIZE], BASE[USTR_SIZE];
register struct arglist *call = &CALL_VEC;
set_traps(trap);
ProgCall = *argv++;
append(&CEM_FLAGS, "-L");
while (--argc > 0) {
if (*(str = *argv++) != '-') {
append(&SRCFILES, str);
continue;
}
switch (str[1]) {
case '-':
switch (str[2]) {
case 'C':
case 'E':
case 'P':
FLAG(E) = 1;
append(&PP_FLAGS, str);
PP = CEM;
FLAG(P) = (str[2] == 'P');
break;
default:
append(&DEBUG_FLAGS, str);
break;
}
break;
case 'B':
PP = CEM = &str[2];
break;
case 'C':
case 'E':
case 'P':
FLAG(E) = 1;
append(&PP_FLAGS, str);
FLAG(P) = (str[1] == 'P');
break;
case 'c':
if (str[2] == '.') {
switch (str[3]) {
case 's':
FLAG(S) = 1;
break;
case 'k':
FLAG(k) = 1;
break;
case 'o':
FLAG(c) = 1;
break;
case 'm':
FLAG(m) = 1;
break;
case 'e':
FLAG(e) = 1;
break;
default:
bad_option(str);
}
}
else
if (str[2] == '\0')
FLAG(c) = 1;
else
bad_option(str);
break;
case 'D':
case 'I':
case 'U':
append(&PP_FLAGS, str);
break;
case 'k':
FLAG(k) = 1;
break;
case 'l':
if (str[2] == '\0') /* no standard libraries */
LD_HEAD.al_argc = LD_TAIL.al_argc = 0;
else /* use library from library directory */
append(&SRCFILES, library(&str[2]));
break;
case 'L': /* change default library directory */
LIBDIR = &str[2];
break;
case 'm':
FLAG(m) = 1;
break;
#ifdef MANTRA
case 'N':
switch (str[2]) {
case 'c': /* no a.out conversion */
Nc_flag = 1;
break;
case 'l': /* no default options to led */
LD_FLAGS.al_argc = 0;
break;
default:
bad_option(str);
}
break;
#endif MANTRA
case 'o':
FLAG(o) = 1;
if (argc-- < 0)
bad_option(str);
else
o_FILE = *argv++;
break;
case 'O':
append(&O_FLAGS, "-O");
break;
case 'R':
if (str[2] == '\0')
append(&CEM_FLAGS, str);
else
Roption(str);
break;
case 'S':
FLAG(S) = 1;
break;
case 't':
FLAG(t) = 1;
break;
case 'v': /* set debug switches */
FLAG(v) = 1;
switch (str[2]) {
case 'd':
debug = 1;
break;
case 'n': /* no execute */
exec = 0;
break;
case '\0':
break;
default:
bad_option(str);
}
break;
case 'V':
V_FLAG = str;
break;
default:
append(&LD_FLAGS, str);
}
}
if (debug) report("Note: debug output");
if (exec == 0)
report("Note: no execution");
count = SRCFILES.al_argc;
argvec = &(SRCFILES.al_argv[0]);
Nfile[0] = '\0';
while (count-- > 0) {
basename(file = *argvec++, BASE);
if (FLAG(E)) {
char ifile[USTR_SIZE];
init(call);
append(call, PP);
concat(call, &DEBUG_FLAGS);
concat(call, &PP_FLAGS);
append(call, file);
runvec(call, FLAG(P) ? mkname(ifile, BASE, ".i") : 0);
continue;
}
ext = extension(file);
/* .c to .k and .N */
if (ext == 'c' || ext == 'i') {
init(call);
append(call, CEM);
concat(call, &DEBUG_FLAGS);
append(call, V_FLAG);
concat(call, &CEM_FLAGS);
concat(call, &PP_FLAGS);
append(call, file);
append(call, mkname(kfile, BASE, ".k"));
append(call, mkname(Nfile, BASE, ".N"));
if (runvec(call, (char *)0)) {
file = kfile;
ext = 'k';
if (sizeof_file(Nfile) <= 0L)
remove(Nfile);
}
else {
remove(kfile);
remove(Nfile);
continue;
}
}
/* .e to .k */
if (ext == 'e') {
init(call);
append(call, ENCODE);
concat(call, &ENCODE_FLAGS);
append(call, file);
append(call, mkname(kfile, BASE, ".k"));
if (runvec(call, (char *)0) == 0)
continue;
file = kfile;
ext = 'k';
}
if (FLAG(k))
continue;
/* decode .k or .m */
if (FLAG(e) && (ext == 'k' || ext == 'm')) {
char efile[USTR_SIZE];
init(call);
append(call, DECODE);
concat(call, &DECODE_FLAGS);
append(call, file);
append(call, mkname(efile, BASE, ".e"));
runvec(call, (char *)0);
cleanup(kfile);
continue;
}
/* .k to .m */
if (ext == 'k') {
init(call);
append(call, OPT);
concat(call, &OPT_FLAGS);
append(call, file);
if (runvec(call, mkname(mfile, BASE, ".m")) == 0)
continue;
file = mfile;
ext = 'm';
cleanup(kfile);
}
if (FLAG(m))
continue;
/* .m to .s */
if (ext == 'm') {
init(call);
append(call, CG);
concat(call, &CG_FLAGS);
append(call, file);
append(call, mkname(sfile, BASE, ".s"));
if (runvec(call, (char *)0) == 0)
continue;
if (Nfile[0] != '\0') {
#ifndef MANTRA
init(call);
append(call, AS_FIX);
append(call, Nfile);
append(call, sfile);
runvec(call, (char *)0);
#endif MANTRA
remove(Nfile);
}
cleanup(mfile);
file = sfile;
ext = 's';
}
if (FLAG(S))
continue;
/* .s to .o */
if (ext == 's') {
ldfile = FLAG(c) ?
ofile :
alloc((unsigned)strlen(BASE) + 3);
init(call);
append(call, AS);
concat(call, &AS_FLAGS);
#ifdef MANTRA
append(call, "-");
#endif MANTRA
append(call, "-o");
append(call, mkname(ldfile, BASE, ".o"));
append(call, file);
if (runvec(call, (char *)0) == 0)
continue;
file = ldfile;
ext = 'o';
cleanup(sfile);
}
if (FLAG(c))
continue;
append(&LDFILES, file);
if (ldfile) {
append(&GEN_LDFILES, ldfile);
ldfile = 0;
}
}
/* *.o to a.out */
if (RET_CODE == 0 && LDFILES.al_argc > 0) {
init(call);
append(call, LD);
concat(call, &LD_FLAGS);
append(call, "-o");
#ifndef MANTRA
append(call, o_FILE);
#else MANTRA
append(call, Nc_flag ? o_FILE : cv_FILE);
#endif MANTRA
concat(call, &LD_HEAD);
concat(call, &LDFILES);
concat(call, &LD_TAIL);
if (runvec(call, (char *)0)) {
register i = GEN_LDFILES.al_argc;
while (i-- > 0)
remove(GEN_LDFILES.al_argv[i]);
#ifdef MANTRA
/* convert to local a.out format */
if (Nc_flag == 0) {
init(call);
append(call, CV);
concat(call, &CV_FLAGS);
append(call, cv_FILE);
append(call, o_FILE);
if (runvec(call, (char *)0))
remove(cv_FILE);
}
#endif MANTRA
}
}
exit(RET_CODE);
}
#define BUFSIZE (USTR_SIZE * MAXARGC)
char alloc_buf[BUFSIZE];
char *
alloc(u)
unsigned u;
{
static char *bufptr = &alloc_buf[0];
register char *p = bufptr;
if ((bufptr += u) >= &alloc_buf[BUFSIZE])
panic("no space");
return p;
}
append(al, arg)
register struct arglist *al;
char *arg;
{
if (al->al_argc >= MAXARGC)
panic("argument list overflow");
al->al_argv[(al->al_argc)++] = arg;
}
concat(al1, al2)
struct arglist *al1, *al2;
{
register int i = al2->al_argc;
register char **p = &(al1->al_argv[al1->al_argc]);
register char **q = &(al2->al_argv[0]);
if ((al1->al_argc += i) >= MAXARGC)
panic("argument list overflow");
while (i-- > 0)
*p++ = *q++;
}
/* The next function is a dirty old one, taking a variable number of
arguments.
Take care that the last argument is a null-valued pointer!
*/
/*VARARGS1*/
char *
mkstr(dst, arg)
char *dst, *arg;
{
char **vec = (char **) &arg;
register char *p;
register char *q = dst;
while (p = *vec++) {
while (*q++ = *p++);
q--;
}
return dst;
}
Roption(str)
char *str; /* of the form "prog=/-arg" */
{
char *eq;
char *prog, *arg;
char bc;
char *cindex();
prog = &str[2];
if (eq = cindex(prog, '='))
bc = '=';
else
if (eq = cindex(prog, '-'))
bc = '-';
else {
bad_option(str);
return;
}
*eq++ = '\0';
if (arg = eq) {
char *opt = 0;
struct prog *pp = &ProgParts[0];
if (bc == '-')
opt = mkstr(alloc((unsigned)strlen(arg) + 2),
"-", arg, 0);
while (pp->p_name) {
if (strcmp(prog, pp->p_name) == 0) {
if (opt)
append(pp->p_flags, opt);
else
*(pp->p_task) = arg;
return;
}
pp++;
}
}
bad_option(str);
}
basename(str, dst)
char *str;
register char *dst;
{
register char *p1 = str;
register char *p2 = p1;
while (*p1)
if (*p1++ == '/')
p2 = p1;
p1--;
if (*--p1 == '.') {
*p1 = '\0';
while (*dst++ = *p2++) {}
*p1 = '.';
}
else
while (*dst++ = *p2++) {}
}
int
extension(fn)
register char *fn;
{
char c;
while (*fn++) {}
fn--;
c = *--fn;
return (*--fn == '.') ? c : 0;
}
long
sizeof_file(nm)
char *nm;
{
struct stat stbuf;
if (stat(nm, &stbuf) == 0)
return stbuf.st_size;
return -1;
}
char * sysmsg[] = {
0,
"Hangup",
"Interrupt",
"Quit",
"Illegal instruction",
"Trace/BPT trap",
"IOT trap",
"EMT trap",
"Floating exception",
"Killed",
"Bus error",
"Memory fault",
"Bad system call",
"Broken pipe",
"Alarm call",
"Terminated",
"Signal 16"
};
runvec(vec, outp)
struct arglist *vec;
char *outp;
{
int status, fd;
char *task = vec->al_argv[1];
vec->al_argv[vec->al_argc] = 0;
if (FLAG(v))
print_vec(vec);
if (exec == 0)
return 1;
if (fork() == 0) { /* start up the process */
extern int errno;
if (outp) { /* redirect standard output */
close(1);
if ((fd = creat(outp, 0666)) < 0)
panic("cannot create %s", outp);
if (fd != 1)
panic("illegal redirection");
}
if (debug) report("exec %s", task);
execv(task, &(vec->al_argv[1]));
/* not an a.out file, let's try it with the SHELL */
if (debug) report("try it with %s", SHELL);
if (errno == ENOEXEC) {
vec->al_argv[0] = SHELL;
execv(SHELL, &(vec->al_argv[0]));
}
/* failed, so ... */
panic("cannot execute %s", task);
exit(1);
}
else {
int loworder, highorder, sig;
wait(&status);
loworder = status & 0377;
highorder = (status >> 8) & 0377;
if (loworder == 0) {
if (highorder)
report("%s: exit status %d", task, highorder);
return highorder ? ((RET_CODE = 1), 0) : 1;
}
else {
sig = loworder & 0177;
if (sig == 0177)
report("%s: stopped by ptrace", task);
else
if (sysmsg[sig])
report("%s: %s%s", task, sysmsg[sig],
(loworder & 0200)
? " - core dumped"
: "");
RET_CODE = 1;
return 0;
}
}
/*NOTREACHED*/
}
bad_option(str)
char *str;
{
report("bad option %s", str);
}
/*VARARGS1*/
report(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
char *fmt;
{
fprintf(stderr, "%s: ", ProgCall);
fprintf(stderr, fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
fprintf(stderr, "\n");
}
/*VARARGS1*/
panic(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
char *fmt;
{
fprintf(stderr, "%s: ", ProgCall);
fprintf(stderr, fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
fprintf(stderr, "\n");
exit(1);
}
set_traps(f)
int (*f)();
{
signal(SIGHUP, f);
signal(SIGINT, f);
signal(SIGQUIT, f);
signal(SIGALRM, f);
signal(SIGTERM, f);
}
/*ARGSUSED*/
trap(sig)
{
set_traps(SIG_IGN);
panic("Trapped");
}
print_vec(vec)
struct arglist *vec;
{
register i;
for (i = 1; i < vec->al_argc; i++)
printf("%s ", vec->al_argv[i]);
printf("\n");
}
char *
cindex(s, c)
char *s, c;
{
while (*s)
if (*s++ == c)
return s - 1;
return (char *) 0;
}

View File

@ -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

540
lang/cem/cemcom.ansi/ch7.c Normal file
View File

@ -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;
}
}

View File

@ -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 <alloc.h>
#include "nofloat.h"
#include "lint.h"
#include "idf.h"
#include "arith.h"
#include "type.h"
#include "struct.h"
#include "label.h"
#include "expr.h"
#include "Lpars.h"
#include "noRoption.h"
extern char options[];
extern char *symbol2str();
/* This chapter asks for the repeated application of code to handle
an operation that may be executed at compile time or at run time,
depending on the constancy of the operands.
*/
#define commutative_binop(expp, oper, expr) mk_binop(expp, oper, expr, 1)
#define non_commutative_binop(expp, oper, expr) mk_binop(expp, oper, expr, 0)
ch7bin(expp, oper, expr)
register struct expr **expp;
struct expr *expr;
{
/* apply binary operator oper between *expp and expr.
NB: don't swap operands if op is one of the op= operators!!!
*/
any2opnd(expp, oper);
any2opnd(&expr, oper);
switch (oper) {
case '[': /* RM 7.1 */
/* RM 14.3 states that indexing follows the commutative laws */
switch ((*expp)->ex_type->tp_fund) {
case POINTER:
case ARRAY:
break;
case ERRONEOUS:
return;
default: /* unindexable */
switch (expr->ex_type->tp_fund) {
case POINTER:
case ARRAY:
break;
case ERRONEOUS:
return;
default:
expr_error(*expp,
"indexing an object of type %s",
symbol2str((*expp)->ex_type->tp_fund));
return;
}
break;
}
ch7bin(expp, '+', expr);
ch7mon('*', expp);
break;
case '(': /* RM 7.1 */
if ( (*expp)->ex_type->tp_fund == POINTER &&
(*expp)->ex_type->tp_up->tp_fund == FUNCTION
) {
#ifndef NOROPTION
if (options['R'])
warning("function pointer called");
#endif NOROPTION
ch7mon('*', expp);
}
if ((*expp)->ex_type->tp_fund != FUNCTION) {
expr_error(*expp, "call of non-function (%s)",
symbol2str((*expp)->ex_type->tp_fund));
/* leave the expression; it may still serve */
free_expression(expr); /* there go the parameters */
}
else
*expp = new_oper((*expp)->ex_type->tp_up,
*expp, '(', expr);
(*expp)->ex_flags |= EX_SIDEEFFECTS;
break;
case PARCOMMA: /* RM 7.1 */
if ((*expp)->ex_type->tp_fund == FUNCTION)
function2pointer(*expp);
*expp = new_oper(expr->ex_type, *expp, PARCOMMA, expr);
break;
case '%':
case MODAB:
case ANDAB:
case XORAB:
case ORAB:
opnd2integral(expp, oper);
opnd2integral(&expr, oper);
/* Fall through */
case '/':
case DIVAB:
case TIMESAB:
arithbalance(expp, oper, &expr);
non_commutative_binop(expp, oper, expr);
break;
case '&':
case '^':
case '|':
opnd2integral(expp, oper);
opnd2integral(&expr, oper);
/* Fall through */
case '*':
arithbalance(expp, oper, &expr);
commutative_binop(expp, oper, expr);
break;
case '+':
if (expr->ex_type->tp_fund == POINTER) { /* swap operands */
struct expr *etmp = expr;
expr = *expp;
*expp = etmp;
}
/*FALLTHROUGH*/
case PLUSAB:
case POSTINCR:
case PLUSPLUS:
if ((*expp)->ex_type->tp_fund == POINTER) {
pointer_arithmetic(expp, oper, &expr);
if (expr->ex_type->tp_size != (*expp)->ex_type->tp_size)
ch7cast(&expr, CAST, (*expp)->ex_type);
pointer_binary(expp, oper, expr);
}
else {
arithbalance(expp, oper, &expr);
if (oper == '+')
commutative_binop(expp, oper, expr);
else
non_commutative_binop(expp, oper, expr);
}
break;
case '-':
case MINAB:
case POSTDECR:
case MINMIN:
if ((*expp)->ex_type->tp_fund == POINTER) {
if (expr->ex_type->tp_fund == POINTER)
pntminuspnt(expp, oper, expr);
else {
pointer_arithmetic(expp, oper, &expr);
pointer_binary(expp, oper, expr);
}
}
else {
arithbalance(expp, oper, &expr);
non_commutative_binop(expp, oper, expr);
}
break;
case LEFT:
case RIGHT:
case LEFTAB:
case RIGHTAB:
opnd2integral(expp, oper);
opnd2integral(&expr, oper);
arithbalance(expp, oper, &expr); /* ch. 7.5 */
ch7cast(&expr, oper, int_type); /* cvt. rightop to int */
non_commutative_binop(expp, oper, expr);
break;
case '<':
case '>':
case LESSEQ:
case GREATEREQ:
case EQUAL:
case NOTEQUAL:
relbalance(expp, oper, &expr);
non_commutative_binop(expp, oper, expr);
(*expp)->ex_type = int_type;
break;
case AND:
case OR:
opnd2test(expp, oper);
opnd2test(&expr, oper);
if (is_cp_cst(*expp)) {
register struct expr *ex = *expp;
/* the following condition is a short-hand for
((oper == AND) && o1) || ((oper == OR) && !o1)
where o1 == (*expp)->VL_VALUE;
and ((oper == AND) || (oper == OR))
*/
if ((oper == AND) == (ex->VL_VALUE != (arith)0))
*expp = expr;
else {
ex->ex_flags |= expr->ex_flags;
free_expression(expr);
*expp = intexpr((arith)((oper == AND) ? 0 : 1),
INT);
}
(*expp)->ex_flags |= ex->ex_flags;
free_expression(ex);
}
else
if (is_cp_cst(expr)) {
/* Note!!!: the following condition is a short-hand for
((oper == AND) && o2) || ((oper == OR) && !o2)
where o2 == expr->VL_VALUE
and ((oper == AND) || (oper == OR))
*/
if ((oper == AND) == (expr->VL_VALUE != (arith)0)) {
(*expp)->ex_flags |= expr->ex_flags;
free_expression(expr);
}
else {
if (oper == OR)
expr->VL_VALUE = (arith)1;
ch7bin(expp, ',', expr);
}
}
else
*expp = new_oper(int_type, *expp, oper, expr);
(*expp)->ex_flags |= EX_LOGICAL;
break;
case ':':
if ( is_struct_or_union((*expp)->ex_type->tp_fund)
|| is_struct_or_union(expr->ex_type->tp_fund)
) {
if (!equal_type((*expp)->ex_type, expr->ex_type))
expr_error(*expp, "illegal balance");
}
else
relbalance(expp, oper, &expr);
#ifdef LINT
if ( (is_cp_cst(*expp) && is_cp_cst(expr))
&& (*expp)->VL_VALUE == expr->VL_VALUE
) {
hwarning("operands of : are constant and equal");
}
#endif LINT
*expp = new_oper((*expp)->ex_type, *expp, oper, expr);
break;
case '?':
opnd2logical(expp, oper);
if (is_cp_cst(*expp)) {
#ifdef LINT
hwarning("condition in ?: expression is constant");
#endif LINT
*expp = (*expp)->VL_VALUE ?
expr->OP_LEFT : expr->OP_RIGHT;
}
else {
*expp = new_oper(expr->ex_type, *expp, oper, expr);
}
break;
case ',':
if (is_cp_cst(*expp))
*expp = expr;
else
*expp = new_oper(expr->ex_type, *expp, oper, expr);
(*expp)->ex_flags |= EX_COMMA;
break;
}
}
pntminuspnt(expp, oper, expr)
register struct expr **expp, *expr;
{
/* Subtracting two pointers is so complicated it merits a
routine of its own.
*/
struct type *up_type = (*expp)->ex_type->tp_up;
if (!equal_type(up_type, expr->ex_type->tp_up)) {
expr_error(*expp, "subtracting incompatible pointers");
free_expression(expr);
erroneous2int(expp);
return;
}
/* we hope the optimizer will eliminate the load-time
pointer subtraction
*/
*expp = new_oper((*expp)->ex_type, *expp, oper, expr);
ch7cast(expp, CAST, pa_type); /* ptr-ptr: result has pa_type */
ch7bin(expp, '/',
intexpr(size_of_type(up_type, "object"), pa_type->tp_fund));
ch7cast(expp, CAST, int_type); /* result will be an integer expr */
}
mk_binop(expp, oper, expr, commutative)
struct expr **expp;
register struct expr *expr;
{
/* Constructs in *expp the operation indicated by the operands.
"commutative" indicates whether "oper" is a commutative
operator.
*/
register struct expr *ex = *expp;
if (is_cp_cst(expr) && is_cp_cst(ex))
cstbin(expp, oper, expr);
else {
*expp = (commutative && expr->ex_depth >= ex->ex_depth) ?
new_oper(ex->ex_type, expr, oper, ex) :
new_oper(ex->ex_type, ex, oper, expr);
}
}
pointer_arithmetic(expp1, oper, expp2)
register struct expr **expp1, **expp2;
{
/* prepares the integral expression expp2 in order to
apply it to the pointer expression expp1
*/
#ifndef NOFLOAT
if (any2arith(expp2, oper) == DOUBLE) {
expr_error(*expp2,
"illegal combination of float and pointer");
erroneous2int(expp2);
}
#endif NOFLOAT
ch7bin( expp2, '*',
intexpr(size_of_type((*expp1)->ex_type->tp_up, "object"),
pa_type->tp_fund)
);
}
pointer_binary(expp, oper, expr)
register struct expr **expp, *expr;
{
/* constructs the pointer arithmetic expression out of
a pointer expression, a binary operator and an integral
expression.
*/
if (is_ld_cst(expr) && is_ld_cst(*expp))
cstbin(expp, oper, expr);
else
*expp = new_oper((*expp)->ex_type, *expp, oper, expr);
}

View File

@ -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 <alloc.h>
#include "nofloat.h"
#include "nobitfield.h"
#include "Lpars.h"
#include "arith.h"
#include "type.h"
#include "label.h"
#include "expr.h"
#include "idf.h"
#include "def.h"
extern char options[];
extern long full_mask[/*MAXSIZE*/]; /* cstoper.c */
char *symbol2str();
ch7mon(oper, expp)
register struct expr **expp;
{
/* The monadic prefix operator oper is applied to *expp.
*/
register struct expr *expr;
switch (oper) {
case '*': /* RM 7.2 */
/* no FIELD type allowed */
if ((*expp)->ex_type->tp_fund == ARRAY)
array2pointer(*expp);
if ((*expp)->ex_type->tp_fund != POINTER) {
expr_error(*expp,
"* applied to non-pointer (%s)",
symbol2str((*expp)->ex_type->tp_fund));
}
else {
expr = *expp;
if (expr->ex_lvalue == 0 && expr->ex_class != String)
/* dereference in administration only */
expr->ex_type = expr->ex_type->tp_up;
else /* runtime code */
*expp = new_oper(expr->ex_type->tp_up, NILEXPR,
'*', expr);
(*expp)->ex_lvalue = (
(*expp)->ex_type->tp_fund != ARRAY &&
(*expp)->ex_type->tp_fund != FUNCTION
);
if ((*expp)->ex_type->tp_typequal & TQ_CONST)
(*expp)->ex_flags |= EX_READONLY;
if ((*expp)->ex_type->tp_typequal & TQ_VOLATILE)
(*expp)->ex_flags |= EX_VOLATILE;
}
break;
case '&':
if ((*expp)->ex_type->tp_fund == ARRAY) {
warning("& before array ignored");
array2pointer(*expp);
}
else
if ((*expp)->ex_type->tp_fund == FUNCTION) {
warning("& before function ignored");
function2pointer(*expp);
}
else
#ifndef NOBITFIELD
if ((*expp)->ex_type->tp_fund == FIELD)
expr_error(*expp, "& applied to field variable");
else
#endif NOBITFIELD
if (!(*expp)->ex_lvalue)
expr_error(*expp, "& applied to non-lvalue");
else {
/* assume that enums are already filtered out */
if (ISNAME(*expp)) {
register struct def *def =
(*expp)->VL_IDF->id_def;
/* &<var> indicates that <var>
cannot be used as register
anymore
*/
if (def->df_sc == REGISTER) {
expr_error(*expp,
"& on register variable not allowed");
break; /* break case '&' */
}
}
(*expp)->ex_type = pointer_to((*expp)->ex_type);
(*expp)->ex_lvalue = 0;
(*expp)->ex_flags &= ~EX_READONLY;
}
break;
case '~':
#ifndef NOFLOAT
{
int fund = (*expp)->ex_type->tp_fund;
if (fund == FLOAT || fund == DOUBLE) {
expr_error(
*expp,
"~ not allowed on %s operands",
symbol2str(fund)
);
erroneous2int(expp);
break;
}
/* FALLTHROUGH */
}
#endif NOFLOAT
case '-':
any2arith(expp, oper);
if (is_cp_cst(*expp)) {
arith o1 = (*expp)->VL_VALUE;
(*expp)->VL_VALUE = (oper == '-') ? -o1 :
((*expp)->ex_type->tp_unsigned ?
(~o1) & full_mask[(*expp)->ex_type->tp_size] :
~o1
);
}
else
#ifndef NOFLOAT
if (is_fp_cst(*expp))
switch_sign_fp(*expp);
else
#endif NOFLOAT
*expp = new_oper((*expp)->ex_type,
NILEXPR, oper, *expp);
break;
case '!':
if ((*expp)->ex_type->tp_fund == FUNCTION)
function2pointer(*expp);
if ((*expp)->ex_type->tp_fund != POINTER)
any2arith(expp, oper);
opnd2test(expp, '!');
if (is_cp_cst(*expp)) {
(*expp)->VL_VALUE = !((*expp)->VL_VALUE);
(*expp)->ex_type = int_type; /* a cast ???(EB) */
}
else
*expp = new_oper(int_type, NILEXPR, oper, *expp);
(*expp)->ex_flags |= EX_LOGICAL;
break;
case PLUSPLUS:
case MINMIN:
ch7incr(expp, oper);
break;
case SIZEOF:
if (ISNAME(*expp) && (*expp)->VL_IDF->id_def->df_formal_array)
warning("sizeof formal array %s is sizeof pointer!",
(*expp)->VL_IDF->id_text);
expr = intexpr((*expp)->ex_class == String ?
(arith)((*expp)->SG_LEN) :
size_of_type((*expp)->ex_type, "object"),
INT);
expr->ex_flags |= EX_SIZEOF;
free_expression(*expp);
*expp = expr;
break;
}
}

View File

@ -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};

View File

@ -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[];

657
lang/cem/cemcom.ansi/code.c Normal file
View File

@ -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 <em.h>
#include "botch_free.h"
#include <alloc.h>
#include "dataflow.h"
#include "use_tmp.h"
#include "arith.h"
#include "type.h"
#include "idf.h"
#include "label.h"
#include "code.h"
#include "stmt.h"
#include "def.h"
#include "expr.h"
#include "sizes.h"
#include "stack.h"
#include "level.h"
#include "decspecs.h"
#include "declar.h"
#include "Lpars.h"
#include "specials.h"
#include "atw.h"
#include "assert.h"
#include "noRoption.h"
#include "file_info.h"
#ifdef LINT
#include "l_lint.h"
#endif LINT
label lab_count = 1;
label datlab_count = 1;
#ifndef NOFLOAT
int fp_used;
#endif NOFLOAT
/* global function info */
char *func_name;
struct type *func_type;
int func_notypegiven;
#ifdef USE_TMP
static int tmp_id;
static int pro_id;
#endif USE_TMP
extern char options[];
extern char *symbol2str();
#ifndef LINT
init_code(dst_file)
char *dst_file;
{
/* init_code() initialises the output file on which the
compact EM code is written
*/
C_init(word_size, pointer_size); /* initialise EM module */
if (C_open(dst_file) == 0)
fatal("cannot write to %s\n", dst_file);
C_magic();
C_ms_emx(word_size, pointer_size);
#ifdef USE_TMP
#ifdef PREPEND_SCOPES
C_insertpart(tmp_id = C_getid());
#endif USE_TMP
#endif PREPEND_SCOPES
}
#endif LINT
struct string_cst *str_list = 0;
code_string(val, len, dlb)
char *val;
int len;
label dlb;
{
register struct string_cst *sc = new_string_cst();
C_ina_dlb(dlb);
sc->next = str_list;
str_list = sc;
sc->sc_value = val;
sc->sc_len = len;
sc->sc_dlb = dlb;
}
def_strings(sc)
register struct string_cst *sc;
{
while (sc) {
struct string_cst *sc1 = sc;
C_df_dlb(sc->sc_dlb);
str_cst(sc->sc_value, sc->sc_len);
sc = sc->next;
free_string_cst(sc1);
}
}
end_code()
{
/* end_code() performs the actions to be taken when closing
the output stream.
*/
#ifndef NOFLOAT
if (fp_used) {
/* floating point used */
C_ms_flt();
}
#endif NOFLOAT
def_strings(str_list);
str_list = 0;
C_ms_src((int)(LineNumber - 2), FileName);
C_close();
}
#ifdef PREPEND_SCOPES
prepend_scopes()
{
/* prepend_scopes() runs down the list of global idf's
and generates those exa's, exp's, ina's and inp's
that superior hindsight has provided.
*/
register struct stack_entry *se = local_level->sl_entry;
#ifdef USE_TMP
C_beginpart(tmp_id);
#endif USE_TMP
while (se != 0) {
register struct idf *id = se->se_idf;
register struct def *df = id->id_def;
if (df && (df->df_initialized || df->df_used || df->df_alloc))
code_scope(id->id_text, df);
se = se->next;
}
#ifdef USE_TMP
C_endpart(tmp_id);
#endif USE_TMP
}
#endif PREPEND_SCOPES
code_scope(text, def)
char *text;
register struct def *def;
{
/* generates code for one name, text, of the storage class
as given by def, if meaningful.
*/
int fund = def->df_type->tp_fund;
switch (def->df_sc) {
case EXTERN:
case GLOBAL:
case IMPLICIT:
if (fund == FUNCTION)
C_exp(text);
else
C_exa_dnam(text);
break;
case STATIC:
if (fund == FUNCTION)
C_inp(text);
else
C_ina_dnam(text);
break;
}
}
static label return_label, return2_label;
static char return_expr_occurred;
static arith func_size;
static label func_res_label;
static char *last_fn_given = "";
static label file_name_label;
begin_proc(ds, idf) /* to be called when entering a procedure */
struct decspecs *ds;
struct idf *idf;
{
/* begin_proc() is called at the entrance of a new function
and performs the necessary code generation:
- a scope indicator (if needed) exp/inp
- the procedure entry pro $name
- reserves some space if the result of the function
does not fit in the return area
- a fil pseudo instruction
*/
register char *name = idf->id_text;
register struct def *def = idf->id_def;
#ifndef PREPEND_SCOPES
code_scope(name, def);
#endif PREPEND_SCOPES
#ifdef DATAFLOW
if (options['d'])
DfaStartFunction(name);
#endif DATAFLOW
/* set global function info */
func_name = name;
if (def->df_type->tp_fund != FUNCTION) {
error("making function body for non-function");
func_type = error_type;
}
else {
func_type = def->df_type->tp_up;
}
func_notypegiven = ds->ds_notypegiven;
func_size = ATW(func_type->tp_size);
#ifndef USE_TMP
C_pro_narg(name);
#else
C_insertpart(pro_id = C_getid());
#endif
if (is_struct_or_union(func_type->tp_fund)) {
C_df_dlb(func_res_label = data_label());
C_bss_cst(func_size, (arith)0, 1);
}
else
func_res_label = 0;
/* Special arrangements if the function result doesn't fit in
the function return area of the EM machine. The size of
the function return area is implementation dependent.
*/
lab_count = (label) 1;
return_label = text_label();
return2_label = text_label();
return_expr_occurred = 0;
LocalInit();
prc_entry(name);
if (! options['L']) { /* profiling */
if (strcmp(last_fn_given, FileName) != 0) {
/* previous function came from other file */
C_df_dlb(file_name_label = data_label());
C_con_scon(last_fn_given = FileName,
(arith)(strlen(FileName) + 1));
}
/* enable debug trace of EM source */
C_fil_dlb(file_name_label, (arith)0);
C_lin((arith)LineNumber);
}
}
end_proc(fbytes)
arith fbytes;
{
/* end_proc() deals with the code to be generated at the end of
a function, as there is:
- the EM ret instruction: "ret 0"
- loading of the function result in the function
result area if there has been a return <expr>
in the function body (see do_return_expr())
- indication of the use of floating points
- indication of the number of bytes used for
formal parameters
- use of special identifiers such as "setjmp"
- "end" + number of bytes used for local variables
*/
arith nbytes;
char optionsn = options['n'];
#ifdef DATAFLOW
if (options['d'])
DfaEndFunction();
#endif DATAFLOW
C_df_ilb(return2_label);
if (return_expr_occurred) C_asp(-func_size);
C_df_ilb(return_label);
prc_exit();
#ifndef LINT
if (return_expr_occurred) {
if (func_res_label != 0) {
C_lae_dlb(func_res_label, (arith)0);
store_block(func_size, func_type->tp_align);
C_lae_dlb(func_res_label, (arith)0);
C_ret(pointer_size);
}
else
C_ret(func_size);
}
else C_ret((arith) 0);
#endif LINT
/* getting the number of "local" bytes is posponed until here,
because copying the function result in "func_res_label" may
need temporaries! However, local_level is now L_FORMAL2, because
L_LOCAL is already unstacked. Therefore, "unstack_level" must
also pass "sl_max_block" to the level above L_LOCAL.
*/
nbytes = ATW(- local_level->sl_max_block);
#ifdef USE_TMP
C_beginpart(pro_id);
C_pro(func_name, nbytes);
#endif
if (fbytes > max_int) {
error("%s has more than %ld parameter bytes",
func_name, (long) max_int);
}
C_ms_par(fbytes); /* # bytes for formals */
if (sp_occurred[SP_SETJMP]) { /* indicate use of "setjmp" */
options['n'] = 1;
C_ms_gto();
sp_occurred[SP_SETJMP] = 0;
}
#ifdef USE_TMP
C_endpart(pro_id);
#endif
LocalFinish();
C_end(nbytes);
if (nbytes > max_int) {
error("%s has more than %ld bytes of local variables",
func_name, (long) max_int);
}
options['n'] = optionsn;
}
do_return()
{
/* do_return handles the case of a return without expression.
This version branches to the return label, which is
probably smarter than generating a direct return.
Return sequences may be expensive.
*/
C_bra(return2_label);
}
do_return_expr(expr)
struct expr *expr;
{
/* do_return_expr() generates the expression and the jump for
a return statement with an expression.
*/
ch7cast(&expr, RETURN, func_type);
code_expr(expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
C_bra(return_label);
return_expr_occurred = 1;
}
code_declaration(idf, expr, lvl, sc)
register struct idf *idf; /* idf to be declared */
struct expr *expr; /* initialisation; NULL if absent */
int lvl; /* declaration level */
int sc; /* storage class, as in the declaration */
{
/* code_declaration() does the actual declaration of the
variable indicated by "idf" on declaration level "lvl".
If the variable is initialised, the expression is given
in "expr", but for global and static initialisations it
is just non-zero, as the expression is not parsed yet.
There are some cases to be considered:
- filter out typedefs, they don't correspond to code;
- global variables, coded only if initialized;
- local static variables;
- local automatic variables;
Since the expression may be modified in the process,
code_declaration() frees it after use, as the caller can
no longer do so.
If there is a storage class indication (EXTERN/STATIC),
code_declaration() will generate an exa or ina.
The sc is the actual storage class, as given in the
declaration. This is to allow:
extern int a;
int a = 5;
while at the same time forbidding
extern int a = 5;
*/
register struct def *def = idf->id_def;
register arith size = def->df_type->tp_size;
int def_sc = def->df_sc;
if (def_sc == TYPEDEF) /* no code for typedefs */
return;
if (sc == EXTERN && expr && !is_anon_idf(idf))
error("%s is extern; cannot initialize", idf->id_text);
#ifndef PREPEND_SCOPES
if (def->df_type->tp_fund == FUNCTION) {
code_scope(idf->id_text, def);
}
#endif PREPEND_SCOPES
if (lvl == L_GLOBAL) { /* global variable */
/* is this an allocating declaration? */
if ( (sc == 0 || sc == STATIC)
&& def->df_type->tp_fund != FUNCTION
&& size >= 0
)
def->df_alloc = ALLOC_SEEN;
if (expr) { /* code only if initialized */
#ifndef PREPEND_SCOPES
code_scope(idf->id_text, def);
#endif PREPEND_SCOPES
def->df_alloc = ALLOC_DONE;
C_df_dnam(idf->id_text);
}
}
else
if (lvl >= L_LOCAL) { /* local variable */
/* STATIC, EXTERN, GLOBAL, IMPLICIT, AUTO or REGISTER */
switch (def_sc) {
case STATIC:
if (def->df_type->tp_fund == FUNCTION) {
/* should produce "inp $function" ??? */
break;
}
/* they are handled on the spot and get an
integer label in EM.
*/
C_df_dlb((label)def->df_address);
if (expr) { /* there is an initialisation */
}
else { /* produce blank space */
if (size <= 0) {
error("size of %s unknown", idf->id_text);
size = (arith)0;
}
C_bss_cst(ATW(size), (arith)0, 1);
}
break;
case EXTERN:
case GLOBAL:
case IMPLICIT:
/* we are sure there is no expression */
#ifndef PREPEND_SCOPES
code_scope(idf->id_text, def);
#endif PREPEND_SCOPES
break;
case AUTO:
case REGISTER:
if (expr)
loc_init(expr, idf);
break;
default:
crash("bad local storage class");
/*NOTREACHED*/
}
}
}
loc_init(expr, id)
struct expr *expr;
register struct idf *id;
{
/* loc_init() generates code for the assignment of
expression expr to the local variable described by id.
It frees the expression afterwards.
*/
register struct expr *e = expr;
register struct type *tp = id->id_def->df_type;
ASSERT(id->id_def->df_sc != STATIC);
switch (tp->tp_fund) {
case ARRAY:
case STRUCT:
case UNION:
error("automatic %s cannot be initialized in declaration",
symbol2str(tp->tp_fund));
free_expression(e);
return;
}
if (ISCOMMA(e)) { /* embraced: int i = {12}; */
#ifndef NOROPTION
if (options['R']) {
if (ISCOMMA(e->OP_LEFT)) /* int i = {{1}} */
expr_error(e, "extra braces not allowed");
else
if (e->OP_RIGHT != 0) /* int i = {1 , 2} */
expr_error(e, "too many initializers");
}
#endif NOROPTION
while (e) {
loc_init(e->OP_LEFT, id);
e = e->OP_RIGHT;
}
}
else { /* not embraced */
ch7cast(&expr, '=', tp); /* may modify expr */
#ifndef LINT
{
struct value vl;
EVAL(expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
vl.vl_class = Name;
vl.vl_data.vl_idf = id;
vl.vl_value = (arith)0;
store_val(&vl, tp);
}
#else LINT
id->id_def->df_set = 1;
#endif LINT
free_expression(expr);
}
}
bss(idf)
register struct idf *idf;
{
/* bss() allocates bss space for the global idf.
*/
arith size = idf->id_def->df_type->tp_size;
#ifndef PREPEND_SCOPES
code_scope(idf->id_text, idf->id_def);
#endif PREPEND_SCOPES
/* Since bss() is only called if df_alloc is non-zero, and
since df_alloc is only non-zero if size >= 0, we have:
*/
/* but we already gave a warning at the declaration of the
array. Besides, the message given here does not apply to
voids
if (options['R'] && size == 0)
warning("actual array of size 0");
*/
C_df_dnam(idf->id_text);
C_bss_cst(ATW(size), (arith)0, 1);
}
formal_cvt(df)
register struct def *df;
{
/* formal_cvt() converts a formal parameter of type char or
short from int to that type.
*/
register struct type *tp = df->df_type;
if (tp->tp_size != int_size &&
(tp->tp_fund == CHAR || tp->tp_fund == SHORT)
) {
LoadLocal(df->df_address, int_size);
/* conversion(int_type, df->df_type); ???
No, you can't do this on the stack! (CJ)
*/
StoreLocal(df->df_address, tp->tp_size);
}
}
#ifdef LINT
/*ARGSUSED*/
#endif LINT
code_expr(expr, val, code, tlbl, flbl)
struct expr *expr;
label tlbl, flbl;
{
/* code_expr() is the parser's interface to the expression code
generator. If line number trace is wanted, it generates a
lin instruction. EVAL() is called directly.
*/
#ifndef LINT
if (! options['L']) /* profiling */
C_lin((arith)(expr->ex_line));
/* HERE WE SHOULD GENERATE A MESSAGE:
if (expr->ex_flags & EX_VOLATILE)
HANDS_OFF
*/
EVAL(expr, val, code, tlbl, flbl);
#else LINT
lint_expr(expr, code ? USED : IGNORED);
#endif LINT
}
/* The FOR/WHILE/DO/SWITCH stacking mechanism:
stack_stmt() has to be called at the entrance of a
for, while, do or switch statement to indicate the
EM labels where a subsequent break or continue causes
the program to jump to.
*/
static struct stmt_block *stmt_stack; /* top of statement stack */
/* code_break() generates EM code needed at the occurrence of "break":
it generates a branch instruction to the break label of the
innermost statement in which break has a meaning.
As "break" is legal in any of 'while', 'do', 'for' or 'switch',
which are the only ones that are stacked, only the top of
the stack is interesting.
*/
code_break()
{
register struct stmt_block *stmt_block = stmt_stack;
if (stmt_block)
C_bra(stmt_block->st_break);
else
error("break not inside for, while, do or switch");
}
/* code_continue() generates EM code needed at the occurrence of
"continue":
it generates a branch instruction to the continue label of the
innermost statement in which continue has a meaning.
*/
code_continue()
{
register struct stmt_block *stmt_block = stmt_stack;
while (stmt_block) {
if (stmt_block->st_continue) {
C_bra(stmt_block->st_continue);
return;
}
stmt_block = stmt_block->next;
}
error("continue not inside for, while or do");
}
stack_stmt(break_label, cont_label)
label break_label, cont_label;
{
register struct stmt_block *stmt_block = new_stmt_block();
stmt_block->next = stmt_stack;
stmt_block->st_break = break_label;
stmt_block->st_continue = cont_label;
stmt_stack = stmt_block;
}
unstack_stmt()
{
/* unstack_stmt() unstacks the data of a statement
which may contain break or continue
*/
register struct stmt_block *sbp = stmt_stack;
stmt_stack = sbp->next;
free_stmt_block(sbp);
}
static label prc_name;
prc_entry(name)
char *name;
{
if (options['p']) {
C_df_dlb(prc_name = data_label());
C_rom_scon(name, (arith) (strlen(name) + 1));
C_lae_dlb(prc_name, (arith) 0);
C_cal("procentry");
C_asp(pointer_size);
}
}
prc_exit()
{
if (options['p']) {
C_lae_dlb(prc_name, (arith) 0);
C_cal("procexit");
C_asp(pointer_size);
}
}

View File

@ -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

View File

@ -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 <em.h>
#include "arith.h"
#include "type.h"
#include "sizes.h"
#include "Lpars.h"
#define T_SIGNED 1
#define T_UNSIGNED 2
#ifndef NOFLOAT
#define T_FLOATING 3
#endif NOFLOAT
/* conversion() generates the EM code for a conversion between
the types char, short, int, long, float, double and pointer.
There are three conversion types: signed, unsigned and floating.
The EM code to obtain this conversion looks like:
LOC sizeof(from_type)
LOC sizeof(to_type)
C??
*/
static int convtype();
conversion(from_type, to_type)
register struct type *from_type, *to_type;
{
register arith from_size = from_type->tp_size;
register arith to_size = to_type->tp_size;
int from_cnvtype = convtype(from_type);
int to_cnvtype = convtype(to_type);
if ((int)to_size < (int)word_size) to_size = word_size;
if ((int)from_size == (int)to_size && from_cnvtype == to_cnvtype)
return;
switch (from_cnvtype) {
case T_SIGNED:
switch (to_cnvtype) {
case T_SIGNED:
C_loc(from_size);
C_loc(to_size);
C_cii();
break;
case T_UNSIGNED:
#ifndef NOFLOAT
case T_FLOATING:
#endif NOOFLOAT
if ((int)from_size < (int)word_size) {
C_loc(from_size);
C_loc(word_size);
C_cii();
from_size = word_size;
}
C_loc(from_size);
C_loc(to_size);
if (to_cnvtype == T_UNSIGNED) C_ciu();
else C_cif();
break;
}
break;
case T_UNSIGNED:
if ((int)from_size < (int)word_size) from_size = word_size;
C_loc(from_size);
C_loc(to_size);
switch (to_cnvtype) {
case T_SIGNED:
C_cui();
break;
case T_UNSIGNED:
C_cuu();
break;
#ifndef NOFLOAT
case T_FLOATING:
C_cuf();
break;
#endif NOFLOAT
}
break;
#ifndef NOFLOAT
case T_FLOATING:
C_loc(from_size);
C_loc(to_size);
switch (to_cnvtype) {
case T_SIGNED:
C_cfi();
break;
case T_UNSIGNED:
C_cfu();
break;
case T_FLOATING:
C_cff();
break;
}
break;
#endif NOFLOAT
default:
crash("(conversion) illegal type conversion");
/*NOTREACHED*/
}
if ((int)(to_type->tp_size) < (int)word_size
#ifndef NOFLOAT
&& to_cnvtype != T_FLOATING
#endif NOFLOAT
) {
extern long full_mask[];
if (to_cnvtype == T_SIGNED) {
C_loc(to_type->tp_size);
C_loc(word_size);
C_cii();
}
else {
C_loc((arith) full_mask[(int)(to_type->tp_size)]);
C_and(word_size);
}
}
}
/* convtype() returns in which category a given type falls:
signed, unsigned or floating
*/
static int
convtype(tp)
register struct type *tp;
{
switch (tp->tp_fund) {
case GENERIC:
case CHAR:
case SHORT:
case INT:
case ERRONEOUS:
case LONG:
case ENUM:
return tp->tp_unsigned ? T_UNSIGNED : T_SIGNED;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
case LNGDBL:
return T_FLOATING;
#endif NOFLOAT
case POINTER:
return T_UNSIGNED;
}
return 0;
}
#endif LINT

View File

@ -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];
}

View File

@ -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

View File

@ -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 <alloc.h>
#include "nobitfield.h"
#include "debug.h"
#include "arith.h"
#include "LLlex.h"
#include "label.h"
#include "code.h"
#include "idf.h"
#include "type.h"
#include "proto.h"
#include "struct.h"
#include "field.h"
#include "decspecs.h"
#include "def.h"
#include "declar.h"
#include "label.h"
#include "expr.h"
#include "sizes.h"
#include "level.h"
#ifdef LINT
#include "l_lint.h"
#include "l_state.h"
#endif LINT
}
/* 8 */
declaration
{struct decspecs Ds;}
:
{Ds = null_decspecs;}
decl_specifiers(&Ds)
init_declarator_list(&Ds)?
';'
;
/* A `decl_specifiers' describes a sequence of a storage_class_specifier,
an unsigned_specifier, a size_specifier and a simple type_specifier,
which may occur in arbitrary order and each of which may be absent;
at least one of them must be present, however, since the totally
empty case has already be dealt with in `external_definition'.
This means that something like:
unsigned extern int short xx;
is perfectly good C.
On top of that, multiple occurrences of storage_class_specifiers,
unsigned_specifiers and size_specifiers are errors, but a second
type_specifier should end the decl_specifiers and be treated as
the name to be declared (see the thin ice in RM11.1).
Such a language is not easily expressed in a grammar; enumeration
of the permutations is unattractive. We solve the problem by
having a regular grammar for the "soft" items, handling the single
occurrence of the type_specifier in the grammar (we have no choice),
collecting all data in a `struct decspecs' and turning that data
structure into what we want.
The existence of declarations like
short typedef yepp;
makes all hope of writing a specific grammar for typedefs illusory.
*/
decl_specifiers /* non-empty */ (register struct decspecs *ds;)
/* Reads a non-empty decl_specifiers and fills the struct
decspecs *ds.
*/
:
[
other_specifier(ds)+
[%if (DOT != IDENTIFIER || AHEAD == IDENTIFIER)
/* the thin ice in R.M. 11.1 */
single_type_specifier(ds) other_specifier(ds)*
|
empty
]
|
single_type_specifier(ds) other_specifier(ds)*
]
{do_decspecs(ds);}
;
/* 8.1 */
other_specifier(register struct decspecs *ds;)
:
[ AUTO | STATIC | EXTERN | TYPEDEF | REGISTER ]
{ if (ds->ds_sc_given)
error("repeated storage class specifier");
ds->ds_sc_given = 1;
ds->ds_sc = DOT;
}
|
[ SHORT | LONG ]
{ if (ds->ds_size)
error("repeated size specifier");
ds->ds_size = DOT;
}
|
[ SIGNED | UNSIGNED ]
{ if (ds->ds_unsigned != 0)
error("repeated sign specifier");
ds->ds_unsigned = DOT;
}
|
/* This qualifier applies to the top type.
E.g. const float * is a pointer to const float.
*/
[ VOLATILE | CONST ]
{ if (DOT == VOLATILE) {
if (ds->ds_typequal & TQ_VOLATILE)
error("repeated type qualifier");
ds->ds_typequal |= TQ_VOLATILE;
}
if (DOT == CONST) {
if (ds->ds_typequal & TQ_CONST)
error("repeated type qualifier");
ds->ds_typequal |= TQ_CONST;
}
}
;
/* 8.2 */
type_specifier(struct type **tpp;)
/* Used in struct/union declarations and in casts; only the
type is relevant.
*/
{struct decspecs Ds; Ds = null_decspecs;}
:
decl_specifiers(&Ds)
{
if (Ds.ds_sc_given)
error("storage class ignored");
if (Ds.ds_sc == REGISTER)
error("register ignored");
}
{*tpp = Ds.ds_type;}
;
single_type_specifier(register struct decspecs *ds;):
%default TYPE_IDENTIFIER /* this includes INT, CHAR, etc. */
{idf2type(dot.tk_idf, &ds->ds_type);}
|
IDENTIFIER
{
error("%s is not a type identifier", dot.tk_idf->id_text);
ds->ds_type = error_type;
if (dot.tk_idf->id_def) {
dot.tk_idf->id_def->df_type = error_type;
dot.tk_idf->id_def->df_sc = TYPEDEF;
}
}
|
struct_or_union_specifier(&ds->ds_type)
|
enum_specifier(&ds->ds_type)
;
/* 8.3 */
init_declarator_list(struct decspecs *ds;):
init_declarator(ds)
[ ',' init_declarator(ds) ]*
;
init_declarator(register struct decspecs *ds;)
{
struct declarator Dc;
}
:
{
Dc = null_declarator;
}
[
declarator(&Dc)
{
reject_params(&Dc);
declare_idf(ds, &Dc, level);
#ifdef LINT
lint_declare_idf(Dc.dc_idf, ds->ds_sc);
#endif LINT
}
[
initializer(Dc.dc_idf, ds->ds_sc)
|
{ code_declaration(Dc.dc_idf, (struct expr *) 0, level, ds->ds_sc); }
]
]
{
#ifdef LINT
add_auto(Dc.dc_idf);
#endif LINT
remove_declarator(&Dc);
}
;
/* 8.6: initializer */
initializer(struct idf *idf; int sc;)
{
struct expr *expr = (struct expr *) 0;
int globalflag = level == L_GLOBAL ||
(level >= L_LOCAL && sc == STATIC);
}
:
{ if (idf->id_def->df_type->tp_fund == FUNCTION) {
error("illegal initialization of function");
idf->id_def->df_type->tp_fund = ERRONEOUS;
}
}
'='
{
#ifdef LINT
lint_statement();
#endif LINT
if (globalflag) {
struct expr ex;
code_declaration(idf, &ex, level, sc);
}
}
initial_value(globalflag ? &(idf->id_def->df_type) : (struct type **)0,
&expr)
{ if (! globalflag) {
if (idf->id_def->df_type->tp_fund == FUNCTION) {
free_expression(expr);
expr = 0;
}
#ifdef DEBUG
print_expr("initializer-expression", expr);
#endif DEBUG
#ifdef LINT
change_state(idf, SET);
#endif LINT
code_declaration(idf, expr, level, sc);
}
init_idf(idf);
}
;
/*
Functions yielding pointers to functions must be declared as, e.g.,
int (*hehe(par1, par2))() char *par1, *par2; {}
Since the function heading is read as a normal declarator,
we just include the (formal) parameter list in the declarator
description list dc.
*/
declarator(register struct declarator *dc;)
{ struct formal *fm = NO_PARAMS;
struct proto *pl = NO_PROTO;
arith count;
int qual;
}
:
primary_declarator(dc)
[/*%while(1)*/
'('
[ %if (DOT != IDENTIFIER && DOT != ')')
parameter_type_list(&pl)
|
formal_list(&fm)
|
empty
]
')'
{ add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl);
fm = NO_PARAMS;
}
|
arrayer(&count)
{add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
]*
|
pointer(&qual) declarator(dc)
{add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
;
primary_declarator(register struct declarator *dc;) :
identifier(&dc->dc_idf)
|
'(' declarator(dc) ')'
;
arrayer(arith *sizep;)
{ struct expr *expr; }
:
'['
[
constant_expression(&expr)
{
check_array_subscript(expr);
*sizep = expr->VL_VALUE;
free_expression(expr);
}
|
empty
{ *sizep = (arith)-1; }
]
']'
;
formal_list (struct formal **fmp;)
:
formal(fmp) [ ',' formal(fmp) ]*
;
formal(struct formal **fmp;)
{struct idf *idf; }
:
identifier(&idf)
{
register struct formal *new = new_formal();
new->fm_idf = idf;
new->next = *fmp;
*fmp = new;
}
;
/* Change 2 */
enum_specifier(register struct type **tpp;)
{
struct idf *idf;
arith l = (arith)0;
}
:
ENUM
[
{declare_struct(ENUM, (struct idf *) 0, tpp);}
enumerator_pack(*tpp, &l)
|
identifier(&idf)
[
{declare_struct(ENUM, idf, tpp);}
enumerator_pack(*tpp, &l)
|
{apply_struct(ENUM, idf, tpp);}
empty
]
]
;
enumerator_pack(register struct type *tp; arith *lp;) :
'{'
enumerator(tp, lp)
[%while (AHEAD != '}')
','
enumerator(tp, lp)
]*
[
',' {warning("unexpected trailing comma in enumerator pack");}
]?
'}'
{tp->tp_size = int_size;}
/* fancy implementations that put small enums in 1 byte
or so should start here.
*/
;
enumerator(struct type *tp; arith *lp;)
{
struct idf *idf;
struct expr *expr;
}
:
identifier(&idf)
[
'='
constant_expression(&expr)
{
*lp = expr->VL_VALUE;
free_expression(expr);
}
]?
{declare_enum(tp, idf, (*lp)++);}
;
/* 8.5 */
struct_or_union_specifier(register struct type **tpp;)
{
int fund;
struct idf *idfX;
register struct idf *idf;
}
:
[ STRUCT | UNION ]
{fund = DOT;}
[
{
declare_struct(fund, (struct idf *)0, tpp);
}
struct_declaration_pack(*tpp)
|
identifier(&idfX) { idf = idfX; }
[
{
declare_struct(fund, idf, tpp);
(idf->id_struct->tg_busy)++;
}
struct_declaration_pack(*tpp)
{
(idf->id_struct->tg_busy)--;
}
|
{apply_struct(fund, idf, tpp);}
empty
]
]
;
struct_declaration_pack(register struct type *stp;)
{
struct sdef **sdefp = &stp->tp_sdef;
arith size = (arith)0;
}
:
/* The size is only filled in after the whole struct has
been read, to prevent recursive definitions.
*/
'{'
struct_declaration(stp, &sdefp, &size)+
'}'
{stp->tp_size = align(size, stp->tp_align);}
;
struct_declaration(struct type *stp; struct sdef ***sdefpp; arith *szp;)
{struct type *tp;}
:
type_specifier(&tp) struct_declarator_list(tp, stp, sdefpp, szp) ';'
;
struct_declarator_list(struct type *tp, *stp;
struct sdef ***sdefpp; arith *szp;)
:
struct_declarator(tp, stp, sdefpp, szp)
[ ',' struct_declarator(tp, stp, sdefpp, szp) ]*
;
struct_declarator(struct type *tp; struct type *stp;
struct sdef ***sdefpp; arith *szp;)
{
struct declarator Dc;
struct field *fd = 0;
}
:
{
Dc = null_declarator;
}
[
declarator(&Dc)
{reject_params(&Dc);}
bit_expression(&fd)?
|
{Dc.dc_idf = gen_idf();}
bit_expression(&fd)
]
{add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd);}
{remove_declarator(&Dc);}
;
bit_expression(struct field **fd;)
{ struct expr *expr; }
:
{
*fd = new_field();
}
':'
constant_expression(&expr)
{
(*fd)->fd_width = expr->VL_VALUE;
free_expression(expr);
#ifdef NOBITFIELD
error("bitfields are not implemented");
#endif NOBITFIELD
}
;
/* 8.7 */
cast(struct type **tpp;)
{struct declarator Dc;}
:
{Dc = null_declarator;}
'('
type_specifier(tpp)
abstract_declarator(&Dc)
')'
{*tpp = declare_type(*tpp, &Dc);}
{remove_declarator(&Dc);}
;
/* This code is an abject copy of that of 'declarator', for lack of
a two-level grammar.
*/
abstract_declarator(register struct declarator *dc;)
{ struct proto *pl = NO_PROTO;
arith count;
int qual;
}
:
primary_abstract_declarator(dc)
[
'('
[
parameter_type_list(&pl)
|
empty
]
')'
{add_decl_unary(dc, FUNCTION, 0, (arith)0, NO_PARAMS, pl);}
|
arrayer(&count)
{add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
]*
|
pointer(&qual) abstract_declarator(dc)
{add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
;
primary_abstract_declarator(struct declarator *dc;)
:
[%if (AHEAD == ')')
empty
|
'(' abstract_declarator(dc) ')'
]
;
parameter_type_list(struct proto **plp;)
{ int save_level; }
:
{ if (level > L_PROTO) {
save_level = level;
level = L_PROTO;
} else level--;
}
parameter_decl_list(plp)
[
',' ELLIPSIS
{ register struct proto *new = new_proto();
new->next = *plp;
new->pl_flag = ELLIPSIS;
*plp = new;
}
]?
{ if (level == L_PROTO)
level = save_level;
else level++;
}
;
parameter_decl_list(struct proto **plp;)
:
parameter_decl(plp)
[ %while (AHEAD != ELLIPSIS)
',' parameter_decl(plp)
]*
;
parameter_decl(struct proto **plp;)
{ register struct proto *new = new_proto();
struct declarator Dc;
struct decspecs Ds;
}
:
{ Dc = null_declarator;
Ds = null_decspecs;
}
decl_specifiers(&Ds)
parameter_declarator(&Dc)
{ add_proto(new, &Ds, &Dc, level);
new->next = *plp;
*plp = new;
}
;
/* This is weird. Due to the LR structure of the ANSI C grammar
we have to duplicate the actions of 'declarator' and
'abstract_declarator'. Calling these separate, as in
parameter_decl:
decl_specifiers
[
declarator
|
abstract_declarator
]
gives us a conflict on the terminals '(' and '*'. E.i. on
some input, it is impossible to decide which rule we take.
Combining the two declarators into one common declarator
is out of the question, since this results in an empty
string for the non-terminal 'declarator'.
So we combine the two only for the use of parameter_decl,
since this is the only place where they don't give
conflicts. However, this makes the grammar messy.
*/
parameter_declarator(register struct declarator *dc;)
{ struct formal *fm = NO_PARAMS;
struct proto *pl = NO_PROTO;
arith count;
int qual;
}
:
primary_parameter_declarator(dc)
[
'('
[ %if(DOT != IDENTIFIER && DOT != ')')
parameter_type_list(&pl)
|
formal_list(&fm)
|
empty
]
')'
{add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl);}
|
arrayer(&count)
{add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);}
]*
|
pointer(&qual) parameter_declarator(dc)
{add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);}
;
primary_parameter_declarator(register struct declarator *dc;)
:
[ %if(AHEAD == ')')
empty
|
identifier(&dc->dc_idf)
|
'(' parameter_declarator(dc) ')'
]
;
pointer(int *qual;)
:
'*' type_qualifier_list(qual)
;
/* Type qualifiers may come in three flavours:
volatile, const, const volatile.
These all have different semantic properties:
volatile:
means that the object can be modified
without prior knowledge of the implementation.
const:
means that the object can not be modified; thus
it's illegal to use this as a l-value.
const volatile:
means that the object can be modified without
prior knowledge of the implementation, but may
not be used as a l-value.
*/
type_qualifier_list(int *qual;)
:
[
[ VOLATILE | CONST ]
{ *qual = (DOT == VOLATILE) ? TQ_VOLATILE : TQ_CONST; }
[
[ VOLATILE | CONST ]
{ if (DOT == VOLATILE) {
if (*qual & TQ_VOLATILE)
error("repeated type qualifier");
*qual |= TQ_VOLATILE;
}
if (DOT == CONST) {
if (*qual & TQ_CONST)
error("repeated type qualifier");
*qual |= TQ_CONST;
}
}
]*
|
empty
{ *qual = 0; }
]
;
empty:
;
/* 8.8 */
/* included in the IDENTIFIER/TYPE_IDENTIFIER mechanism */

View File

@ -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;

View File

@ -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 <alloc.h>
#include "arith.h"
#include "type.h"
#include "proto.h"
#include "Lpars.h"
#include "declar.h"
#include "def.h"
#include "idf.h"
#include "label.h"
#include "expr.h"
#include "sizes.h"
#include "debug.h"
#include "level.h"
extern char options[];
struct declarator null_declarator;
struct type *
declare_type(tp, dc)
struct type *tp;
struct declarator *dc;
{
/* Applies the decl_unary list starting at dc->dc_decl_unary
to the type tp and returns the result.
Functions that are declared within a parameter type list
are purely prototypes. Simply add the type list to the
function node.
*/
register struct decl_unary *du = dc->dc_decl_unary;
while (du) {
tp = construct_type(du->du_fund, tp, du->du_typequal,
du->du_count, du->du_proto);
du = du->next;
}
return tp;
}
add_decl_unary(dc, fund, qual, count, fm, pl)
register struct declarator *dc;
int qual;
arith count;
struct formal *fm;
struct proto *pl;
{
/* A decl_unary describing a constructor with fundamental
type fund and with size count is inserted in front of the
declarator dc.
*/
register struct decl_unary *new = new_decl_unary();
new->next = dc->dc_decl_unary;
new->du_fund = fund;
new->du_count = count;
new->du_typequal = qual;
new->du_proto = pl;
if (fm) {
if (dc->dc_decl_unary) {
/* parameters only allowed at first decl_unary */
error("formal parameters list discarded");
}
else {
/* register the proto */
dc->dc_formal = fm;
}
}
dc->dc_decl_unary = new;
}
remove_declarator(dc)
struct declarator *dc;
{
/* The decl_unary list starting at dc->dc_decl_unary is
removed.
*/
register struct decl_unary *du = dc->dc_decl_unary;
while (du) {
struct decl_unary *old_du = du;
du = du->next;
free_decl_unary(old_du);
}
}
reject_params(dc)
register struct declarator *dc;
{
/* The declarator is checked to have no parameters, if it
is a function.
*/
if (dc->dc_formal) {
error("non_empty formal parameter pack");
free_formals(dc->dc_formal);
dc->dc_formal = 0;
}
}
check_array_subscript(expr)
register struct expr *expr;
{
arith size = expr->VL_VALUE;
if (size < 0) {
error("array size is negative");
expr->VL_VALUE = (arith)1;
}
else
if (size == 0) {
warning("array size is 0");
}
else
if (size & ~max_unsigned) { /* absolutely ridiculous */
expr_error(expr, "overflow in array size");
expr->VL_VALUE = (arith)1;
}
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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 */

View File

@ -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 <alloc.h>
#include "class.h"
#include "macro.h"
extern char **inctable; /* list of include directories */
extern char *getwdir();
char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */
/* 1 if a corresponding ELSE has been */
/* encountered. */
int nestlevel = -1;
struct idf *
GetIdentifier()
{
/* returns a pointer to the descriptor of the identifier that is
read from the input stream. A null-pointer is returned if
the input does not contain an identifier.
The substitution of macros is disabled.
*/
int tok;
struct token tk;
ReplaceMacros = 0;
tok = GetToken(&tk);
ReplaceMacros = 1;
return tok == IDENTIFIER ? tk.tk_idf : (struct idf *)0;
}
/* domacro() is the control line interpreter. The '#' has already
been read by the lexical analyzer by which domacro() is called.
The token appearing directly after the '#' is obtained by calling
the basic lexical analyzing function GetToken() and is interpreted
to perform the action belonging to that token.
An error message is produced when the token is not recognized,
i.e. it is not one of "define" .. "undef" , integer or newline.
*/
domacro()
{
struct token tk; /* the token itself */
EoiForNewline = 1;
switch(GetToken(&tk)) { /* select control line action */
case IDENTIFIER: /* is it a macro keyword? */
switch (tk.tk_idf->id_resmac) {
case K_DEFINE: /* "define" */
do_define();
break;
case K_ELIF: /* "elif" */
do_elif();
break;
case K_ELSE: /* "else" */
do_else();
break;
case K_ENDIF: /* "endif" */
do_endif();
break;
case K_IF: /* "if" */
do_if();
break;
case K_IFDEF: /* "ifdef" */
do_ifdef(1);
break;
case K_IFNDEF: /* "ifndef" */
do_ifdef(0);
break;
case K_INCLUDE: /* "include" */
do_include();
break;
case K_LINE: /* "line" */
/* set LineNumber and FileName according to
the arguments.
*/
if (GetToken(&tk) != INTEGER) {
lexerror("#line without linenumber");
SkipToNewLine(0);
}
else
do_line((unsigned int)tk.tk_ival);
break;
case K_ERROR: /* "error" */
do_error();
break;
case K_PRAGMA: /* "pragma" */
do_pragma();
break;
case K_UNDEF: /* "undef" */
do_undef();
break;
default:
/* invalid word seen after the '#' */
lexerror("%s: unknown control", tk.tk_idf->id_text);
SkipToNewLine(0);
}
break;
case INTEGER: /* # <integer> [<filespecifier>]? */
do_line((unsigned int)tk.tk_ival);
break;
case EOI: /* only `#' on this line: do nothing, ignore */
break;
default: /* invalid token following '#' */
lexerror("illegal # line");
SkipToNewLine(0);
}
EoiForNewline = 0;
}
skip_block()
{
/* skip_block() skips the input from
1) a false #if, #ifdef, #ifndef or #elif until the
corresponding #elif (resulting in true), #else or
#endif is read.
2) a #else corresponding to a true #if, #ifdef,
#ifndef or #elif until the corresponding #endif is
seen.
*/
register int ch;
register int skiplevel = nestlevel; /* current nesting level */
struct token tk;
NoUnstack++;
for (;;) {
ch = GetChar(); /* read first character after newline */
while (class(ch) == STSKIP)
ch = GetChar();
if (ch != '#') {
if (ch == EOI) {
NoUnstack--;
return;
}
SkipToNewLine(0);
continue;
}
if (GetToken(&tk) != IDENTIFIER) {
SkipToNewLine(0);
continue;
}
/* an IDENTIFIER: look for #if, #ifdef and #ifndef
without interpreting them.
Interpret #else, #elif and #endif if they occur
on the same level.
*/
switch(tk.tk_idf->id_resmac) {
case K_IF:
case K_IFDEF:
case K_IFNDEF:
push_if();
break;
case K_ELIF:
if (nestlevel == skiplevel) {
nestlevel--;
push_if();
if (ifexpr()) {
NoUnstack--;
return;
}
}
break;
case K_ELSE:
++(ifstack[nestlevel]);
if (nestlevel == skiplevel) {
if (SkipToNewLine(1))
strict("garbage following #endif");
NoUnstack--;
return;
}
break;
case K_ENDIF:
ASSERT(nestlevel > nestlow);
if (nestlevel == skiplevel) {
if (SkipToNewLine(1))
strict("garbage following #endif");
nestlevel--;
NoUnstack--;
return;
}
nestlevel--;
break;
}
}
}
ifexpr()
{
/* ifexpr() returns whether the restricted constant
expression following #if or #elif evaluates to true. This
is done by calling the LLgen generated subparser for
constant expressions. The result of this expression will
be given in the extern long variable "ifval".
*/
extern arith ifval;
int errors = err_occurred;
ifval = (arith)0;
AccDefined = 1;
UnknownIdIsZero = 1;
PushLex(); /* NEW parser */
If_expr(); /* invoke constant expression parser */
PopLex(); /* OLD parser */
AccDefined = 0;
UnknownIdIsZero = 0;
return (errors == err_occurred) && (ifval != (arith)0);
}
do_include()
{
/* do_include() performs the inclusion of a file.
*/
char *filenm;
char *result;
int tok;
struct token tk;
AccFileSpecifier = 1;
if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
filenm = tk.tk_bts;
else {
lexerror("bad include syntax");
filenm = (char *)0;
}
AccFileSpecifier = 0;
SkipToNewLine(0);
inctable[0] = WorkingDir;
if (filenm) {
if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
fatal("cannot open include file \"%s\"", filenm);
}
else {
WorkingDir = getwdir(result);
File_Inserted = 1;
FileName = result;
LineNumber = 0;
nestlow = nestlevel;
}
}
}
do_define()
{
/* do_define() interprets a #define control line.
*/
struct idf *id; /* the #defined identifier's descriptor */
int nformals = -1; /* keep track of the number of formals */
char *formals[NPARAMS]; /* pointers to the names of the formals */
char parbuf[PARBUFSIZE]; /* names of formals */
char *repl_text; /* start of the replacement text */
int length; /* length of the replacement text */
register ch;
char *get_text();
/* read the #defined macro's name */
if (!(id = GetIdentifier())) {
lexerror("#define: illegal macro name");
SkipToNewLine(0);
return;
}
/* there is a formal parameter list if the identifier is
followed immediately by a '('.
*/
ch = GetChar();
if (ch == '(') {
if ((nformals = getparams(formals, parbuf)) == -1) {
SkipToNewLine(0);
return; /* an error occurred */
}
ch = GetChar();
}
/* read the replacement text if there is any */
ch = skipspaces(ch,0); /* find first character of the text */
ASSERT(ch != EOI);
if (class(ch) == STNL) {
/* Treat `#define something' as `#define something ""'
*/
repl_text = "";
length = 0;
}
else {
UnGetChar();
repl_text = get_text((nformals > 0) ? formals : 0, &length);
}
macro_def(id, repl_text, nformals, length, NOFLAG);
LineNumber++;
}
push_if()
{
if (nestlevel >= IFDEPTH)
fatal("too many nested #if/#ifdef/#ifndef");
else
ifstack[++nestlevel] = 0;
}
do_elif()
{
if (nestlevel <= nestlow || (ifstack[nestlevel])) {
lexerror("#elif without corresponding #if");
SkipToNewLine(0);
}
else { /* restart at this level as if a #if is detected. */
nestlevel--;
push_if();
skip_block();
}
}
do_else()
{
struct token tok;
if (SkipToNewLine(1))
strict("garbage following #else");
if (nestlevel <= nestlow || (ifstack[nestlevel]))
lexerror("#else without corresponding #if");
else { /* mark this level as else-d */
++(ifstack[nestlevel]);
skip_block();
}
}
do_endif()
{
struct token tok;
if (SkipToNewLine(1))
strict("garbage following #endif");
if (nestlevel <= nestlow) {
lexerror("#endif without corresponding #if");
}
else nestlevel--;
}
do_if()
{
push_if();
if (!ifexpr()) /* a false #if/#elif expression */
skip_block();
}
do_ifdef(how)
{
register struct idf *id;
/* how == 1 : ifdef; how == 0 : ifndef
*/
push_if();
if (!(id = GetIdentifier()))
lexerror("illegal #ifdef construction");
/* The next test is a shorthand for:
(how && !id->id_macro) || (!how && id->id_macro)
*/
if (how ^ (id && id->id_macro != 0))
skip_block();
else
SkipToNewLine(0);
}
do_undef()
{
register struct idf *id;
/* Forget a macro definition. */
if (id = GetIdentifier()) {
if (id->id_macro) { /* forget the macro */
free_macro(id->id_macro);
id->id_macro = (struct macro *) 0;
} /* else: don't complain */
}
else
lexerror("illegal #undef construction");
SkipToNewLine(0);
}
do_error()
{
static char errbuf[512];
register char *bp = errbuf;
register int ch;
while ((ch = GetChar()) != '\n')
*bp++ = ch;
*bp = '\0';
UnGetChar();
lexerror("user error: %s", errbuf);
}
int
getparams(buf, parbuf)
char *buf[];
char parbuf[];
{
/* getparams() reads the formal parameter list of a macro
definition.
The number of parameters is returned.
As a formal parameter list is expected when calling this
routine, -1 is returned if an error is detected, for
example:
#define one(1), where 1 is not an identifier.
Note that the '(' has already been eaten.
The names of the formal parameters are stored into parbuf.
*/
register char **pbuf = &buf[0];
register int c;
register char *ptr = &parbuf[0];
register char **pbuf2;
c = GetChar();
c = skipspaces(c,0);
if (c == ')') { /* no parameters: #define name() */
*pbuf = (char *) 0;
return 0;
}
for (;;) { /* eat the formal parameter list */
if (class(c) != STIDF && class(c) != STELL) {
lexerror("#define: bad formal parameter");
return -1;
}
*pbuf = ptr; /* name of the formal */
*ptr++ = c;
if (ptr >= &parbuf[PARBUFSIZE])
fatal("formal parameter buffer overflow");
do { /* eat the identifier name */
c = GetChar();
*ptr++ = c;
if (ptr >= &parbuf[PARBUFSIZE])
fatal("formal parameter buffer overflow");
} while (in_idf(c));
*(ptr - 1) = '\0'; /* mark end of the name */
/* Check if this formal parameter is already used.
Usually, macros do not have many parameters, so ...
*/
for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--) {
if (!strcmp(*pbuf2, *pbuf)) {
warning("formal parameter \"%s\" already used",
*pbuf);
}
}
pbuf++;
c = skipspaces(c,0);
if (c == ')') { /* end of the formal parameter list */
*pbuf = (char *) 0;
return pbuf - buf;
}
if (c != ',') {
lexerror("#define: bad formal parameter list");
return -1;
}
c = GetChar();
c = skipspaces(c,0);
}
/*NOTREACHED*/
}
macro_def(id, text, nformals, length, flags)
register struct idf *id;
char *text;
{
register struct macro *newdef = id->id_macro;
/* macro_def() puts the contents and information of a macro
definition into a structure and stores it into the symbol
table entry belonging to the name of the macro.
A warning is given if the definition overwrites another.
*/
if (newdef) { /* is there a redefinition? */
if (macroeq(newdef->mc_text, text))
return;
lexwarning("redefine \"%s\"", id->id_text);
}
else
id->id_macro = newdef = new_macro();
newdef->mc_text = text; /* replacement text */
newdef->mc_nps = nformals; /* nr of formals */
newdef->mc_length = length; /* length of repl. text */
newdef->mc_flag = flags; /* special flags */
newdef->mc_count = 0;
}
int
find_name(nm, index)
char *nm, *index[];
{
/* find_name() returns the index of "nm" in the namelist
"index" if it can be found there. 0 is returned if it is
not there.
*/
register char **ip = &index[0];
while (*ip)
if (strcmp(nm, *ip++) == 0)
return ip - &index[0];
/* arrived here, nm is not in the name list. */
return 0;
}
char *
get_text(formals, length)
char *formals[];
int *length;
{
/* get_text() copies the replacement text of a macro
definition with zero, one or more parameters, thereby
substituting each formal parameter by a special character
(non-ascii: 0200 & (order-number in the formal parameter
list)) in order to substitute this character later by the
actual parameter. The replacement text is copied into
itself because the copied text will contain fewer or the
same amount of characters. The length of the replacement
text is returned.
Implementation:
finite automaton : we are only interested in
identifiers, because they might be replaced by some actual
parameter. Other tokens will not be seen as such.
*/
register int c;
register int text_size;
char *text = Malloc(text_size = ITEXTSIZE);
register int pos = 0;
c = GetChar();
while ((c != EOI) && (class(c) != STNL)) {
if (c == '\'' || c == '"') {
register int delim = c;
do {
/* being careful, as ever */
if (pos+3 >= text_size)
text = Srealloc(text,
text_size += RTEXTSIZE);
text[pos++] = c;
if (c == '\\')
text[pos++] = GetChar();
c = GetChar();
} while (c != delim && c != EOI && class(c) != STNL);
text[pos++] = c;
c = GetChar();
}
else
if (c == '/') {
c = GetChar();
if (pos+1 >= text_size)
text = Srealloc(text, text_size += RTEXTSIZE);
if (c == '*') {
skipcomment();
text[pos++] = ' ';
c = GetChar();
}
else
text[pos++] = '/';
}
else
if (formals && (class(c) == STIDF || class(c) == STELL)) {
char id_buf[IDFSIZE + 1];
register id_size = 0;
register n;
/* read identifier: it may be a formal parameter */
id_buf[id_size++] = c;
do {
c = GetChar();
if (id_size <= IDFSIZE)
id_buf[id_size++] = c;
} while (in_idf(c));
id_buf[--id_size] = '\0';
if (n = find_name(id_buf, formals)) {
/* construct the formal parameter mark */
if (pos+1 >= text_size)
text = Srealloc(text,
text_size += RTEXTSIZE);
text[pos++] = FORMALP | (char) n;
}
else {
register char *ptr = &id_buf[0];
while (pos + id_size >= text_size)
text = Srealloc(text,
text_size += RTEXTSIZE);
while (text[pos++] = *ptr++) ;
pos--;
}
}
else {
if (pos+1 >= text_size)
text = Srealloc(text, text_size += RTEXTSIZE);
text[pos++] = c;
c = GetChar();
}
}
text[pos++] = '\0';
*length = pos - 1;
return text;
}
#define BLANK(ch) ((ch == ' ') || (ch == '\t'))
/* macroeq() decides whether two macro replacement texts are
identical. This version compares the texts, which occur
as strings, without taking care of the leading and trailing
blanks (spaces and tabs).
*/
macroeq(s, t)
register char *s, *t;
{
/* skip leading spaces */
while (BLANK(*s)) s++;
while (BLANK(*t)) t++;
/* first non-blank encountered in both strings */
/* The actual comparison loop: */
while (*s && *s == *t)
s++, t++;
/* two cases are possible when arrived here: */
if (*s == '\0') { /* *s == '\0' */
while (BLANK(*t)) t++;
return *t == '\0';
}
else { /* *s != *t */
while (BLANK(*s)) s++;
while (BLANK(*t)) t++;
return (*s == '\0') && (*t == '\0');
}
}
#else NOPP
domacro()
{
int tok;
struct token tk;
EoiForNewline = 1;
if ((tok = GetToken(&tk)) == IDENTIFIER) {
if (strcmp(tk.tk_idf->id_text, "line") != 0) {
error("illegal # line");
SkipToNewLine(0);
return;
}
tok = GetToken(&tk);
}
if (tok != INTEGER) {
error("illegal # line");
SkipToNewLine(0);
return;
}
do_line((unsigned int) tk.tk_ival);
EoiForNewline = 0;
}
#endif NOPP
do_line(l)
unsigned int l;
{
struct token tk;
LineNumber = l - 1; /* the number of the next input line */
if (GetToken(&tk) == STRING) /* is there a filespecifier? */
FileName = tk.tk_bts;
SkipToNewLine(0);
}

View File

@ -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" : "<UNKNOWN>",
tp->tp_idf->id_text
);
if (is_struct_or_union(fund)) {
print(" {");
dumpsdefs(tp->tp_sdef, field);
newline();
print("}");
}
print(";");
tag = tag->next;
}
dumplevel--;
}
dumpsdefs(sdef, sdk)
register struct sdef *sdef;
enum sdef_kind sdk;
{
/* Since sdef's are members of two chains, there are actually
two dumpsdefs's, one following the chain of all selectors
belonging to the same idf, starting at idf->id_sdef;
and the other following the chain of all selectors belonging
to the same struct, starting at stp->tp_sdef.
*/
dumplevel++;
while (sdef) {
newline();
print("L%d: ", sdef->sd_level);
#ifndef NOBITFIELD
if (sdk == selector)
#endif NOBITFIELD
print("selector %s at offset %lu in %s;",
type2str(sdef->sd_type),
sdef->sd_offset, type2str(sdef->sd_stype)
);
#ifndef NOBITFIELD
else print("field %s at offset %lu;",
type2str(sdef->sd_type), sdef->sd_offset
);
#endif NOBITFIELD
sdef = (sdk == selector ? sdef->next : sdef->sd_sdef);
}
dumplevel--;
}
dump_proto(pl)
register struct proto *pl;
{
register struct type *type;
register int argcnt = 0;
newline();
print("dump proto type list (start)");
newline();
while (pl) {
print("%d: %s", argcnt++,
pl->pl_flag == FORMAL ?
(pl->pl_flag == VOID ? "void" : "formal")
: "ellipsis");
newline();
if (type = pl->pl_type){
dump_type(type);
newline();
}
if (pl->pl_idf) {
dumplevel++;
print("idf:");
dumpidf(pl->pl_idf, 7);
dumplevel--;
}
newline();
pl = pl->next;
}
print("dump proto type list (end)\n");
}
dump_type(tp)
register struct type *tp;
{
int ops = 1;
dumplevel++;
newline();
if (!tp) {
print("<NILTYPE>");
newline();
return;
}
print("(@%lx, #%ld, &%d) ", tp, (long)tp->tp_size, tp->tp_align);
while (ops) {
print("%s", qual2str(tp->tp_typequal));
switch (tp->tp_fund) {
case POINTER:
print("pointer to ");
break;
case ARRAY:
print("array [%ld] of ", tp->tp_size);
break;
case FUNCTION:
print("function ");
if (tp->tp_proto) {
print("with prototype");
dumplevel++;
dump_proto(tp->tp_proto);
dumplevel--;
newline();
}
print("yielding ");
break;
default:
print("%s%s ", tp->tp_unsigned ? "unsigned " : "",
symbol2str(tp->tp_fund));
if (tp->tp_idf)
print("%s ", tp->tp_idf->id_text);
#ifndef NOBITFIELD
if (tp->tp_field) {
struct field *fd = tp->tp_field;
print("[s=%ld,w=%ld] of ",
fd->fd_shift, fd->fd_width);
}
else
#endif NOBITFIELD
ops = 0;
break;
}
tp = tp->tp_up;
}
dumplevel--;
}
char *
type2str(tp)
register struct type *tp;
{
/* Yields a pointer to a one-line description of the type tp.
*/
char *buf = next_transient();
int ops = 1;
buf[0] = '\0';
if (!tp) {
sprint(buf, "<NILTYPE>");
return buf;
}
sprint(buf, "%s(@%lx, #%ld, &%d) ",
buf, tp, (long)tp->tp_size, tp->tp_align);
while (ops) {
sprint(buf, "%s%s", buf, qual2str(tp->tp_typequal));
switch (tp->tp_fund) {
case POINTER:
sprint(buf, "%spointer to ", buf);
break;
case ARRAY:
sprint(buf, "%sarray [%ld] of ", buf, tp->tp_size);
break;
case FUNCTION:
sprint(buf, "%sfunction yielding ", buf);
break;
default:
sprint(buf, "%s%s%s ", buf,
tp->tp_unsigned ? "unsigned " : "",
symbol2str(tp->tp_fund)
);
if (tp->tp_idf)
sprint(buf, "%s %s ", buf,
tp->tp_idf->id_text);
#ifndef NOBITFIELD
if (tp->tp_field) {
struct field *fd = tp->tp_field;
sprint(buf, "%s [s=%ld,w=%ld] of ", buf,
fd->fd_shift, fd->fd_width);
}
else
#endif NOBITFIELD
ops = 0;
break;
}
tp = tp->tp_up;
}
return buf;
}
char *
qual2str(qual)
int qual;
{
char *buf = next_transient();
*buf = '\0';
if (qual == 0)
sprint(buf, "(none)");
if (qual & TQ_CONST)
sprint(buf, "%sconst ", buf);
if (qual & TQ_VOLATILE)
sprint(buf, "%svolatile ", buf);
return qual == 0 ? "" : buf;
}
GSTATIC char trans_buf[MAXTRANS][300];
char * /* the ultimate transient buffer supplier */
next_transient()
{
static int bnum;
if (++bnum == MAXTRANS)
bnum = 0;
return trans_buf[bnum];
}
print_expr(msg, expr)
char msg[];
struct expr *expr;
{
/* Provisional routine to print an expression preceded by a
message msg.
*/
if (options['x']) {
print("\n%s: ", msg);
print("(L=line, T=type, r/lV=r/lvalue, F=flags, D=depth)\n");
p1_expr(0, expr);
}
}
p1_expr(lvl, expr)
register struct expr *expr;
{
p1_indent(lvl);
if (!expr) {
print("NILEXPR\n");
return;
}
print("expr: L=%u, T=%s, %cV, F=%03o, D=%d, %s: ",
expr->ex_line,
type2str(expr->ex_type),
expr->ex_lvalue ? 'l' : 'r',
expr->ex_flags & 0xFF,
expr->ex_depth,
expr->ex_class == Value ? "Value" :
expr->ex_class == String ? "String" :
#ifndef NOFLOAT
expr->ex_class == Float ? "Float" :
#endif NOFLOAT
expr->ex_class == Oper ? "Oper" :
expr->ex_class == Type ? "Type" : "UNKNOWN CLASS"
);
switch (expr->ex_class) {
struct oper *o;
case Value:
switch (expr->VL_CLASS) {
case Const:
print("(Const) ");
break;
case Name:
print("(Name) %s + ", expr->VL_IDF->id_text);
break;
case Label:
print("(Label) .%lu + ", expr->VL_LBL);
break;
default:
print("(Unknown) ");
break;
}
print(expr->ex_type->tp_unsigned ? "%lu\n" : "%ld\n",
expr->VL_VALUE);
break;
case String:
{
char *bts2str();
print(
"\"%s\"\n",
bts2str(expr->SG_VALUE, expr->SG_LEN-1,
next_transient())
);
break;
}
#ifndef NOFLOAT
case Float:
print("%s\n", expr->FL_VALUE);
break;
#endif NOFLOAT
case Oper:
o = &expr->ex_object.ex_oper;
print("\n");
p1_expr(lvl+1, o->op_left);
p1_indent(lvl);
print("%s <%s>\n", symbol2str(o->op_oper),
type2str(o->op_type)
);
p1_expr(lvl+1, o->op_right);
break;
case Type:
print("\n");
break;
default:
print("UNKNOWN CLASS\n");
break;
}
}
p1_indent(lvl)
register int lvl;
{
while (lvl--)
print(" ");
}
#endif DEBUG

View File

@ -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 <varargs.h>
#include <system.h>
#include <em.h>
#include "lint.h"
#include "nopp.h"
#include "errout.h"
#include "debug.h"
#include "tokenname.h"
#include "arith.h"
#include "label.h"
#include "expr.h"
#include "def.h"
#include "LLlex.h"
/* This file contains the error-message and diagnostic
functions. Beware, they are called with a variable number of
arguments!
*/
/* error classes */
#define STRICT 1
#define WARNING 2
#define ERROR 3
#define CRASH 4
#define FATAL 5
int err_occurred = 0;
extern char options[];
#ifdef LINT
extern char loptions[];
#endif LINT
/* There are three general error-message functions:
lexerror() lexical and pre-processor error messages
error() syntactic and semantic error messages
expr_error() errors in expressions
The difference lies in the place where the file name and line
number come from.
Lexical errors report from the global variables LineNumber and
FileName, expression errors get their information from the
expression, whereas other errors use the information in the token.
*/
static _error();
/*VARARGS*/
error(va_alist) /* fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
_error(ERROR, dot.tk_file, dot.tk_line, ap);
}
va_end(ap);
}
/*VARARGS*/
expr_error(va_alist) /* expr, fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
register struct expr *expr = va_arg(ap, struct expr *);
if (!(expr->ex_flags & EX_ERROR)) {
/* to prevent proliferation */
_error(ERROR, expr->ex_file, expr->ex_line, ap);
expr->ex_flags |= EX_ERROR;
}
}
va_end(ap);
}
/*VARARGS*/
strict(va_alist)
va_dcl
{
va_list ap;
va_start(ap);
{
_error(STRICT, FileName, LineNumber, ap);
}
va_end(ap);
}
/*VARARGS*/
warning(va_alist)
va_dcl
{
va_list ap;
va_start(ap);
{
_error(WARNING, NILEXPR, ap);
}
va_end(ap);
}
/*VARARGS*/
expr_warning(va_alist) /* expr, fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
struct expr *expr = va_arg(ap, struct expr *);
if (!(expr->ex_flags & EX_ERROR)) {
/* to prevent proliferation */
_error(WARNING, expr->ex_file, expr->ex_line, ap);
}
}
va_end(ap);
}
#ifdef LINT
/*VARARGS*/
def_warning(va_alist) /* def, fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
register struct def *def = va_arg(ap, struct def *);
_error(WARNING, def->df_file, def->df_line, ap);
}
va_end(ap);
}
/*VARARGS*/
hwarning(va_alist) /* fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
if (loptions['h'])
_error(WARNING, dot.tk_file, dot.tk_line, ap);
}
va_end(ap);
}
/*VARARGS*/
awarning(va_alist) /* fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
if (loptions['a'])
_error(WARNING, dot.tk_file, dot.tk_line, ap);
}
va_end(ap);
}
#endif LINT
/*VARARGS*/
lexerror(va_alist) /* fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
_error(ERROR, FileName, LineNumber, ap);
}
va_end(ap);
}
#ifndef NOPP
/*VARARGS*/
lexwarning(va_alist) /* fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
_error(WARNING, FileName, LineNumber, ap);
}
va_end(ap);
}
#endif NOPP
/*VARARGS*/
crash(va_alist) /* fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
_error(CRASH, FileName, LineNumber, ap);
}
va_end(ap);
C_close();
#ifdef DEBUG
sys_stop(S_ABORT);
#else DEBUG
sys_stop(S_EXIT);
#endif DEBUG
/* NOTREACHED */
}
/*VARARGS*/
fatal(va_alist) /* fmt, args */
va_dcl
{
va_list ap;
va_start(ap);
{
_error(FATAL, FileName, LineNumber, ap);
}
va_end(ap);
if (C_busy()) C_close();
sys_stop(S_EXIT);
/*NOTREACHED*/
}
static
_error(class, fn, ln, ap)
int class;
char *fn;
unsigned int ln;
va_list ap;
{
/* _error attempts to limit the number of error messages
for a given line to MAXERR_LINE.
*/
#ifndef LINT
static char *last_fn = 0;
static unsigned int last_ln = 0;
static int e_seen = 0;
#endif LINT
char *remark;
char *fmt = va_arg(ap, char *);
/* Since name and number are gathered from different places
depending on the class, we first collect the relevant
values and then decide what to print.
*/
/* preliminaries */
switch (class) {
case WARNING:
if (options['w'])
return;
break;
case STRICT:
if (options['s'])
return;
break;
case ERROR:
case CRASH:
case FATAL:
if (C_busy())
C_ms_err();
err_occurred = 1;
break;
}
/* the remark */
switch (class) {
case STRICT:
remark = "(strict)";
break;
case WARNING:
#ifndef LINT
remark = "(warning)";
#else LINT
remark = 0;
#endif LINT
break;
case ERROR:
remark = 0;
break;
case CRASH:
remark = "CRASH\007";
break;
case FATAL:
remark = "fatal error --";
break;
default:
/*NOTREACHED*/;
}
#ifndef LINT
if (ln == last_ln && fn && last_fn && strcmp(fn, last_fn) == 0) {
/* we've seen this place before */
e_seen++;
if (e_seen == MAXERR_LINE)
fmt = "etc ...";
else
if (e_seen > MAXERR_LINE)
/* and too often, I'd say ! */
return;
}
else {
/* brand new place */
last_fn = fn;
last_ln = ln;
e_seen = 0;
}
#endif LINT
#ifdef LINT
if ( /* there is a file name */
fn
&& /* the file name is global */
fn[0] == '/'
&& /* it is not a .c file */
strcmp(&fn[strlen(fn)-2], ".c") != 0
) {
/* we skip this message */
return;
}
#endif LINT
if (fn)
fprint(ERROUT, "\"%s\", line %u: ", fn, ln);
if (remark)
fprint(ERROUT, "%s ", remark);
doprnt(ERROUT, fmt, ap); /* contents of error */
fprint(ERROUT, "\n");
}

View File

@ -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

994
lang/cem/cemcom.ansi/eval.c Normal file
View File

@ -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 <em.h>
#include <em_reg.h>
#include "debug.h"
#include "nobitfield.h"
#include "dataflow.h"
#include "arith.h"
#include "type.h"
#include "idf.h"
#include "label.h"
#include "code.h"
#include "assert.h"
#include "def.h"
#include "expr.h"
#include "sizes.h"
#include "Lpars.h"
#include "level.h"
#include "stack.h"
#include "align.h"
#include "mes.h"
#include "atw.h"
#include "specials.h"
#define CRASH() crash("EVAL: CRASH at line %u", __LINE__)
char *symbol2str();
char *long2str();
arith NewLocal(); /* util.c */
#define LocalPtrVar() NewLocal(pointer_size, pointer_align, reg_pointer, REGISTER)
/* EVAL() is the main expression-tree evaluator, which turns
any legal expression tree into EM code. Parameters:
struct expr *expr
pointer to root of the expression tree to be evaluated
int val
indicates whether the resulting expression is to be
dereferenced (if val == RVAL and expr->ex_lvalue == 1)
or not (val == LVAL). The latter case indicates that
the resulting expression is an lvalue expression which
should not be dereferenced by EVAL
int code
indicates whether the expression tree must be turned
into EM code or not. E.g. the expression statement "12;"
delivers the expression "12" to EVAL while this should
not result in any EM code
label false_label, label true_label
if the expression is a logical or relational expression
and if the loop of the program depends on the resulting
value then EVAL generates jumps to the specified program
labels, in case they are specified (i.e. are non-zero)
*/
EVAL(expr, val, code, true_label, false_label)
register struct expr *expr;
int val, code;
label true_label, false_label;
{
register int gencode = (code == TRUE);
switch (expr->ex_class) {
case Value: /* just a simple value */
if (gencode)
load_val(expr, val);
break;
case String: /* a string constant */
if (gencode) {
string2pointer(expr);
C_lae_dlb(expr->VL_LBL, expr->VL_VALUE);
}
break;
#ifndef NOFLOAT
case Float: /* a floating constant */
if (gencode) {
label datlab = data_label();
C_df_dlb(datlab);
C_rom_fcon(expr->FL_VALUE, expr->ex_type->tp_size);
C_lae_dlb(datlab, (arith)0);
C_loi(expr->ex_type->tp_size);
}
break;
#endif NOFLOAT
case Oper: /* compound expression */
{
int oper = expr->OP_OPER;
register struct expr *left = expr->OP_LEFT;
register struct expr *right = expr->OP_RIGHT;
register struct type *tp = expr->OP_TYPE;
if (tp->tp_fund == ERRONEOUS || (expr->ex_flags & EX_ERROR)) {
/* stop immediately */
break;
}
if (tp->tp_fund == VOID)
gencode = 0;
switch (oper) {
case '+':
/* We have the following possibilities :
int + int, pointer + int, pointer + long,
long + long, double + double
*/
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode) {
switch (tp->tp_fund) {
case INT:
case LONG:
if (tp->tp_unsigned)
C_adu(tp->tp_size);
else
C_adi(tp->tp_size);
break;
case POINTER:
C_loc(right->ex_type->tp_size);
C_loc(pointer_size);
C_cuu();
C_ads(pointer_size);
break;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
case LNGDBL:
C_adf(tp->tp_size);
break;
#endif NOFLOAT
default:
crash("bad type +");
}
}
break;
case '-':
if (left == 0) { /* unary */
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode) {
switch (tp->tp_fund) {
case INT:
case LONG:
case POINTER:
C_ngi(tp->tp_size);
break;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
case LNGDBL:
C_ngf(tp->tp_size);
break;
#endif NOFLOAT
default:
CRASH();
}
}
break;
}
/* else binary; we have the following flavours:
int - int, pointer - int, pointer - long,
pointer - pointer, long - long, double - double
*/
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (!gencode)
break;
switch (tp->tp_fund) {
case INT:
case LONG:
if (tp->tp_unsigned)
C_sbu(tp->tp_size);
else
C_sbi(tp->tp_size);
break;
case POINTER:
if (right->ex_type->tp_fund == POINTER)
C_sbs(pointer_size);
else {
C_ngi(right->ex_type->tp_size);
C_loc(right->ex_type->tp_size);
C_loc(pointer_size);
C_cuu();
C_ads(pointer_size);
}
break;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
case LNGDBL:
C_sbf(tp->tp_size);
break;
#endif NOFLOAT
default:
crash("bad type -");
}
break;
case '*':
if (left == 0) { /* unary */
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode && right->ex_class == String) {
C_loi((arith)1);
}
}
else { /* binary */
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode)
switch (tp->tp_fund) {
case INT:
case LONG:
case POINTER:
if (tp->tp_unsigned)
C_mlu(tp->tp_size);
else
C_mli(tp->tp_size);
break;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
case LNGDBL:
/*C_mlf(double_size);*/
C_mlf(tp->tp_size);
break;
#endif NOFLOAT
default:
crash("bad type *");
}
}
break;
case '/':
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode)
switch (tp->tp_fund) {
case INT:
case LONG:
case POINTER:
if (tp->tp_unsigned)
C_dvu(tp->tp_size);
else
C_dvi(tp->tp_size);
break;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
case LNGDBL:
/*C_dvf(double_size);*/
C_dvf(tp->tp_size);
break;
#endif NOFLOAT
default:
crash("bad type /");
}
break;
case '%':
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
ASSERT(tp->tp_fund==INT || tp->tp_fund==LONG);
if (gencode)
if (tp->tp_unsigned)
C_rmu(tp->tp_size);
else
C_rmi(tp->tp_size);
break;
case LEFT:
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode)
if (tp->tp_unsigned)
C_slu(tp->tp_size);
else
C_sli(tp->tp_size);
break;
case RIGHT:
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode)
if (tp->tp_unsigned)
C_sru(tp->tp_size);
else
C_sri(tp->tp_size);
break;
case '<':
case LESSEQ:
case '>':
case GREATEREQ:
case EQUAL:
case NOTEQUAL:
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode) {
/* The operands have the same type */
arith size = left->ex_type->tp_size;
switch (tp->tp_fund) {
case INT:
case LONG:
if (left->ex_type->tp_unsigned)
C_cmu(size);
else
C_cmi(size);
break;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
case LNGDBL:
C_cmf(size);
break;
#endif NOFLOAT
case POINTER:
C_cmp();
break;
case ENUM:
C_cmi(size);
break;
default:
CRASH();
}
if (true_label != 0) {
compare(oper, true_label);
C_bra(false_label);
}
else {
truthvalue(oper);
}
}
break;
case '&':
case '|':
case '^':
/* both operands should have type int */
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode) {
arith size = tp->tp_size;
if ((int)size < (int)word_size)
size = word_size;
switch (oper) {
case '&':
C_and(size);
break;
case '|':
C_ior(size);
break;
case '^':
C_xor(size);
break;
}
}
break;
case '=': {
int newcode = tp->tp_size > 0; /* CJ */
#ifndef NOBITFIELD
if (left->ex_type->tp_fund == FIELD) {
eval_field(expr, gencode);
break;
}
#endif NOBITFIELD
EVAL(right, RVAL, newcode, NO_LABEL, NO_LABEL);
if (gencode)
C_dup(ATW(tp->tp_size));
if (left->ex_class != Value) {
EVAL(left, LVAL, newcode, NO_LABEL, NO_LABEL);
if (newcode)
store_block(tp->tp_size, tp->tp_align);
}
else if (newcode)
store_val(&(left->EX_VALUE), left->ex_type);
}
break;
case PLUSAB:
case MINAB:
case TIMESAB:
case DIVAB:
case MODAB:
case LEFTAB:
case RIGHTAB:
case ANDAB:
case XORAB:
case ORAB:
case POSTINCR:
case POSTDECR:
case PLUSPLUS:
case MINMIN:
{
arith tmp;
int compl; /* Complexity of left operand */
int newcode = left->ex_type->tp_size > 0; /* CJ */
#ifndef NOBITFIELD
if (left->ex_type->tp_fund == FIELD) {
eval_field(expr, gencode);
break;
}
#endif NOBITFIELD
if (newcode && left->ex_class == Value) {
compl = 0; /* Value */
load_val(left, RVAL);
}
else
if (left->ex_depth == 1 &&
!(left->ex_flags & EX_SIDEEFFECTS)) {
compl = 1;
EVAL(left, RVAL, newcode, NO_LABEL, NO_LABEL);
}
else {
compl = 2; /* otherwise */
EVAL(left, LVAL, newcode, NO_LABEL, NO_LABEL);
if (newcode) {
tmp = LocalPtrVar();
C_dup(pointer_size);
StoreLocal(tmp, pointer_size);
C_loi(left->ex_type->tp_size);
}
}
if (newcode) {
if (gencode && (oper == POSTINCR ||
oper == POSTDECR))
C_dup(ATW(left->ex_type->tp_size));
conversion(left->ex_type, tp);
}
EVAL(right, RVAL, newcode, NO_LABEL, NO_LABEL);
if (newcode) {
int dupval = gencode && oper != POSTINCR &&
oper != POSTDECR;
assop(tp, oper);
conversion(tp, left->ex_type);
if (compl == 0) {
store_val(&(left->EX_VALUE),
left->ex_type);
if (dupval) load_val(left, RVAL);
}
else if (compl == 1) {
EVAL(left, LVAL,1, NO_LABEL, NO_LABEL);
C_sti(left->ex_type->tp_size);
if (dupval) {
EVAL(left, LVAL, 1, NO_LABEL,
NO_LABEL);
C_loi(left->ex_type->tp_size);
}
}
else {
LoadLocal(tmp, pointer_size);
C_sti(left->ex_type->tp_size);
if (dupval) {
LoadLocal(tmp, pointer_size);
C_loi(left->ex_type->tp_size);
}
FreeLocal(tmp);
}
}
break;
}
case '(':
{
register struct expr *ex;
arith ParSize = (arith)0;
label setjmp_label = 0;
if (ISNAME(left)) {
if (left->VL_IDF->id_special == SP_SETJMP) {
label addr_label = data_label();
setjmp_label = text_label();
C_df_dlb(addr_label);
C_rom_ilb(setjmp_label);
C_lae_dlb(addr_label, (arith) 0);
C_loi(pointer_size);
ParSize += pointer_size;
}
}
if ((ex = right) != NILEXPR) {
/* function call with parameters*/
while ( ex->ex_class == Oper &&
ex->OP_OPER == PARCOMMA
) {
EVAL(ex->OP_RIGHT, RVAL,
ex->ex_type->tp_size > 0,
NO_LABEL, NO_LABEL);
ParSize += ATW(ex->ex_type->tp_size);
ex = ex->OP_LEFT;
}
EVAL(ex, RVAL, ex->ex_type->tp_size > 0,
NO_LABEL, NO_LABEL);
ParSize += ATW(ex->ex_type->tp_size);
}
if (ISNAME(left)) {
/* e.g., main() { (*((int (*)())0))(); } */
C_cal(left->VL_IDF->id_text);
if (setjmp_label) {
C_df_ilb(setjmp_label);
}
#ifdef DATAFLOW
{ extern char options[];
if (options['d'])
DfaCallFunction(
left->VL_IDF->id_text);
}
#endif DATAFLOW
}
else {
EVAL(left, LVAL, TRUE, NO_LABEL, NO_LABEL);
C_cai();
}
/* remove parameters from stack */
if (ParSize > (arith)0)
C_asp(ParSize);
if (gencode) {
if (is_struct_or_union(tp->tp_fund)) {
C_lfr(pointer_size);
load_block(tp->tp_size, (int) word_size);
}
else
C_lfr(ATW(tp->tp_size));
}
break;
}
case '.':
EVAL(left, LVAL, gencode, NO_LABEL, NO_LABEL);
ASSERT(is_cp_cst(right));
if (gencode)
C_adp(right->VL_VALUE);
break;
case ARROW:
EVAL(left, RVAL, gencode, NO_LABEL, NO_LABEL);
ASSERT(is_cp_cst(right));
if (gencode)
C_adp(right->VL_VALUE);
break;
case ',':
EVAL(left, RVAL, FALSE, NO_LABEL, NO_LABEL);
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
break;
case '~':
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode)
C_com(tp->tp_size);
break;
case '?': /* must be followed by ':' */
{
label l_true = text_label();
label l_false = text_label();
label l_end = text_label();
EVAL(left, RVAL, TRUE, l_true, l_false);
C_df_ilb(l_true);
EVAL(right->OP_LEFT, RVAL, gencode, NO_LABEL, NO_LABEL);
C_bra(l_end);
C_df_ilb(l_false);
EVAL(right->OP_RIGHT, RVAL, gencode, NO_LABEL, NO_LABEL);
C_df_ilb(l_end);
break;
}
case OR:
case AND: {
label l_false, l_true, l_maybe;
l_maybe = text_label();
if (true_label) {
l_false = false_label;
l_true = true_label;
}
else {
l_false = text_label();
l_true = gencode ? text_label(): l_false;
}
EVAL(left, RVAL, TRUE, oper == AND ? l_maybe : l_true,
oper == AND ? l_false : l_maybe);
C_df_ilb(l_maybe);
EVAL(right, RVAL, gencode, l_true, l_false);
if (gencode && !true_label) {
label l_end = text_label();
C_df_ilb(l_true);
C_loc((arith)1);
C_bra(l_end);
C_df_ilb(l_false);
C_loc((arith)0);
C_df_ilb(l_end);
}
else {
if (! true_label) C_df_ilb(l_false);
}
}
break;
case '!':
if (true_label == 0) {
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode) {
C_teq();
}
}
else
EVAL(right, RVAL, gencode, false_label,
true_label);
break;
case INT2INT:
#ifndef NOFLOAT
case INT2FLOAT:
case FLOAT2INT:
case FLOAT2FLOAT:
#endif NOFLOAT
EVAL(right, RVAL, gencode, NO_LABEL, NO_LABEL);
if (gencode)
conversion(right->ex_type, left->ex_type);
break;
default:
crash("(EVAL) bad operator %s\n", symbol2str(oper));
}
/* If the rvalue of the expression is required but
only its lvalue is evaluated, its rvalue is
loaded by the following statements:
*/
if (gencode && val == RVAL && expr->ex_lvalue == 1)
load_block(expr->ex_type->tp_size,
expr->ex_type->tp_align);
break;
}
default:
crash("(EVAL) bad expression class");
}
}
/* compare() serves as an auxiliary function of EVAL */
compare(relop, lbl)
int relop;
label lbl;
{
switch (relop) {
case '<':
C_zlt(lbl);
break;
case LESSEQ:
C_zle(lbl);
break;
case '>':
C_zgt(lbl);
break;
case GREATEREQ:
C_zge(lbl);
break;
case EQUAL:
C_zeq(lbl);
break;
case NOTEQUAL:
C_zne(lbl);
break;
default:
CRASH();
}
}
/* truthvalue() serves as an auxiliary function of EVAL */
truthvalue(relop)
int relop;
{
switch (relop) {
case '<':
C_tlt();
break;
case LESSEQ:
C_tle();
break;
case '>':
C_tgt();
break;
case GREATEREQ:
C_tge();
break;
case EQUAL:
C_teq();
break;
case NOTEQUAL:
C_tne();
break;
default:
CRASH();
}
}
/* assop() generates the opcode of an assignment operators op= */
assop(type, oper)
register struct type *type;
int oper;
{
register arith size;
register uns = type->tp_unsigned;
if ((int)(size = type->tp_size) < (int)word_size)
size = word_size;
switch (type->tp_fund) {
case CHAR:
case SHORT:
case INT:
case LONG:
case ENUM:
switch (oper) {
case PLUSAB:
case PLUSPLUS:
case POSTINCR:
if (uns)
C_adu(size);
else
C_adi(size);
break;
case MINAB:
case MINMIN:
case POSTDECR:
if (uns)
C_sbu(size);
else
C_sbi(size);
break;
case TIMESAB:
if (uns)
C_mlu(size);
else
C_mli(size);
break;
case DIVAB:
if (uns)
C_dvu(size);
else
C_dvi(size);
break;
case MODAB:
if (uns)
C_rmu(size);
else
C_rmi(size);
break;
case LEFTAB:
if (uns)
C_slu(size);
else
C_sli(size);
break;
case RIGHTAB:
if (uns)
C_sru(size);
else
C_sri(size);
break;
case ANDAB:
C_and(size);
break;
case XORAB:
C_xor(size);
break;
case ORAB:
C_ior(size);
break;
}
break;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
case LNGDBL:
switch (oper) {
case PLUSAB:
case PLUSPLUS:
case POSTINCR:
C_adf(size);
break;
case MINAB:
case MINMIN:
case POSTDECR:
C_sbf(size);
break;
case TIMESAB:
C_mlf(size);
break;
case DIVAB:
C_dvf(size);
break;
}
break;
#endif NOFLOAT
case POINTER:
if (oper == MINAB || oper == MINMIN || oper == POSTDECR)
C_ngi(size);
C_loc(size);
C_loc(pointer_size);
C_cuu();
C_ads(pointer_size);
break;
case ERRONEOUS:
break;
default:
crash("(assop) bad type %s\n", symbol2str(type->tp_fund));
}
}
/* store_val() generates code for a store operation.
There are four ways of storing data:
- into a global variable
- into an automatic local variable
- into a local static variable
- absolute addressing
*/
store_val(vl, tp)
register struct value *vl;
struct type *tp;
{
arith size = tp->tp_size;
int tpalign = tp->tp_align;
int al_on_word;
register int inword;
register int indword;
arith val = vl->vl_value;
if (vl->vl_class == Const) { /* absolute addressing */
load_cst(val, pointer_size);
store_block(size, tpalign);
return;
}
al_on_word = (tpalign % word_align == 0);
if (!(inword = (size == word_size && al_on_word)))
indword = (size == dword_size && al_on_word);
if (vl->vl_class == Name) {
register struct idf *id = vl->vl_data.vl_idf;
register struct def *df = id->id_def;
if (df->df_level == L_GLOBAL) {
if (inword)
C_ste_dnam(id->id_text, val);
else
if (indword)
C_sde_dnam(id->id_text, val);
else {
C_lae_dnam(id->id_text, val);
store_block(size, tpalign);
}
}
else {
ASSERT(df->df_sc != STATIC);
if (inword || indword)
StoreLocal(df->df_address + val, size);
else {
AddrLocal(df->df_address + val);
store_block(size, tpalign);
}
}
}
else {
label dlb = vl->vl_data.vl_lbl;
ASSERT(vl->vl_class == Label);
if (inword)
C_ste_dlb(dlb, val);
else
if (indword)
C_sde_dlb(dlb, val);
else {
C_lae_dlb(dlb, val);
store_block(size, tpalign);
}
}
}
/* load_val() generates code for stacking a certain value (from ex),
which can be obtained in one of the following ways:
- value from absolute addressed memory
- constant value
- function result
- global variable
- static variable
- local variable
*/
load_val(expr, rlval)
register struct expr *expr; /* expression containing the value */
int rlval; /* generate either LVAL or RVAL */
{
register struct type *tp = expr->ex_type;
int rvalue = (rlval == RVAL && expr->ex_lvalue != 0);
arith size = tp->tp_size;
int tpalign = tp->tp_align;
int al_on_word;
register int inword, indword;
register arith val = expr->VL_VALUE;
if (expr->VL_CLASS == Const) {
if (rvalue) { /* absolute addressing */
load_cst(val, pointer_size);
load_block(size, tpalign);
}
else /* integer, unsigned, long, enum etc */
load_cst(val, size);
return;
}
if (rvalue) {
al_on_word = (tpalign % word_align == 0);
if (!(inword = (size == word_size && al_on_word)))
indword = (size == dword_size && al_on_word);
}
if (expr->VL_CLASS == Label) {
if (rvalue) {
if (inword)
C_loe_dlb(expr->VL_LBL, val);
else
if (indword)
C_lde_dlb(expr->VL_LBL, val);
else {
C_lae_dlb(expr->VL_LBL, val);
load_block(size, tpalign);
}
}
else {
C_lae_dlb(expr->VL_LBL, (arith)0);
C_adp(val);
}
}
else {
register struct idf *id = expr->VL_IDF;
register struct def *df = id->id_def;
ASSERT(ISNAME(expr));
if (df->df_type->tp_fund == FUNCTION) {
/* the previous statement tried to catch a function
identifier, which may be cast to a pointer to a
function.
ASSERT(!(rvalue)); ???
*/
C_lpi(id->id_text);
}
else
if (df->df_level == L_GLOBAL) {
if (rvalue) {
if (inword)
C_loe_dnam(id->id_text, val);
else
if (indword)
C_lde_dnam(id->id_text, val);
else {
C_lae_dnam(id->id_text, val);
load_block(size, tpalign);
}
}
else {
C_lae_dnam(id->id_text, (arith)0);
C_adp(val);
}
}
else {
ASSERT(df->df_sc != STATIC);
if (rvalue) {
if (inword || indword)
LoadLocal(df->df_address + val, size);
else {
AddrLocal(df->df_address + val);
load_block(size, tpalign);
}
}
else {
AddrLocal(df->df_address);
C_adp(val);
}
}
}
}
load_cst(val, siz)
arith val, siz;
{
if (siz <= word_size)
C_loc(val);
else
if (siz == dword_size)
C_ldc(val);
else {
label datlab;
C_df_dlb(datlab = data_label());
C_rom_icon(long2str((long)val, 10), siz);
C_lae_dlb(datlab, (arith)0);
C_loi(siz);
}
}
#endif LINT

536
lang/cem/cemcom.ansi/expr.c Normal file
View File

@ -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 <alloc.h>
#include "idf.h"
#include "arith.h"
#include "def.h"
#include "type.h"
#include "label.h"
#include "expr.h"
#include "LLlex.h"
#include "Lpars.h"
#include "decspecs.h"
#include "declar.h"
#include "sizes.h"
#include "level.h"
#include "noRoption.h"
extern char *symbol2str();
extern char options[];
int
rank_of(oper)
int oper;
{
/* The rank of the operator oper is returned.
*/
switch (oper) {
default:
return 0; /* INT2INT etc. */
case '[':
case '(':
case '.':
case ARROW:
case PARCOMMA:
return 1;
case '!':
case PLUSPLUS:
case MINMIN:
case CAST:
case SIZEOF:
return 2; /* monadic */
case '*':
case '/':
case '%':
return 3;
case '+':
case '-':
return 4;
case LEFT:
case RIGHT:
return 5;
case '<':
case '>':
case LESSEQ:
case GREATEREQ:
return 6;
case EQUAL:
case NOTEQUAL:
return 7;
case '&':
return 8;
case '^':
return 9;
case '|':
return 10;
case AND:
return 11;
case OR:
return 12;
case '?':
case ':':
return 13;
case '=':
case PLUSAB:
case MINAB:
case TIMESAB:
case DIVAB:
case MODAB:
case RIGHTAB:
case LEFTAB:
case ANDAB:
case XORAB:
case ORAB:
return 14;
case ',':
return 15;
}
/*NOTREACHED*/
}
#ifndef NOROPTION
int
rank_of_expression(ex)
register struct expr *ex;
{
/* Returns the rank of the top node in the expression.
*/
if (!ex || (ex->ex_flags & EX_PARENS) || ex->ex_class != Oper)
return 0;
return rank_of(ex->OP_OPER);
}
check_conditional(expr, oper, pos_descr)
register struct expr *expr;
char *pos_descr;
{
/* Warn if restricted C is in effect and the expression expr,
which occurs at the position pos_descr, is not lighter than
the operator oper.
*/
if (options['R'] && rank_of_expression(expr) >= rank_of(oper))
expr_warning(expr, "%s %s is ungrammatical",
symbol2str(expr->OP_OPER), pos_descr);
}
#endif
dot2expr(expp)
struct expr **expp;
{
/* The token in dot is converted into an expression, a
pointer to which is stored in *expp.
*/
register struct expr *ex = new_expr();
*expp = ex;
ex->ex_file = dot.tk_file;
ex->ex_line = dot.tk_line;
switch (DOT) {
case IDENTIFIER:
idf2expr(ex);
break;
case INTEGER:
int2expr(ex);
break;
#ifndef NOFLOAT
case FLOATING:
float2expr(ex);
break;
#endif NOFLOAT
default:
crash("bad conversion to expression");
/*NOTREACHED*/
}
}
idf2expr(expr)
register struct expr *expr;
{
/* Dot contains an identifier which is turned into an
expression.
Note that this constitutes an applied occurrence of
the identifier.
*/
register struct idf *idf = dot.tk_idf; /* != 0*/
register struct def *def = idf->id_def;
if (def == 0) {
if (AHEAD == '(') /* function call, declare name IMPLICITly */
add_def(idf, IMPLICIT, funint_type, level); /* RM 13 */
else {
if (!is_anon_idf(idf))
error("%s undefined", idf->id_text);
/* declare idf anyway */
add_def(idf, 0, error_type, level);
}
def = idf->id_def;
}
/* now def != 0 */
if (def->df_type->tp_fund == LABEL) {
expr_error(expr, "illegal use of label %s", idf->id_text);
expr->ex_type = error_type;
}
else {
#ifndef LINT
def->df_used = 1;
#endif LINT
expr->ex_type = def->df_type;
if (expr->ex_type == error_type)
expr->ex_flags |= EX_ERROR;
}
expr->ex_lvalue =
( def->df_type->tp_fund == FUNCTION ||
def->df_type->tp_fund == ARRAY ||
def->df_sc == ENUM
) ? 0 : 1;
if (def->df_type->tp_typequal & TQ_CONST)
expr->ex_flags |= EX_READONLY;
if (def->df_type->tp_typequal & TQ_VOLATILE)
expr->ex_flags |= EX_VOLATILE;
expr->ex_class = Value;
if (def->df_sc == ENUM) {
expr->VL_CLASS = Const;
expr->VL_VALUE = def->df_address;
}
#ifndef LINT
else
if (def->df_sc == STATIC && def->df_level >= L_LOCAL) {
expr->VL_CLASS = Label;
expr->VL_LBL = def->df_address;
expr->VL_VALUE = (arith)0;
}
#endif LINT
else {
expr->VL_CLASS = Name;
expr->VL_IDF = idf;
expr->VL_VALUE = (arith)0;
}
}
string2expr(expp, typ, str, len)
register struct expr **expp;
int typ, len;
char *str;
{
/* The string in the argument is converted into an expression,
a pointer to which is stored in *expp.
*/
register struct expr *ex = new_expr();
*expp = ex;
ex->ex_file = dot.tk_file;
ex->ex_line = dot.tk_line;
ex->ex_type = string_type;
/*
ex->ex_type = qualifier_type(ex->ex_type, TQ_CONST);
*/
ex->ex_flags |= EX_READONLY;
ex->ex_lvalue = 0;
ex->ex_class = String;
ex->SG_VALUE = str;
ex->SG_LEN = len;
ex->SG_DATLAB = 0;
}
int2expr(expr)
struct expr *expr;
{
/* Dot contains an integer constant which is turned
into an expression.
*/
fill_int_expr(expr, dot.tk_ival, dot.tk_fund);
}
#ifndef NOFLOAT
float2expr(expr)
register struct expr *expr;
{
/* Dot contains a floating point constant which is turned
into an expression.
*/
register int fund;
fund = dot.tk_fund;
switch (fund) {
case FLOAT:
expr->ex_type = float_type;
break;
case DOUBLE:
expr->ex_type = double_type;
break;
case LNGDBL:
expr->ex_type = lngdbl_type;
break;
default:
crash("(float2expr) bad fund %s\n", symbol2str(fund));
}
expr->ex_class = Float;
expr->FL_VALUE = dot.tk_fval;
expr->FL_DATLAB = 0;
}
#endif NOFLOAT
struct expr*
intexpr(ivalue, fund)
arith ivalue;
int fund;
{
/* The value ivalue is turned into an integer expression of
the size indicated by fund.
*/
register struct expr *expr = new_expr();
expr->ex_file = dot.tk_file;
expr->ex_line = dot.tk_line;
fill_int_expr(expr, ivalue, fund);
return expr;
}
fill_int_expr(ex, ivalue, fund)
register struct expr *ex;
arith ivalue;
int fund;
{
/* Details derived from ivalue and fund are put into the
constant integer expression ex.
*/
switch (fund) {
case INT:
ex->ex_type = int_type;
break;
case INTEGER:
if (ivalue >= 0 && ivalue <= max_int) {
ex->ex_type = int_type;
break;
}
/*FALL THROUGH*/
case LONG:
ex->ex_type =
(ivalue & (1L << (8*long_size - 1))) ? ulong_type
: long_type;
break;
case ULONG:
ex->ex_type = ulong_type;
break;
case UNSIGNED:
/* We cannot make a test like
ivalue <= max_unsigned
because, if
sizeof(long) == int_size
holds, max_unsigned may be a negative long in
which case the comparison results in an unexpected
answer.
*/
ex->ex_type =
(ivalue & ~max_int) ?
( (ivalue & ~max_unsigned) ?
( ivalue & (1L<<(8*long_size-1)) ?
ulong_type : long_type
) : uint_type
) : int_type;
break;
default:
crash("(intexpr) bad fund %s\n", symbol2str(fund));
/*NOTREACHED*/
}
ex->ex_class = Value;
ex->VL_CLASS = Const;
ex->VL_VALUE = ivalue;
cut_size(ex);
}
struct expr *
new_oper(tp, e1, oper, e2)
struct type *tp;
register struct expr *e1, *e2;
{
/* A new expression is constructed which consists of the
operator oper which has e1 and e2 as operands; for a
monadic operator e1 == NILEXPR.
During the construction of the right recursive initialisation
tree it is possible for e2 to be NILEXPR.
*/
register struct expr *expr = new_expr();
register struct oper *op;
if (e2) {
register struct expr *e = e2;
while (e->ex_class == Oper && e->OP_LEFT)
e = e->OP_LEFT;
expr->ex_file = e->ex_file;
expr->ex_line = e->ex_line;
}
else
if (e1) {
register struct expr *e = e1;
while (e->ex_class == Oper && e->OP_RIGHT)
e = e->OP_RIGHT;
expr->ex_file = e->ex_file;
expr->ex_line = e->ex_line;
}
else {
expr->ex_file = dot.tk_file;
expr->ex_line = dot.tk_line;
}
expr->ex_type = tp;
expr->ex_class = Oper;
/* combine depths and flags of both expressions */
if (e2) {
int e1_depth = e1 ? e1->ex_depth : 0;
int e1_flags = e1 ? e1->ex_flags : 0;
expr->ex_depth =
(e1_depth > e2->ex_depth ? e1_depth : e2->ex_depth) + 1;
expr->ex_flags = (e1_flags | e2->ex_flags) & ~EX_PARENS;
}
op = &expr->ex_object.ex_oper;
op->op_type = tp;
op->op_oper = oper;
op->op_left = e1;
op->op_right = e2;
#ifdef LINT
lint_new_oper(expr);
#endif LINT
return expr;
}
chk_cst_expr(expp)
register struct expr **expp;
{
/* The expression expr is checked for constancy.
There are 6 places where constant expressions occur in C:
1. after #if
2. in a global initialization
3. as size in an array declaration
4. as value in an enum declaration
5. as width in a bit field
6. as case value in a switch
The constant expression in a global initialization is
handled separately (by IVAL()).
There are various disparate restrictions on each of
the others in the various C compilers. I have tried some
hypotheses to unify them, but all have failed.
This routine will give a warning for those operators
not allowed by K&R, under the R-option only. The anomalies
are cast, logical operators and the expression comma.
Special problems (of which there is only one, sizeof in
Preprocessor #if) have to be dealt with locally
Note that according to K&R the negation ! is illegal in
constant expressions and is indeed rejected by the
Ritchie compiler.
*/
register struct expr *expr = *expp;
register int fund = expr->ex_type->tp_fund;
register int flags = expr->ex_flags;
int err = 0;
#ifdef DEBUG
print_expr("constant_expression", expr);
#endif DEBUG
if ( fund != CHAR && fund != SHORT && fund != INT &&
fund != ENUM && fund != LONG
)
expr_error(expr, "non-numerical constant expression"), err++;
else
if (!is_ld_cst(expr))
expr_error(expr, "expression is not constant"), err++;
#ifndef NOROPTION
if (options['R']) {
if (flags & EX_CAST)
expr_warning(expr, "cast in constant expression");
if (flags & EX_LOGICAL)
expr_warning(expr,
"logical operator in constant expression");
if (flags & EX_COMMA)
expr_warning(expr,
"expression comma in constant expression");
}
#endif NOROPTION
if (err)
erroneous2int(expp);
}
init_expression(eppp, expr)
register struct expr ***eppp, *expr;
{
/* The expression expr is added to the tree designated
indirectly by **eppp.
The natural form of a tree representing an
initial_value_list is right-recursive, ie. with the
left-most comma as main operator. The iterative grammar in
expression.g, however, tends to produce a left-recursive
tree, ie. one with the right-most comma as its main
operator.
To produce a right-recursive tree from the iterative
grammar, we keep track of the address of the pointer where
the next expression must be hooked in.
*/
**eppp = new_oper(void_type, expr, INITCOMMA, NILEXPR);
*eppp = &(**eppp)->OP_RIGHT;
}
int
is_ld_cst(expr)
register struct expr *expr;
{
/* An expression is a `load-time constant' if it is of the form
<idf> +/- <integral> or <integral>.
*/
#ifdef LINT
if (expr->ex_class == String)
return 1;
#endif LINT
return expr->ex_lvalue == 0 && expr->ex_class == Value;
}
int
is_cp_cst(expr)
register struct expr *expr;
{
/* An expression is a `compile-time constant' if it is a
load-time constant, and the idf is not there.
*/
return is_ld_cst(expr) && expr->VL_CLASS == Const;
}
#ifndef NOFLOAT
int
is_fp_cst(expr)
register struct expr *expr;
{
/* An expression is a `floating-point constant' if it consists
of the float only.
*/
return expr->ex_class == Float;
}
#endif NOFLOAT
free_expression(expr)
register struct expr *expr;
{
/* The expression expr is freed recursively.
*/
if (expr) {
if (expr->ex_class == Oper) {
free_expression(expr->OP_LEFT);
free_expression(expr->OP_RIGHT);
}
free_expr(expr);
}
}

View File

@ -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 */

View File

@ -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 <alloc.h>
#include "lint.h"
#include "arith.h"
#include "LLlex.h"
#include "type.h"
#include "idf.h"
#include "label.h"
#include "expr.h"
#include "code.h"
#include "noRoption.h"
extern struct expr *intexpr();
}
/* 7.1 */
primary(register struct expr **expp;) :
IDENTIFIER
{dot2expr(expp);}
|
constant(expp)
|
string(expp)
|
'(' expression(expp) ')'
{(*expp)->ex_flags |= EX_PARENS;}
;
/* Character string literals that are adjacent tokens
are concatenated into a single character string
literal.
*/
string(register struct expr **expp;)
{ register int i, len;
register char *str;
register int fund;
}
:
STRING
{ str = dot.tk_bts;
len = dot.tk_len;
fund = dot.tk_fund;
}
[
STRING
{ /* A pasted string keeps the type of the first
string literal.
The pasting of normal strings and wide
character strings are stated as having an
undefined behaviour.
*/
if (dot.tk_fund != fund)
warning("illegal pasting of string literals");
str = Srealloc(str, (unsigned) (--len + dot.tk_len));
for (i = 0; i < dot.tk_len; i++)
str[len++] = dot.tk_bts[i];
}
]*
{string2expr(expp, STRING, str, len);}
;
secundary(register struct expr **expp;) :
primary(expp)
[
index_pack(expp)
|
parameter_pack(expp)
|
selection(expp)
]*
;
index_pack(struct expr **expp;)
{struct expr *e1;}
:
'[' expression(&e1) ']'
{ch7bin(expp, '[', e1);}
;
parameter_pack(struct expr **expp;)
{struct expr *e1 = 0;}
:
'(' parameter_list(&e1)? ')'
{ ch7bin(expp, '(', e1);
call_proto(expp);
}
;
selection(struct expr **expp;)
{int oper; struct idf *idf;}
:
[ '.' | ARROW ]
{oper = DOT;}
identifier(&idf)
{ch7sel(expp, oper, idf);}
;
parameter_list(struct expr **expp;)
{struct expr *e1 = 0;}
:
assignment_expression(expp)
{any2opnd(expp, PARCOMMA);}
[ ','
assignment_expression(&e1)
{any2opnd(&e1, PARCOMMA);}
{ch7bin(expp, PARCOMMA, e1);}
]*
;
/* 7.2 */
postfixed(struct expr **expp;)
{int oper;}
:
secundary(expp)
[
postop(&oper)
{ch7incr(expp, oper);}
|
empty
]
;
%first first_of_type_specifier, type_specifier;
unary(register struct expr **expp;)
{struct type *tp; int oper;}
:
%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER)
cast(&tp) unary(expp)
{ ch7cast(expp, CAST, tp);
(*expp)->ex_flags |= EX_CAST;
}
|
postfixed(expp)
|
unop(&oper) unary(expp)
{ch7mon(oper, expp);}
|
size_of(expp)
;
size_of(register struct expr **expp;)
{struct type *tp;}
:
SIZEOF
[%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER)
cast(&tp)
{
*expp = intexpr(size_of_type(tp, "type"), INT);
(*expp)->ex_flags |= EX_SIZEOF;
}
|
unary(expp)
{ch7mon(SIZEOF, expp);}
]
;
/* 7.3-7.12 */
/* The set of operators in C is stratified in 15 levels, with level
N being treated in RM 7.N. In principle each operator is
assigned a rank, ranging from 1 to 15. Such an expression can
be parsed by a construct like:
binary_expression(int maxrank;)
{int oper;}
:
binary_expression(maxrank - 1)
[%if (rank_of(DOT) <= maxrank)
binop(&oper)
binary_expression(rank_of(oper)-1)
]?
;
except that some call of 'unary' is necessary, depending on the
grammar.
This simple view is marred by three complications:
1. Level 15 (comma operator) is not allowed in many
contexts and is different.
2. Level 13 (conditional operator) is a ternary operator,
which does not fit this scheme at all.
3. Level 14 (assignment operators) group right-to-left, as
opposed to 2-12, which group left-to-right (or are
immaterial).
4. The operators in level 14 start with operators in levels
2-13 (RM 7.14: The two parts of a compound assignment
operator are separate tokens.) This causes LL1 problems.
This forces us to have four rules:
binary_expression for level 2-12
conditional_expression for level 13
assignment_expression for level 14 and
expression for the most general expression
*/
binary_expression(int maxrank; struct expr **expp;)
{int oper; struct expr *e1;}
:
unary(expp)
[%while (rank_of(DOT) <= maxrank && AHEAD != '=')
/* '?', '=', and ',' are no binops, and the test
for AHEAD != '=' keeps the other assignment
operators out
*/
binop(&oper)
binary_expression(rank_of(oper)-1, &e1)
{
ch7bin(expp, oper, e1);
}
]*
;
/* 7.13 */
conditional_expression(struct expr **expp;)
/* There is some unfortunate disagreement about what is allowed
between the '?' and the ':' of a conditional_expression.
Although the Ritchie compiler does not even allow
conditional_expressions there, some other compilers (e.g., VAX)
accept a full assignment_expression there, and programs
(like, e.g., emacs) rely on it. So we have little choice.
*/
{struct expr *e1 = 0, *e2 = 0;}
:
/* allow all binary operators */
binary_expression(rank_of('?') - 1, expp)
[ '?'
expression(&e1)
{
#ifndef NOROPTION
check_conditional(e1, '?', "between ? and :");
#endif
}
':'
assignment_expression(&e2)
{
#ifndef NOROPTION
check_conditional(e2, '=', "after :");
#endif
ch7bin(&e1, ':', e2);
opnd2test(expp, '?');
ch7bin(expp, '?', e1);
}
]?
;
/* 7.14 */
assignment_expression(struct expr **expp;)
{
int oper;
struct expr *e1 = 0;
}
:
conditional_expression(expp)
[%prefer /* (rank_of(DOT) <= maxrank) for any asgnop */
asgnop(&oper)
assignment_expression(&e1)
{ch7asgn(expp, oper, e1);}
|
empty /* LLgen artefact ??? */
]
;
/* 7.15 */
expression(struct expr **expp;)
{struct expr *e1;}
:
assignment_expression(expp)
[ ','
assignment_expression(&e1)
{
ch7bin(expp, ',', e1);
}
]*
;
unop(int *oper;) :
['*' | '&' | '-' | '+' | '!' | '~' | PLUSPLUS | MINMIN]
{*oper = DOT;}
;
postop(int *oper;):
PLUSPLUS {*oper = POSTINCR;}
|
MINMIN {*oper = POSTDECR;}
;
multop:
'*' | '/' | '%'
;
addop:
'+' | '-'
;
shiftop:
LEFT | RIGHT
;
relop:
'<' | '>' | LESSEQ | GREATEREQ
;
eqop:
EQUAL | NOTEQUAL
;
arithop:
multop | addop | shiftop
|
'&' | '^' | '|'
;
binop(int *oper;) :
[ arithop | relop | eqop | AND | OR ]
{*oper = DOT;}
;
asgnop(register int *oper;):
'=' {*oper = DOT;}
|
'+' '=' {*oper = PLUSAB;}
|
'-' '=' {*oper = MINAB;}
|
'*' '=' {*oper = TIMESAB;}
|
'/' '=' {*oper = DIVAB;}
|
'%' '=' {*oper = MODAB;}
|
LEFT '=' {*oper = LEFTAB;}
|
RIGHT '=' {*oper = RIGHTAB;}
|
'&' '=' {*oper = ANDAB;}
|
'^' '=' {*oper = XORAB;}
|
'|' '=' {*oper = ORAB;}
|
[ PLUSAB | MINAB | TIMESAB | DIVAB | MODAB | LEFTAB | RIGHTAB
| ANDAB | XORAB | ORAB ]
{ *oper = DOT; }
;
constant(struct expr **expp;) :
[
INTEGER
|
FLOATING
] {dot2expr(expp);}
;
/* 15 */
constant_expression (struct expr **expp;) :
assignment_expression(expp)
{chk_cst_expr(expp);}
;
identifier(struct idf **idfp;) :
[
IDENTIFIER
|
TYPE_IDENTIFIER
]
{
*idfp = dot.tk_idf;
}
;

View File

@ -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 <em.h>
#include <em_reg.h>
#include "debug.h"
#include "arith.h"
#include "type.h"
#include "idf.h"
#include "label.h"
#include "code.h"
#include "assert.h"
#include "expr.h"
#include "sizes.h"
#include "align.h"
#include "Lpars.h"
#include "field.h"
arith NewLocal(); /* util.c */
char *symbol2str(); /* symbol2str.c */
/* Eval_field() evaluates expressions involving bit fields.
The various instructions are not yet optimised in the expression
tree and are therefore dealt with in this function.
The actions taken at any operation are described clearly by the
code for this actions.
Notes
[1] the bitfields are packed in target machine integers!
[2] op is either an assignment operator or an increment/
decrement operator
[3] atype: the type in which the bitfield arithmetic is done;
and in which bitfields are stored!
*/
eval_field(expr, code)
struct expr *expr;
int code;
{
int op = expr->OP_OPER;
register struct expr *leftop = expr->OP_LEFT;
register struct expr *rightop = expr->OP_RIGHT;
register struct field *fd = leftop->ex_type->tp_field;
struct type *tp = leftop->ex_type->tp_up;
arith tmpvar;
struct type *atype = tp->tp_unsigned ? uword_type : word_type;
arith asize = atype->tp_size;
/* First some assertions to be sure that the rest is legal */
ASSERT(asize == word_size); /* make sure that C_loc() is legal */
ASSERT(leftop->ex_type->tp_fund == FIELD);
leftop->ex_type = atype; /* this is cheating but it works... */
if (op == '=') {
/* F = E: f = ((E & mask)<<shift) | (~(mask<<shift) & f) */
ASSERT(tp == rightop->ex_type);
EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
conversion(tp, atype);
C_loc(fd->fd_mask);
C_and(asize);
if (code == TRUE)
C_dup(asize);
C_loc((arith)fd->fd_shift);
if (atype->tp_unsigned)
C_slu(asize);
else
C_sli(asize);
C_loc(~((fd->fd_mask << fd->fd_shift) | (~0 << (8 * asize))));
if (leftop->ex_depth == 0) { /* simple case */
load_val(leftop, RVAL);
C_and(asize);
C_ior(asize);
store_val(&(leftop->EX_VALUE), atype);
}
else { /* complex case */
tmpvar = NewLocal(pointer_size, pointer_align,
reg_pointer, 0);
EVAL(leftop, LVAL, TRUE, NO_LABEL, NO_LABEL);
C_dup(pointer_size);
StoreLocal(tmpvar, pointer_size);
C_loi(asize);
C_and(asize);
C_ior(asize);
LoadLocal(tmpvar, pointer_size);
C_sti(asize);
FreeLocal(tmpvar);
}
}
else { /* treat ++F as F += 1 and --F as F -= 1 */
/* F op= e: f = (((((f>>shift)&mask) op e)&mask)<<shift)|
(f&~(mask<<shift))
*/
if (leftop->ex_depth == 0) /* simple case */
load_val(leftop, RVAL);
else { /* complex case */
tmpvar = NewLocal(pointer_size, pointer_align,
reg_pointer, 0);
EVAL(leftop, LVAL, TRUE, NO_LABEL, NO_LABEL);
C_dup(pointer_size);
StoreLocal(tmpvar, pointer_size);
C_loi(asize);
}
if (atype->tp_unsigned) {
C_loc((arith)fd->fd_shift);
C_sru(asize);
C_loc(fd->fd_mask);
C_and(asize);
}
else {
arith bits_in_type = asize * 8;
C_loc(bits_in_type - (fd->fd_width + fd->fd_shift));
C_sli(asize);
C_loc(bits_in_type - fd->fd_width);
C_sri(asize);
}
if (code == TRUE && (op == POSTINCR || op == POSTDECR))
C_dup(asize);
conversion(atype, rightop->ex_type);
EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
/* the 'op' operation: */
if (op == PLUSPLUS || op == POSTINCR)
assop(rightop->ex_type, PLUSAB);
else
if (op == MINMIN || op == POSTDECR)
assop(rightop->ex_type, MINAB);
else
assop(rightop->ex_type, op);
conversion(rightop->ex_type, atype);
C_loc(fd->fd_mask);
C_and(asize);
if (code == TRUE && op != POSTINCR && op != POSTDECR)
C_dup(asize);
C_loc((arith)fd->fd_shift);
if (atype->tp_unsigned)
C_slu(asize);
else
C_sli(asize);
C_loc(~((fd->fd_mask << fd->fd_shift) | (~0 << (8 * asize))));
if (leftop->ex_depth == 0) {
load_val(leftop, RVAL);
C_and(asize);
C_ior(asize);
store_val(&(leftop->EX_VALUE), atype);
}
else {
LoadLocal(tmpvar, pointer_size);
C_loi(asize);
C_and(asize);
C_ior(asize);
LoadLocal(tmpvar, pointer_size);
C_sti(asize);
FreeLocal(tmpvar);
}
}
if (code == TRUE) {
/* Take care that the effective value stored in
the bit field (i.e. the value that is got on
retrieval) is on top of stack.
*/
if (atype->tp_unsigned == 0) { /* sign extension */
register arith shift = asize * 8 - fd->fd_width;
C_loc(shift);
C_sli(asize);
C_loc(shift);
C_sri(asize);
}
conversion(atype, expr->ex_type);
}
}
#endif NOBITFIELD
#endif LINT

View File

@ -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 */

View File

@ -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 */

736
lang/cem/cemcom.ansi/idf.c Normal file
View File

@ -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 <em_reg.h>
#include "nofloat.h"
#include "debug.h"
#include "idfsize.h"
#include "botch_free.h"
#include "nopp.h"
#include "nparams.h"
#include <alloc.h>
#include "arith.h"
#include "align.h"
#include "LLlex.h"
#include "level.h"
#include "stack.h"
#include "idf.h"
#include "label.h"
#include "def.h"
#include "type.h"
#include "proto.h"
#include "struct.h"
#include "declar.h"
#include "decspecs.h"
#include "sizes.h"
#include "Lpars.h"
#include "assert.h"
#include "specials.h" /* registration of special identifiers */
#include "noRoption.h"
int idfsize = IDFSIZE;
extern char options[];
extern arith NewLocal();
char sp_occurred[SP_TOTAL+1]; /* indicate occurrence of special id */
struct idf *idf_hashtable[HASHSIZE];
/* All identifiers can in principle be reached through
idf_hashtable; idf_hashtable[hc] is the start of a chain of
idf's whose tags all hash to hc. Each idf is the start of
a chain of def's for that idf, sorted according to level,
with the most recent one on top.
Any identifier occurring on a level is entered into this
list, regardless of the nature of its declaration
(variable, selector, structure tag, etc.).
*/
struct idf *
idf_hashed(tg, size, hc)
char *tg;
int size; /* includes the '\0' character */
int hc;
{
/* The tag tg with length size and known hash value hc is
looked up in the identifier table; if not found, it is
entered. A pointer to it is returned.
The identifier has already been truncated to idfsize
characters.
*/
register struct idf **hook = &idf_hashtable[hc], *notch;
while ((notch = *hook)) {
register char *s1 = tg;
register char *cp = notch->id_text;
register int cmp;
while (!(cmp = (*s1 - *cp++))) {
if (*s1++ == '\0') {
break;
}
}
if (cmp < 0)
break;
if (cmp == 0) {
/* suppose that special identifiers, as
"setjmp", are already inserted
*/
sp_occurred[notch->id_special] = 1;
return notch;
}
hook = &notch->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;
}
}

View File

@ -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();

View File

@ -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 <system.h>
#include <alloc.h>
#include <time.h>
#include "class.h"
#include "macro.h"
#include "idf.h"
struct mkey {
char *mk_reserved;
int mk_key;
} mkey[] = {
{"define", K_DEFINE},
{"elif", K_ELIF},
{"else", K_ELSE},
{"endif", K_ENDIF},
{"error", K_ERROR},
{"if", K_IF},
{"ifdef", K_IFDEF},
{"ifndef", K_IFNDEF},
{"include", K_INCLUDE},
{"line", K_LINE},
{"pragma", K_PRAGMA},
{"undef", K_UNDEF},
{0, K_UNKNOWN}
};
char *strcpy();
init_pp()
{
static char *months[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
long clock, sys_time();
static char dbuf[30];
static char tbuf[30];
struct tm *tp;
/* Initialise the control line keywords (if, include, define, etc)
Although the lexical analyzer treats them as identifiers, the
control line handler can recognize them as keywords by the
id_resmac field of the identifier.
*/
{
register struct mkey *mk = &mkey[0];
while (mk->mk_reserved) {
register struct idf *idf = str2idf(mk->mk_reserved);
if (idf->id_resmac)
fatal("maximum identifier length insufficient");
idf->id_resmac = mk->mk_key;
mk++;
}
}
/* Initialize __LINE__, __FILE__, __DATE__, __TIME__,
and __STDC__ macro definitions.
*/
clock = sys_time();
tp = localtime(&clock);
/* __DATE__ */
sprintf(dbuf, "\"%.3s %.2d %d\"", months[tp->tm_mon],
tp->tm_mday, tp->tm_year+1900);
macro_def(str2idf("__DATE__"), dbuf, -1, 12, NOFLAG);
/* __TIME__ */
sprintf(tbuf, "\"%.2d:%.2d:%.2d\"", tp->tm_hour, tp->tm_min, tp->tm_sec);
macro_def(str2idf("__TIME__"), tbuf, -1, 10, NOFLAG);
/* __LINE__ */
macro_def(str2idf("__LINE__"), "0", -1, 1, FUNC);
/* __FILE__ */
macro_def(str2idf("__FILE__"), "", -1, 1, FUNC);
/* __STDC__ */
macro_def(str2idf("__STDC__"), "1", -1, 1, NOFLAG);
/* defined(??) */
macro_def(str2idf("defined"), "", 1, 1, FUNC);
}
#endif NOPP

View File

@ -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 <inp_pkg.body>
#ifndef NOPP
char *
getwdir(fn)
register char *fn;
{
register char *p;
char *strrindex();
p = strrindex(fn, '/');
while (p && *(p + 1) == '\0') { /* remove trailing /'s */
*p = '\0';
p = strrindex(fn, '/');
}
if (fn[0] == '\0' || (fn[0] == '/' && p == &fn[0])) /* absolute path */
return "";
if (p) {
*p = '\0';
fn = Salloc(fn, p - &fn[0] + 1);
*p = '/';
return fn;
}
return ".";
}
#endif NOPP
int NoUnstack;
AtEoIT()
{
unstackrepl();
return 0;
}
AtEoIF()
{
#ifndef NOPP
if (nestlevel != nestlow) lexwarning("missing #endif");
else
#endif NOPP
if (NoUnstack) lexerror("unexpected EOF");
#ifndef NOPP
nestlevel = nestlow;
#endif
return 0;
}

View File

@ -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 <inp_pkg.spec>
/* Note: The following macro only garuantees one PushBack.
*/
#define UnGetChar() ChPushBack(LexSave)
extern int LexSave; /* last character read by GetChar */
extern int GetChar(); /* character input, with trigraph parsing */

View File

@ -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

700
lang/cem/cemcom.ansi/ival.g Normal file
View File

@ -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 <em.h>
#include "debug.h"
#include <alloc.h>
#include <assert.h>
#include "nobitfield.h"
#include "arith.h"
#include "label.h"
#include "expr.h"
#include "type.h"
#include "proto.h"
#include "struct.h"
#include "field.h"
#include "assert.h"
#include "Lpars.h"
#include "sizes.h"
#include "idf.h"
#include "level.h"
#include "def.h"
#include "LLlex.h"
#include "noRoption.h"
#include "estack.h"
#ifdef LINT
#include "l_lint.h"
#endif LINT
#define con_nullbyte() C_con_ucon("0", (arith)1)
#define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT)
char *long2str();
char *strncpy();
extern char options[];
static int gen_error;
struct type **gen_tphead(), **gen_tpmiddle();
struct sdef *gen_align_to_next();
struct e_stack *p_stack;
}
/* initial_value recursively guides the initialisation expression.
Upto now, the initialisation of a union is not allowed!
*/
/* 7 */
initial_value(register struct type **tpp; register struct expr **expp;) :
{ if (tpp) gen_tpcheck(tpp, 0); }
[
assignment_expression(expp)
{
#ifdef LINT
lint_expr(*expp, USED);
#endif LINT
if ((*expp)->ex_type->tp_fund == ARRAY)
array2pointer(*expp);
if (tpp) {
gen_simple_exp(tpp, expp);
free_expression(*expp);
*expp = 0;
}
}
|
initial_value_pack(tpp, expp)
]
;
initial_value_pack(struct type **tpp; struct expr **expp;)
{ static int pack_level; }
:
'{'
{ if (pack_level == 0) gen_error = 0; pack_level++; }
initial_value_list(tpp, expp)
{ pack_level--;
if (!pack_level) {
while (p_stack) {
struct e_stack *p = p_stack->next;
free_e_stack(p_stack);
p_stack = p;
}
}
}
'}'
;
initial_value_list(register struct type **tpp; struct expr **expp;)
{ struct expr *e1;
register struct type **tpp2 = 0;
}
:
{ if (tpp) tpp2 = gen_tphead(tpp, 0); }
initial_value(tpp2, &e1)
{ if (!tpp) init_expression(&expp, e1); }
[%while (AHEAD != '}') /* >>> conflict on ',' */
','
{ if (tpp) tpp2 = gen_tpmiddle(); }
initial_value(tpp2, &e1)
{ if (!tpp) init_expression(&expp, e1); }
]*
{ if (tpp) gen_tpend(); }
','? /* optional trailing comma */
;
{
gen_tpcheck(tpp, union_allowed)
struct type **tpp;
{
register struct type *tp;
if (gen_error) return;
switch((tp = *tpp)->tp_fund) {
case ARRAY:
if (! valid_type(tp->tp_up, "array element"))
gen_error = 1;
break;
case STRUCT:
if (! valid_type(tp, "struct"))
gen_error = 1;
break;
case UNION:
if (! valid_type(tp, "union"))
gen_error = 1;
break;
}
}
gen_simple_exp(tpp, expp)
struct type **tpp;
struct expr **expp;
{
register struct type *tp;
if (gen_error) return;
tp = *tpp;
switch(tp->tp_fund) {
case ARRAY:
if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) {
ch_array(tpp,*expp);
break;
}
/* Fall through */
case UNION:
case STRUCT:
check_and_pad(expp, tpp);
break;
case ERRONEOUS:
gen_error = 1;
break;
default:
check_ival(expp, tp);
break;
}
}
struct type **
arr_elem(tpp, p)
struct type **tpp;
struct e_stack *p;
{
register struct type *tp = *tpp;
if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) {
p->nelem = 1;
return tpp;
}
if (AHEAD == '{' || ! aggregate_type(tp->tp_up))
return &(tp->tp_up);
return gen_tphead(&(tp->tp_up), 1);
}
struct sdef *
next_field(sd, p)
register struct sdef *sd;
register struct e_stack *p;
{
if (sd->sd_sdef)
p->bytes_upto_here += zero_bytes(sd);
if (p->last_offset != sd->sd_offset) {
p->bytes_upto_here +=
size_of_type(sd->sd_type, "selector");
p->last_offset = sd->sd_offset;
}
return sd->sd_sdef;
}
struct type **
gen_tphead(tpp, nest)
struct type **tpp;
{
register struct type *tp = *tpp;
register struct e_stack *p;
register struct sdef *sd;
if (tpp && *tpp == error_type) {
gen_error = 1;
return 0;
}
if (gen_error) return tpp;
p = new_e_stack();
p->next = p_stack;
p_stack = p;
p->s_nested = nest;
p->s_tpp = tpp;
switch(tp->tp_fund) {
case ARRAY:
p->nelem = -1;
p->elem_count = 1;
if (tp->tp_size != (arith) -1) {
p->nelem = (tp->tp_size / tp->tp_up->tp_size);
}
return arr_elem(tpp, p);
case STRUCT:
p->s_def = sd = tp->tp_sdef;
p->bytes_upto_here = 0;
p->last_offset = -1;
#ifndef NOBITFIELD
while (sd && is_anon_idf(sd->sd_idf)) {
put_bf(sd->sd_type, (arith) 0);
sd = next_field(sd, p);
}
#endif
if (! sd) {
/* something wrong with this struct */
gen_error = 1;
p_stack = p->next;
free_e_stack(p);
return 0;
}
p->s_def = sd;
if (AHEAD != '{' && aggregate_type(sd->sd_type)) {
return gen_tphead(&(sd->sd_type), 1);
}
return &(sd->sd_type);
default:
p->nelem = 1;
p->elem_count = 1;
return tpp;
}
}
struct type **
gen_tpmiddle()
{
register struct type *tp;
register struct sdef *sd;
register struct e_stack *p = p_stack;
if (gen_error) {
if (p) return p->s_tpp;
return 0;
}
again:
tp = *(p->s_tpp);
switch(tp->tp_fund) {
default:
if (p->elem_count == p->nelem && p->s_nested) {
p = p->next;
free_e_stack(p_stack);
p_stack = p;
goto again;
}
p->elem_count++;
if (p->nelem >= 0 && p->elem_count > p->nelem) {
too_many_initialisers();
return p->s_tpp;
}
if (tp->tp_fund == ARRAY) {
return arr_elem(p->s_tpp, p);
}
return p->s_tpp;
case STRUCT:
sd = gen_align_to_next(p);
if (! sd) {
while (p->bytes_upto_here++ < tp->tp_size)
con_nullbyte();
if (p->s_nested) {
p = p->next;
free_e_stack(p_stack);
p_stack = p;
goto again;
}
too_many_initialisers();
return p->s_tpp;
}
if (AHEAD != '{' && aggregate_type(sd->sd_type)) {
return gen_tphead(&(sd->sd_type), 1);
}
return &(sd->sd_type);
}
}
struct sdef *
gen_align_to_next(p)
register struct e_stack *p;
{
register struct sdef *sd = p->s_def;
if (! sd) return sd;
#ifndef NOBITFIELD
do {
if (is_anon_idf(sd->sd_idf)) put_bf(sd->sd_type, (arith) 0);
#endif
sd = next_field(sd, p);
#ifndef NOBITFIELD
} while (sd && is_anon_idf(sd->sd_idf));
#endif
p->s_def = sd;
return sd;
}
gen_tpend()
{
register struct e_stack *p = p_stack;
register struct type *tp;
register struct sdef *sd;
int getout = 0;
while (!getout && p) {
if (!gen_error) {
tp = *(p->s_tpp);
switch(tp->tp_fund) {
case ARRAY:
if (tp->tp_size == -1) {
*(p->s_tpp) = construct_type(ARRAY, tp->tp_up,
0, p->elem_count, NO_PROTO);
}
else {
while (p->nelem-- > p->elem_count) {
pad(tp->tp_up);
}
}
break;
case STRUCT:
sd = gen_align_to_next(p);
while (sd) {
pad(sd->sd_type);
if (sd->sd_sdef)
p->bytes_upto_here += zero_bytes(sd);
p->bytes_upto_here +=
size_of_type(sd->sd_type, "selector");
sd = sd->sd_sdef;
}
while (p->bytes_upto_here++ < tp->tp_size)
con_nullbyte();
break;
}
}
if (! p->s_nested) getout = 1;
p = p->next;
free_e_stack(p_stack);
p_stack = p;
}
gen_error = 0;
}
/* check_and_pad() is given a simple initialisation expression
where the type can be either a simple or an aggregate type.
In the latter case, only the first member is initialised and
the rest is zeroed.
*/
check_and_pad(expp, tpp)
struct type **tpp;
struct expr **expp;
{
register struct type *tp = *tpp;
if (tp->tp_fund == ARRAY) {
check_and_pad(expp, &(tp->tp_up)); /* first member */
if (tp->tp_size == (arith)-1)
/* no size specified upto here: just
set it to the size of one member.
*/
tp = *tpp = construct_type(ARRAY, tp->tp_up,
0, (arith)1, NO_PROTO);
else {
register int dim = tp->tp_size / tp->tp_up->tp_size;
/* pad remaining members with zeroes */
while (--dim > 0)
pad(tp->tp_up);
}
}
else
if (tp->tp_fund == STRUCT) {
register struct sdef *sd = tp->tp_sdef;
check_and_pad(expp, &(sd->sd_type));
/* next selector is aligned by adding extra zeroes */
if (sd->sd_sdef)
zero_bytes(sd);
while (sd = sd->sd_sdef) { /* pad remaining selectors */
pad(sd->sd_type);
if (sd->sd_sdef)
zero_bytes(sd);
}
}
else if (tp->tp_fund == UNION) {
/* only the first selector can be initialized */
register struct sdef *sd = tp->tp_sdef;
check_and_pad(expp, &(sd->sd_type));
}
else /* simple type */
check_ival(expp, tp);
}
/* pad() fills an element of type tp with zeroes.
If the element is an aggregate, pad() is called recursively.
*/
pad(tpx)
struct type *tpx;
{
register struct type *tp = tpx;
register arith sz = tp->tp_size;
gen_tpcheck(&tpx, 1);
if (gen_error) return;
switch (tp->tp_fund) {
case UNION:
#ifndef NOROPTION
if (options['R']) {
warning("initialisation of unions not allowed");
}
#endif
break;
#ifndef NOBITFIELD
case FIELD:
put_bf(tp, (arith)0);
return;
#endif NOBITFIELD
default:
break;
}
while (sz >= word_size) {
C_con_cst((arith) 0);
sz -= word_size;
}
while (sz) {
C_con_icon("0", (arith) 1);
sz--;
}
}
/* check_ival() checks whether the initialisation of an element
of a fundamental type is legal and, if so, performs the initialisation
by directly generating the necessary code.
No further comment is needed to explain the internal structure
of this straightforward function.
*/
check_ival(expp, tp)
register struct type *tp;
struct expr **expp;
{
/* The philosophy here is that ch7cast puts an explicit
conversion node in front of the expression if the types
are not compatible. In this case, the initialisation
expression is no longer a constant.
*/
register struct expr *expr = *expp;
switch (tp->tp_fund) {
case CHAR:
case SHORT:
case INT:
case LONG:
case ENUM:
case POINTER:
ch7cast(expp, '=', tp);
expr = *expp;
#ifdef DEBUG
print_expr("init-expr after cast", expr);
#endif DEBUG
if (!is_ld_cst(expr))
illegal_init_cst(expr);
else
if (expr->VL_CLASS == Const)
con_int(expr);
else
if (expr->VL_CLASS == Name) {
register struct idf *idf = expr->VL_IDF;
if (idf->id_def->df_level >= L_LOCAL)
illegal_init_cst(expr);
else /* e.g., int f(); int p = f; */
if (idf->id_def->df_type->tp_fund == FUNCTION)
C_con_pnam(idf->id_text);
else /* e.g., int a; int *p = &a; */
C_con_dnam(idf->id_text, expr->VL_VALUE);
}
else {
ASSERT(expr->VL_CLASS == Label);
C_con_dlb(expr->VL_LBL, expr->VL_VALUE);
}
break;
#ifndef NOFLOAT
case FLOAT:
case DOUBLE:
ch7cast(expp, '=', tp);
expr = *expp;
#ifdef DEBUG
print_expr("init-expr after cast", expr);
#endif DEBUG
if (expr->ex_class == Float)
C_con_fcon(expr->FL_VALUE, expr->ex_type->tp_size);
#ifdef NOTDEF
Coercion from int to float is now always done compile time.
This, to accept declarations like
double x = -(double)1;
and also to prevent runtime coercions for compile-time constants.
else
if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) {
/* float f = 1; */
expr = expr->OP_RIGHT;
if (is_cp_cst(expr))
C_con_fcon(long2str((long)expr->VL_VALUE, 10),
tp->tp_size);
else
illegal_init_cst(expr);
}
#endif NOTDEF
else
illegal_init_cst(expr);
break;
#endif NOFLOAT
#ifndef NOBITFIELD
case FIELD:
ch7cast(expp, '=', tp->tp_up);
expr = *expp;
#ifdef DEBUG
print_expr("init-expr after cast", expr);
#endif DEBUG
if (is_cp_cst(expr))
put_bf(tp, expr->VL_VALUE);
else
illegal_init_cst(expr);
break;
#endif NOBITFIELD
case ERRONEOUS:
break;
default:
crash("check_ival");
/*NOTREACHED*/
}
}
/* ch_array() initialises an array of characters when given
a string constant.
Alignment is taken care of.
*/
ch_array(tpp, ex)
struct type **tpp; /* type tp = array of characters */
struct expr *ex;
{
register struct type *tp = *tpp;
register arith length = ex->SG_LEN;
char *s;
ASSERT(ex->ex_class == String);
if (tp->tp_size == (arith)-1) {
/* set the dimension */
tp = *tpp = construct_type(ARRAY, tp->tp_up, 0, length, NO_PROTO);
}
else {
arith dim = tp->tp_size / tp->tp_up->tp_size;
if (length > dim) {
expr_warning(ex, "too many initialisers");
}
length = dim;
}
/* throw out the characters of the already prepared string */
s = Malloc((unsigned) (length));
clear(s, (int) (length));
strncpy(s, ex->SG_VALUE, (int) length);
free(ex->SG_VALUE);
str_cst(s, (int) (length));
free(s);
}
/* As long as some parts of the pipeline cannot handle very long string
constants, string constants are written out in chunks
*/
str_cst(str, len)
register char *str;
register int len;
{
int chunksize = ((127 + (int) word_size) / (int) word_size) * (int) word_size;
while (len > chunksize) {
C_con_scon(str, (arith) chunksize);
len -= chunksize;
str += chunksize;
}
C_con_scon(str, (arith) len);
}
#ifndef NOBITFIELD
/* put_bf() takes care of the initialisation of (bit-)field
selectors of a struct: each time such an initialisation takes place,
put_bf() is called instead of the normal code generating routines.
Put_bf() stores the given integral value into "field" and
"throws" the result of "field" out if the current selector
is the last of this number of fields stored at the same address.
*/
put_bf(tp, val)
struct type *tp;
arith val;
{
static long field = (arith)0;
static arith offset = (arith)-1;
register struct field *fd = tp->tp_field;
register struct sdef *sd = fd->fd_sdef;
static struct expr exp;
ASSERT(sd);
if (offset == (arith)-1) {
/* first bitfield in this field */
offset = sd->sd_offset;
exp.ex_type = tp->tp_up;
exp.ex_class = Value;
exp.VL_CLASS = Const;
}
if (val != 0) /* insert the value into "field" */
field |= (val & fd->fd_mask) << fd->fd_shift;
if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) {
/* the selector was the last stored at this address */
exp.VL_VALUE = field;
con_int(&exp);
field = (arith)0;
offset = (arith)-1;
}
}
#endif NOBITFIELD
int
zero_bytes(sd)
register struct sdef *sd;
{
/* fills the space between a selector of a struct
and the next selector of that struct with zero-bytes.
*/
register int n = sd->sd_sdef->sd_offset - sd->sd_offset -
size_of_type(sd->sd_type, "struct member");
register int count = n;
while (n-- > 0)
con_nullbyte();
return count;
}
int
valid_type(tp, str)
struct type *tp;
char *str;
{
ASSERT(tp!=(struct type *)0);
if (tp->tp_size < 0) {
error("size of %s unknown", str);
return 0;
}
return 1;
}
con_int(ex)
register struct expr *ex;
{
register struct type *tp = ex->ex_type;
ASSERT(is_cp_cst(ex));
if (tp->tp_unsigned)
C_con_ucon(long2str((long)ex->VL_VALUE, -10), tp->tp_size);
else if (tp->tp_size == word_size)
C_con_cst(ex->VL_VALUE);
else
C_con_icon(long2str((long)ex->VL_VALUE, 10), tp->tp_size);
}
illegal_init_cst(ex)
struct expr *ex;
{
expr_error(ex, "illegal initialisation constant");
gen_error = 1;
}
too_many_initialisers()
{
error("too many initialisers");
gen_error = 1;
}
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 <ctype.h>
#include "lint.h"
#ifdef LINT
#include <alloc.h>
#include "interface.h"
#include "arith.h"
#include "l_state.h"
#include "l_comment.h"
extern char loptions[];
/* Since the lexical analyser does a one-token look-ahead, pseudo-
comments are read too soon. This is remedied by first storing them
in static variables and then moving them to the real variables
one token later.
*/
PRIVATE int notreached;
PRIVATE int varargsN = -1;
PRIVATE int argsused;
PRIVATE int formatN;
PRIVATE int formatVAR;
PRIVATE char *format;
PRIVATE char *prev_format;
PRIVATE make_format();
int LINTLIB; /* file is lint library */
int s_NOTREACHED; /* statement not reached */
int f_VARARGSn; /* function with variable # of args */
int f_ARGSUSED; /* function does not use all args */
int f_FORMATn; /* argument f_FORMATn is f_FORMAT */
char *f_FORMAT;
int f_FORMATvar; /* but the formal argument may be
absent because of varargs.h */
lint_init_comment()
{
LINTLIB = loptions['L'];
}
lint_comment_ahead()
{
s_NOTREACHED = notreached;
notreached = 0;
}
lint_comment_function()
{
f_ARGSUSED = argsused | loptions['v'];
argsused = 0;
f_VARARGSn = varargsN;
varargsN = -1;
f_FORMATn = formatN;
formatN = 0;
f_FORMAT = format;
if (format)
prev_format = format;
format = 0;
f_FORMATvar = formatVAR;
formatVAR = 0;
}
PRIVATE char buf[1000];
PRIVATE char *bufpos; /* next free position in buf */
lint_start_comment()
{
bufpos = &buf[0];
}
lint_comment_char(c)
int c;
{
/* This function is called with every character between /_* and *_/ */
if (bufpos - &buf[0] < sizeof(buf)-1)
*bufpos++ = (char)c;
}
lint_end_comment()
{
*bufpos++ = '\0';
bufpos = &buf[0];
/* skip initial blanks */
while (*bufpos && isspace(*bufpos)) {
bufpos++;
}
/* now test for one of the pseudo-comments */
if (strncmp(bufpos, "NOTREACHED", 10) == 0) {
notreached = 1;
}
else
if (strncmp(bufpos, "ARGSUSED", 8) == 0) {
argsused = 1;
}
else
if (strncmp(bufpos, "LINTLIBRARY", 11) == 0) {
LINTLIB = 1;
}
else
if (strncmp(bufpos, "VARARGS", 7) == 0) {
bufpos += 7;
varargsN = isdigit(*bufpos) ? atoi(bufpos) : 0;
}
else
if (strncmp(bufpos, "FORMAT", 6) == 0 && isdigit(bufpos[6])) {
register int argn;
bufpos += 6;
argn = *bufpos++ - '0';
varargsN = argn + 1;
if (*bufpos == 'v') {
/* something like FORMAT3v */
formatVAR = 1;
bufpos++;
}
make_format(argn, bufpos);
}
}
/* We use a small FSA to skip layout inside formats, but to preserve
a space between letters and digits.
*/
#define NONE 0
#define LETGIT 1
#define LETGITSPACE 2
PRIVATE
make_format(argn, oldf)
int argn;
char *oldf;
{
register char *newf;
register int last_stat;
while (*oldf && *oldf != '$') {
oldf++;
}
if (!*oldf) {
/* no format given, repeat previous format */
if (!prev_format) {
warning("format missing and no previous format");
}
formatN = argn;
format = prev_format;
return;
}
if (*oldf++ != '$') {
warning("no format in FORMAT pseudo-comment");
format = 0;
return;
}
/* there is a new format to be composed */
newf = Malloc(strlen(oldf));
/* certainly enough and probably not overly too much */
formatN = argn;
format = newf;
last_stat = NONE;
while (*oldf && *oldf != '$') {
register char ch = *oldf++;
if (isspace(ch)) {
if (last_stat == LETGIT)
last_stat = LETGITSPACE;
}
else
if (isalnum(ch)) {
switch (last_stat) {
case NONE:
last_stat = LETGIT;
break;
case LETGITSPACE:
*newf++ = ' ';
last_stat = LETGIT;
break;
}
*newf++ = ch;
}
else {
last_stat = NONE;
*newf++ = ch;
}
}
if (*oldf != '$') {
warning("no end of format in FORMAT pseudo-comment");
format = 0;
return;
}
*newf++ = '\0';
}
#endif LINT

View File

@ -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 */

View File

@ -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

View File

@ -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 <alloc.h> /* for st_free */
#include "interface.h"
#include "assert.h"
#include "arith.h" /* definition arith */
#include "label.h" /* definition label */
#include "expr.h"
#include "idf.h"
#include "def.h"
#include "code.h" /* RVAL etc */
#include "LLlex.h"
#include "Lpars.h"
#include "stack.h"
#include "type.h"
#include "level.h"
#include "nofloat.h"
#include "l_lint.h"
#include "l_state.h"
extern char *symbol2str();
PRIVATE check_ev_order();
check_and_merge(expr, espp, esp)
struct expr *expr;
struct expr_state **espp, *esp;
{
/* Checks for undefined evaluation orders in case of a non-sequencing operator.
* In addition the sets of used and set variables of both expressions are
* united.
* *espp will be pointing to this new list. esp is used for this list.
*/
register struct expr_state **pp, *p1, *p2;
int oper = expr->OP_OPER;
int is_sequencer =
(oper == '?' || oper == OR || oper == AND || oper ==',');
for (p1 = *espp; p1; p1 = p1->next) {
/* scan the list esp for the same variable */
p2 = esp;
pp = &esp;
while (p2) {
if ( /* p1 and p2 refer to the same location */
p1->es_idf == p2->es_idf
&& p1->es_offset == p2->es_offset
) {
/* check */
if (!is_sequencer)
check_ev_order(p1, p2, expr);
/* merge the info */
p1->es_used |= p2->es_used;
p1->es_referred |= p2->es_referred;
p1->es_set |= p2->es_set;
/* and remove the entry from esp */
*pp = p2->next;
free_expr_state(p2);
p2 = *pp;
}
else {
/* skip over the entry in esp */
pp = &p2->next;
p2 = p2->next;
}
}
}
/* If there is anything left in the list esp, this is put in
front of the list *espp is now pointing to, and *espp will be
left pointing to this new list.
*/
if (!esp)
return;
p1 = *espp;
*espp = esp;
while (esp->next)
esp = esp->next;
esp->next = p1;
}
PRIVATE
check_ev_order(esp1, esp2, expr)
struct expr_state *esp1, *esp2;
struct expr *expr;
{
if ( (esp1->es_used && esp2->es_set)
|| (esp1->es_set && esp2->es_used)
|| (esp1->es_set && esp2->es_set)
) {
expr_warning(expr,
"result of %s depends on evaluation order on %s",
symbol2str(expr->OP_OPER),
esp1->es_idf->id_text);
}
}
#endif LINT

View File

@ -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 <alloc.h> /* for st_free */
#include "debug.h"
#include "interface.h"
#include "assert.h"
#include "arith.h" /* definition arith */
#include "label.h" /* definition label */
#include "expr.h"
#include "idf.h"
#include "def.h"
#include "code.h" /* RVAL etc */
#include "LLlex.h"
#include "Lpars.h"
#include "stack.h"
#include "type.h"
#include "level.h"
#include "nofloat.h"
#include "l_lint.h"
#include "l_state.h"
#include "l_outdef.h"
extern char options[128];
extern char *symbol2str();
PRIVATE struct expr_state *expr2state();
PRIVATE struct expr_state *value2state();
PRIVATE struct expr_state *oper2state();
PRIVATE expr_ignored();
PRIVATE add_expr_state();
PRIVATE referred_esp();
PRIVATE free_expr_states();
lint_init()
{
lint_init_comment();
lint_init_stack();
}
lint_expr(expr, used)
struct expr *expr;
int used; /* USED or IGNORED */
{
register struct expr_state *esp;
esp = expr2state(expr, RVAL, used);
referred_esp(esp);
free_expr_states(esp);
}
PRIVATE struct expr_state *
expr2state(expr, val, used)
register struct expr *expr;
int val; /* RVAL or LVAL */
int used; /* USED or IGNORED */
{
/* Main function to process an expression tree.
* It returns a structure containing information about which variables
* are set and which are used in the expression.
* In addition it sets 'used' and 'set' fields of the corresponding
* variables in the current state.
* If the value of an operation without side-effects is not used,
* a warning is given.
*/
if (used == IGNORED) {
expr_ignored(expr);
}
switch (expr->ex_class) {
case Value:
return value2state(expr, val);
case Oper:
return oper2state(expr, val, used);
default: /* String, Float, Type */
return 0;
}
}
PRIVATE struct expr_state *
value2state(expr, val)
struct expr *expr;
int val; /* RVAL or LVAL */
{
switch (expr->VL_CLASS) {
case Const:
case Label:
return 0;
case Name:
{
register struct idf *idf = expr->VL_IDF;
struct expr_state *esp = 0;
if (!idf || !idf->id_def)
return 0;
if (val == RVAL && expr->ex_lvalue == 1) {
/* value of identifier used */
change_state(idf, USED);
add_expr_state(expr->EX_VALUE, USED, &esp);
}
if (val == RVAL && expr->ex_lvalue == 0) {
/* address of identifier used */
add_expr_state(expr->EX_VALUE, REFERRED, &esp);
}
return esp;
}
default:
NOTREACHED();
/* NOTREACHED */
}
}
/* Let's get this straight.
An assignment is performed by elaborating the LHS and the RHS
collaterally, to use the A68 terminology, and then serially do the
actual assignment. This means:
1. evaluate the LHS as an LVAL,
2. evaluate the RHS as an RVAL,
3. merge them checking for interference,
4. set the result of the LHS to SET, if it is a named variable
*/
PRIVATE struct expr_state *
oper2state(expr, val, used)
struct expr *expr;
int val; /* RVAL or LVAL */
int used; /* USED or IGNORED */
{
register int oper = expr->OP_OPER;
register struct expr *left = expr->OP_LEFT;
register struct expr *right = expr->OP_RIGHT;
struct expr_state *esp_l = 0;
struct expr_state *esp_r = 0;
switch (oper) {
/* assignments */
case '=':
case PLUSAB:
case MINAB:
case TIMESAB:
case DIVAB:
case MODAB:
case LEFTAB:
case RIGHTAB:
case ANDAB:
case XORAB:
case ORAB:
/* evaluate the LHS, only once; see RM 7.14 */
esp_l = expr2state(left, (oper == '=' ? LVAL : RVAL), USED);
/* evaluate the RHS as an RVAL and merge */
esp_r = expr2state(right, RVAL, USED);
check_and_merge(expr, &esp_l, esp_r);
/* set resulting variable, if any */
if (ISNAME(left)) {
change_state(left->VL_IDF, SET);
add_expr_state(left->EX_VALUE, SET, &esp_l);
}
return esp_l;
case POSTINCR:
case POSTDECR:
case PLUSPLUS:
case MINMIN:
esp_l = expr2state(left, RVAL, USED);
/* set resulting variable, if any */
if (ISNAME(left)) {
change_state(left->VL_IDF, SET);
add_expr_state(left->EX_VALUE, SET, &esp_l);
}
return esp_l;
case '?':
esp_l = expr2state(left, RVAL, USED);
esp_r = expr2state(right->OP_LEFT, RVAL, USED);
check_and_merge(expr, &esp_l, esp_r);
esp_r = expr2state(right->OP_RIGHT, RVAL, USED);
check_and_merge(expr, &esp_l, esp_r);
return esp_l;
case '(':
if (right != 0) {
/* function call with parameters */
register struct expr *ex = right;
while ( ex->ex_class == Oper
&& ex->OP_OPER == PARCOMMA
) {
esp_r = expr2state(ex->OP_RIGHT, RVAL, USED);
check_and_merge(expr, &esp_l, esp_r);
ex = ex->OP_LEFT;
}
esp_r = expr2state(ex, RVAL, USED);
check_and_merge(expr, &esp_l, esp_r);
}
if (ISNAME(left)) {
fill_outcall(expr,
expr->ex_type->tp_fund == VOID ?
VOIDED : used
);
outcall();
left->VL_IDF->id_def->df_used = 1;
}
else {
esp_r = expr2state(left, RVAL, USED);
check_and_merge(expr, &esp_l, esp_r);
}
referred_esp(esp_l);
return esp_l;
case '.':
return expr2state(left, val, USED);
case ARROW:
return expr2state(left, RVAL, USED);
case INT2INT:
case INT2FLOAT:
case FLOAT2INT:
case FLOAT2FLOAT:
return expr2state(right, RVAL, USED);
/* monadic operators */
case '-':
case '*':
if (left)
goto dyadic;
case '~':
case '!':
return expr2state(right, RVAL, USED);
/* relational operators */
case '<':
case '>':
case LESSEQ:
case GREATEREQ:
case EQUAL:
case NOTEQUAL:
lint_relop(left, right, oper);
lint_relop(right, left,
oper == '<' ? '>' :
oper == '>' ? '<' :
oper == LESSEQ ? GREATEREQ :
oper == GREATEREQ ? LESSEQ :
oper
);
goto dyadic;
/* dyadic operators */
dyadic:
case '+':
case '/':
case '%':
case ',':
case LEFT:
case RIGHT:
case '&':
case '|':
case '^':
case OR:
case AND:
esp_l = expr2state(left, RVAL,
oper == ',' ? IGNORED : USED);
esp_r = expr2state(right, RVAL,
oper == ',' ? used : USED);
check_and_merge(expr, &esp_l, esp_r);
return esp_l;
default:
return 0; /* for initcomma */
}
}
PRIVATE
expr_ignored(expr)
struct expr *expr;
{
switch (expr->ex_class) {
case Oper:
switch (expr->OP_OPER) {
case '=':
case TIMESAB:
case DIVAB:
case MODAB:
case LEFTAB:
case RIGHTAB:
case ANDAB:
case XORAB:
case ORAB:
case AND: /* doubtful but useful */
case OR: /* doubtful but useful */
case '(':
case '?':
case ',':
break;
case PLUSAB:
case MINAB:
case POSTINCR:
case POSTDECR:
case PLUSPLUS:
case MINMIN:
/* may hide the operator '*' */
if ( /* operation on a pointer */
expr->OP_TYPE->tp_fund == POINTER
&& /* the result is dereferenced, e.g. *p++; */
expr->ex_type == expr->OP_TYPE->tp_up
) {
hwarning("result of * ignored");
}
break;
default:
hwarning("result of %s ignored",
symbol2str(expr->OP_OPER));
break;
}
break;
case Value:
hwarning("value as statement");
break;
default: /* String Float */
hwarning("constant as statement");
break;
}
}
PRIVATE
add_expr_state(value, to_state, espp)
struct value value;
struct expr_state **espp;
{
register struct expr_state *esp = *espp;
ASSERT(value.vl_class == Name);
/* try to find the esp */
while ( esp
&& !( esp->es_idf == value.vl_data.vl_idf
&& esp->es_offset == value.vl_value
)
) {
esp = esp->next;
}
/* if not found, add it */
if (!esp) {
esp = new_expr_state();
esp->es_idf = value.vl_data.vl_idf;
esp->es_offset = value.vl_value;
esp->next = *espp;
*espp = esp;
}
/* set state */
switch (to_state) {
case USED:
esp->es_used = 1;
break;
case REFERRED:
esp->es_referred = 1;
break;
case SET:
esp->es_set = 1;
break;
default:
NOTREACHED();
/* NOTREACHED */
}
}
PRIVATE
referred_esp(esp)
struct expr_state *esp;
{
/* raises all REFERRED items to SET and USED status */
while (esp) {
if (esp->es_referred) {
esp->es_set = 1;
change_state(esp->es_idf, SET);
esp->es_used = 1;
change_state(esp->es_idf, USED);
esp->es_referred = 0;
}
esp = esp->next;
}
}
PRIVATE
free_expr_states(esp)
register struct expr_state *esp;
{
while (esp) {
register struct expr_state *esp2 = esp;
esp = esp->next;
free_expr_state(esp2);
}
}
#ifdef DEBUG
print_esp(msg, esp)
char *msg;
struct expr_state *esp;
{
print("%s: <", msg);
while (esp) {
print(" %s[%d]%c%c%c ",
esp->es_idf->id_text, esp->es_offset,
(esp->es_used ? 'U' : ' '),
(esp->es_referred ? 'R' : ' '),
(esp->es_set ? 'S' : ' ')
);
esp = esp->next;
}
print(">\n");
}
#endif DEBUG
#endif LINT

View File

@ -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 */

View File

@ -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 <alloc.h> /* for st_free */
#include "interface.h"
#include "arith.h" /* definition arith */
#include "label.h" /* definition label */
#include "expr.h"
#include "idf.h"
#include "def.h"
#include "code.h" /* RVAL etc */
#include "LLlex.h"
#include "Lpars.h"
#include "stack.h"
#include "type.h"
#include "level.h"
#include "nofloat.h"
#include "l_state.h"
extern char *symbol2str();
extern struct type *func_type;
PRIVATE lint_enum_arith();
PRIVATE lint_conversion();
PRIVATE int numsize();
lint_new_oper(expr)
struct expr *expr;
{
/* Does additional checking on a newly constructed expr node
of class Oper.
Some code in this routine could be contracted, but since
I am not sure we have covered the entire ground, we'll
leave the contracting for some rainy day.
*/
register struct expr *left = expr->OP_LEFT;
register struct expr *right = expr->OP_RIGHT;
register int oper = expr->OP_OPER;
register int l_fund =
left == 0 ? 0 : /* for monadics */
left->ex_type->tp_fund;
register int r_fund =
right == 0 ? 0 : /* for ( without parameters */
right->ex_type->tp_fund;
/* In ch7.c, in ch7asgn(), a combined operator/assignment
is hammered into correctness by repeated application of
ch7bin(), which calls new_oper(), which calls lint_new_oper().
These spurious calls understandably cause spurious error
messages, which we don't like. So we try to suppress these
wierd calls here. This refers to the code marked
this is really $#@&*%$# !
in ch7asgn().
*/
switch (oper) {
case PLUSAB:
case MINAB:
case TIMESAB:
case DIVAB:
case MODAB:
case LEFTAB:
case RIGHTAB:
case ANDAB:
case XORAB:
case ORAB:
/* is the left operand wierd? */
if ( left->ex_class == Value
&& left->VL_CLASS == Const
&& left->VL_VALUE == 0
) {
return;
}
}
switch (oper) {
case '=':
lint_conversion(right, l_fund);
break;
case PLUSAB:
lint_conversion(right, l_fund);
case '+':
lint_enum_arith(l_fund, oper, r_fund);
break;
case MINAB:
lint_conversion(right, l_fund);
case '-':
if (left == 0) {
/* unary */
if (r_fund == ENUM)
warning("negating an enum");
}
else {
/* binary */
if (l_fund == ENUM && r_fund == ENUM) {
if (!equal_type(left->ex_type, right->ex_type))
warning("subtracting enums of different type");
/* update the type, cem does not do it */
expr->ex_type = int_type;
}
lint_enum_arith(l_fund, oper, r_fund);
}
break;
case TIMESAB:
lint_conversion(right, l_fund);
case '*':
if (left == 0) {
/* unary */
}
else {
/* binary */
if (l_fund == ENUM || r_fund == ENUM)
warning("multiplying enum");
}
break;
case DIVAB:
lint_conversion(right, l_fund);
case '/':
if (l_fund == ENUM || r_fund == ENUM)
warning("division on enum");
break;
case MODAB:
lint_conversion(right, l_fund);
case '%':
if (l_fund == ENUM || r_fund == ENUM)
warning("modulo on enum");
break;
case '~':
if (r_fund == ENUM || r_fund == FLOAT || r_fund == DOUBLE)
warning("~ on %s", symbol2str(r_fund));
break;
case '!':
if (r_fund == ENUM)
warning("! on enum");
break;
case INT2INT:
case INT2FLOAT:
case FLOAT2INT:
case FLOAT2FLOAT:
lint_conversion(right, l_fund);
break;
case '<':
case '>':
case LESSEQ:
case GREATEREQ:
case EQUAL:
case NOTEQUAL:
if ( (l_fund == ENUM || r_fund == ENUM)
&& !equal_type(left->ex_type, right->ex_type)
) {
warning("comparing enum with non-enum");
}
lint_relop(left, right, oper);
lint_relop(right, left,
oper == '<' ? '>' :
oper == '>' ? '<' :
oper == LESSEQ ? GREATEREQ :
oper == GREATEREQ ? LESSEQ :
oper
);
break;
case LEFTAB:
case RIGHTAB:
lint_conversion(right, l_fund);
case LEFT:
case RIGHT:
if (l_fund == ENUM || r_fund == ENUM)
warning("shift on enum");
break;
case ANDAB:
case ORAB:
case XORAB:
lint_conversion(right, l_fund);
case '&':
case '|':
case '^':
if (l_fund == ENUM || r_fund == ENUM)
warning("bit operations on enum");
break;
case ',':
case '?':
case ':':
case AND:
case OR:
case POSTINCR:
case POSTDECR:
case PLUSPLUS:
case MINMIN:
case '(':
case '.':
case ARROW:
default:
/* OK with lint */
break;
}
}
PRIVATE
lint_enum_arith(l_fund, oper, r_fund)
int l_fund, oper, r_fund;
{
if ( l_fund == ENUM
&& r_fund != CHAR
&& r_fund != SHORT
&& r_fund != INT
) {
warning("%s on enum and %s",
symbol2str(oper), symbol2str(r_fund));
}
else
if ( r_fund == ENUM
&& l_fund != CHAR
&& l_fund != SHORT
&& l_fund != INT
) {
warning("%s on %s and enum",
symbol2str(oper), symbol2str(l_fund));
}
}
PRIVATE
lint_conversion(from_expr, to_fund)
struct expr *from_expr;
int to_fund;
{
register int from_fund = from_expr->ex_type->tp_fund;
/* was there an attempt to reduce the type of the from_expr
of the form
expr & 0377
or something like this?
*/
if (from_expr->ex_class == Oper && from_expr->OP_OPER == INT2INT) {
from_expr = from_expr->OP_LEFT;
}
if (from_expr->ex_class == Oper && from_expr->OP_OPER == '&') {
struct expr *bits =
is_cp_cst(from_expr->OP_LEFT) ? from_expr->OP_LEFT :
is_cp_cst(from_expr->OP_RIGHT) ? from_expr->OP_RIGHT :
0;
if (bits) {
arith val = bits->VL_VALUE;
if (val < 256)
from_fund = CHAR;
else if (val < 256)
from_fund = SHORT;
}
}
if (numsize(from_fund) > numsize(to_fund)) {
awarning("conversion from %s to %s may lose accuracy",
symbol2str(from_fund), symbol2str(to_fund));
}
}
PRIVATE int
numsize(fund)
{
switch (fund) {
case CHAR: return 1;
case SHORT: return 2;
case INT: return 3;
case ENUM: return 3;
case LONG: return 4;
case FLOAT: return 5;
case DOUBLE: return 6;
default: return 0;
}
}
lint_ret_conv(from_expr)
struct expr *from_expr;
{
lint_conversion(from_expr, func_type->tp_fund);
}
lint_ptr_conv(from, to)
short from, to;
{
/* X -> X ok -- this includes struct -> struct, of any size
* X -> CHAR ok
* DOUBLE -> X ok
* FLOAT -> LONG -> INT -> SHORT ok
*/
if (from == to)
return;
if (to == CHAR)
return;
if (from == DOUBLE)
return;
switch (from) {
case FLOAT:
switch (to) {
case LONG:
case INT:
case SHORT:
return;
}
break;
case LONG:
switch (to) {
case INT:
case SHORT:
return;
}
break;
case INT:
switch (to) {
case SHORT:
return;
}
break;
}
if (from == CHAR) {
hwarning("pointer to char may not align correctly for a %s",
symbol2str(to));
}
else {
warning("pointer to %s may not align correctly for a %s",
symbol2str(from), symbol2str(to));
}
}
lint_relop(left, right, oper)
struct expr *left, *right;
int oper; /* '<', '>', LESSEQ, GREATEREQ, EQUAL, NOTEQUAL */
{
/* left operand may be converted */
if ( left->ex_class == Oper
&& left->OP_OPER == INT2INT
) {
left = left->OP_RIGHT;
}
/* <unsigned> <relop> <neg-const|0> is doubtful */
if ( left->ex_type->tp_unsigned
&& right->ex_class == Value
&& right->VL_CLASS == Const
) {
if (right->VL_VALUE < 0) {
warning("unsigned compared to negative constant");
}
if (right->VL_VALUE == 0) {
switch (oper) {
case '<':
warning("unsigned < 0 will always fail");
break;
case LESSEQ:
warning("unsigned <= 0 is probably wrong");
break;
case GREATEREQ:
warning("unsigned >= 0 will always succeed");
break;
}
}
}
/* <char> <relop> <neg-const> is undefined */
if ( left->ex_type->tp_fund == CHAR
&& right->ex_class == Value
&& right->VL_CLASS == Const
&& (right->VL_VALUE < 0 || right->VL_VALUE > 127)
) {
warning("character compared to negative constant");
}
}
#endif LINT

View File

@ -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 <alloc.h>
#include "interface.h"
#include "arith.h"
#include "assert.h"
#include "type.h"
#include "LLlex.h"
#include "Lpars.h"
#include "stack.h"
#include "def.h"
#include "struct.h"
#include "field.h"
#include "idf.h"
#include "level.h"
#include "label.h"
#include "code.h"
#include "expr.h"
#include "l_lint.h"
#include "l_comment.h"
#include "l_outdef.h"
#include "l_class.h"
extern char *bts2str();
extern char *symbol2str();
int stat_number = 9999; /* static scope number */
struct outdef OutDef;
PRIVATE struct outdef OutCall;
PRIVATE local_EFDC();
PRIVATE output_def();
PRIVATE outargs();
PRIVATE outarg();
PRIVATE outargstring();
PRIVATE outargtype();
PRIVATE implicit_func_decl();
PRIVATE fill_arg();
lint_declare_idf(idf, sc)
struct idf *idf;
int sc;
{
register struct def *def = idf->id_def;
register int is_function = def->df_type->tp_fund == FUNCTION;
if (level == L_GLOBAL) {
lint_ext_def(idf, sc);
if (is_function)
def2decl(sc);
if (sc != TYPEDEF)
outdef();
}
else
if (level >= L_LOCAL && sc != STATIC && is_function) {
local_EFDC(idf);
}
}
lint_ext_def(idf, sc)
struct idf *idf;
{
/* At this place the following fields of the outputdefinition can be
* filled:
* name, stat_number, class, file, line, type.
* For variable definitions and declarations this will be all.
* For functions the fields nrargs and argtps are filled after parsing
* the arguments.
* The returns-field is known at the end of the function definition.
* sc indicates the storage class defined by the declaration specifier.
*/
register struct def *def = idf->id_def;
register struct type *type = def->df_type;
OutDef.od_name = idf->id_text;
OutDef.od_statnr = (sc == STATIC ? stat_number : 0);
switch (type->tp_fund) {
case ERRONEOUS:
OutDef.od_class = XXDF;
break;
case FUNCTION:
/* For the moment assume it will be a definition.
* If no compound_statement follows, it is a declaration,
* in which case the class will be adjusted by def2decl().
*/
OutDef.od_class = (sc == STATIC ? SFDF : EFDF);
break;
default: /* a variable */
OutDef.od_class =
sc == EXTERN ? EVDC :
sc == STATIC ? SVDF : EVDF;
break;
}
OutDef.od_file = def->df_file;
OutDef.od_line = def->df_line;
OutDef.od_type = (type->tp_fund == FUNCTION ? type->tp_up : type);
OutDef.od_valreturned = NORETURN;
}
def2decl(sc)
int sc;
{
/* It was assumed we were parsing a function definition.
* There was no compound statement following, so actually it was a
* declaration. This function updates the class.
*/
OutDef.od_class = (sc == STATIC ? XXDF : EFDC);
}
set_od_valreturned(n)
{
OutDef.od_valreturned = n;
}
PRIVATE
local_EFDC(idf)
struct idf *idf;
{
struct outdef od;
od.od_class = EFDC;
od.od_statnr = 0;
od.od_name = idf->id_text;
od.od_file = idf->id_def->df_file;
od.od_line = idf->id_def->df_line;
od.od_type = idf->id_def->df_type->tp_up;
output_def(&od);
/* The other fields are not used for this class. */
}
lint_formals()
{
/* Make a list of tp_entries containing the types of the formal
* parameters of the function definition just parsed.
*/
register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
register struct argument **hook = &OutDef.od_arg;
register int nrargs = 0;
while (se) {
register struct type *type = se->se_idf->id_def->df_type;
register struct argument *arg = new_argument();
/* Do the conversions on the formals that could not be
done in declare_idf().
It is, unfortunately, impossible not to do them,
since the corresponding actuals will have been
converted to generate proper code and we do not
want to duplicate the whole of expression handling
for lint.
*/
switch (type->tp_fund) {
case CHAR:
case SHORT:
type = int_type;
break;
case FLOAT:
type = double_type;
break;
}
if (f_FORMAT && nrargs == f_FORMATn) {
if ( !f_FORMATvar
&& ( type->tp_fund != POINTER
|| type->tp_up->tp_fund != CHAR
)
) {
warning("format parameter %d is not pointer to char",
nrargs);
}
arg->ar_type = string_type;
arg->ar_class = ArgString;
arg->CAS_VALUE = f_FORMAT;
arg->CAS_LEN = strlen(f_FORMAT);
f_FORMAT = 0;
}
else {
arg->ar_type = type;
arg->ar_class = ArgFormal;
}
*hook = arg;
hook = &arg->next;
nrargs++;
se = se->next;
}
if (f_FORMAT) {
/* f_FORMAT has not been consumed, perhaps due to
a varargs-like construction; add erroneous ArgFormals
until f_FORMATn, then an ArgString, if necessary.
*/
if (!f_FORMATvar) {
warning("FORMAT%d function has only %d argument%s",
f_FORMATn, nrargs, nrargs == 1 ? "" : "s"
);
}
while (nrargs < f_FORMATn) {
register struct argument *arg = new_argument();
arg->ar_type = error_type;
arg->ar_class = ArgFormal;
*hook = arg;
hook = &arg->next;
nrargs++;
}
if (nrargs == f_FORMATn) {
register struct argument *arg = new_argument();
arg->ar_type = string_type;
arg->ar_class = ArgString;
arg->CAS_VALUE = f_FORMAT;
arg->CAS_LEN = strlen(f_FORMAT);
f_FORMAT = 0;
*hook = arg;
hook = &arg->next;
nrargs++;
}
/* life is full of duplicated code; this is no good */
}
if (f_VARARGSn > nrargs) {
warning("VARARGS%d function has only %d argument%s",
f_VARARGSn, nrargs, nrargs == 1 ? "" : "s"
);
f_VARARGSn = nrargs;
}
OutDef.od_nrargs = nrargs;
}
output_use(idf)
struct idf *idf;
{
/* Output the usage-definition of the variable described by idf.
*/
OutDef.od_name = idf->id_text;
OutDef.od_statnr = (idf->id_def->df_sc == STATIC ? stat_number : 0);
OutDef.od_class = VU;
OutDef.od_file = FileName;
OutDef.od_line = LineNumber;
OutDef.od_type = idf->id_def->df_type;
outdef();
}
outdef()
{
output_def(&OutDef);
}
outcall()
{
output_def(&OutCall);
}
PRIVATE
output_def(od)
struct outdef *od;
{
/* As the types are output the tp_entries are removed, because they
* are then not needed anymore.
*/
if (od->od_class == XXDF)
return;
if (LINTLIB) {
switch (od->od_class) {
case EFDF:
od->od_class = LFDF;
break;
case EVDF:
od->od_class = LVDF;
break;
case SFDF:
/* remove tp_entries */
while (od->od_arg) {
register struct argument *tmp = od->od_arg;
od->od_arg = od->od_arg->next;
free_argument(tmp);
}
return;
default:
return;
}
}
printf("%s:%d:%c", od->od_name, od->od_statnr, od->od_class);
switch (od->od_class) {
case EFDF:
case SFDF:
case LFDF:
if (f_VARARGSn != -1) {
printf(":%d", -1 - f_VARARGSn);
outargs(od->od_arg, f_VARARGSn);
}
else {
printf(":%d", od->od_nrargs);
outargs(od->od_arg, od->od_nrargs);
}
od->od_arg = 0;
printf(":%d", od->od_valreturned);
break;
case FC:
printf(":%d", od->od_nrargs);
outargs(od->od_arg, od->od_nrargs);
od->od_arg = 0;
printf(":%d", od->od_valused);
break;
case EVDF:
case SVDF:
case LVDF:
case EFDC:
case EVDC:
case IFDC:
case VU:
break;
default:
NOTREACHED();
/*NOTREACHED*/
}
printf(":");
outargtype(od->od_type);
printf(":%u:%s\n", od->od_line, od->od_file);
}
PRIVATE
outargs(arg, n)
struct argument *arg;
{
/* Output the n arguments in the argument list and remove them */
register struct argument *tmp;
while (n--) {
ASSERT(arg);
outarg(arg);
tmp = arg;
arg = arg->next;
free_argument(tmp);
}
/* remove the remaining entries */
while (arg) {
tmp = arg;
arg = arg->next;
free_argument(tmp);
}
}
PRIVATE
outarg(arg)
struct argument *arg;
{
printf(":");
switch (arg->ar_class) {
case ArgConst:
if (arg->CAA_VALUE >= 0) {
/* constant non-negative actual parameter */
printf("+");
}
outargtype(arg->ar_type);
break;
case ArgString:
outargstring(arg);
break;
case ArgFormal:
case ArgExpr:
outargtype(arg->ar_type);
if (arg->ar_type->tp_fund == FUNCTION) {
/* UGLY PATCH !!! ??? */
/* function names as operands are sometimes
FUNCTION and sometimes POINTER to FUNCTION,
depending on opaque circumstances. E.g., in
f(main, main);
the first main is PtF and the second is F.
*/
printf("*");
}
break;
default:
NOTREACHED();
/*NOTREACHED*/
}
}
PRIVATE
outargstring(arg)
struct argument *arg;
{
char buff[1000];
register char *p;
bts2str(arg->CAS_VALUE, arg->CAS_LEN, buff);
for (p = &buff[0]; *p; p++) {
if (*p == '"' || *p == ':')
*p = ' ';
}
printf("\"%s\"", buff);
}
PRIVATE
outargtype(tp)
struct type *tp;
{
switch (tp->tp_fund) {
case POINTER:
outargtype(tp->tp_up);
printf("*");
break;
case ARRAY:
outargtype(tp->tp_up);
printf("*"); /* compatible with [] */
break;
case FUNCTION:
outargtype(tp->tp_up);
printf("()");
break;
case STRUCT:
case UNION:
case ENUM:
printf("%s %s", symbol2str(tp->tp_fund), tp->tp_idf->id_text);
break;
case CHAR:
case INT:
case SHORT:
case LONG:
case FLOAT:
case DOUBLE:
case VOID:
case ERRONEOUS:
if (tp->tp_unsigned)
printf("unsigned ");
printf("%s", symbol2str(tp->tp_fund));
break;
default:
NOTREACHED();
/*NOTREACHED*/
}
}
PRIVATE
implicit_func_decl(idf, file, line)
struct idf *idf;
char *file;
unsigned int line;
{
struct outdef od;
od.od_class = IFDC;
od.od_statnr = 0;
od.od_name = idf->id_text;
od.od_file = file;
od.od_line = line;
od.od_type = idf->id_def->df_type->tp_up;
output_def(&od);
/* The other fields are not used for this class. */
}
fill_outcall(ex, used)
struct expr *ex;
int used;
{
register struct idf *idf = ex->OP_LEFT->VL_IDF;
register struct def *def = idf->id_def;
if (def->df_sc == IMPLICIT && !idf->id_def->df_used) {
/* IFDC, first time */
implicit_func_decl(idf, ex->ex_file, ex->ex_line);
}
OutCall.od_type = def->df_type->tp_up;
OutCall.od_statnr = (def->df_sc == STATIC ? stat_number : 0);
OutCall.od_class = FC;
OutCall.od_name = idf->id_text;
OutCall.od_file = ex->ex_file;
OutCall.od_line = ex->ex_line;
OutCall.od_arg = (struct argument *)0;
OutCall.od_nrargs = 0;
if ((ex = ex->OP_RIGHT) != 0) { /* function call with arguments */
/* store types of argument expressions in tp_entries */
while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
fill_arg(ex->OP_RIGHT);
ex = ex->OP_LEFT;
}
fill_arg(ex);
}
OutCall.od_valused = used; /* USED, IGNORED or VOIDED */
}
PRIVATE
fill_arg(e)
struct expr *e;
{
register struct argument *arg;
arg = new_argument();
arg->ar_type = e->ex_type;
if (is_cp_cst(e)) {
arg->ar_class = ArgConst;
arg->CAA_VALUE = e->VL_VALUE;
}
else if (e->ex_class == Value && e->VL_CLASS == Label) {
/* it may be a string; let's look it up */
register struct string_cst *sc = str_list;
while (sc) {
if (sc->sc_dlb == e->VL_LBL)
break;
sc = sc->next;
}
if (sc) {
/* it was a string */
arg->ar_class = ArgString;
arg->CAS_VALUE = sc->sc_value;
arg->CAS_LEN = sc->sc_len - 1; /* included the \0 */
}
else {
arg->ar_class = ArgExpr;
}
}
else {
arg->ar_class = ArgExpr;
}
arg->next = OutCall.od_arg;
OutCall.od_arg = arg;
OutCall.od_nrargs++;
}
#endif LINT

View File

@ -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;
};

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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 <em_label.h> /* obtain definition of "label" */
#define NO_LABEL (label) 0
extern label lab_count;
#define text_label() (lab_count++) /* returns a new text label */
extern label datlab_count;
#define data_label() (datlab_count++) /* returns a new data label */
#define define_label(idf) enter_label(idf, 1);
/* The identifier idf is defined as a label. If it is new,
it is entered into the idf list with the largest possible
scope, i.e., on the lowest possible level.
*/
#define apply_label(idf) enter_label(idf, 0);
/* The identifier idf is applied as a label. It may or may
not be there, and if it is there, it may be from a
declaration or another application.
*/

View File

@ -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 */

View File

@ -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

406
lang/cem/cemcom.ansi/main.c Normal file
View File

@ -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 <system.h>
#include "nopp.h"
#include "target_sizes.h"
#include "debug.h"
#include "use_tmp.h"
#include "inputtype.h"
#include "input.h"
#include "level.h"
#include "idf.h"
#include "arith.h"
#include "type.h"
#include "proto.h"
#include "declar.h"
#include "tokenname.h"
#include "Lpars.h"
#include "LLlex.h"
#include <alloc.h>
#include "specials.h"
#include "noRoption.h"
#include "nocross.h"
#include "sizes.h"
#include "align.h"
extern struct tokenname tkidf[];
extern char *symbol2str();
extern char options[128];
#ifndef NOPP
int inc_pos = 1; /* place where next -I goes */
int inc_total = 0;
int inc_max;
char **inctable;
extern char *getwdir();
#endif NOPP
struct sp_id special_ids[] = {
{"setjmp", SP_SETJMP}, /* non-local goto's are registered */
{0, 0}
};
#ifndef NOCROSS
arith
short_size = SZ_SHORT,
word_size = SZ_WORD,
dword_size = (2 * SZ_WORD),
int_size = SZ_INT,
long_size = SZ_LONG,
#ifndef NOFLOAT
float_size = SZ_FLOAT,
double_size = SZ_DOUBLE,
lngdbl_size = SZ_LNGDBL,
#endif NOFLOAT
pointer_size = SZ_POINTER;
int
short_align = AL_SHORT,
word_align = AL_WORD,
int_align = AL_INT,
long_align = AL_LONG,
#ifndef NOFLOAT
float_align = AL_FLOAT,
double_align = AL_DOUBLE,
lngdbl_align = AL_LNGDBL,
#endif NOFLOAT
pointer_align = AL_POINTER,
struct_align = AL_STRUCT,
union_align = AL_UNION;
#endif NOCROSS
#ifndef NOPP
arith ifval; /* ifval will contain the result of the #if expression */
#endif NOPP
char *prog_name;
main(argc, argv)
char *argv[];
{
/* parse and interpret the command line options */
prog_name = argv[0];
init_hmask();
#ifndef NOPP
inctable = (char **) Malloc(10 * sizeof(char *));
inctable[0] = ".";
inctable[1] = "/usr/include";
inctable[2] = 0;
inc_total = 2;
inc_max = 10;
init_pp(); /* initialise the preprocessor macros */
#endif NOPP
/* Note: source file "-" indicates that the source is supplied
as standard input. This is only allowed if INP_READ_IN_ONE is
not defined!
*/
#ifdef INP_READ_IN_ONE
while (argc > 1 && *argv[1] == '-')
#else INP_READ_IN_ONE
while (argc > 1 && *argv[1] == '-' && argv[1][1] != '\0')
#endif INP_READ_IN_ONE
{
char *par = &argv[1][1];
do_option(par, 1);
argc--, argv++;
}
#ifdef LINT
lint_init();
#endif LINT
compile(argc - 1, &argv[1]);
#ifdef DEBUG
hash_stat();
#endif DEBUG
sys_stop(err_occurred ? S_EXIT : S_END);
/*NOTREACHED*/
}
char *source = 0;
char *nmlist = 0;
compile(argc, argv)
char *argv[];
{
char *result;
#ifndef LINT
register char *destination = 0;
#endif LINT
#ifdef DEBUG
#ifndef NOPP
int pp_only = options['E'] || options['P'] || options['C'];
#endif NOPP
#endif
switch (argc) {
case 1:
#ifndef LINT
#ifdef DEBUG
#ifndef NOPP
if (!pp_only)
#endif NOPP
#endif
fatal("%s: destination file not specified", prog_name);
#endif LINT
break;
#ifndef LINT
case 2:
destination = argv[1];
break;
case 3:
nmlist = argv[2];
destination = argv[1];
break;
#endif LINT
default:
#ifndef LINT
fatal("use: %s source destination [namelist]", prog_name);
#else LINT
fatal("use: %s source", prog_name);
#endif LINT
break;
}
if (strcmp(argv[0], "-"))
FileName = source = argv[0];
else {
source = 0;
FileName = "standard input";
}
if (!InsertFile(source, (char **) 0, &result)) /* read the source file */
fatal("%s: no source file %s\n", prog_name, FileName);
File_Inserted = 1;
init();
LineNumber = 0;
nestlow = -1;
#ifndef NOPP
WorkingDir = getwdir(source);
#endif NOPP
PushLex(); /* initialize lex machine */
#ifdef DEBUG
#ifndef NOPP
if (pp_only) /* run the preprocessor as if it is stand-alone */
preprocess();
else
#endif NOPP
#endif DEBUG
{
#ifndef LINT
init_code(destination && strcmp(destination, "-") != 0 ?
destination : 0);
#endif LINT
/* compile the source text */
C_program();
#ifdef PREPEND_SCOPES
prepend_scopes();
#endif PREPEND_SCOPES
end_code();
#ifdef DEBUG
if (options['u']) {
unstack_level(); /* unstack L_GLOBAL */
}
if (options['f'] || options['t'])
dumpidftab("end of main", options['f'] ? 7 : 0);
#endif DEBUG
}
PopLex();
}
init()
{
init_cst(); /* initialize variables of "cstoper.c" */
reserve(tkidf); /* mark the C reserved words as such */
init_specials(special_ids); /* mark special ids as such */
/* Treat the type generic as int, having the same size and
alignment requirements.
This type is used as top type for void pointers, and is
transparent to the user.
*/
gen_type = standard_type(GENERIC, 0, 1, (arith)1);
char_type = standard_type(CHAR, 0, 1, (arith)1);
uchar_type = standard_type(CHAR, UNSIGNED, 1, (arith)1);
short_type = standard_type(SHORT, 0, short_align, short_size);
ushort_type = standard_type(SHORT, UNSIGNED, short_align, short_size);
/* Treat type `word' as `int', having its own size and
alignment requirements.
This type is transparent to the user.
*/
word_type = standard_type(INT, 0, word_align, word_size);
uword_type = standard_type(INT, UNSIGNED, word_align, word_size);
int_type = standard_type(INT, 0, int_align, int_size);
uint_type = standard_type(INT, UNSIGNED, int_align, int_size);
long_type = standard_type(LONG, 0, long_align, long_size);
ulong_type = standard_type(LONG, UNSIGNED, long_align, long_size);
#ifndef NOFLOAT
float_type = standard_type(FLOAT, 0, float_align, float_size);
double_type = standard_type(DOUBLE, 0, double_align, double_size);
lngdbl_type = standard_type(LNGDBL, 0, lngdbl_align, lngdbl_size);
#endif NOFLOAT
void_type = standard_type(VOID, 0, 1, (arith)0);
label_type = standard_type(LABEL, 0, 0, (arith)0);
error_type = standard_type(ERRONEOUS, 0, 1, (arith)1);
/* Pointer Arithmetic type: all arithmetics concerning
pointers is supposed to be performed in the
pointer arithmetic type which is equal to either
int_type or long_type, depending on the pointer_size
*/
if ((int)pointer_size == (int)word_size)
pa_type = word_type;
else
if ((int)pointer_size == (int)short_size)
pa_type = short_type;
else
if ((int)pointer_size == (int)int_size)
pa_type = int_type;
else
if ((int)pointer_size == (int)long_size)
pa_type = long_type;
else
fatal("pointer size incompatible with any integral size");
if ((int)int_size != (int)word_size)
fatal("int_size and word_size are not equal");
if ((int)short_size > (int)int_size || (int)int_size > (int)long_size)
fatal("sizes of short/int/long decreasing");
/* Build a type for function returning int, RM 13 */
funint_type = construct_type(FUNCTION, int_type, 0, (arith)0, NO_PROTO);
string_type = construct_type(POINTER, char_type, 0, (arith)0, NO_PROTO);
/* Define the standard type identifiers. */
add_def(str2idf("char"), TYPEDEF, char_type, L_UNIVERSAL);
add_def(str2idf("int"), TYPEDEF, int_type, L_UNIVERSAL);
#ifndef NOFLOAT
add_def(str2idf("float"), TYPEDEF, float_type, L_UNIVERSAL);
add_def(str2idf("double"), TYPEDEF, double_type, L_UNIVERSAL);
#endif NOFLOAT
add_def(str2idf("void"), TYPEDEF, void_type, L_UNIVERSAL);
stack_level();
}
init_specials(si)
register struct sp_id *si;
{
while (si->si_identifier) {
struct idf *idf = str2idf(si->si_identifier);
if (idf->id_special)
fatal("maximum identifier length insufficient");
idf->id_special = si->si_flag;
si++;
}
}
#ifdef DEBUG
#ifndef NOPP
preprocess()
{
/* preprocess() is the "stand-alone" preprocessor which
consecutively calls the lexical analyzer LLlex() to get
the tokens and prints them in a suitable way.
*/
static unsigned int lastlineno = 0;
static char *lastfilenm = "";
while (LLlex() != EOI) {
if (lastlineno != dot.tk_line) {
if (strcmp(lastfilenm, dot.tk_file) == 0) {
if (dot.tk_line - lastlineno <= 1) {
lastlineno++;
print("\n");
}
else {
lastlineno = dot.tk_line;
if (!options['P'])
print("\n#line %ld \"%s\"\n",
lastlineno,
lastfilenm
);
}
}
else {
lastfilenm = dot.tk_file;
lastlineno = dot.tk_line;
if (!options['P'])
print("\n#line %ld \"%s\"\n",
lastlineno, lastfilenm);
}
}
else
if (strcmp(lastfilenm, dot.tk_file) != 0) {
lastfilenm = dot.tk_file;
if (!options['P'])
print("\n#line %ld \"%s\"\n",
lastlineno, lastfilenm);
}
switch (DOT) {
case IDENTIFIER:
case TYPE_IDENTIFIER:
print("%s ", dot.tk_idf->id_text);
break;
case STRING:
{
char sbuf[1024]; /* a transient buffer */
char *bts2str();
print("\"%s\" ", bts2str(dot.tk_bts, dot.tk_len, sbuf));
break;
}
case INTEGER:
print("%ld ", dot.tk_ival);
break;
#ifndef NOFLOAT
case FLOATING:
print("%s ", dot.tk_fval);
break;
#endif NOFLOAT
case EOI:
case EOF:
return;
default: /* very expensive... */
print("%s ", symbol2str(DOT));
}
}
}
#endif NOPP
#endif DEBUG
No_Mem() /* called by alloc package */
{
fatal("out of memory");
}
C_failed() /* called by EM_code module */
{
fatal("write failed");
}

View File

@ -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))\
:'

View File

@ -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

3
lang/cem/cemcom.ansi/make.next Executable file
View File

@ -0,0 +1,3 @@
sed -n '
s:^.*ALLOCDEF.*"\(.*\)".*$:struct \1 *h_\1 = 0;:p
' $*

View File

@ -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--

View File

@ -0,0 +1,11 @@
cat <<'--EOT--'
/* Generated by make.tokfile */
/* $Header: */
--EOT--
sed '
/{[A-Z]/!d
s/.*{//
s/,.*//
s/.*/%token &;/
'

View File

@ -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 <stdio.h>
#define IDFSIZE 4096
char *readfile();
struct node {
char *name;
struct node *left, *right;
};
char *
Malloc(n)
unsigned n;
{
char *space;
char *malloc();
if ((space = malloc(n)) == 0) {
fprintf(stderr, "out of memory\n");
exit(1);
}
return space;
}
struct node *make_tree();
#define new_node() ((struct node *) Malloc(sizeof (struct node)))
main(argc, argv)
char *argv[];
{
char *nl_file, *as_file;
char *nl_text, *as_text;
struct node *nl_tree = 0;
int nl_siz, as_siz;
if (argc != 3) {
fprintf(stderr, "use: %s namelist assembler_file\n", argv[0]);
exit(1);
}
nl_file = argv[1];
as_file = argv[2];
if ((nl_text = readfile(nl_file, &nl_siz)) == 0) {
fprintf(stderr, "%s: cannot read namelist %s\n",
argv[0], nl_file);
exit(1);
}
if ((as_text = readfile(as_file, &as_siz)) == 0) {
fprintf(stderr, "%s: cannot read assembler file %s\n",
argv[0], as_file);
exit(1);
}
nl_tree = make_tree(nl_text);
edit(as_text, nl_tree);
if (writefile(as_file, as_text, as_siz) == 0) {
fprintf(stderr, "%s: cannot write to %s\n", argv[0], as_file);
exit(1);
}
return 0;
}
#include <sys/types.h>
#include <stat.h>
char *
readfile(filename, psiz)
char *filename;
int *psiz;
{
struct stat stbuf; /* for `stat' to get filesize */
register int fd; /* filedescriptor for `filename' */
register char *cbuf; /* pointer to buffer to be returned */
if (((fd = open(filename, 0)) < 0) || (fstat(fd, &stbuf) != 0))
return 0;
cbuf = Malloc(stbuf.st_size + 1);
if (read(fd, cbuf, stbuf.st_size) != stbuf.st_size)
return 0;
cbuf[stbuf.st_size] = '\0';
close(fd); /* filedes no longer needed */
*psiz = stbuf.st_size;
return cbuf;
}
int
writefile(filename, text, size)
char *filename, *text;
{
register fd;
if ((fd = open(filename, 1)) < 0)
return 0;
if (write(fd, text, size) != size)
return 0;
close(fd);
return 1;
}
struct node *
make_tree(nl)
char *nl;
{
char *id = nl;
struct node *tree = 0;
while (*nl) {
if (*nl == '\n') {
*nl = '\0';
insert(&tree, id);
id = ++nl;
}
else {
++nl;
}
}
return tree;
}
insert(ptree, id)
struct node **ptree;
char *id;
{
register cmp;
if (*ptree == 0) {
register struct node *nnode = new_node();
nnode->name = id;
nnode->left = nnode->right = 0;
*ptree = nnode;
}
else
if ((cmp = strcmp((*ptree)->name, id)) < 0)
insert(&((*ptree)->right), id);
else
if (cmp > 0)
insert(&((*ptree)->left), id);
}
struct node *
find(tree, id)
struct node *tree;
char *id;
{
register cmp;
if (tree == 0)
return 0;
if ((cmp = strcmp(tree->name, id)) < 0)
return find(tree->right, id);
if (cmp > 0)
return find(tree->left, id);
return tree;
}
edit(text, tree)
char *text;
struct node *tree;
{
register char *ptr = text;
char idbuf[IDFSIZE];
register char *id;
register char *save_ptr;
while (*ptr) {
if (
*ptr == '.' &&
*++ptr == 'l' &&
*++ptr == 'c' &&
*++ptr == 'o' &&
*++ptr == 'm' &&
*++ptr == 'm' &&
(*++ptr == ' ' || *ptr == '\t')
)
{
save_ptr = ptr - 6;
while (*++ptr == ' ' || *ptr == '\t')
;
if (*ptr == '_')
++ptr;
if (InId(*ptr)) {
id = &idbuf[0];
*id++ = *ptr++;
while (InId(*ptr))
*id++ = *ptr++;
*id = '\0';
if (find(tree, idbuf) != 0) {
*save_ptr++ = ' ';
*save_ptr++ = '.';
}
}
}
while (*ptr && *ptr++ != '\n')
;
}
}
InId(c)
{
switch (c) {
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
case '_':
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return 1;
default:
return 0;
}
}
puttree(nd)
struct node *nd;
{
if (nd) {
puttree(nd->left);
printf("%s\n", nd->name);
puttree(nd->right);
}
}

View File

@ -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 */

View File

@ -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() { }

View File

@ -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

View File

@ -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 <alloc.h>
#include "nofloat.h"
#include "nopp.h"
#include "idfsize.h"
#include "nobitfield.h"
#include "class.h"
#include "macro.h"
#include "idf.h"
#include "arith.h"
#include "sizes.h"
#include "align.h"
#include "use_tmp.h"
#include "dataflow.h"
#include "noRoption.h"
#ifndef NOPP
extern char **inctable;
extern int inc_pos;
extern int inc_max;
extern int inc_total;
#endif NOPP
char options[128]; /* one for every char */
#ifdef LINT
char loptions[128]; /* one for every char */
#endif LINT
extern int idfsize;
static int txt2int();
do_option(text)
char *text;
{
register char opt;
next_option: /* to allow combined one-char options */
switch (opt = *text++) {
case 0: /* to end the goto next_option loop */
break;
default:
#ifndef LINT
fatal("illegal option: %c", opt);
#else LINT
warning("illegal option: %c", opt);
#endif LINT
break;
case '-':
options[*text++] = 1; /* flags, debug options etc. */
goto next_option;
#ifndef LINT
#ifdef DATAFLOW
case 'd':
#endif DATAFLOW
case 'p': /* procentry/procexit */
case 'L' : /* no fil/lin */
case 'n': /* use no registers */
case 'w': /* no warnings will be given */
case 's': /* no stricts will be given */
options[opt] = 1;
goto next_option;
#endif LINT
#ifdef LINT
case 'h': /* heuristic tests */
case 'v': /* no complaints about unused arguments */
case 'a': /* check long->int int->long conversions */
case 'b': /* don't report unreachable break-statements */
case 'x': /* complain about unused extern declared variables */
case 'u': /* no "used but not defined"; for pass 2 */
case 'L': /* lintlibrary */
loptions[opt] = 1;
goto next_option;
#endif LINT
case 'R': /* strict version */
#ifndef NOROPTION
options[opt] = 1;
#else NOROPTION
warning("-R option not implemented");
#endif NOROPTION
goto next_option;
#ifdef ___XXX___
deleted, is now a debug-flag
case 'C' : /* E option + comment output */
#ifndef NOPP
options['E'] = 1;
warning("-C: comment is not output");
#else NOPP
warning("-C option ignored");
#endif NOPP
break;
#endif ___XXX___
case 'D' : { /* -Dname : predefine name */
#ifndef NOPP
register char *cp = text, *name, *mactext;
if (class(*cp) != STIDF && class(*cp) != STELL) {
error("identifier missing in -D%s", text);
break;
}
name = cp;
while (*cp && in_idf(*cp)) {
++cp;
}
if (!*cp) { /* -Dname */
mactext = "1";
}
else
if (*cp == '=') { /* -Dname=text */
*cp++ = '\0'; /* end of name */
mactext = cp;
}
else { /* -Dname?? */
error("malformed option -D%s", text);
break;
}
macro_def(str2idf(name), mactext, -1, strlen(mactext),
NOFLAG);
#else NOPP
warning("-D option ignored");
#endif NOPP
break;
}
#ifdef ___XXX___
deleted, is now a debug-flag
case 'E' : /* run preprocessor only, with #<int> */
#ifndef NOPP
options['E'] = 1;
#else NOPP
warning("-E option ignored");
#endif NOPP
break;
#endif ___XXX___
case 'I' : /* -Ipath : insert "path" into include list */
#ifndef NOPP
if (*text) {
int i;
register char *new = text;
if (++inc_total > inc_max) {
char **n = (char **)
Malloc((10+inc_max)*sizeof(char *));
for (i = 0; i < inc_max; i++) {
n[i] = inctable[i];
}
free((char *) inctable);
inctable = n;
inc_max += 10;
}
i = inc_pos++;
while (new) {
char *tmp = inctable[i];
inctable[i++] = new;
new = tmp;
}
}
else inctable[inc_pos] = 0;
#else NOPP
warning("-I option ignored");
#endif NOPP
break;
case 'M': /* maximum identifier length */
idfsize = txt2int(&text);
if (*text || idfsize <= 0)
fatal("malformed -M option");
if (idfsize > IDFSIZE)
fatal("maximum identifier length is %d", IDFSIZE);
break;
#ifdef ___XXX___
deleted, is now a debug-flag
case 'P' : /* run preprocessor stand-alone, without #'s */
#ifndef NOPP
options['E'] = 1;
options['P'] = 1;
#else NOPP
warning("-P option ignored");
#endif NOPP
break;
#endif ___XXX___
#ifdef LINT
case 'S' : { /* -Sint : static scope number for lint */
extern int stat_number;
stat_number = txt2int(&text);
break;
}
#endif LINT
case 'T' : {
#ifdef USE_TMP
extern char *C_tmpdir;
if (*text)
C_tmpdir = text;
else
C_tmpdir = ".";
#else USE_TMP
warning("-T option ignored");
#endif USE_TMP
break;
}
case 'U' : { /* -Uname : undefine predefined */
#ifndef NOPP
register struct idf *idef;
if (*text) {
if ((idef = str2idf(text))->id_macro) {
free_macro(idef->id_macro);
idef->id_macro = (struct macro *) 0;
}
}
#else NOPP
warning("-U option ignored");
#endif NOPP
break;
}
#ifndef LINT
case 'V' : /* set object sizes and alignment requirements */
#ifdef NOCROSS
warning("-V option ignored");
break;
#else NOCROSS
{
register arith sz, algn;
char c;
while (c = *text++) {
sz = txt2int(&text);
algn = 0;
if (*text == '.') {
text++;
algn = txt2int(&text);
}
switch (c) {
case 's': /* short */
if (sz != (arith)0)
short_size = sz;
if (algn != 0)
short_align = algn;
break;
case 'w': /* word */
if (sz != (arith)0)
dword_size = (word_size = sz) << 1;
if (algn != 0)
word_align = algn;
break;
case 'i': /* int */
if (sz != (arith)0)
int_size = sz;
if (algn != 0)
int_align = algn;
break;
case 'l': /* long */
if (sz != (arith)0)
long_size = sz;
if (algn != 0)
long_align = algn;
break;
case 'f': /* float */
#ifndef NOFLOAT
if (sz != (arith)0)
float_size = sz;
if (algn != 0)
float_align = algn;
#endif NOFLOAT
break;
case 'd': /* double */
#ifndef NOFLOAT
if (sz != (arith)0)
double_size = sz;
if (algn != 0)
double_align = algn;
#endif NOFLOAT
break;
case 'x': /* long double */
#ifndef NOFLOAT
if (sz != (arith)0)
lngdbl_size = sz;
if (algn != 0)
lngdbl_align = algn;
#endif NOFLOAT
break;
case 'p': /* pointer */
if (sz != (arith)0)
pointer_size = sz;
if (algn != 0)
pointer_align = algn;
break;
case 'r': /* adjust bitfields right */
#ifndef NOBITFIELD
options['r'] = 1;
#else NOBITFIELD
warning("bitfields are not implemented");
#endif NOBITFIELD
break;
case 'S': /* initial struct alignment */
if (sz != (arith)0)
struct_align = sz;
break;
case 'U': /* initial union alignment */
if (sz != (arith)0)
union_align = sz;
break;
default:
error("-V: bad type indicator %c\n", c);
}
}
break;
}
#endif NOCROSS
#endif LINT
}
}
static int
txt2int(tp)
register char **tp;
{
/* the integer pointed to by *tp is read, while increasing
*tp; the resulting value is yielded.
*/
register int val = 0, ch;
while (ch = **tp, ch >= '0' && ch <= '9') {
val = val * 10 + ch - '0';
(*tp)++;
}
return val;
}

View File

@ -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 <alloc.h>
#include "class.h"
#include "macro.h"
#define P_UNKNOWN 0
#define P_FLAGS 1
struct pkey {
char *pk_name;
int pk_key;
} pragmas[] = {
{"flags", P_FLAGS},
{0, P_UNKNOWN}
};
extern struct idf *GetIdentifier();
do_pragma()
{
register struct pkey *pkp;
register struct idf *id;
struct token tk;
int flag;
if ((id = GetIdentifier()) != (struct idf *)0) {
/* Lineair search - why bother ?
*/
for (pkp = &pragmas[0]; pkp->pk_key != P_UNKNOWN; pkp++)
if (strcmp(pkp->pk_name, id->id_text) == 0)
break;
switch (pkp->pk_key) {
case P_FLAGS:
if (GetToken(&tk) == STRING)
do_option(tk.tk_bts);
break;
case P_UNKNOWN:
strict("unknown pragma directive %s", id->id_text);
break;
default:
strict("unimplemented pragma directive");
break;
}
}
SkipToNewLine(0);
}
#endif

View File

@ -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
}
;

View File

@ -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 <alloc.h>
#include "Lpars.h"
#include "level.h"
#include "arith.h"
#include "align.h"
#include "stack.h"
#include "idf.h"
#include "def.h"
#include "type.h"
#include "struct.h"
#include "label.h"
#include "expr.h"
#include "declar.h"
#include "decspecs.h"
#include "proto.h"
#include "assert.h"
extern char options[];
add_proto(pl, ds, dc, level)
struct proto *pl;
struct decspecs *ds;
struct declarator *dc;
int level;
{
/* The full typed identifier or abstract type, described
by the structures decspecs and declarator are turned
a into parameter type list structure.
The parameters will be declared at level L_FORMAL2,
later on it's decided whether they were prototypes
or actual declarations.
*/
register struct idf *idf;
register struct def *def = (struct def *)0;
register int sc = ds->ds_sc;
register struct type *type;
char formal_array = 0;
ASSERT(ds->ds_type != (struct type *)0);
pl->pl_flag = FORMAL;
if ((idf = dc->dc_idf) != (struct idf *)0)
def = idf->id_def;
type = declare_type(ds->ds_type, dc);
if (type->tp_size < (arith)0 && actual_declaration(sc, type)) {
extern char *symbol2str();
error("unknown %s-type", symbol2str(type->tp_fund));
} else if (type->tp_size == 0) {
pl->pl_flag = VOID;
if (idf != (struct idf *)0)
strict("illegal use of void in argument list");
}
/* Perform some special conversions for parameters.
*/
if (type->tp_fund == FUNCTION) {
if (type->tp_proto)
remove_proto_idfs(type->tp_proto);
type = construct_type(POINTER, type, 0, (arith) 0, NO_PROTO);
} else if (type->tp_fund == ARRAY) {
type = construct_type(POINTER, type, 0, (arith) 0, NO_PROTO);
formal_array = 1;
}
/* According to the standard we should ignore the storage
class of a parameter, unless it's part of a function
definition.
However, in the routine declare_protos we don't know decspecs,
and therefore we can't complain up there. So we build up the
storage class, and keep quiet until we reach declare_protos.
*/
sc = (ds->ds_sc_given && ds->ds_sc != REGISTER) ?
0 : sc == 0 ? FORMAL : REGISTER;
if (def && (def->df_level == level || def->df_level < L_PROTO)) {
/* redeclaration at the same level */
error("parameter %s redeclared", idf->id_text);
} else if (idf != (struct idf *)0) {
/* New definition, redefinition hides earlier one
*/
register struct def *newdef = new_def();
newdef->next = def;
newdef->df_level = level;
newdef->df_sc = sc;
newdef->df_type = type;
newdef->df_formal_array = formal_array;
newdef->df_file = idf->id_file;
newdef->df_line = idf->id_line;
#ifdef LINT
newdef->df_set = (type->tp_fund == ARRAY);
newdef->df_firstbrace = 0;
#endif
/* We can't put the idf onto the stack, since these kinds
of declaration may occurs at any level, and the idf
does not necessarily go at this level. E.g.
f() {
...
{ int func(int a, int b);
...
The idf's a and b declared in the prototype declaration
do not go at any level, they are simply ignored.
However, in
f(int a, int b) {
...
They should go at level L_FORMAL2. But at this stage
we don't know whether we have a prototype or function
definition. So, this process is postponed.
*/
idf->id_def = newdef;
update_ahead(idf);
}
pl->pl_idf = idf;
pl->pl_type = type;
}
declare_protos(idf, dc)
register struct idf *idf;
register struct declarator *dc;
{
/* At this points we know that the idf's in protolist are formal
parameters. So it's time to declare them at level L_FORMAL2.
*/
struct stack_level *stl = stack_level_of(L_FORMAL1);
register struct decl_unary *du;
register struct type *type;
register struct proto *pl;
register struct def *def;
#ifdef DEBUG
if (options['t'])
dumpidftab("start declare_protos", 0);
#endif DEBUG
du = dc->dc_decl_unary;
while (du && du->du_fund != FUNCTION)
du = du->next;
pl = du ? du->du_proto : NO_PROTO;
if (pl) {
idf->id_proto = 0;
do {
type = pl->pl_type;
/* `...' only for type checking */
if (pl->pl_flag == ELLIPSIS) {
pl = pl->next;
continue;
}
/* special case: int f(void) { ; } */
if (type->tp_fund == VOID)
break;
if (!pl->pl_idf || !(def = pl->pl_idf->id_def)) {
error("no parameter supplied");
pl = pl->next;
continue;
}
/* Postponed storage class checking.
*/
if (def->df_sc == 0)
error("illegal storage class in parameter declaration");
def->df_level = L_FORMAL2;
stack_idf(pl->pl_idf, stl);
pl = pl->next;
} while (pl);
}
#ifdef DEBUG
if (options['t'])
dumpidftab("end declare_protos", 0);
#endif DEBUG
}
def_proto(dc)
register struct declarator *dc;
{
/* Prototype declarations may have arguments, but the idf's
in the parameter type list can be ignored.
*/
register struct decl_unary *du = dc->dc_decl_unary;
while (du) {
if (du->du_fund == FUNCTION)
remove_proto_idfs(du->du_proto);
du = du->next;
}
}
update_proto(tp, otp)
register struct type *tp, *otp;
{
/* This routine performs the proto type updates.
Consider the following code:
int f(double g());
int f(double g(int f(), int));
int f(double g(int f(long double), int));
The most accurate definition is the third line.
This routine will silently update all lists,
and removes the redundant occupied space.
*/
register struct proto *pl, *opl;
#if 0
/* THE FOLLOWING APPROACH IS PRESUMABLY WRONG.
THE ONLY THING THIS CODE IS SUPPOSED TO DO
IS TO UPDATE THE PROTOTYPELISTS, I HAVEN'T
EVEN CONSIDERED THE DISPOSAL OF REDUNDANT
SPACE !!.
THIS ROUTINE DUMPS CORE. SORRY, BUT IT'S 10
P.M. AND I'M SICK AN TIRED OF THIS PROBLEM.
*/
print("Entering\n");
if (tp == otp) {
print("OOPS - they are equal\n");
return;
}
if (!tp || !otp) {
print("OOPS - Nil pointers tp=@%o otp=@%o\n", tp, otp);
return;
}
print("Search function\n");
while (tp && tp->tp_fund != FUNCTION) {
if (!(tp->tp_up)) {
print("TP is NIL\n");
return;
}
tp = tp->tp_up;
if (!(otp->tp_up)) {
print("OTP is NIL\n");
return;
}
otp = otp->tp_up;
if (!tp) return;
}
print("Do it\n");
pl = tp->tp_proto;
opl = otp->tp_proto;
if (pl && opl) {
/* both have prototypes */
print("Both have proto type\n");
print("New proto type list\n");
dump_proto(pl);
print("Old proto type list\n");
dump_proto(opl);
while (pl && opl) {
update_proto(pl->pl_type, opl->pl_type);
pl = pl->next;
opl = pl->next;
}
/*free_proto_list(tp->tp_proto);*/
tp->tp_proto = otp->tp_proto;
} else if (opl) {
/* old decl has type */
print("Old decl has type\n");
print("Old proto type list\n");
dump_proto(opl);
tp->tp_proto = opl;
} else if (pl) {
/* new decl has type */
print("New decl has type\n");
print("New proto type list\n");
dump_proto(pl);
print("otp = @%o\n", otp);
otp->tp_proto = pl;
print("after assign\n");
} else
print("none has prototype\n");
print("Going for another top type\n");
update_proto(tp->tp_up, otp->tp_up);
# endif
}
free_proto_list(pl)
register struct proto *pl;
{
while (pl) {
register struct proto *tmp = pl->next;
free_proto(pl);
pl = tmp;
}
}
remove_proto_idfs(pl)
register struct proto *pl;
{
/* Remove all the identifier definitions from the
prototype list. Keep in account the recursive
function definitions.
*/
register struct def *def;
while (pl) {
if (pl->pl_idf) {
#ifdef DEBUG
if (options['t'])
print("Removing idf %s from list\n",
pl->pl_idf->id_text);
#endif
/* Remove all the definitions made within
a prototype.
*/
if (pl->pl_flag == FORMAL) {
register struct type *tp = pl->pl_type;
while (tp && tp->tp_fund != FUNCTION)
tp = tp->tp_up;
if (tp)
remove_proto_idfs(tp->tp_proto);
}
def = pl->pl_idf->id_def;
if (def && def->df_level <= L_PROTO){
pl->pl_idf->id_def = def->next;
free_def(def);
}
pl->pl_idf = (struct idf *) 0;
}
pl = pl->next;
}
}
call_proto(expp)
register struct expr **expp;
{
/* If the function specified by (*expp)->OP_LEFT has a prototype,
the parameters are converted according the rules specified in
par. 3.3.2.2. E.i. the parameters are converted to the prototype
counter parts as if by assignment. For the parameters falling
under ellipsis clause the old parameters conversion stuff
applies.
*/
register struct expr *left = (*expp)->OP_LEFT;
register struct expr *right = (*expp)->OP_RIGHT;
register struct proto *pl = NO_PROTO;
if (left != NILEXPR) { /* in case of an error */
register struct type *tp = left->ex_type;
while (tp && tp->tp_fund != FUNCTION)
tp = tp->tp_up;
pl = (tp && tp->tp_proto) ? tp->tp_proto : NO_PROTO;
}
if (right != NILEXPR) { /* function call with parameters */
register struct expr *ex = right;
register struct expr **ep = &((*expp)->OP_RIGHT);
register int ecnt = 0, pcnt = 0;
struct expr **estack[NPARAMS];
struct proto *pstack[NPARAMS];
if (pl == NO_PROTO) {
register struct idf *idf;
if (left->ex_class != Value || left->VL_CLASS != Name) {
strict("no prototype supplied");
return;
}
if ((idf = left->VL_IDF)->id_proto)
return;
strict("'%s' no prototype supplied", idf->id_text);
idf->id_proto++;
return;
}
/* stack up the parameter expressions */
while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
if (ecnt == STDC_NPARAMS)
strict("number of parameters exceeds ANSI limit");
if (ecnt >= NPARAMS-1) {
error("too many parameters");
return;
}
estack[ecnt++] = &(ex->OP_RIGHT);
ep = &(ex->OP_LEFT);
ex = ex->OP_LEFT;
}
estack[ecnt++] = ep;
/* Declarations like int f(void) do not expect any
parameters.
*/
if (pl && pl->pl_flag == VOID) {
strict("no parameters expected");
return;
}
/* stack up the prototypes */
while (pl) {
/* stack prototypes */
pstack[pcnt++] = pl;
pl = pl->next;
}
pcnt--;
for (--ecnt; ecnt >= 0; ecnt--) {
/* Only the parameters specified in the prototype
are checked and converted. The parameters that
fall under the ellipsis clause are neither
checked nor converted !
*/
if (pcnt < 0) {
error("more parameters than specified in prototype");
break;
}
if (pstack[pcnt]->pl_flag != ELLIPSIS) {
ch7cast(estack[ecnt],CASTAB,pstack[pcnt]->pl_type);
pcnt--;
} else
break; /* against unnecessary looping */
}
if (pcnt >= 0 && pstack[0]->pl_flag != ELLIPSIS)
error("less parameters than specified in prototype");
} else {
if (pl && pl->pl_flag != VOID)
error("less parameters than specified in prototype");
}
}

View File

@ -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 */

View File

@ -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 <alloc.h>
#include "idf.h"
#include "input.h"
#include "macro.h"
#include "arith.h"
#include "LLlex.h"
#include "class.h"
#include "assert.h"
#include "static.h"
#include "lapbuf.h"
#include "argbuf.h"
#include "replace.h"
struct repl *ReplaceList; /* list of currently active macros */
int
replace(idf)
register struct idf *idf;
{
/* replace is called by the lexical analyzer to perform
macro replacement. The routine actualy functions as a
higher interface to the real thing: expand_macro().
*/
struct repl *repl;
int size;
repl = new_repl();
repl->r_ptr = repl->r_text;
repl->r_args = new_args();
if (!expand_macro(repl, idf, (struct idf *)0))
return 0;
free_args(repl->r_args);
InsertText(repl->r_text, repl->r_ptr - repl->r_text);
repl->next = ReplaceList;
ReplaceList = repl;
return 1;
}
unstackrepl()
{
struct repl *repl = ReplaceList;
#ifdef PERSONAL_TOUCH
if (repl == NO_REPL) {
print("Leendert, you don't understand the principle yet\n");
return;
}
#else
ASSERT(repl != NO_REPL);
#endif
ReplaceList = repl->next;
free_repl(repl);
}
expand_macro(repl, idf, previdf)
register struct repl *repl;
register struct idf *idf;
struct idf *previdf;
{
/* expand_macro() does the actual macro replacement.
"idf" is a description of the identifier which
caused the replacement.
If the identifier represents a function-like macro
call, the number of actual parameters is checked
against the number of formal parameters. Note that
in ANSI C the parameters are expanded first;
this is done by calling getactuals().
When the possible parameters are expanded, the replace-
ment list associated with "idf" is expanded.
expand_macro() returns 1 if the replacement succeeded
and 0 if some error occurred.
*/
register struct macro *mac = idf->id_macro;
struct args *args = repl->r_args;
register int ch;
if (mac->mc_nps != -1) { /* with parameter list */
if (mac->mc_flag & FUNC) {
/* the following assertion won't compile:
ASSERT(!strcmp("defined", idf->id_text));
*/
if (!AccDefined) return 0;
}
ch = GetChar();
ch = skipspaces(ch,1);
if (ch != '(') { /* no replacement if no () */
/* This is obscure. See the examples for the replace
algorithm in section 3`.8.3.5.
lexwarning("macro %s needs arguments", idf->id_text);
*/
UnGetChar();
return 0;
} else
getactuals(args, idf);
if (mac->mc_flag & FUNC) {
struct idf *param = str2idf(args->a_rawbuf);
*repl->r_ptr++ = param->id_macro ? '1' : '0';
*repl->r_ptr = '\0';
return 1;
}
}
if (mac->mc_flag & FUNC) /* this macro leads to special action */
macro_func(idf);
if (mac->mc_nps == -1) {
register int size = mac->mc_length;
register char *text = mac->mc_text;
ASSERT((repl->r_ptr+size) < &(repl->r_text[LAPBUF]));
while (size-- > 0)
*repl->r_ptr++ = *text++;
*repl->r_ptr = '\0';
} else
macro2buffer(repl, idf, args);
/* According to the ANSI definition:
#define a +
a+b; --> + + b ;
'a' must be substituded, but the result should be
three tokens: + + ID. Because this preprocessor is
character based, we have a problem.
For now: just insert a space after all tokens,
until ANSI fixes this flaw.
*/
*repl->r_ptr++ = ' ';
*repl->r_ptr = '\0';
if (idf != previdf)
maccount(repl, idf);
return 1;
}
getactuals(args, idf)
register struct args *args;
register struct idf *idf;
{
/* Get the actual parameters from the input stream.
The hard part is done by actual(), only comma's and
other syntactic trivialities are checked here.
*/
register int nps = idf->id_macro->mc_nps;
register int argcnt;
register int ch;
argcnt = 0;
args->a_expvec[0] = args->a_expptr = &args->a_expbuf[0];
args->a_rawvec[0] = args->a_rawptr = &args->a_rawbuf[0];
if ((ch = GetChar()) != ')') {
PushBack();
while ((ch = actual(args, idf)) != ')' ) {
if (ch != ',') {
lexerror("illegal macro call");
return;
}
stash(args, '\0');
++argcnt;
args->a_expvec[argcnt] = args->a_expptr;
args->a_rawvec[argcnt] = args->a_rawptr;
if (argcnt == STDC_NPARAMS)
strict("number of parameters exceeds ANSI standard");
if (argcnt >= NPARAMS)
fatal("argument vector overflow");
}
stash(args, '\0');
++argcnt;
}
if (argcnt < nps)
lexerror("too few macro arguments");
if (argcnt > nps)
lexerror("too many macro arguments");
}
int
actual(args, idf)
register struct args *args;
register struct idf *idf;
{
/* This routine deals with the scanning of an actual parameter.
It keeps in account the openning and clossing brackets,
preprocessor numbers, strings and character constants.
*/
register int ch;
register int level = 0;
while (1) {
ch = GetChar();
if (class(ch) == STIDF || class(ch) == STELL) {
/* Scan a preprocessor identifier token. If the
token is a macro, it is expanded first.
*/
char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
register char *p = buf;
register struct idf *idef;
register int pos = -1;
register int hash;
extern int idfsize;
int size;
hash = STARTHASH();
do {
if (++pos < idfsize) {
*p++ = ch;
hash = ENHASH(hash, ch, pos);
}
ch = GetChar();
} while (in_idf(ch));
hash = STOPHASH(hash);
*p++ = '\0';
UnGetChar();
/* When the identifier has an associated macro
replacement list, it's expanded.
*/
idef = idf_hashed(buf, p - buf, hash);
if (idef->id_macro) /* expand macro identifier */
expand_actual(args, idef, idf);
else
for (p = buf; *p != '\0'; p++)
stash(args, *p);
} else if (class(ch) == STNUM || class(ch) == '.') {
/* preprocessor number token. No this is no joke,
the commitee decided (in all it's wisdom) that
a preprocessing number has the following regular
expression:
[0-9"."]{[0-9"."a-zA-Z_]|{[Ee][+-]}}*
*/
do {
stash(args, ch);
if ((ch = GetChar()) == 'e' || ch == 'E') {
ch = GetChar();
if (ch == '+' || ch == '-') {
stash(args, ch);
ch = GetChar();
}
}
} while (class(ch) == STNUM || class(ch) == STIDF ||
class(ch) == STELL || ch == '.');
UnGetChar();
} else if (ch == '(' || ch == '[' || ch == '{') {
/* a comma may occur within these constructions */
level++;
stash(args, ch);
} else if (ch == ')' || ch == ']' || ch == '}') {
level--;
/* clossing parenthesis of macro call */
if (ch == ')' && level < 0)
return ')';
stash(args, ch);
} else if (ch == ',') {
if (level <= 0) { /* comma separator for next argument */
if (level)
lexerror("unbalanced parenthesis");
return ',';
}
stash(args, ch);
} else if (ch == '\n') {
/* newlines are accepted as white spaces */
LineNumber++;
while ((ch = GetChar()), class(ch) == STSKIP)
/* VOID */;
/* This piece of code needs some explanation:
consider the call of a macro defined as:
#define sum(a,b) (a+b)
in the following form:
sum(
#include phone_number
,2);
in which case the include must be handled
interpreted as such.
*/
if (ch == '#')
domacro();
UnGetChar();
stash(args, ' ');
} else if (ch == '/') {
/* comments are treated as one white space token */
if ((ch = GetChar()) == '*') {
skipcomment();
stash(args, ' ');
} else {
UnGetChar();
stash(args, '/');
}
} else if (ch == '\'' || ch == '"') {
/* Strings are considered as ONE token, thus no
replacement within strings.
*/
register int match = ch;
stash(args, ch);
while ((ch = GetChar()) != EOI) {
if (ch == match)
break;
if (ch == '\\') {
stash(args, ch);
ch = GetChar();
} else if (ch == '\n') {
lexerror("newline in string");
LineNumber++;
stash(args, match);
break;
}
stash(args, ch);
}
if (ch != match) {
lexerror("unterminated macro call");
return ')';
}
stash(args, ch);
} else
stash(args, ch);
}
}
expand_actual(args, idef, idf)
register struct args *args;
register struct idf *idf, *idef;
{
struct repl *nrepl = new_repl();
register char *p;
nrepl->r_args = new_args();
nrepl->r_ptr = nrepl->r_text;
if (expand_macro(nrepl, idef, idf)) {
register struct args *ap = nrepl->r_args;
for (p = nrepl->r_text; p < nrepl->r_ptr; p++)
*args->a_expptr++ = *p;
/* stash idef name */
for (p = idef->id_text; *p != '\0'; p++)
*args->a_rawptr++ = *p;
/* The following code deals with expanded function
like macro calls. It makes the following code
work:
#define def(a,b) x(a,b)
#define glue(a,b) a ## b
glue(abc,def(a,b))
Results in:
abcdef(a,b);
*/
if (ap->a_rawvec[0]) {
/* stash arguments */
register int i;
*args->a_rawptr++ = '(';
for (i = 0; ap->a_rawvec[i] != (char *)0; i++) {
for (p = ap->a_rawvec[i]; *p != '\0'; p++)
*args->a_rawptr++ = *p;
*args->a_rawptr++ = ',';
}
*--args->a_rawptr = ')';
++args->a_rawptr; /* one too far */
}
} else /* something happened during the macro expansion */
for (p = idef->id_text; *p != '\0'; p++)
stash(args, *p);
free_args(nrepl->r_args);
free_repl(nrepl);
}
maccount(repl, idf)
register struct repl *repl;
register struct idf *idf;
{
/* To prevent re-expansion of already expanded macro's we count
the occurrences of the currently expanded macro name in the
replacement list. This is mainly to prevent recursion as in:
#define f(a) f(2 * (a))
f(y+1);
This results in:
f(2*(y+1));
When reading the inserted text we decrement the count of a
macro name until it's zero. Then we start expanding it again.
*/
register char *text = repl->r_text;
register int pos = -1;
extern int idfsize;
while (*text != '\0') {
if (*text == '\'' || *text == '"') {
register int delim;
for (delim = *text++; *text != delim; text++)
if (*text == '\\')
text++;
text++;
} else
if (class(*text) == STIDF || class(*text) == STELL) {
char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
register char *p = buf;
do {
if (++pos < idfsize)
*p++ = *text;
text++;
} while (in_idf(*text));
*p++ = '\0';
if (!strcmp(idf->id_text, buf))
idf->id_macro->mc_count++;
} else
text++;
}
}
macro_func(idef)
register struct idf *idef;
{
/* macro_func() performs the special actions needed with some
macros. These macros are __FILE__ and __LINE__ which
replacement texts must be evaluated at the time they are
used.
*/
register struct macro *mac = idef->id_macro;
static char FilNamBuf[PATHLENGTH];
char *long2str();
switch (idef->id_text[2]) {
case 'F': /* __FILE__ */
FilNamBuf[0] = '"';
strcpy(&FilNamBuf[1], FileName);
strcat(FilNamBuf, "\"");
mac->mc_text = FilNamBuf;
mac->mc_length = strlen(FilNamBuf);
break;
case 'L': /* __LINE__ */
mac->mc_text = long2str((long)LineNumber, 10);
mac->mc_length = 1;
break;
default:
crash("(macro_func)");
/*NOTREACHED*/
}
}
macro2buffer(repl, idf, args)
register struct repl *repl;
register struct idf *idf;
register struct args *args;
{
/* macro2buffer expands the replacement list and places the
result onto the replacement buffer. It deals with the #
and ## operators, and inserts the actual parameters.
The argument buffer contains the raw argument (needed
for the ## operator), and the expanded argument (for
all other parameter substitutions).
The grammar of the replacement list is:
repl_list: TOKEN repl_list
| PARAMETER repl_list
| '#' PARAMETER
| TOKEN '##' TOKEN
| PARAMETER '##' TOKEN
| TOKEN '##' PARAMETER
| PARAMETER '##' PARAMETER
;
As the grammar indicates, we could make a DFA and
use this finite state machine for the replacement
list parsing (inserting the arguments, etc.).
Currently we go through the replacement list in a
linear fashion. This is VERY expensive, something
smarter should be done (but even a DFA is O(|s|)).
*/
register char *ptr = idf->id_macro->mc_text;
char *stringify();
while (*ptr) {
ASSERT(repl->r_ptr < &(repl->r_text[LAPBUF]));
if (*ptr == '\'' || *ptr == '"') {
register int delim = *ptr;
do {
*repl->r_ptr++ = *ptr;
if (*ptr == '\\')
*repl->r_ptr++ = *++ptr;
if (*ptr == '\0') {
lexerror("unterminated string");
*repl->r_ptr = '\0';
return;
}
ptr++;
} while (*ptr != delim || *ptr == '\0');
*repl->r_ptr++ = *ptr++;
} else if (*ptr == '#') {
if (*++ptr == '#') {
/* ## - paste operator */
ptr++;
/* trim the actual replacement list */
--repl->r_ptr;
while (is_wsp(*repl->r_ptr) &&
repl->r_ptr >= repl->r_text)
--repl->r_ptr;
/* ## occurred at the beginning of the
replacement list.
*/
if (repl->r_ptr == repl->r_text)
goto paste;
++repl->r_ptr;
/* skip space in macro replacement list */
while ((*ptr & FORMALP) == 0 && is_wsp(*ptr))
ptr++;
/* ## occurred at the end of the
replacement list.
*/
if (*ptr & FORMALP) {
register int n = *ptr++ & 0177;
register char *p;
ASSERT(n != 0);
p = args->a_rawvec[n-1];
while (is_wsp(*p))
p++;
while (*p)
*repl->r_ptr++ = *p++;
} else if (*ptr == '\0')
goto paste;
} else
ptr = stringify(repl, ptr, args);
} else if (*ptr & FORMALP) {
/* insert actual parameter */
register int n = *ptr++ & 0177;
register char *p, *q;
ASSERT(n != 0);
/* This is VERY dirty, we look ahead for the
## operater. If it's found we use the raw
argument buffer instead of the expanded
one.
*/
for (p = ptr; (*p & FORMALP) == 0 && is_wsp(*p); p++)
/* VOID */;
if (*p == '#' && p[1] == '#')
q = args->a_rawvec[n-1];
else
q = args->a_expvec[n-1];
while (*q)
*repl->r_ptr++ = *q++;
*repl->r_ptr++ = ' ';
} else
*repl->r_ptr++ = *ptr++;
}
*repl->r_ptr = '\0';
return;
paste:
/* Sorry, i know this looks a bit like
a unix device driver code.
*/
lexerror("illegal use of the ## operator");
return;
}
char *
stringify(repl, ptr, args)
register struct repl *repl;
register char *ptr;
register struct args *args;
{
/* If a parameter is immediately preceded by a # token
both are replaced by a single string literal that
contains the spelling of the token sequence for the
corresponding argument.
Each occurrence of white space between the argument's
tokens become a single space character in the string
literal. White spaces before the first token and after
the last token comprising the argument are deleted.
To retain the original spelling we insert backslashes
as appropriate. We only escape backslashes if they
occure within string tokens.
*/
register int space = 1; /* skip leading spaces */
register int delim = 0; /* string or character constant delim */
register int backslash = 0; /* last character was a \ */
/* skip spaces macro replacement list */
while ((*ptr & FORMALP) == 0 && is_wsp(*ptr))
ptr++;
if (*ptr & FORMALP) {
register int n = *ptr++ & 0177;
register char *p;
ASSERT(n != 0);
p = args->a_expvec[n-1];
*repl->r_ptr++ = '"';
while (*p) {
if (is_wsp(*p)) {
if (!space) {
space = 1;
*repl->r_ptr++ = ' ';
}
p++;
continue;
}
space = 0;
if (!delim && (*p == '"' || *p == '\''))
delim = *p;
else if (*p == delim && !backslash)
delim = 0;
backslash = *p == '\\';
if (*p == '"' || (delim && *p == '\\'))
*repl->r_ptr++ = '\\';
*repl->r_ptr++ = *p++;
}
/* trim spaces in the replacement list */
for (--repl->r_ptr; is_wsp(*repl->r_ptr); repl->r_ptr--)
/* VOID */;
*++repl->r_ptr = '"';
++repl->r_ptr; /* oops, one to far */
} else
error("illegal use of # operator");
return ptr;
}
stash(args, ch)
register struct args *args;
register int ch;
{
/* Stash characters into the macro expansion buffer.
*/
if (args->a_expptr >= &(args->a_expbuf[ARGBUF]))
fatal("macro argument buffer overflow");
*args->a_expptr++ = ch;
if (args->a_rawptr >= &(args->a_rawbuf[ARGBUF]))
fatal("raw macro argument buffer overflow");
*args->a_rawptr++ = ch;
}
#endif NOPP

View File

@ -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

237
lang/cem/cemcom.ansi/scan.c Normal file
View File

@ -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 ( <spaces, comment, ...> )
*/
register char *p = actparams[0];
while ((class(*p) == STSKIP) || (*p == '\n')) {
++p;
}
if (!*p) { /* the case () : 0 parameters */
nr_of_params--;
}
}
if (nr_of_params != acnt) {
/* argument mismatch: too many or too few
actual parameters.
*/
lexwarning("argument mismatch, %s", idef->id_text);
while (nr_of_params < acnt) {
/* too few paraeters: remaining actuals are ""
*/
actparams[nr_of_params] = "";
nr_of_params++;
}
}
return actparams;
}
PRIVATE
copyact(ch1, ch2, lvl)
char ch1, ch2;
int lvl;
{
/* copyact() is taken from Ceriel Jacobs' LLgen, with
permission. Its task is to build a list of actuals
parameters, which list is surrounded by '(' and ')' and in
which the parameters are separated by ',' if there are
more than 1. The balancing of '(',')' and '[',']' and
'{','}' is taken care of by calling this function
recursively. At each level lvl, copyact() reads the input,
upto the corresponding closing bracket.
Opening bracket is ch1, closing bracket is ch2. If
lvl != 0, copy opening and closing parameters too.
*/
register int ch; /* Current char */
register int match; /* used to read strings */
if (lvl) {
copy(ch1);
}
for (;;) {
LoadChar(ch);
if (ch == ch2) {
if (lvl) {
copy(ch);
}
return;
}
switch(ch) {
#ifdef __MATCHING_PAR__
case ')':
case '}':
case ']':
lexerror("unbalanced parenthesis");
break;
#endif __MATCHING_PAR__
case '(':
copyact('(', ')', lvl+1);
break;
#ifdef __MATCHING_PAR__
case '{':
/* example:
#define declare(v, t) t v
declare(v, union{int i, j; float r;});
*/
copyact('{', '}', lvl+1);
break;
case '[':
copyact('[', ']', lvl+1);
break;
#endif __MATCHING_PAR__
case '\n':
LineNumber++;
while (LoadChar(ch), ch == '#') {
/* This piece of code needs some
explanation: consider the call of
the macro defined as:
#define sum(b,c) (b + c)
in the following form:
sum(
#include my_phone_number
,2)
in which case the include must be
interpreted as such.
*/
domacro(); /* has read nl, vt or ff */
/* Loop, for another control line */
}
PushBack();
copy(' ');
break;
case '/':
LoadChar(ch);
if (ch == '*') { /* skip comment */
skipcomment();
continue;
}
PushBack();
copy('/');
break;
case ',':
if (!lvl) {
/* next parameter encountered */
copy(EOS);
if (++nr_of_params >= NPARAMS) {
fatal("too many actual parameters");
}
actparams[nr_of_params] = aptr;
}
else {
copy(ch);
}
break;
case '\'':
case '"' :
/* watch out for brackets in strings, they do
not count !
*/
match = ch;
copy(ch);
while (LoadChar(ch), ch != EOI) {
if (ch == match) {
break;
}
if (ch == '\\') {
copy(ch);
LoadChar(ch);
}
else
if (ch == '\n') {
lexerror("newline in string");
LineNumber++;
copy(match);
break;
}
copy(ch);
}
if (ch == match) {
copy(ch);
break;
}
/* Fall through */
case EOI :
lexerror("unterminated macro call");
return;
default:
copy(ch);
break;
}
}
}
#endif NOPP

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 <system.h>
#include <em.h>
#include "debug.h"
#include "botch_free.h"
#include <alloc.h>
#include "Lpars.h"
#include "arith.h"
#include "stack.h"
#include "type.h"
#include "idf.h"
#include "def.h"
#include "struct.h"
#include "level.h"
#include "mes.h"
#include "noRoption.h"
/* #include <em_reg.h> */
extern char options[];
static struct stack_level UniversalLevel;
struct stack_level *local_level = &UniversalLevel;
/* The main reason for having this secondary stacking
mechanism besides the linked lists pointed to by the idf's
is efficiency.
To remove the idf's of a given level, one could scan the
hash table and chase down the idf chains; with a hash
table size of 100 this is feasible, but with a size of say
100000 this becomes painful. Therefore all idf's are also
kept in a stack of sets, one set for each level.
*/
int level; /* Always equal to local_level->sl_level. */
stack_level() {
/* A new level is added on top of the identifier stack.
*/
register struct stack_level *stl = new_stack_level();
register struct stack_level *loclev = local_level;
loclev->sl_next = stl;
stl->sl_previous = loclev;
stl->sl_level = ++level;
stl->sl_max_block = loclev->sl_max_block;
local_level = stl;
#ifdef LINT
lint_start_local();
#endif LINT
}
stack_idf(idf, stl)
struct idf *idf;
register struct stack_level *stl;
{
/* The identifier idf is inserted in the stack on level stl.
*/
register struct stack_entry *se = new_stack_entry();
/* link it into the stack level */
se->next = stl->sl_entry;
se->se_idf = idf;
stl->sl_entry = se;
}
struct stack_level *
stack_level_of(lvl)
{
/* The stack_level corresponding to level lvl is returned.
The stack should probably be an array, to be extended with
realloc where needed.
*/
register struct stack_level *stl;
if (lvl == level)
return local_level;
stl = &UniversalLevel;
while (stl->sl_level != lvl)
stl = stl->sl_next;
return stl;
}
unstack_level()
{
/* The top level of the identifier stack is removed.
*/
struct stack_level *lastlvl;
#ifdef DEBUG
if (options['t'])
dumpidftab("before unstackidfs", 0);
#endif DEBUG
#ifdef LINT
lint_local_level(local_level);
#endif LINT
/* The implementation below is more careful than strictly
necessary. Optimists may optimize it afterwards.
*/
while (local_level->sl_entry) {
register struct stack_entry *se = local_level->sl_entry;
register struct idf *idf = se->se_idf;
register struct def *def;
register struct sdef *sdef;
register struct tag *tag;
/* unlink it from the local stack level */
local_level->sl_entry = se->next;
free_stack_entry(se);
while ((def = idf->id_def) && def->df_level >= level) {
/* unlink it from the def list under the idf block */
if (def->df_sc == LABEL)
unstack_label(idf);
else if (def->df_sc == REGISTER || def->df_sc == AUTO)
FreeLocal(def->df_address);
idf->id_def = def->next;
free_def(def);
update_ahead(idf);
}
while ( (sdef = idf->id_sdef)
&& sdef->sd_level >= level
) {
/* unlink it from the sdef list under the idf block */
idf->id_sdef = sdef->next;
free_sdef(sdef);
}
while ( (tag = idf->id_struct)
&& tag->tg_level >= level
) {
/* unlink it from the struct list under the idf block */
idf->id_struct = tag->next;
free_tag(tag);
}
while ((tag = idf->id_enum) && tag->tg_level >= level) {
/* unlink it from the enum list under the idf block */
idf->id_enum = tag->next;
free_tag(tag);
}
}
/* Unlink the local stack level from the stack.
*/
lastlvl = local_level;
local_level = local_level->sl_previous;
if (level >= L_LOCAL) {
local_level->sl_max_block = lastlvl->sl_max_block;
}
free_stack_level(lastlvl);
local_level->sl_next = (struct stack_level *) 0;
level = local_level->sl_level;
#ifdef DEBUG
if (options['t'])
dumpidftab("after unstackidfs", 0);
#endif DEBUG
}
unstack_world()
{
/* The global level of identifiers is scanned, and final
decisions are taken about such issues as
extern/static/global and un/initialized.
Effects on the code generator: initialised variables
have already been encoded while the uninitialised ones
are not and have to be encoded at this moment.
*/
register struct stack_entry *se = local_level->sl_entry;
#ifdef LINT
lint_global_level(local_level);
#endif LINT
open_name_list();
while (se) {
register struct idf *idf = se->se_idf;
register struct def *def = idf->id_def;
if (!def) {
/* global selectors, etc. */
se = se->next;
continue;
}
#ifdef DEBUG
if (options['a']) {
char *symbol2str();
print("\"%s\", %s, %s, %s, %s\n",
idf->id_text,
(def->df_alloc == 0) ? "no alloc" :
(def->df_alloc == ALLOC_SEEN) ? "alloc seen" :
(def->df_alloc == ALLOC_DONE) ? "alloc done" :
"illegal alloc info",
symbol2str(def->df_sc),
def->df_initialized ? "init" : "no init",
def->df_used ? "used" : "not used");
}
#endif DEBUG
/*
/_* find final storage class *_/
if (def->df_sc == GLOBAL || def->df_sc == IMPLICIT)
/_* even now we still don't know *_/
def->df_sc = EXTERN;
*/
if ( def->df_sc == STATIC
&& def->df_type->tp_fund == FUNCTION
&& !def->df_initialized
) {
/* orphaned static function */
#ifndef NOROPTION
if (options['R'])
warning("static function %s never defined, %s",
idf->id_text,
"changed to extern"
);
#endif
def->df_sc = EXTERN;
}
if (
def->df_alloc == ALLOC_SEEN &&
!def->df_initialized
) {
/* space must be allocated */
bss(idf);
if (def->df_sc != STATIC)
namelist(idf->id_text); /* may be common */
def->df_alloc = ALLOC_DONE; /* see Note below */
}
se = se->next;
}
/* Note:
df_alloc must be set to ALLOC_DONE because the idf entry
may occur several times in the list.
The reason for this is that the same name may be used
for different purposes on the same level, e.g.
struct s {int s;} s;
is a legal definition and contains 3 defining occurrences
of s.
Each definition has been entered into the identifier stack.
Although only one of them concerns a variable, we meet the
s 3 times when scanning the identifier stack.
*/
}
/* A list of potential common names is kept, to be fed to
an understanding loader. The list is written to a file
the name of which is nmlist. If nmlist == NULL, no name
list is generated.
*/
extern char *nmlist; /* BAH! -- main.c */
static File *nfp = 0;
open_name_list()
{
if (nmlist && sys_open(nmlist, OP_WRITE, &nfp) == 0)
fatal("cannot create namelist %s", nmlist);
}
namelist(nm)
char *nm;
{
if (nmlist) {
sys_write(nfp, nm, strlen(nm));
sys_write(nfp, "\n", 1);
}
}

View File

@ -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;

View File

@ -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 <em.h>
#include "lint.h"
#include "debug.h"
#include "botch_free.h"
#include "arith.h"
#include "LLlex.h"
#include "type.h"
#include "idf.h"
#include "label.h"
#include "expr.h"
#include "code.h"
#include "stack.h"
#include "def.h"
#ifdef LINT
#include "l_lint.h"
#include "l_state.h"
#endif LINT
extern int level;
}
/* Each statement construction is stacked in order to trace a
statement to such a construction. Example: a case statement should
be recognized as a piece of the most enclosing switch statement.
*/
/* 9 */
statement
{
#ifdef LINT
lint_statement();
#endif LINT
}
:
%if (AHEAD != ':')
expression_statement
|
label ':' statement
|
compound_statement
|
if_statement
|
while_statement
|
do_statement
|
for_statement
|
switch_statement
|
case_statement
|
default_statement
|
BREAK
{
code_break();
#ifdef LINT
lint_break_stmt();
#endif LINT
}
';'
|
CONTINUE
{
code_continue();
#ifdef LINT
lint_continue_stmt();
#endif LINT
}
';'
|
return_statement
|
jump
|
';'
;
expression_statement
{ struct expr *expr;
}
:
expression(&expr)
';'
{
#ifdef DEBUG
print_expr("expression_statement", expr);
#endif DEBUG
code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL);
free_expression(expr);
}
;
label
{ struct idf *idf;
}
:
identifier(&idf)
{
/* This allows the following absurd case:
typedef int grz;
main() {
grz: printf("A labelled statement\n");
}
*/
#ifdef LINT
lint_label();
#endif LINT
define_label(idf);
C_df_ilb((label)idf->id_def->df_address);
}
;
if_statement
{
struct expr *expr;
label l_true = text_label();
label l_false = text_label();
label l_end = text_label();
}
:
IF
'('
expression(&expr)
{
opnd2test(&expr, IF);
if (is_cp_cst(expr)) {
/* The comparison has been optimized
to a 0 or 1.
*/
if (expr->VL_VALUE == (arith)0) {
C_bra(l_false);
}
/* else fall through */
#ifdef LINT
start_if_part(1);
#endif LINT
}
else {
code_expr(expr, RVAL, TRUE, l_true, l_false);
C_df_ilb(l_true);
#ifdef LINT
start_if_part(0);
#endif LINT
}
free_expression(expr);
}
')'
statement
[%prefer
ELSE
{
#ifdef LINT
start_else_part();
#endif LINT
C_bra(l_end);
C_df_ilb(l_false);
}
statement
{ C_df_ilb(l_end);
#ifdef LINT
end_if_else_stmt();
#endif LINT
}
|
empty
{ C_df_ilb(l_false);
#ifdef LINT
end_if_stmt();
#endif LINT
}
]
;
while_statement
{
struct expr *expr;
label l_break = text_label();
label l_continue = text_label();
label l_body = text_label();
}
:
WHILE
{
stack_stmt(l_break, l_continue);
C_df_ilb(l_continue);
}
'('
expression(&expr)
{
opnd2test(&expr, WHILE);
if (is_cp_cst(expr)) {
if (expr->VL_VALUE == (arith)0) {
C_bra(l_break);
}
#ifdef LINT
start_loop_stmt(WHILE, 1,
expr->VL_VALUE != (arith)0);
#endif LINT
}
else {
code_expr(expr, RVAL, TRUE, l_body, l_break);
C_df_ilb(l_body);
#ifdef LINT
start_loop_stmt(WHILE, 0, 0);
#endif LINT
}
}
')'
statement
{
C_bra(l_continue);
C_df_ilb(l_break);
unstack_stmt();
free_expression(expr);
#ifdef LINT
end_loop_stmt();
#endif LINT
}
;
do_statement
{ struct expr *expr;
label l_break = text_label();
label l_continue = text_label();
label l_body = text_label();
}
:
DO
{ C_df_ilb(l_body);
stack_stmt(l_break, l_continue);
#ifdef LINT
start_loop_stmt(DO, 1, 1);
#endif LINT
}
statement
WHILE
'('
{ C_df_ilb(l_continue);
}
expression(&expr)
{
opnd2test(&expr, WHILE);
if (is_cp_cst(expr)) {
if (expr->VL_VALUE == (arith)1) {
C_bra(l_body);
}
#ifdef LINT
end_do_stmt(1, expr->VL_VALUE != (arith)0);
#endif LINT
}
else {
code_expr(expr, RVAL, TRUE, l_body, l_break);
#ifdef LINT
end_do_stmt(0, 0);
#endif LINT
}
C_df_ilb(l_break);
}
')'
';'
{
unstack_stmt();
free_expression(expr);
}
;
for_statement
{ struct expr *e_init = 0, *e_test = 0, *e_incr = 0;
label l_break = text_label();
label l_continue = text_label();
label l_body = text_label();
label l_test = text_label();
#ifdef LINT
int const = 1, cond = 1; /* the default case */
#endif LINT
}
:
FOR
{ stack_stmt(l_break, l_continue);
}
'('
[
expression(&e_init)
{ code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL);
}
]?
';'
{ C_df_ilb(l_test);
}
[
expression(&e_test)
{
opnd2test(&e_test, FOR);
if (is_cp_cst(e_test)) {
if (e_test->VL_VALUE == (arith)0) {
C_bra(l_break);
}
#ifdef LINT
const = 1,
cond = e_test->VL_VALUE != (arith)0;
#endif LINT
}
else {
code_expr(e_test, RVAL, TRUE, l_body, l_break);
C_df_ilb(l_body);
#ifdef LINT
const = 0, cond = 0;
#endif LINT
}
}
]?
';'
expression(&e_incr)?
')'
{
#ifdef LINT
start_loop_stmt(FOR, const, cond);
#endif LINT
}
statement
{
#ifdef LINT
end_loop_stmt();
#endif LINT
C_df_ilb(l_continue);
if (e_incr)
code_expr(e_incr, RVAL, FALSE,
NO_LABEL, NO_LABEL);
C_bra(l_test);
C_df_ilb(l_break);
unstack_stmt();
free_expression(e_init);
free_expression(e_test);
free_expression(e_incr);
}
;
switch_statement
{
struct expr *expr;
}
:
SWITCH
'('
expression(&expr)
{
code_startswitch(&expr);
#ifdef LINT
start_switch_part(expr);
#endif LINT
}
')'
statement
{
#ifdef LINT
end_switch_stmt();
#endif LINT
code_endswitch();
free_expression(expr);
}
;
case_statement
{
struct expr *expr;
}
:
CASE
constant_expression(&expr)
{
#ifdef LINT
lint_case_stmt(0);
#endif LINT
code_case(expr);
free_expression(expr);
}
':'
statement
;
default_statement
:
DEFAULT
{
#ifdef LINT
lint_case_stmt(1);
#endif LINT
code_default();
}
':'
statement
;
return_statement
{ struct expr *expr = 0;
}
:
RETURN
[
expression(&expr)
{
#ifdef LINT
lint_ret_conv(expr);
#endif LINT
do_return_expr(expr);
free_expression(expr);
#ifdef LINT
lint_return_stmt(1);
#endif LINT
}
|
empty
{
do_return();
#ifdef LINT
lint_return_stmt(0);
#endif LINT
}
]
';'
;
jump
{ struct idf *idf;
}
:
GOTO
identifier(&idf)
';'
{
apply_label(idf);
C_bra((label)idf->id_def->df_address);
#ifdef LINT
lint_jump_stmt(idf);
#endif LINT
}
;
compound_statement:
'{'
{
stack_level();
}
[%while ((DOT != IDENTIFIER && AHEAD != ':') ||
(DOT == IDENTIFIER && AHEAD == IDENTIFIER))
/* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */
declaration
]*
[%persistent
statement
]*
'}'
{
unstack_level();
}
;

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 <alloc.h>
#include "arith.h"
#include "stack.h"
#include "idf.h"
#include "def.h"
#include "type.h"
#include "proto.h"
#include "struct.h"
#include "field.h"
#include "LLlex.h"
#include "Lpars.h"
#include "align.h"
#include "level.h"
#include "assert.h"
#include "sizes.h"
#include "noRoption.h"
/* Type of previous selector declared with a field width specified,
if any. If a selector is declared with no field with it is set to 0.
*/
static field_busy = 0;
extern char options[];
int lcm();
/* The semantics of the identification of structure/union tags is
obscure. Some highly regarded compilers are found out to accept,
e.g.:
f(xp) struct aap *xp; {
struct aap {char *za;};
xp->za;
}
Equally highly regarded software uses this feature, so we shall
humbly oblige.
The rules we use are:
1. A structure definition applies at the level where it is
found, unless there is a structure declaration without a
definition on an outer level, in which case the definition
is applied at that level.
2. A selector is applied on the same level as on which its
structure is being defined.
If below struct is mentioned, union is implied (and sometimes enum
as well).
*/
add_sel(stp, tp, idf, sdefpp, szp, fd) /* this is horrible */
register struct type *stp; /* type of the structure */
struct type *tp; /* type of the selector */
register struct idf *idf; /* idf of the selector */
struct sdef ***sdefpp; /* address of hook to selector definition */
arith *szp; /* pointer to struct size upto here */
struct field *fd;
{
/* The selector idf with type tp is added to two chains: the
selector identification chain starting at idf->id_sdef,
and to the end of the member list starting at stp->tp_sdef.
The address of the hook in the latest member (sdef) is
given in sdefpp; the hook itself must still be empty.
*/
arith offset;
#ifndef NOBITFIELD
extern arith add_field();
#endif NOBITFIELD
struct tag *tg = stp->tp_idf->id_struct; /* or union */
struct sdef *sdef = idf->id_sdef;
register struct sdef *newsdef;
int lvl = tg->tg_level;
#ifndef NOROPTION
if (options['R'] && !is_anon_idf(idf)) {
/* a K & R test */
if (idf->id_struct && idf->id_struct->tg_level == level)
warning("%s is also a struct/union tag", idf->id_text);
}
#endif
if (stp->tp_fund == STRUCT) {
#ifndef NOBITFIELD
if (fd == 0) { /* no field width specified */
offset = align(*szp, tp->tp_align);
field_busy = 0;
}
else {
/* if something is wrong, the type of the
specified selector remains unchanged; its
bitfield specifier, however, is thrown away.
*/
offset = add_field(szp, fd, &tp, idf, stp);
}
#else NOBITFIELD
offset = align(*szp, tp->tp_align);
field_busy = 0;
#endif NOBITFIELD
}
else { /* (stp->tp_fund == UNION) */
if (fd) {
error("fields not allowed in unions");
free_field(fd);
fd = 0;
}
offset = (arith)0;
}
check_selector(idf, stp);
#ifndef NOROPTION
if (options['R']) {
if ( sdef && sdef->sd_level == lvl &&
( sdef->sd_offset != offset ||
!equal_type(sdef->sd_type, tp))
) /* RM 8.5 */
warning("selector %s redeclared", idf->id_text);
}
#endif
newsdef = new_sdef();
newsdef->sd_sdef = (struct sdef *) 0;
/* link into selector descriptor list of this id
*/
newsdef->next = sdef;
idf->id_sdef = newsdef;
newsdef->sd_level = lvl;
newsdef->sd_idf = idf;
newsdef->sd_stype = stp;
newsdef->sd_type = tp;
newsdef->sd_offset = offset;
#ifndef NOBITFIELD
if (tp->tp_fund == FIELD)
tp->tp_field->fd_sdef = newsdef;
#endif NOBITFIELD
stack_idf(idf, stack_level_of(lvl));
/* link into selector definition list of the struct/union
*/
**sdefpp = newsdef;
*sdefpp = &newsdef->sd_sdef;
/* update the size of the struct/union upward */
if (stp->tp_fund == STRUCT && fd == 0) {
/* Note: the case that a bitfield is declared is
handled by add_field() !
*/
*szp = offset + size_of_type(tp, "member");
stp->tp_align = lcm(stp->tp_align, tp->tp_align);
}
else
if (stp->tp_fund == UNION) {
arith sel_size = size_of_type(tp, "member");
if (*szp < sel_size)
*szp = sel_size;
stp->tp_align = lcm(stp->tp_align, tp->tp_align);
}
}
check_selector(idf, stp)
register struct idf *idf;
struct type *stp; /* the type of the struct */
{
/* checks if idf occurs already as a selector in
struct or union *stp.
*/
register struct sdef *sdef = stp->tp_sdef;
while (sdef) {
if (sdef->sd_idf == idf)
error("multiple selector %s", idf->id_text);
sdef = sdef->sd_sdef;
}
}
declare_struct(fund, idf, tpp)
register struct idf *idf;
struct type **tpp;
{
/* A struct, union or enum (depending on fund) with tag (!)
idf is declared, and its type (incomplete as it may be) is
returned in *tpp.
The idf may be missing (i.e. idf == 0), in which case an
anonymous struct etc. is defined.
*/
extern char *symbol2str();
register struct tag **tgp;
register struct tag *tg;
if (!idf)
idf = gen_idf();
tgp = (fund == ENUM ? &idf->id_enum : &idf->id_struct);
#ifndef NOROPTION
if (options['R'] && !is_anon_idf(idf)) {
/* a K & R test */
if ( fund != ENUM &&
idf->id_sdef && idf->id_sdef->sd_level == level
) {
warning("%s is also a selector", idf->id_text);
}
if ( fund == ENUM &&
idf->id_def && idf->id_def->df_level == level
) {
warning("%s is also a variable", idf->id_text);
}
}
#endif
tg = *tgp;
if (tg && tg->tg_type->tp_size < 0 && tg->tg_type->tp_fund == fund) {
/* An unfinished declaration has preceded it, possibly on
an earlier level. We just fill in the answer.
*/
if (tg->tg_busy) {
error("recursive declaration of struct/union %s",
idf->id_text);
declare_struct(fund, gen_idf(), tpp);
}
else {
#ifndef NOROPTION
if (options['R'] && tg->tg_level != level)
warning("%s declares %s in different range",
idf->id_text, symbol2str(fund));
#endif
*tpp = tg->tg_type;
}
}
else
if (tg && tg->tg_level == level) {
/* There is an already defined struct/union of this name
on our level!
*/
error("redeclaration of struct/union %s", idf->id_text);
declare_struct(fund, gen_idf(), tpp);
/* to allow a second struct_declaration_pack */
}
else {
/* The struct is new. */
/* Hook in a new struct tag */
tg = new_tag();
tg->next = *tgp;
*tgp = tg;
tg->tg_level = level;
/* and supply room for a type */
tg->tg_type = create_type(fund);
tg->tg_type->tp_align =
fund == ENUM ? int_align :
fund == STRUCT ? struct_align :
/* fund == UNION */ union_align;
tg->tg_type->tp_idf = idf;
*tpp = tg->tg_type;
stack_idf(idf, local_level);
}
}
apply_struct(fund, idf, tpp)
register struct idf *idf;
struct type **tpp;
{
/* The occurrence of a struct, union or enum (depending on
fund) with tag idf is noted. It may or may not have been
declared before. Its type (complete or incomplete) is
returned in *tpp.
*/
register struct tag **tgp;
tgp = (is_struct_or_union(fund) ? &idf->id_struct : &idf->id_enum);
if (*tgp)
*tpp = (*tgp)->tg_type;
else
declare_struct(fund, idf, tpp);
}
struct sdef *
idf2sdef(idf, tp)
register struct idf *idf;
struct type *tp;
{
/* The identifier idf is identified as a selector, preferably
in the struct tp, but we will settle for any unique
identification.
If the attempt fails, a selector of type error_type is
created.
*/
register struct sdef **sdefp = &idf->id_sdef, *sdef;
/* Follow chain from idf, to meet tp. */
while ((sdef = *sdefp)) {
if (equal_type(sdef->sd_stype, tp))
return sdef;
sdefp = &(*sdefp)->next;
}
/* Tp not met; any unique identification will do. */
if (sdef = idf->id_sdef) {
/* There is an identification */
if (uniq_selector(sdef)) {
/* and it is unique, so we accept */
warning("selector %s applied to alien type",
idf->id_text);
}
else {
/* it is ambiguous */
error("ambiguous use of selector %s", idf->id_text);
}
return sdef;
}
/* No luck; create an error entry. */
if (!is_anon_idf(idf))
error("unknown selector %s", idf->id_text);
*sdefp = sdef = new_sdef();
sdef->sd_idf = idf;
sdef->sd_stype = sdef->sd_type = error_type;
return sdef;
}
int
uniq_selector(idf_sdef)
register struct sdef *idf_sdef;
{
/* Returns true if idf_sdef (which is guaranteed to exist)
is unique for this level, i.e there is no other selector
on this level with the same name or the other selectors
with the same name have the same offset.
See /usr/src/cmd/sed/sed.h for an example of this absurd
case!
*/
register struct sdef *sdef = idf_sdef->next;
while (sdef && sdef->sd_level == idf_sdef->sd_level) {
if ( sdef->sd_type != idf_sdef->sd_type
|| sdef->sd_offset != idf_sdef->sd_offset
) {
return 0; /* ambiguity found */
}
sdef = sdef->next;
}
return 1;
}
#ifndef NOBITFIELD
arith
add_field(szp, fd, fdtpp, idf, stp)
arith *szp; /* size of struct upto here */
register struct field *fd; /* bitfield, containing width */
register struct type **fdtpp; /* type of selector */
struct idf *idf; /* name of selector */
register struct type *stp; /* current struct descriptor */
{
/* The address where this selector is put is returned. If the
selector with specified width does not fit in the word, or
an explicit alignment is given, a new address is needed.
Note that the fields are packed into machine words (according
to the RM.)
*/
long bits_in_type = word_size * 8;
static int field_offset = (arith)0;
static struct type *current_struct = 0;
static long bits_declared; /* nr of bits used in *field_offset */
if (current_struct != stp) {
/* This struct differs from the last one
*/
field_busy = 0;
current_struct = stp;
}
if ( fd->fd_width < 0 ||
(fd->fd_width == 0 && !is_anon_idf(idf)) ||
fd->fd_width > bits_in_type
) {
error("illegal field-width specified");
*fdtpp = error_type;
return field_offset;
}
switch ((*fdtpp)->tp_fund) {
case CHAR:
case SHORT:
case INT:
case ENUM:
case LONG:
/* right type; size OK? */
if ((*fdtpp)->tp_size > word_size) {
error("bit field type %s does not fit in a word",
symbol2str((*fdtpp)->tp_fund));
*fdtpp = error_type;
return field_offset;
}
break;
default:
/* wrong type altogether */
error("field type cannot be %s",
symbol2str((*fdtpp)->tp_fund));
*fdtpp = error_type;
return field_offset;
}
if (field_busy == 0) {
/* align this selector on the next boundary :
the previous selector wasn't a bitfield.
*/
field_offset = align(*szp, int_align);
*szp = field_offset + int_size;
stp->tp_align = lcm(stp->tp_align, int_align);
bits_declared = (arith)0;
field_busy = 1;
}
if (fd->fd_width > bits_in_type - bits_declared) {
/* field overflow: fetch next memory unit
*/
field_offset = align(*szp, int_align);
*szp = field_offset + int_size;
stp->tp_align = lcm(stp->tp_align, int_align);
bits_declared = fd->fd_width;
}
else
if (fd->fd_width == 0)
/* next field should be aligned on the next boundary.
This will take care that no field will fit in the
space allocated upto here.
*/
bits_declared = bits_in_type + 1;
else /* the bitfield fits in the current field */
bits_declared += fd->fd_width;
/* Arrived here, the place where the selector is stored in the
struct is computed.
Now we need a mask to use its value in expressions.
*/
*fdtpp = construct_type(FIELD, *fdtpp, 0, (arith)0, NO_PROTO);
(*fdtpp)->tp_field = fd;
/* Set the mask right shifted. This solution avoids the
problem of having sign extension when using the mask for
extracting the value from the field-int.
Sign extension could occur on some machines when shifting
the mask to the left.
*/
fd->fd_mask = (1 << fd->fd_width) - 1;
if (options['r']) /* adjust the field at the right */
fd->fd_shift = bits_declared - fd->fd_width;
else /* adjust the field at the left */
fd->fd_shift = bits_in_type - bits_declared;
return field_offset;
}
#endif NOBITFIELD
/* some utilities */
int
is_struct_or_union(fund)
register int fund;
{
return fund == STRUCT || fund == UNION;
}
/* Greatest Common Divisor
*/
int
gcd(m, n)
register int m, n;
{
register int r;
while (n) {
r = m % n;
m = n;
n = r;
}
return m;
}
/* Least Common Multiple
*/
int
lcm(m, n)
register int m, n;
{
return m * (n / gcd(m, n));
}

View File

@ -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();

Some files were not shown because too many files have changed in this diff Show More