Initial revision
This commit is contained in:
parent
e2fe3fec2c
commit
926da49d39
101
lang/cem/cemcom.ansi/.distr
Normal file
101
lang/cem/cemcom.ansi/.distr
Normal 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
|
||||
145
lang/cem/cemcom.ansi/BigPars
Normal file
145
lang/cem/cemcom.ansi/BigPars
Normal 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 */
|
||||
|
||||
|
||||
777
lang/cem/cemcom.ansi/LLlex.c
Normal file
777
lang/cem/cemcom.ansi/LLlex.c
Normal 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('?');
|
||||
}
|
||||
69
lang/cem/cemcom.ansi/LLlex.h
Normal file
69
lang/cem/cemcom.ansi/LLlex.h
Normal 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)
|
||||
59
lang/cem/cemcom.ansi/LLmessage.c
Normal file
59
lang/cem/cemcom.ansi/LLmessage.c
Normal 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
|
||||
}
|
||||
}
|
||||
145
lang/cem/cemcom.ansi/LintPars
Normal file
145
lang/cem/cemcom.ansi/LintPars
Normal 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 */
|
||||
|
||||
|
||||
1091
lang/cem/cemcom.ansi/Makefile
Normal file
1091
lang/cem/cemcom.ansi/Makefile
Normal file
File diff suppressed because it is too large
Load Diff
718
lang/cem/cemcom.ansi/Makefile.erik
Normal file
718
lang/cem/cemcom.ansi/Makefile.erik
Normal 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
67
lang/cem/cemcom.ansi/Resolve
Executable 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
|
||||
145
lang/cem/cemcom.ansi/SmallPars
Normal file
145
lang/cem/cemcom.ansi/SmallPars
Normal 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 */
|
||||
|
||||
|
||||
8
lang/cem/cemcom.ansi/Version.c
Normal file
8
lang/cem/cemcom.ansi/Version.c
Normal 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
|
||||
35
lang/cem/cemcom.ansi/align.h
Normal file
35
lang/cem/cemcom.ansi/align.h
Normal 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();
|
||||
575
lang/cem/cemcom.ansi/arith.c
Normal file
575
lang/cem/cemcom.ansi/arith.c
Normal 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
|
||||
28
lang/cem/cemcom.ansi/arith.h
Normal file
28
lang/cem/cemcom.ansi/arith.h
Normal 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
|
||||
16
lang/cem/cemcom.ansi/asm.c
Normal file
16
lang/cem/cemcom.ansi/asm.c
Normal 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");
|
||||
}
|
||||
24
lang/cem/cemcom.ansi/assert.h
Normal file
24
lang/cem/cemcom.ansi/assert.h
Normal 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
|
||||
10
lang/cem/cemcom.ansi/atw.h
Normal file
10
lang/cem/cemcom.ansi/atw.h
Normal 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)
|
||||
168
lang/cem/cemcom.ansi/blocks.c
Normal file
168
lang/cem/cemcom.ansi/blocks.c
Normal 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
230
lang/cem/cemcom.ansi/cem.1
Normal 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
764
lang/cem/cemcom.ansi/cem.c
Normal 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;
|
||||
}
|
||||
79
lang/cem/cemcom.ansi/cemcom.1
Normal file
79
lang/cem/cemcom.ansi/cemcom.1
Normal 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
540
lang/cem/cemcom.ansi/ch7.c
Normal 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;
|
||||
}
|
||||
}
|
||||
350
lang/cem/cemcom.ansi/ch7bin.c
Normal file
350
lang/cem/cemcom.ansi/ch7bin.c
Normal 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);
|
||||
}
|
||||
166
lang/cem/cemcom.ansi/ch7mon.c
Normal file
166
lang/cem/cemcom.ansi/ch7mon.c
Normal 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;
|
||||
}
|
||||
}
|
||||
74
lang/cem/cemcom.ansi/char.tab
Normal file
74
lang/cem/cemcom.ansi/char.tab
Normal 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};
|
||||
44
lang/cem/cemcom.ansi/class.h
Normal file
44
lang/cem/cemcom.ansi/class.h
Normal 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
657
lang/cem/cemcom.ansi/code.c
Normal 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);
|
||||
}
|
||||
}
|
||||
22
lang/cem/cemcom.ansi/code.str
Normal file
22
lang/cem/cemcom.ansi/code.str
Normal 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
|
||||
158
lang/cem/cemcom.ansi/conversion.c
Normal file
158
lang/cem/cemcom.ansi/conversion.c
Normal 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
|
||||
|
||||
237
lang/cem/cemcom.ansi/cstoper.c
Normal file
237
lang/cem/cemcom.ansi/cstoper.c
Normal 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];
|
||||
}
|
||||
37
lang/cem/cemcom.ansi/dataflow.c
Normal file
37
lang/cem/cemcom.ansi/dataflow.c
Normal 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
|
||||
696
lang/cem/cemcom.ansi/declar.g
Normal file
696
lang/cem/cemcom.ansi/declar.g
Normal 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 */
|
||||
44
lang/cem/cemcom.ansi/declar.str
Normal file
44
lang/cem/cemcom.ansi/declar.str
Normal 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;
|
||||
126
lang/cem/cemcom.ansi/declarator.c
Normal file
126
lang/cem/cemcom.ansi/declarator.c
Normal 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;
|
||||
}
|
||||
}
|
||||
197
lang/cem/cemcom.ansi/decspecs.c
Normal file
197
lang/cem/cemcom.ansi/decspecs.c
Normal 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);
|
||||
}
|
||||
|
||||
20
lang/cem/cemcom.ansi/decspecs.str
Normal file
20
lang/cem/cemcom.ansi/decspecs.str
Normal 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;
|
||||
40
lang/cem/cemcom.ansi/def.str
Normal file
40
lang/cem/cemcom.ansi/def.str
Normal 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 */
|
||||
688
lang/cem/cemcom.ansi/domacro.c
Normal file
688
lang/cem/cemcom.ansi/domacro.c
Normal 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);
|
||||
}
|
||||
512
lang/cem/cemcom.ansi/dumpidf.c
Normal file
512
lang/cem/cemcom.ansi/dumpidf.c
Normal 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
|
||||
355
lang/cem/cemcom.ansi/error.c
Normal file
355
lang/cem/cemcom.ansi/error.c
Normal 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");
|
||||
}
|
||||
21
lang/cem/cemcom.ansi/estack.str
Normal file
21
lang/cem/cemcom.ansi/estack.str
Normal 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
994
lang/cem/cemcom.ansi/eval.c
Normal 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
536
lang/cem/cemcom.ansi/expr.c
Normal 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);
|
||||
}
|
||||
}
|
||||
116
lang/cem/cemcom.ansi/expr.str
Normal file
116
lang/cem/cemcom.ansi/expr.str
Normal 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 */
|
||||
|
||||
375
lang/cem/cemcom.ansi/expression.g
Normal file
375
lang/cem/cemcom.ansi/expression.g
Normal 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;
|
||||
}
|
||||
;
|
||||
181
lang/cem/cemcom.ansi/field.c
Normal file
181
lang/cem/cemcom.ansi/field.c
Normal 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
|
||||
|
||||
16
lang/cem/cemcom.ansi/field.str
Normal file
16
lang/cem/cemcom.ansi/field.str
Normal 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 */
|
||||
20
lang/cem/cemcom.ansi/file_info.h
Normal file
20
lang/cem/cemcom.ansi/file_info.h
Normal 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
736
lang/cem/cemcom.ansi/idf.c
Normal 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 = ¬ch->next;
|
||||
}
|
||||
/* a new struct idf must be inserted at the hook */
|
||||
notch = new_idf();
|
||||
notch->next = *hook;
|
||||
*hook = notch; /* hooked in */
|
||||
notch->id_text = Salloc(tg, (unsigned) size);
|
||||
#ifndef NOPP
|
||||
notch->id_resmac = 0;
|
||||
#endif NOPP
|
||||
return notch;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
hash_stat()
|
||||
{
|
||||
if (options['h']) {
|
||||
register int i;
|
||||
|
||||
print("Hash table tally:\n");
|
||||
for (i = 0; i < HASHSIZE; i++) {
|
||||
register struct idf *notch = idf_hashtable[i];
|
||||
int cnt = 0;
|
||||
|
||||
while (notch) {
|
||||
cnt++;
|
||||
notch = notch->next;
|
||||
}
|
||||
print("%d %d\n", i, cnt);
|
||||
}
|
||||
print("End hash table tally\n");
|
||||
}
|
||||
}
|
||||
#endif DEBUG
|
||||
|
||||
struct idf *
|
||||
str2idf(tg)
|
||||
char tg[];
|
||||
{
|
||||
/* str2idf() returns an entry in the symbol table for the
|
||||
identifier tg. If necessary, an entry is created.
|
||||
It is used where the text of the identifier is available
|
||||
but its hash value is not; otherwise idf_hashed() is to
|
||||
be used.
|
||||
*/
|
||||
register char *cp = tg;
|
||||
register int hash;
|
||||
register int pos = -1;
|
||||
register int ch;
|
||||
char ntg[IDFSIZE + 1];
|
||||
register char *ncp = ntg;
|
||||
|
||||
hash = STARTHASH();
|
||||
while (++pos < idfsize && (ch = *cp++)) {
|
||||
*ncp++ = ch;
|
||||
hash = ENHASH(hash, ch, pos);
|
||||
}
|
||||
hash = STOPHASH(hash);
|
||||
*ncp++ = '\0';
|
||||
return idf_hashed(ntg, ncp - ntg, hash);
|
||||
}
|
||||
|
||||
struct idf *
|
||||
gen_idf()
|
||||
{
|
||||
/* A new idf is created out of nowhere, to serve as an
|
||||
anonymous name.
|
||||
*/
|
||||
static int name_cnt;
|
||||
char buff[100];
|
||||
|
||||
sprint(buff, "#%d in %s, line %u",
|
||||
++name_cnt, dot.tk_file, dot.tk_line);
|
||||
return str2idf(buff);
|
||||
}
|
||||
|
||||
int
|
||||
is_anon_idf(idf)
|
||||
struct idf *idf;
|
||||
{
|
||||
return idf->id_text[0] == '#';
|
||||
}
|
||||
|
||||
declare_idf(ds, dc, lvl)
|
||||
struct decspecs *ds;
|
||||
struct declarator *dc;
|
||||
{
|
||||
/* The identifier inside dc is declared on the level lvl, with
|
||||
properties deduced from the decspecs ds and the declarator
|
||||
dc.
|
||||
The level is given explicitly to be able to insert, e.g.,
|
||||
labels on the outermost level inside the function.
|
||||
This routine implements the rich semantics of C
|
||||
declarations.
|
||||
*/
|
||||
register struct idf *idf = dc->dc_idf;
|
||||
register int sc = ds->ds_sc;
|
||||
/* This local copy is essential:
|
||||
char b(), c;
|
||||
makes b GLOBAL and c AUTO.
|
||||
*/
|
||||
register struct def *def = idf->id_def; /* may be NULL */
|
||||
register struct type *type;
|
||||
struct stack_level *stl = stack_level_of(lvl);
|
||||
char formal_array = 0;
|
||||
|
||||
/* determine the present type */
|
||||
if (ds->ds_type == 0) {
|
||||
/* at the L_FORMAL1 level there is no type specified yet
|
||||
*/
|
||||
ASSERT(lvl == L_FORMAL1);
|
||||
type = int_type; /* may change at L_FORMAL2 */
|
||||
}
|
||||
else {
|
||||
/* combine the decspecs and the declarator into one type */
|
||||
type = declare_type(ds->ds_type, dc);
|
||||
if (type->tp_size <= (arith)0 &&
|
||||
actual_declaration(sc, type)) {
|
||||
if (type->tp_size == (arith) -1) {
|
||||
/* the type is not yet known,
|
||||
but it has to be:
|
||||
*/
|
||||
extern char *symbol2str();
|
||||
error("unknown %s-type",
|
||||
symbol2str(type->tp_fund));
|
||||
}
|
||||
else if (type->tp_fund != LABEL) {
|
||||
/* CJ */
|
||||
warning("%s has size 0", idf->id_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* some additional work for formal definitions */
|
||||
if (lvl == L_FORMAL2) {
|
||||
switch (type->tp_fund) {
|
||||
case FUNCTION:
|
||||
warning("%s is a function; cannot be formal",
|
||||
idf->id_text);
|
||||
type = construct_type(POINTER, type, 0, (arith)0,
|
||||
NO_PROTO);
|
||||
break;
|
||||
case ARRAY: /* RM 10.1 */
|
||||
type = construct_type(POINTER, type->tp_up, 0, (arith)0,
|
||||
NO_PROTO);
|
||||
formal_array = 1;
|
||||
break;
|
||||
#ifndef NOFLOAT
|
||||
case FLOAT: /* RM 10.1 */
|
||||
type = double_type;
|
||||
break;
|
||||
#endif NOFLOAT
|
||||
case CHAR:
|
||||
case SHORT:
|
||||
/* The RM is not clear about this: we must
|
||||
convert the parameter from int (they have
|
||||
been pushed as ints) to the specified type.
|
||||
The conversion to type int or uint is not
|
||||
allowed.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* The tests on types, postponed from do_decspecs(), can now
|
||||
be performed.
|
||||
*/
|
||||
/* update the storage class */
|
||||
if (type && type->tp_fund == FUNCTION) {
|
||||
if (sc == 0 || (ds->ds_sc_given && sc == AUTO)) /* RM 8.1 */
|
||||
sc = GLOBAL;
|
||||
else
|
||||
if (sc == REGISTER) {
|
||||
error("function storage class cannot be register");
|
||||
ds->ds_sc = sc = GLOBAL;
|
||||
}
|
||||
}
|
||||
else /* non-FUNCTION */
|
||||
if (sc == 0)
|
||||
sc = lvl == L_GLOBAL ? GLOBAL
|
||||
: lvl == L_FORMAL1 || lvl == L_FORMAL2 ? FORMAL
|
||||
: AUTO;
|
||||
#ifndef NOROPTION
|
||||
if (options['R']) { /* some special K & R tests */
|
||||
/* is it also an enum? */
|
||||
if (idf->id_enum && idf->id_enum->tg_level == level)
|
||||
warning("%s is also an enum tag", idf->id_text);
|
||||
/* is it a universal typedef? */
|
||||
if (def && def->df_level == L_UNIVERSAL)
|
||||
warning("redeclaring reserved word %s", idf->id_text);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LINT
|
||||
if ( def && def->df_level < lvl
|
||||
&& !( lvl == L_FORMAL2
|
||||
|| def->df_level == L_UNIVERSAL
|
||||
|| sc == GLOBAL
|
||||
|| sc == EXTERN
|
||||
)
|
||||
) {
|
||||
/* there is already a definition for this non-extern name
|
||||
on a more global level
|
||||
*/
|
||||
warning("%s is already defined as a %s",
|
||||
idf->id_text,
|
||||
def->df_level == L_GLOBAL ? "global" :
|
||||
def->df_level == L_FORMAL2 ? "formal" :
|
||||
"more global local"
|
||||
);
|
||||
}
|
||||
#endif LINT
|
||||
|
||||
if (def &&
|
||||
( def->df_level == lvl ||
|
||||
( lvl != L_GLOBAL && def->df_level > lvl )
|
||||
)
|
||||
) {
|
||||
/* There is already a declaration for idf on this
|
||||
level, or even more inside.
|
||||
The rules differ for different levels.
|
||||
*/
|
||||
switch (lvl) {
|
||||
case L_GLOBAL:
|
||||
global_redecl(idf, sc, type);
|
||||
def->df_file = idf->id_file;
|
||||
def->df_line = idf->id_line;
|
||||
break;
|
||||
case L_FORMAL1: /* formal declaration */
|
||||
error("formal %s redeclared", idf->id_text);
|
||||
break;
|
||||
case L_FORMAL2: /* formal definition */
|
||||
default: /* local */
|
||||
error("%s redeclared", idf->id_text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* the idf is unknown on this level */
|
||||
if (lvl == L_FORMAL2 && sc != ENUM && good_formal(def, idf)) {
|
||||
/* formal declaration, update only */
|
||||
def->df_type = type;
|
||||
def->df_formal_array = formal_array;
|
||||
def->df_sc = sc;
|
||||
def->df_level = L_FORMAL2; /* CJ */
|
||||
def->df_file = idf->id_file;
|
||||
def->df_line = idf->id_line;
|
||||
}
|
||||
else
|
||||
if ( lvl >= L_LOCAL &&
|
||||
(type->tp_fund == FUNCTION || sc == EXTERN)
|
||||
) {
|
||||
/* extern declaration inside function is treated the
|
||||
same way as global extern declaration
|
||||
*/
|
||||
#ifndef NOROPTION
|
||||
if ( options['R'] &&
|
||||
(sc == STATIC && type->tp_fund == FUNCTION)
|
||||
)
|
||||
if (!is_anon_idf(idf))
|
||||
warning("non-global static function %s",
|
||||
idf->id_text);
|
||||
#endif
|
||||
declare_idf(ds, dc, L_GLOBAL);
|
||||
}
|
||||
else { /* fill in the def block */
|
||||
register struct def *newdef = new_def();
|
||||
|
||||
newdef->next = def;
|
||||
newdef->df_level = lvl;
|
||||
newdef->df_type = type;
|
||||
newdef->df_sc = sc;
|
||||
newdef->df_file = idf->id_file;
|
||||
newdef->df_line = idf->id_line;
|
||||
#ifdef LINT
|
||||
newdef->df_set = (type->tp_fund == ARRAY);
|
||||
newdef->df_firstbrace = 0;
|
||||
#endif LINT
|
||||
|
||||
/* link it into the name list in the proper place */
|
||||
idf->id_def = newdef;
|
||||
update_ahead(idf);
|
||||
stack_idf(idf, stl);
|
||||
/* We now calculate the address.
|
||||
Globals have names and don't get addresses, they
|
||||
get numbers instead (through data_label()).
|
||||
Formals are handled by declare_formals().
|
||||
So here we hand out local addresses only.
|
||||
*/
|
||||
if (lvl >= L_LOCAL) {
|
||||
ASSERT(sc);
|
||||
switch (sc) {
|
||||
case REGISTER:
|
||||
case AUTO:
|
||||
if (type->tp_size == (arith)-1) {
|
||||
error("size of local %s unknown",
|
||||
idf->id_text);
|
||||
/** type = idf->id_def->df_type = int_type; **/
|
||||
}
|
||||
newdef->df_address =
|
||||
NewLocal(type->tp_size,
|
||||
type->tp_align,
|
||||
regtype(type),
|
||||
sc);
|
||||
break;
|
||||
case STATIC:
|
||||
newdef->df_address = (arith) data_label();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual_declaration(sc, tp)
|
||||
int sc;
|
||||
struct type *tp;
|
||||
{
|
||||
/* An actual_declaration needs space, right here and now.
|
||||
*/
|
||||
register int fund = tp->tp_fund;
|
||||
|
||||
if (sc == ENUM || sc == TYPEDEF) /* virtual declarations */
|
||||
return 0;
|
||||
if (fund == FUNCTION || fund == ARRAY)
|
||||
/* allocation solved in other ways */
|
||||
return 0;
|
||||
/* to be allocated */
|
||||
return 1;
|
||||
}
|
||||
|
||||
global_redecl(idf, new_sc, tp)
|
||||
register struct idf *idf;
|
||||
struct type *tp;
|
||||
{
|
||||
/* A global identifier may be declared several times,
|
||||
provided the declarations do not conflict; they might
|
||||
conflict in type (or supplement each other in the case of
|
||||
an array) or they might conflict or supplement each other
|
||||
in storage class.
|
||||
*/
|
||||
register struct def *def = idf->id_def;
|
||||
|
||||
if (!equal_type(tp, def->df_type))
|
||||
error("redeclaration of %s with different type", idf->id_text);
|
||||
update_proto(tp, def->df_type);
|
||||
if (tp->tp_fund == ARRAY) {
|
||||
/* Multiple array declaration; this may be interesting */
|
||||
if (tp->tp_size < 0) { /* new decl has [] */
|
||||
/* nothing new */
|
||||
} else
|
||||
if (def->df_type->tp_size < 0) { /* old decl has [] */
|
||||
def->df_type = tp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we may be able to update the storage class.
|
||||
Clean out this mess as soon as we know all the possibilities
|
||||
for new_sc.
|
||||
For now we have:
|
||||
EXTERN: we have seen the word "extern"
|
||||
GLOBAL: the item was declared on the outer
|
||||
level, without either "extern" or
|
||||
"static".
|
||||
STATIC: we have seen the word "static"
|
||||
IMPLICIT: function declaration inferred from
|
||||
call
|
||||
*/
|
||||
if (new_sc == IMPLICIT)
|
||||
return; /* no new information */
|
||||
switch (def->df_sc) { /* the old storage class */
|
||||
case EXTERN:
|
||||
switch (new_sc) { /* the new storage class */
|
||||
case EXTERN:
|
||||
case GLOBAL:
|
||||
break;
|
||||
case STATIC:
|
||||
if (def->df_initialized) {
|
||||
error("cannot redeclare %s to static",
|
||||
idf->id_text);
|
||||
}
|
||||
else {
|
||||
warning("%s redeclared to static",
|
||||
idf->id_text);
|
||||
}
|
||||
def->df_sc = new_sc;
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
break;
|
||||
case GLOBAL:
|
||||
switch (new_sc) { /* the new storage class */
|
||||
case EXTERN:
|
||||
def->df_sc = EXTERN;
|
||||
break;
|
||||
case GLOBAL:
|
||||
break;
|
||||
case STATIC:
|
||||
if (def->df_initialized)
|
||||
error("cannot redeclare %s to static",
|
||||
idf->id_text);
|
||||
else {
|
||||
#ifndef NOROPTION
|
||||
if (options['R'])
|
||||
warning("%s redeclared to static",
|
||||
idf->id_text);
|
||||
#endif
|
||||
def->df_sc = STATIC;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
break;
|
||||
case STATIC:
|
||||
switch (new_sc) { /* the new storage class */
|
||||
case EXTERN:
|
||||
if (def->df_initialized)
|
||||
error("cannot redeclare %s to extern",
|
||||
idf->id_text);
|
||||
else {
|
||||
warning("%s redeclared to extern",
|
||||
idf->id_text);
|
||||
def->df_sc = EXTERN;
|
||||
}
|
||||
break;
|
||||
case GLOBAL:
|
||||
case STATIC:
|
||||
if (def->df_type->tp_fund != FUNCTION)
|
||||
warning("%s was already static",
|
||||
idf->id_text);
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
break;
|
||||
case IMPLICIT:
|
||||
switch (new_sc) { /* the new storage class */
|
||||
case EXTERN:
|
||||
case GLOBAL:
|
||||
def->df_sc = new_sc;
|
||||
break;
|
||||
case STATIC:
|
||||
#ifndef NOROPTION
|
||||
if (options['R'])
|
||||
warning("%s was implicitly declared as extern",
|
||||
idf->id_text);
|
||||
#endif
|
||||
def->df_sc = new_sc;
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
break;
|
||||
case ENUM:
|
||||
case TYPEDEF:
|
||||
error("illegal redeclaration of %s", idf->id_text);
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
good_formal(def, idf)
|
||||
register struct def *def;
|
||||
register struct idf *idf;
|
||||
{
|
||||
/* Succeeds if def is a proper L_FORMAL1 definition and
|
||||
gives an error message otherwise.
|
||||
*/
|
||||
if (!def || def->df_level != L_FORMAL1) { /* not in parameter list */
|
||||
if (!is_anon_idf(idf))
|
||||
error("%s not in parameter list", idf->id_text);
|
||||
return 0;
|
||||
}
|
||||
ASSERT(def->df_sc == FORMAL); /* CJ */
|
||||
return 1;
|
||||
}
|
||||
|
||||
declare_params(dc)
|
||||
register struct declarator *dc;
|
||||
{
|
||||
/* Declares the formal parameters if they exist.
|
||||
*/
|
||||
register struct formal *fm = dc->dc_formal;
|
||||
|
||||
while (fm) {
|
||||
declare_parameter(fm->fm_idf);
|
||||
fm = fm->next;
|
||||
}
|
||||
free_formals(dc->dc_formal);
|
||||
dc->dc_formal = 0;
|
||||
}
|
||||
|
||||
init_idf(idf)
|
||||
register struct idf *idf;
|
||||
{
|
||||
/* The topmost definition of idf is set to initialized.
|
||||
*/
|
||||
register struct def *def = idf->id_def; /* the topmost */
|
||||
|
||||
if (def->df_initialized)
|
||||
error("multiple initialization of %s", idf->id_text);
|
||||
if (def->df_sc == TYPEDEF) {
|
||||
warning("typedef cannot be initialized");
|
||||
def->df_sc = EXTERN; /* ??? *//* What else ? */
|
||||
}
|
||||
def->df_initialized = 1;
|
||||
}
|
||||
|
||||
declare_parameter(idf)
|
||||
struct idf *idf;
|
||||
{
|
||||
/* idf is declared as a formal.
|
||||
*/
|
||||
add_def(idf, FORMAL, int_type, level);
|
||||
}
|
||||
|
||||
declare_enum(tp, idf, l)
|
||||
struct type *tp;
|
||||
struct idf *idf;
|
||||
arith l;
|
||||
{
|
||||
/* idf is declared as an enum constant with value l.
|
||||
*/
|
||||
add_def(idf, ENUM, tp, level);
|
||||
idf->id_def->df_address = l;
|
||||
}
|
||||
|
||||
declare_formals(fp)
|
||||
arith *fp;
|
||||
{
|
||||
/* Declares those formals as int that haven't been declared
|
||||
by the user.
|
||||
An address is assigned to each formal parameter.
|
||||
The total size of the formals is returned in *fp;
|
||||
*/
|
||||
register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
|
||||
arith f_offset = (arith)0;
|
||||
register int nparams = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (options['t'])
|
||||
dumpidftab("start declare_formals", 0);
|
||||
#endif DEBUG
|
||||
while (se) {
|
||||
register struct def *def = se->se_idf->id_def;
|
||||
|
||||
def->df_address = f_offset;
|
||||
/* the alignment convention for parameters is: align on
|
||||
word boundaries, i.e. take care that the following
|
||||
parameter starts on a new word boundary.
|
||||
*/
|
||||
f_offset = align(f_offset + def->df_type->tp_size, (int) word_size);
|
||||
formal_cvt(def); /* cvt int to char or short, if necessary */
|
||||
se = se->next;
|
||||
def->df_level = L_FORMAL2; /* CJ */
|
||||
RegisterAccount(def->df_address, def->df_type->tp_size,
|
||||
regtype(def->df_type),
|
||||
def->df_sc);
|
||||
if (nparams++ >= STDC_NPARAMS)
|
||||
strict("number of formal parameters exceeds ANSI limit");
|
||||
}
|
||||
*fp = f_offset;
|
||||
}
|
||||
|
||||
int
|
||||
regtype(tp)
|
||||
struct type *tp;
|
||||
{
|
||||
switch(tp->tp_fund) {
|
||||
case INT:
|
||||
case LONG:
|
||||
return reg_any;
|
||||
#ifndef NOFLOAT
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
return reg_float;
|
||||
#endif NOFLOAT
|
||||
case POINTER:
|
||||
return reg_pointer;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
add_def(idf, sc, tp, lvl)
|
||||
struct idf *idf;
|
||||
struct type *tp;
|
||||
int lvl;
|
||||
int sc;
|
||||
{
|
||||
/* The identifier idf is declared on level lvl with storage
|
||||
class sc and type tp, through a faked C declaration.
|
||||
This is probably the wrong way to structure the problem,
|
||||
but it will have to do for the time being.
|
||||
*/
|
||||
struct decspecs Ds; struct declarator Dc;
|
||||
|
||||
Ds = null_decspecs;
|
||||
Ds.ds_type = tp;
|
||||
Ds.ds_sc = sc;
|
||||
Dc = null_declarator;
|
||||
Dc.dc_idf = idf;
|
||||
declare_idf(&Ds, &Dc, lvl);
|
||||
}
|
||||
|
||||
update_ahead(idf)
|
||||
register struct idf *idf;
|
||||
{
|
||||
/* The tk_symb of the token ahead is updated in the light of new
|
||||
information about the identifier idf.
|
||||
*/
|
||||
register int tk_symb = AHEAD;
|
||||
|
||||
if ( (tk_symb == IDENTIFIER || tk_symb == TYPE_IDENTIFIER) &&
|
||||
ahead.tk_idf == idf
|
||||
)
|
||||
AHEAD = idf->id_def && idf->id_def->df_sc == TYPEDEF ?
|
||||
TYPE_IDENTIFIER : IDENTIFIER;
|
||||
}
|
||||
|
||||
free_formals(fm)
|
||||
register struct formal *fm;
|
||||
{
|
||||
while (fm) {
|
||||
struct formal *tmp = fm->next;
|
||||
|
||||
free_formal(fm);
|
||||
fm = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
char hmask[IDFSIZE];
|
||||
|
||||
init_hmask()
|
||||
{
|
||||
/* A simple congruence random number generator, as
|
||||
described in Knuth, vol 2.
|
||||
*/
|
||||
register int h, rnd = HASH_X;
|
||||
|
||||
for (h = 0; h < IDFSIZE; h++) {
|
||||
hmask[h] = rnd;
|
||||
rnd = (HASH_A * rnd + HASH_C) & HASHMASK;
|
||||
}
|
||||
}
|
||||
52
lang/cem/cemcom.ansi/idf.str
Normal file
52
lang/cem/cemcom.ansi/idf.str
Normal 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();
|
||||
95
lang/cem/cemcom.ansi/init.c
Normal file
95
lang/cem/cemcom.ansi/init.c
Normal 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
|
||||
64
lang/cem/cemcom.ansi/input.c
Normal file
64
lang/cem/cemcom.ansi/input.c
Normal 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;
|
||||
}
|
||||
15
lang/cem/cemcom.ansi/input.h
Normal file
15
lang/cem/cemcom.ansi/input.h
Normal 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 */
|
||||
8
lang/cem/cemcom.ansi/interface.h
Normal file
8
lang/cem/cemcom.ansi/interface.h
Normal 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
700
lang/cem/cemcom.ansi/ival.g
Normal 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;
|
||||
}
|
||||
}
|
||||
28
lang/cem/cemcom.ansi/l_brace.str
Normal file
28
lang/cem/cemcom.ansi/l_brace.str
Normal 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 */
|
||||
|
||||
21
lang/cem/cemcom.ansi/l_class.h
Normal file
21
lang/cem/cemcom.ansi/l_class.h
Normal 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 */
|
||||
|
||||
211
lang/cem/cemcom.ansi/l_comment.c
Normal file
211
lang/cem/cemcom.ansi/l_comment.c
Normal 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
|
||||
15
lang/cem/cemcom.ansi/l_comment.h
Normal file
15
lang/cem/cemcom.ansi/l_comment.h
Normal 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 */
|
||||
|
||||
74
lang/cem/cemcom.ansi/l_dummy.c
Normal file
74
lang/cem/cemcom.ansi/l_dummy.c
Normal 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
|
||||
107
lang/cem/cemcom.ansi/l_ev_ord.c
Normal file
107
lang/cem/cemcom.ansi/l_ev_ord.c
Normal 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
|
||||
442
lang/cem/cemcom.ansi/l_lint.c
Normal file
442
lang/cem/cemcom.ansi/l_lint.c
Normal 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
|
||||
18
lang/cem/cemcom.ansi/l_lint.h
Normal file
18
lang/cem/cemcom.ansi/l_lint.h
Normal 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 */
|
||||
|
||||
395
lang/cem/cemcom.ansi/l_misc.c
Normal file
395
lang/cem/cemcom.ansi/l_misc.c
Normal 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
|
||||
546
lang/cem/cemcom.ansi/l_outdef.c
Normal file
546
lang/cem/cemcom.ansi/l_outdef.c
Normal 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
|
||||
47
lang/cem/cemcom.ansi/l_outdef.str
Normal file
47
lang/cem/cemcom.ansi/l_outdef.str
Normal 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;
|
||||
};
|
||||
74
lang/cem/cemcom.ansi/l_state.str
Normal file
74
lang/cem/cemcom.ansi/l_state.str
Normal 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 */
|
||||
|
||||
1131
lang/cem/cemcom.ansi/l_states.c
Normal file
1131
lang/cem/cemcom.ansi/l_states.c
Normal file
File diff suppressed because it is too large
Load Diff
74
lang/cem/cemcom.ansi/label.c
Normal file
74
lang/cem/cemcom.ansi/label.c
Normal 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);
|
||||
}
|
||||
28
lang/cem/cemcom.ansi/label.h
Normal file
28
lang/cem/cemcom.ansi/label.h
Normal 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.
|
||||
*/
|
||||
23
lang/cem/cemcom.ansi/level.h
Normal file
23
lang/cem/cemcom.ansi/level.h
Normal 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 */
|
||||
60
lang/cem/cemcom.ansi/macro.str
Normal file
60
lang/cem/cemcom.ansi/macro.str
Normal 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
406
lang/cem/cemcom.ansi/main.c
Normal 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");
|
||||
}
|
||||
|
||||
8
lang/cem/cemcom.ansi/make.allocd
Executable file
8
lang/cem/cemcom.ansi/make.allocd
Executable 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))\
|
||||
:'
|
||||
35
lang/cem/cemcom.ansi/make.hfiles
Executable file
35
lang/cem/cemcom.ansi/make.hfiles
Executable 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
3
lang/cem/cemcom.ansi/make.next
Executable file
@ -0,0 +1,3 @@
|
||||
sed -n '
|
||||
s:^.*ALLOCDEF.*"\(.*\)".*$:struct \1 *h_\1 = 0;:p
|
||||
' $*
|
||||
38
lang/cem/cemcom.ansi/make.tokcase
Executable file
38
lang/cem/cemcom.ansi/make.tokcase
Executable 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--
|
||||
11
lang/cem/cemcom.ansi/make.tokfile
Executable file
11
lang/cem/cemcom.ansi/make.tokfile
Executable file
@ -0,0 +1,11 @@
|
||||
cat <<'--EOT--'
|
||||
/* Generated by make.tokfile */
|
||||
/* $Header: */
|
||||
--EOT--
|
||||
|
||||
sed '
|
||||
/{[A-Z]/!d
|
||||
s/.*{//
|
||||
s/,.*//
|
||||
s/.*/%token &;/
|
||||
'
|
||||
246
lang/cem/cemcom.ansi/mcomm.c
Normal file
246
lang/cem/cemcom.ansi/mcomm.c
Normal 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);
|
||||
}
|
||||
}
|
||||
8
lang/cem/cemcom.ansi/mes.h
Normal file
8
lang/cem/cemcom.ansi/mes.h
Normal 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 */
|
||||
9
lang/cem/cemcom.ansi/nmclash.c
Normal file
9
lang/cem/cemcom.ansi/nmclash.c
Normal 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() { }
|
||||
28
lang/cem/cemcom.ansi/options
Normal file
28
lang/cem/cemcom.ansi/options
Normal 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
|
||||
356
lang/cem/cemcom.ansi/options.c
Normal file
356
lang/cem/cemcom.ansi/options.c
Normal 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;
|
||||
}
|
||||
74
lang/cem/cemcom.ansi/pragma.c
Normal file
74
lang/cem/cemcom.ansi/pragma.c
Normal 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
|
||||
222
lang/cem/cemcom.ansi/program.g
Normal file
222
lang/cem/cemcom.ansi/program.g
Normal 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
|
||||
}
|
||||
;
|
||||
442
lang/cem/cemcom.ansi/proto.c
Normal file
442
lang/cem/cemcom.ansi/proto.c
Normal 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");
|
||||
}
|
||||
}
|
||||
|
||||
17
lang/cem/cemcom.ansi/proto.str
Normal file
17
lang/cem/cemcom.ansi/proto.str
Normal 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 */
|
||||
677
lang/cem/cemcom.ansi/replace.c
Normal file
677
lang/cem/cemcom.ansi/replace.c
Normal 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
|
||||
39
lang/cem/cemcom.ansi/replace.str
Normal file
39
lang/cem/cemcom.ansi/replace.str
Normal 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
237
lang/cem/cemcom.ansi/scan.c
Normal 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
|
||||
33
lang/cem/cemcom.ansi/sizes.h
Normal file
33
lang/cem/cemcom.ansi/sizes.h
Normal 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 */
|
||||
69
lang/cem/cemcom.ansi/skip.c
Normal file
69
lang/cem/cemcom.ansi/skip.c
Normal 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;
|
||||
}
|
||||
18
lang/cem/cemcom.ansi/specials.h
Normal file
18
lang/cem/cemcom.ansi/specials.h
Normal 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 */
|
||||
279
lang/cem/cemcom.ansi/stack.c
Normal file
279
lang/cem/cemcom.ansi/stack.c
Normal 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);
|
||||
}
|
||||
}
|
||||
34
lang/cem/cemcom.ansi/stack.str
Normal file
34
lang/cem/cemcom.ansi/stack.str
Normal 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;
|
||||
472
lang/cem/cemcom.ansi/statement.g
Normal file
472
lang/cem/cemcom.ansi/statement.g
Normal 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();
|
||||
}
|
||||
;
|
||||
15
lang/cem/cemcom.ansi/stb.c
Normal file
15
lang/cem/cemcom.ansi/stb.c
Normal 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);
|
||||
}
|
||||
14
lang/cem/cemcom.ansi/stmt.str
Normal file
14
lang/cem/cemcom.ansi/stmt.str
Normal 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 */
|
||||
499
lang/cem/cemcom.ansi/struct.c
Normal file
499
lang/cem/cemcom.ansi/struct.c
Normal 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));
|
||||
}
|
||||
30
lang/cem/cemcom.ansi/struct.str
Normal file
30
lang/cem/cemcom.ansi/struct.str
Normal 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
Loading…
x
Reference in New Issue
Block a user