Initial revision
This commit is contained in:
parent
ba8482c5ab
commit
1d37165575
549
lang/cem/cpp.ansi/LLlex.c
Normal file
549
lang/cem/cpp.ansi/LLlex.c
Normal file
|
@ -0,0 +1,549 @@
|
||||||
|
/*
|
||||||
|
* (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 "idfsize.h"
|
||||||
|
#include "numsize.h"
|
||||||
|
#include "strsize.h"
|
||||||
|
|
||||||
|
#include <alloc.h>
|
||||||
|
#include "input.h"
|
||||||
|
#include "arith.h"
|
||||||
|
#include "macro.h"
|
||||||
|
#include "idf.h"
|
||||||
|
#include "LLlex.h"
|
||||||
|
#include "Lpars.h"
|
||||||
|
#include "class.h"
|
||||||
|
#include "bits.h"
|
||||||
|
|
||||||
|
#define BUFSIZ 1024
|
||||||
|
|
||||||
|
struct token dot;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
int AccFileSpecifier = 0; /* return filespecifier <...> */
|
||||||
|
int LexSave = 0; /* last character read by GetChar */
|
||||||
|
extern int InputLevel; /* # of current macro expansions */
|
||||||
|
|
||||||
|
char *string_token();
|
||||||
|
arith char_constant();
|
||||||
|
#define FLG_ESEEN 0x01 /* possibly a floating point number */
|
||||||
|
#define FLG_DOTSEEN 0x02 /* certainly a floating point number */
|
||||||
|
|
||||||
|
int
|
||||||
|
LLlex()
|
||||||
|
{
|
||||||
|
return (DOT != EOF) ? GetToken(&dot) : EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
GetToken(ptok)
|
||||||
|
register struct token *ptok;
|
||||||
|
{
|
||||||
|
/* GetToken() 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[BUFSIZ];
|
||||||
|
register int ch, nch;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
switch (class(ch)) { /* detect character class */
|
||||||
|
case STNL: /* newline, vertical space or formfeed */
|
||||||
|
LineNumber++;
|
||||||
|
return ptok->tk_symb = EOF;
|
||||||
|
case STSKIP: /* just skip the skip characters */
|
||||||
|
goto again;
|
||||||
|
case STGARB: /* garbage character */
|
||||||
|
garbage:
|
||||||
|
if (040 < ch && ch < 0177)
|
||||||
|
error("garbage char %c", ch);
|
||||||
|
else
|
||||||
|
error("garbage char \\%03o", ch);
|
||||||
|
goto again;
|
||||||
|
case STSIMP: /* a simple character, no part of compound token*/
|
||||||
|
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;
|
||||||
|
else if (nch == '=')
|
||||||
|
return ptok->tk_symb = ANDAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '+':
|
||||||
|
if (nch == '+')
|
||||||
|
return ptok->tk_symb = PLUSPLUS;
|
||||||
|
else if (nch == '=')
|
||||||
|
return ptok->tk_symb = PLUSAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '-':
|
||||||
|
if (nch == '-')
|
||||||
|
return ptok->tk_symb = MINMIN;
|
||||||
|
else if (nch == '>')
|
||||||
|
return ptok->tk_symb = ARROW;
|
||||||
|
else if (nch == '=')
|
||||||
|
return ptok->tk_symb = MINAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '<':
|
||||||
|
if (AccFileSpecifier) {
|
||||||
|
UnGetChar(); /* pushback nch */
|
||||||
|
ptok->tk_str =
|
||||||
|
string_token("file specifier", '>');
|
||||||
|
return ptok->tk_symb = FILESPECIFIER;
|
||||||
|
} else if (nch == '<') {
|
||||||
|
if ((nch = GetChar()) == '=')
|
||||||
|
return ptok->tk_symb = LEFTAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = LEFT;
|
||||||
|
} else if (nch == '=')
|
||||||
|
return ptok->tk_symb = LESSEQ;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '=':
|
||||||
|
if (nch == '=')
|
||||||
|
return ptok->tk_symb = EQUAL;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '>':
|
||||||
|
if (nch == '=')
|
||||||
|
return ptok->tk_symb = GREATEREQ;
|
||||||
|
else if (nch == '>') {
|
||||||
|
if ((nch = GetChar()) == '=')
|
||||||
|
return ptok->tk_symb = RIGHTAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = RIGHT;
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '|':
|
||||||
|
if (nch == '|')
|
||||||
|
return ptok->tk_symb = OR;
|
||||||
|
else if (nch == '=')
|
||||||
|
return ptok->tk_symb = ORAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '%':
|
||||||
|
if (nch == '=')
|
||||||
|
return ptok->tk_symb = MODAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '*':
|
||||||
|
if (nch == '=')
|
||||||
|
return ptok->tk_symb = TIMESAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '^':
|
||||||
|
if (nch == '=')
|
||||||
|
return ptok->tk_symb = XORAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
case '/':
|
||||||
|
if (nch == '*' && !InputLevel) {
|
||||||
|
skipcomment();
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
else if (nch == '=')
|
||||||
|
return ptok->tk_symb = DIVAB;
|
||||||
|
UnGetChar();
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
default:
|
||||||
|
crash("bad class for char 0%o", ch);
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
case STCHAR: /* character constant */
|
||||||
|
ptok->tk_val = char_constant("character");
|
||||||
|
return ptok->tk_symb = INTEGER;
|
||||||
|
case STSTR: /* string */
|
||||||
|
ptok->tk_str = string_token("string", '"');
|
||||||
|
return ptok->tk_symb = STRING;
|
||||||
|
case STELL: /* wide character constant/string prefix */
|
||||||
|
nch = GetChar();
|
||||||
|
if (nch == '"') {
|
||||||
|
ptok->tk_str =
|
||||||
|
string_token("wide character string", '"');
|
||||||
|
return ptok->tk_symb = STRING;
|
||||||
|
} else if (nch == '\'') {
|
||||||
|
ptok->tk_val = char_constant("wide character");
|
||||||
|
return ptok->tk_symb = INTEGER;
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
/* fallthrough */
|
||||||
|
case STIDF:
|
||||||
|
{
|
||||||
|
extern int idfsize; /* ??? */
|
||||||
|
register char *tg = &buf[0];
|
||||||
|
register char *maxpos = &buf[idfsize];
|
||||||
|
int NoExpandNext = 0;
|
||||||
|
|
||||||
|
#define tstmac(bx) if (!(bits[ch] & bx)) goto nomac
|
||||||
|
#define cpy *tg++ = ch
|
||||||
|
#define load (ch = GetChar()); if (!in_idf(ch)) goto endidf
|
||||||
|
|
||||||
|
if (Unstacked) EnableMacros(); /* unstack macro's when allowed. */
|
||||||
|
if (ch == NOEXPM) {
|
||||||
|
NoExpandNext = 1;
|
||||||
|
ch = GetChar();
|
||||||
|
}
|
||||||
|
#ifdef DOBITS
|
||||||
|
cpy; tstmac(bit0); load;
|
||||||
|
cpy; tstmac(bit1); load;
|
||||||
|
cpy; tstmac(bit2); load;
|
||||||
|
cpy; tstmac(bit3); load;
|
||||||
|
cpy; tstmac(bit4); load;
|
||||||
|
cpy; tstmac(bit5); load;
|
||||||
|
cpy; tstmac(bit6); load;
|
||||||
|
cpy; tstmac(bit7); load;
|
||||||
|
#endif
|
||||||
|
for(;;) {
|
||||||
|
if (tg < maxpos) {
|
||||||
|
cpy;
|
||||||
|
|
||||||
|
}
|
||||||
|
load;
|
||||||
|
}
|
||||||
|
endidf:
|
||||||
|
/*if (ch != EOI) UnGetChar();*/
|
||||||
|
UnGetChar();
|
||||||
|
*tg++ = '\0'; /* mark the end of the identifier */
|
||||||
|
if (ReplaceMacros) {
|
||||||
|
register struct idf *idef = findidf(buf);
|
||||||
|
|
||||||
|
if (idef && idef->id_macro && !NoExpandNext) {
|
||||||
|
if (replace(idef))
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nomac: /* buf can already be null-terminated. soit */
|
||||||
|
ch = GetChar();
|
||||||
|
while (in_idf(ch)) {
|
||||||
|
if (tg < maxpos) *tg++ = ch;
|
||||||
|
ch = GetChar();
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
*tg++ = '\0'; /* mark the end of the identifier */
|
||||||
|
|
||||||
|
NoExpandNext = 0;
|
||||||
|
if (UnknownIdIsZero) {
|
||||||
|
ptok->tk_val = (arith)0;
|
||||||
|
return ptok->tk_symb = INTEGER;
|
||||||
|
}
|
||||||
|
ptok->tk_str = Malloc(tg - buf);
|
||||||
|
strcpy(ptok->tk_str, buf);
|
||||||
|
return IDENTIFIER;
|
||||||
|
}
|
||||||
|
case STNUM: /* a numeric constant */
|
||||||
|
{ /* it may only be an integer constant */
|
||||||
|
register int base = 10, val = 0, vch;
|
||||||
|
|
||||||
|
/* Since the preprocessor only knows integers and has
|
||||||
|
* nothing to do with ellipsis we just return when the
|
||||||
|
* pp-number starts with a '.'
|
||||||
|
*/
|
||||||
|
if (ch == '.') {
|
||||||
|
return ptok->tk_symb = ch;
|
||||||
|
}
|
||||||
|
if (ch == '0') {
|
||||||
|
ch = GetChar();
|
||||||
|
if (ch == 'x' || ch == 'X') {
|
||||||
|
base = 16;
|
||||||
|
ch = GetChar();
|
||||||
|
} else {
|
||||||
|
base = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
while ((vch = val_in_base(ch, base)) >= 0) {
|
||||||
|
val = val * base + vch; /* overflow? nah */
|
||||||
|
ch = GetChar();
|
||||||
|
}
|
||||||
|
while (ch == 'l' || ch == 'L' || ch == 'u' || ch == 'U')
|
||||||
|
ch = GetChar();
|
||||||
|
UnGetChar();
|
||||||
|
ptok->tk_val = val;
|
||||||
|
return ptok->tk_symb = INTEGER;
|
||||||
|
}
|
||||||
|
case STEOI: /* end of text on source file */
|
||||||
|
return ptok->tk_symb = EOF;
|
||||||
|
case STMSPEC:
|
||||||
|
if (!InputLevel) goto garbage;
|
||||||
|
if (ch == TOKSEP) goto again;
|
||||||
|
/* fallthrough shouldn't happen */
|
||||||
|
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();
|
||||||
|
do {
|
||||||
|
while (c != '*') {
|
||||||
|
if (class(c) == STNL) {
|
||||||
|
++LineNumber;
|
||||||
|
} else if (c == EOI) {
|
||||||
|
NoUnstack--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c = GetChar();
|
||||||
|
} /* last Character seen was '*' */
|
||||||
|
c = GetChar();
|
||||||
|
} while (c != '/');
|
||||||
|
NoUnstack--;
|
||||||
|
}
|
||||||
|
|
||||||
|
arith
|
||||||
|
char_constant(nm)
|
||||||
|
char *nm;
|
||||||
|
{
|
||||||
|
register arith val = 0;
|
||||||
|
register int ch;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
ch = GetChar();
|
||||||
|
if (ch == '\'')
|
||||||
|
error("%s constant too short", nm);
|
||||||
|
else
|
||||||
|
while (ch != '\'') {
|
||||||
|
if (ch == '\n') {
|
||||||
|
error("newline in %s constant", nm);
|
||||||
|
LineNumber++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ch == '\\')
|
||||||
|
ch = quoted(GetChar());
|
||||||
|
if (ch >= 128) ch -= 256;
|
||||||
|
if (size < (int)size)
|
||||||
|
val |= ch << 8 * size;
|
||||||
|
size++;
|
||||||
|
ch = GetChar();
|
||||||
|
}
|
||||||
|
if (size > 1)
|
||||||
|
strict("%s constant includes more than one character", nm);
|
||||||
|
if (size > sizeof(arith))
|
||||||
|
error("%s constant too long", nm);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
string_token(nm, stop_char)
|
||||||
|
char *nm;
|
||||||
|
{
|
||||||
|
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') {
|
||||||
|
error("newline in %s", nm);
|
||||||
|
LineNumber++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ch == EOI) {
|
||||||
|
error("end-of-file inside %s", nm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ch == '\\' && !AccFileSpecifier)
|
||||||
|
ch = quoted(GetChar());
|
||||||
|
str[pos++] = ch;
|
||||||
|
if (pos == str_size)
|
||||||
|
str = Realloc(str, str_size <<= 1);
|
||||||
|
ch = GetChar();
|
||||||
|
}
|
||||||
|
str[pos++] = '\0'; /* for filenames etc. */
|
||||||
|
str = Realloc(str, 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:
|
||||||
|
return is_dig(ch) ? ch - '0' : -1;
|
||||||
|
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('?');
|
||||||
|
}
|
42
lang/cem/cpp.ansi/LLlex.h
Normal file
42
lang/cem/cpp.ansi/LLlex.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* (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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* the structure of a token: */
|
||||||
|
struct token {
|
||||||
|
int tok_symb; /* the token itself */
|
||||||
|
union {
|
||||||
|
char *tok_str;
|
||||||
|
arith tok_val; /* for INTEGER */
|
||||||
|
} tok_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "file_info.h"
|
||||||
|
|
||||||
|
#define tk_symb tok_symb
|
||||||
|
#define tk_str tok_data.tok_str
|
||||||
|
#define tk_val tok_data.tok_val
|
||||||
|
|
||||||
|
extern struct token dot;
|
||||||
|
|
||||||
|
extern int ReplaceMacros; /* "LLlex.c" */
|
||||||
|
extern int AccDefined; /* "LLlex.c" */
|
||||||
|
extern int Unstacked; /* "LLlex.c" */
|
||||||
|
extern int UnknownIdIsZero; /* "LLlex.c" */
|
||||||
|
extern int AccFileSpecifier; /* "LLlex.c" */
|
||||||
|
|
||||||
|
extern int NoUnstack; /* buffer.c */
|
||||||
|
|
||||||
|
extern int err_occurred; /* "error.c" */
|
||||||
|
|
||||||
|
#define DOT dot.tk_symb
|
||||||
|
|
||||||
|
#define EOF (-1)
|
25
lang/cem/cpp.ansi/LLmessage.c
Normal file
25
lang/cem/cpp.ansi/LLmessage.c
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* (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 "arith.h"
|
||||||
|
#include "LLlex.h"
|
||||||
|
#include "Lpars.h"
|
||||||
|
|
||||||
|
extern char *symbol2str();
|
||||||
|
|
||||||
|
LLmessage(tk) {
|
||||||
|
err_occurred = 1;
|
||||||
|
if (tk < 0)
|
||||||
|
error("garbage at end of line");
|
||||||
|
else if (tk) {
|
||||||
|
error("%s missing", symbol2str(tk));
|
||||||
|
if (DOT != EOF) SkipToNewLine(0);
|
||||||
|
DOT = EOF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error("%s deleted", symbol2str(DOT));
|
||||||
|
}
|
256
lang/cem/cpp.ansi/Makefile
Normal file
256
lang/cem/cpp.ansi/Makefile
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
# MAKEFILE FOR (STAND_ALONE) CEM PREPROCESSOR
|
||||||
|
|
||||||
|
EMHOME=../../..
|
||||||
|
MODULES=$(EMHOME)/modules
|
||||||
|
MODULESLIB=$(MODULES)/lib
|
||||||
|
BIN=$(EMHOME)/lib
|
||||||
|
MANDIR=$(EMHOME)/man
|
||||||
|
|
||||||
|
# Some paths
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
SYSLIB = $(MODULESLIB)/libsystem.a
|
||||||
|
STRLIB = $(MODULESLIB)/libstring.a
|
||||||
|
PRTLIB = $(MODULESLIB)/libprint.a
|
||||||
|
ALLOCLIB = $(MODULESLIB)/liballoc.a
|
||||||
|
ASSERTLIB = $(MODULESLIB)/libassert.a
|
||||||
|
MALLOC = $(MODULESLIB)/malloc.o
|
||||||
|
LIBS = $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(ASSERTLIB) $(SYSLIB)
|
||||||
|
LIB_INCLUDES = -I$(MODULES)/h -I$(MODULES)/pkg
|
||||||
|
|
||||||
|
# Where to install the preprocessor
|
||||||
|
CEMPP = $(BIN)/ncpp
|
||||||
|
|
||||||
|
TABGEN = $(EMHOME)/bin/tabgen
|
||||||
|
|
||||||
|
# What C compiler to use and how
|
||||||
|
CC = fcc
|
||||||
|
COPTIONS =
|
||||||
|
LDFLAGS = -i
|
||||||
|
|
||||||
|
# What parser generator to use and how
|
||||||
|
GEN = $(EMHOME)/bin/LLgen
|
||||||
|
GENOPTIONS =
|
||||||
|
|
||||||
|
# Special #defines during compilation
|
||||||
|
CDEFS = $(LIB_INCLUDES)
|
||||||
|
CFLAGS = $(CDEFS) $(COPTIONS) -O# # we cannot pass the COPTIONS to lint!
|
||||||
|
|
||||||
|
# Grammar files and their objects
|
||||||
|
LSRC = tokenfile.g expression.g
|
||||||
|
LCSRC = tokenfile.c expression.c Lpars.c
|
||||||
|
LOBJ = tokenfile.o expression.o Lpars.o
|
||||||
|
|
||||||
|
# Objects of hand-written C files
|
||||||
|
CSRC = LLlex.c LLmessage.c ch7bin.c ch7mon.c domacro.c \
|
||||||
|
error.c idf.c init.c input.c main.c options.c \
|
||||||
|
preprocess.c replace.c skip.c tokenname.c expr.c
|
||||||
|
COBJ = LLlex.o LLmessage.o ch7bin.o ch7mon.o domacro.o \
|
||||||
|
error.o idf.o init.o input.o main.o options.o \
|
||||||
|
preprocess.o replace.o skip.o tokenname.o next.o expr.o
|
||||||
|
|
||||||
|
PRFILES = Makefile Parameters \
|
||||||
|
make.hfiles make.tokcase make.tokfile LLlex.h bits.h file_info.h \
|
||||||
|
idf.h input.h interface.h macro.str replace.str \
|
||||||
|
class.h char.tab expression.g $(CSRC)
|
||||||
|
|
||||||
|
# Objects of other generated C files
|
||||||
|
GOBJ = char.o symbol2str.o
|
||||||
|
|
||||||
|
# generated source files
|
||||||
|
GSRC = char.c symbol2str.c
|
||||||
|
|
||||||
|
# .h files generated by `make.allod'
|
||||||
|
STRSRC = macro.str replace.str
|
||||||
|
GSTRSRC = macro.h replace.h
|
||||||
|
|
||||||
|
# .h files generated by `make hfiles'; PLEASE KEEP THIS UP-TO-DATE!
|
||||||
|
GHSRC = errout.h idfsize.h ifdepth.h lapbuf.h \
|
||||||
|
nparams.h numsize.h obufsize.h argbuf.h \
|
||||||
|
parbufsize.h pathlength.h strsize.h textsize.h \
|
||||||
|
botch_free.h debug.h inputtype.h dobits.h line_prefix.h
|
||||||
|
|
||||||
|
# Other generated files, for 'make clean' only
|
||||||
|
GENERATED = tokenfile.g Lpars.h LLfiles LL.output lint.out \
|
||||||
|
Xref hfiles cfiles next.c tags Makefile.old
|
||||||
|
|
||||||
|
all: cc
|
||||||
|
|
||||||
|
cc: hfiles LLfiles
|
||||||
|
make "EMHOME="$(EMHOME) ncpp
|
||||||
|
|
||||||
|
hfiles: Parameters char.c
|
||||||
|
./make.hfiles Parameters
|
||||||
|
@touch hfiles
|
||||||
|
|
||||||
|
.SUFFIXES: .str .h
|
||||||
|
.str.h:
|
||||||
|
./make.allocd <$*.str >$*.h
|
||||||
|
|
||||||
|
char.c: char.tab
|
||||||
|
$(TABGEN) -fchar.tab > char.c
|
||||||
|
|
||||||
|
next.c: make.next $(STRSRC)
|
||||||
|
./make.next $(STRSRC) >next.c
|
||||||
|
|
||||||
|
macro.h: make.allocd
|
||||||
|
repl.h: make.allocd
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# Objects needed for 'ncpp'
|
||||||
|
OBJ = $(COBJ) $(LOBJ) $(GOBJ)
|
||||||
|
SRC = $(CSRC) $(LCSRC) $(GSRC)
|
||||||
|
|
||||||
|
ncpp: $(OBJ) Makefile
|
||||||
|
$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) $(LIBS) -o ncpp
|
||||||
|
-size ncpp
|
||||||
|
|
||||||
|
cfiles: hfiles LLfiles $(GSRC) $(GSTRSRC)
|
||||||
|
@touch cfiles
|
||||||
|
|
||||||
|
install: all
|
||||||
|
rm -f $(CEMPP)
|
||||||
|
cp ncpp $(CEMPP)
|
||||||
|
rm -f $(MANDIR)/ncpp.6
|
||||||
|
cp ncpp.6 $(MANDIR)/ncpp.6
|
||||||
|
|
||||||
|
cmp: all
|
||||||
|
-cmp ncpp $(CEMPP)
|
||||||
|
-cmp ncpp.6 $(MANDIR)/ncpp.6
|
||||||
|
|
||||||
|
pr:
|
||||||
|
@pr $(PRFILES)
|
||||||
|
|
||||||
|
opr:
|
||||||
|
make pr | opr
|
||||||
|
|
||||||
|
tags: cfiles
|
||||||
|
ctags $(SRC)
|
||||||
|
|
||||||
|
depend: cfiles
|
||||||
|
sed '/^#AUTOAUTO/,$$d' Makefile >Makefile.new
|
||||||
|
echo '#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO' >>Makefile.new
|
||||||
|
$(EMHOME)/bin/mkdep $(SRC) | \
|
||||||
|
sed 's/\.c:/.o:/' >>Makefile.new
|
||||||
|
mv Makefile Makefile.old
|
||||||
|
mv Makefile.new Makefile
|
||||||
|
|
||||||
|
xref:
|
||||||
|
ctags -x `grep "\.[ch]" Files`|sed "s/).*/)/">Xref
|
||||||
|
|
||||||
|
lint: cfiles
|
||||||
|
lint -bx $(CDEFS) $(SRC) >lint.out
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(LCSRC) $(OBJ) $(GENERATED) $(GSRC) $(GHSRC) $(GSTRSRC) ncpp Out
|
||||||
|
|
||||||
|
#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
|
||||||
|
LLlex.o: LLlex.h
|
||||||
|
LLlex.o: Lpars.h
|
||||||
|
LLlex.o: arith.h
|
||||||
|
LLlex.o: bits.h
|
||||||
|
LLlex.o: class.h
|
||||||
|
LLlex.o: dobits.h
|
||||||
|
LLlex.o: file_info.h
|
||||||
|
LLlex.o: idf.h
|
||||||
|
LLlex.o: idfsize.h
|
||||||
|
LLlex.o: input.h
|
||||||
|
LLlex.o: inputtype.h
|
||||||
|
LLlex.o: macro.h
|
||||||
|
LLlex.o: numsize.h
|
||||||
|
LLlex.o: strsize.h
|
||||||
|
LLmessage.o: LLlex.h
|
||||||
|
LLmessage.o: Lpars.h
|
||||||
|
LLmessage.o: file_info.h
|
||||||
|
ch7bin.o: Lpars.h
|
||||||
|
ch7bin.o: arith.h
|
||||||
|
ch7mon.o: Lpars.h
|
||||||
|
ch7mon.o: arith.h
|
||||||
|
domacro.o: LLlex.h
|
||||||
|
domacro.o: Lpars.h
|
||||||
|
domacro.o: arith.h
|
||||||
|
domacro.o: bits.h
|
||||||
|
domacro.o: botch_free.h
|
||||||
|
domacro.o: class.h
|
||||||
|
domacro.o: dobits.h
|
||||||
|
domacro.o: file_info.h
|
||||||
|
domacro.o: idf.h
|
||||||
|
domacro.o: idfsize.h
|
||||||
|
domacro.o: ifdepth.h
|
||||||
|
domacro.o: input.h
|
||||||
|
domacro.o: inputtype.h
|
||||||
|
domacro.o: macro.h
|
||||||
|
domacro.o: nparams.h
|
||||||
|
domacro.o: parbufsize.h
|
||||||
|
domacro.o: textsize.h
|
||||||
|
error.o: LLlex.h
|
||||||
|
error.o: errout.h
|
||||||
|
error.o: file_info.h
|
||||||
|
idf.o: idf.h
|
||||||
|
init.o: class.h
|
||||||
|
init.o: idf.h
|
||||||
|
init.o: macro.h
|
||||||
|
input.o: file_info.h
|
||||||
|
input.o: input.h
|
||||||
|
input.o: inputtype.h
|
||||||
|
main.o: arith.h
|
||||||
|
main.o: file_info.h
|
||||||
|
main.o: idfsize.h
|
||||||
|
options.o: class.h
|
||||||
|
options.o: idf.h
|
||||||
|
options.o: idfsize.h
|
||||||
|
options.o: macro.h
|
||||||
|
preprocess.o: LLlex.h
|
||||||
|
preprocess.o: bits.h
|
||||||
|
preprocess.o: class.h
|
||||||
|
preprocess.o: dobits.h
|
||||||
|
preprocess.o: file_info.h
|
||||||
|
preprocess.o: idf.h
|
||||||
|
preprocess.o: idfsize.h
|
||||||
|
preprocess.o: input.h
|
||||||
|
preprocess.o: inputtype.h
|
||||||
|
preprocess.o: line_prefix.h
|
||||||
|
preprocess.o: macro.h
|
||||||
|
preprocess.o: obufsize.h
|
||||||
|
replace.o: LLlex.h
|
||||||
|
replace.o: argbuf.h
|
||||||
|
replace.o: class.h
|
||||||
|
replace.o: file_info.h
|
||||||
|
replace.o: idf.h
|
||||||
|
replace.o: idfsize.h
|
||||||
|
replace.o: input.h
|
||||||
|
replace.o: inputtype.h
|
||||||
|
replace.o: lapbuf.h
|
||||||
|
replace.o: macro.h
|
||||||
|
replace.o: nparams.h
|
||||||
|
replace.o: numsize.h
|
||||||
|
replace.o: pathlength.h
|
||||||
|
replace.o: replace.h
|
||||||
|
replace.o: strsize.h
|
||||||
|
skip.o: LLlex.h
|
||||||
|
skip.o: class.h
|
||||||
|
skip.o: file_info.h
|
||||||
|
skip.o: input.h
|
||||||
|
skip.o: inputtype.h
|
||||||
|
tokenname.o: LLlex.h
|
||||||
|
tokenname.o: Lpars.h
|
||||||
|
tokenname.o: file_info.h
|
||||||
|
tokenname.o: idf.h
|
||||||
|
expr.o: Lpars.h
|
||||||
|
tokenfile.o: Lpars.h
|
||||||
|
expression.o: LLlex.h
|
||||||
|
expression.o: Lpars.h
|
||||||
|
expression.o: arith.h
|
||||||
|
expression.o: file_info.h
|
||||||
|
Lpars.o: Lpars.h
|
||||||
|
char.o: class.h
|
||||||
|
symbol2str.o: Lpars.h
|
74
lang/cem/cpp.ansi/Parameters
Normal file
74
lang/cem/cpp.ansi/Parameters
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
!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 */
|
||||||
|
#define STDC_NPARAMS 31 /* ANSI limit on number of parameters */
|
||||||
|
|
||||||
|
|
||||||
|
!File: ifdepth.h
|
||||||
|
#define IFDEPTH 256 /* maximum number of nested if-constructions */
|
||||||
|
|
||||||
|
|
||||||
|
!File: lapbuf.h
|
||||||
|
#define LAPBUF 4096 /* size of macro actual parameter buffer */
|
||||||
|
|
||||||
|
|
||||||
|
!File: argbuf.h
|
||||||
|
#define ARGBUF 2048 /* sizeof of macro actual parameter buffer */
|
||||||
|
|
||||||
|
|
||||||
|
!File: strsize.h
|
||||||
|
#define ISTRSIZE 16 /* minimum number of bytes allocated for
|
||||||
|
storing a string */
|
||||||
|
|
||||||
|
|
||||||
|
!File: botch_free.h
|
||||||
|
#undef BOTCH_FREE 1 /* botch freed memory, as a check */
|
||||||
|
|
||||||
|
|
||||||
|
!File: debug.h
|
||||||
|
#define DEBUG 1 /* perform various self-tests */
|
||||||
|
|
||||||
|
|
||||||
|
!File: parbufsize.h
|
||||||
|
#define PARBUFSIZE 1024
|
||||||
|
|
||||||
|
|
||||||
|
!File: textsize.h
|
||||||
|
#define ITEXTSIZE 16 /* 1st piece of memory for repl. text */
|
||||||
|
|
||||||
|
|
||||||
|
!File: inputtype.h
|
||||||
|
#undef INP_READ_IN_ONE 1 /* read input file in one. */
|
||||||
|
/* If defined, we cannot read from a pipe */
|
||||||
|
|
||||||
|
|
||||||
|
!File: obufsize.h
|
||||||
|
#define OBUFSIZE 8192 /* output buffer size */
|
||||||
|
|
||||||
|
|
||||||
|
!File: dobits.h
|
||||||
|
#define DOBITS 1 /* use trick to reduce symboltable accesses */
|
||||||
|
|
||||||
|
|
||||||
|
!File: line_prefix.h
|
||||||
|
#define LINE_PREFIX "#" /* prefix for generated line directives,
|
||||||
|
either "#" or "#line"
|
||||||
|
*/
|
||||||
|
|
18
lang/cem/cpp.ansi/arith.h
Normal file
18
lang/cem/cpp.ansi/arith.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$ */
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* All preprocessor arithmetic should be done in longs.
|
||||||
|
*/
|
||||||
|
#define arith long /* dummy */
|
18
lang/cem/cpp.ansi/bits.h
Normal file
18
lang/cem/cpp.ansi/bits.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$ */
|
||||||
|
#include "dobits.h"
|
||||||
|
#ifdef DOBITS
|
||||||
|
#define bit0 0x01
|
||||||
|
#define bit1 0x02
|
||||||
|
#define bit2 0x04
|
||||||
|
#define bit3 0x08
|
||||||
|
#define bit4 0x10
|
||||||
|
#define bit5 0x20
|
||||||
|
#define bit6 0x40
|
||||||
|
#define bit7 0x80
|
||||||
|
|
||||||
|
extern char bits[];
|
||||||
|
#endif
|
80
lang/cem/cpp.ansi/ch3bin.c
Normal file
80
lang/cem/cpp.ansi/ch3bin.c
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||||
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||||
|
*/
|
||||||
|
/* $Header$ */
|
||||||
|
/* EVALUATION OF BINARY OPERATORS */
|
||||||
|
|
||||||
|
#include "Lpars.h"
|
||||||
|
#include "arith.h"
|
||||||
|
|
||||||
|
ch7bin(pval, oper, val)
|
||||||
|
register arith *pval, val;
|
||||||
|
int oper;
|
||||||
|
{
|
||||||
|
switch (oper) {
|
||||||
|
case '%':
|
||||||
|
if (val == 0)
|
||||||
|
error("% by 0");
|
||||||
|
else
|
||||||
|
*pval = *pval % val;
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
if (val == 0)
|
||||||
|
error("/ by 0");
|
||||||
|
else
|
||||||
|
*pval = *pval / val;
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
*pval = *pval * val;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
*pval = *pval + val;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
*pval = *pval - val;
|
||||||
|
break;
|
||||||
|
case LEFT:
|
||||||
|
*pval = *pval << val;
|
||||||
|
break;
|
||||||
|
case RIGHT:
|
||||||
|
*pval = *pval >> val;
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
*pval = (*pval < val);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
*pval = (*pval > val);
|
||||||
|
break;
|
||||||
|
case LESSEQ:
|
||||||
|
*pval = (*pval <= val);
|
||||||
|
break;
|
||||||
|
case GREATEREQ:
|
||||||
|
*pval = (*pval >= val);
|
||||||
|
break;
|
||||||
|
case EQUAL:
|
||||||
|
*pval = (*pval == val);
|
||||||
|
break;
|
||||||
|
case NOTEQUAL:
|
||||||
|
*pval = (*pval != val);
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
*pval = *pval & val;
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
*pval = *pval ^ val;
|
||||||
|
break;
|
||||||
|
case '|':
|
||||||
|
*pval = *pval | val;
|
||||||
|
break;
|
||||||
|
case AND:
|
||||||
|
*pval = (*pval && val);
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
*pval = (*pval || val);
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
*pval = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
25
lang/cem/cpp.ansi/ch3mon.c
Normal file
25
lang/cem/cpp.ansi/ch3mon.c
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||||
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||||
|
*/
|
||||||
|
/* $Header$ */
|
||||||
|
/* EVALUATION OF MONADIC OPERATORS */
|
||||||
|
|
||||||
|
#include "Lpars.h"
|
||||||
|
#include "arith.h"
|
||||||
|
|
||||||
|
ch7mon(oper, pval)
|
||||||
|
register arith *pval;
|
||||||
|
{
|
||||||
|
switch (oper) {
|
||||||
|
case '~':
|
||||||
|
*pval = ~(*pval);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
*pval = -(*pval);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
*pval = !(*pval);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
67
lang/cem/cpp.ansi/char.tab
Normal file
67
lang/cem/cpp.ansi/char.tab
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
%
|
||||||
|
% 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_\003
|
||||||
|
STELL:L
|
||||||
|
STNUM:.0-9
|
||||||
|
STSTR:"
|
||||||
|
STEOI:\200
|
||||||
|
STMSPEC:\004
|
||||||
|
%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:0-9a-fA-F
|
||||||
|
%Tchar ishex[] = {
|
||||||
|
%p
|
||||||
|
%T};
|
||||||
|
%
|
||||||
|
% ISOCT
|
||||||
|
%
|
||||||
|
%C
|
||||||
|
1:0-7
|
||||||
|
%Tchar isoct[] = {
|
||||||
|
%p
|
||||||
|
%T};
|
||||||
|
%
|
||||||
|
% ISWSP
|
||||||
|
%
|
||||||
|
%C
|
||||||
|
1: \t\n
|
||||||
|
%Tchar iswsp[] = {
|
||||||
|
%p
|
||||||
|
%T};
|
48
lang/cem/cpp.ansi/class.h
Normal file
48
lang/cem/cpp.ansi/class.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* (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, as 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 */
|
||||||
|
#define STSIMP 3 /* this character can occur as token */
|
||||||
|
#define STCOMP 4 /* this one can start a compound token */
|
||||||
|
#define STELL 5 /* wide character- or string- constant prefix */
|
||||||
|
#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 */
|
||||||
|
#define STMSPEC 11 /* special class for token expansion */
|
||||||
|
|
||||||
|
#define NOEXPM '\003' /* don't expand the next macro identifier */
|
||||||
|
#define TOKSEP '\004' /* the token separator */
|
||||||
|
|
||||||
|
/* 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[];
|
738
lang/cem/cpp.ansi/domacro.c
Normal file
738
lang/cem/cpp.ansi/domacro.c
Normal file
|
@ -0,0 +1,738 @@
|
||||||
|
/*
|
||||||
|
* (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 "idf.h"
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
#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"
|
||||||
|
#include "bits.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;
|
||||||
|
int svnestlevel[30] = {-1};
|
||||||
|
int nestcount;
|
||||||
|
|
||||||
|
char *
|
||||||
|
GetIdentifier(skiponerr)
|
||||||
|
int skiponerr; /* skip the rest of the line on error */
|
||||||
|
{
|
||||||
|
/* Returns a pointer to the identifier that is read from the
|
||||||
|
input stream. When the input does not contain an
|
||||||
|
identifier, the rest of the line is skipped when skiponerr
|
||||||
|
is on, and a null-pointer is returned.
|
||||||
|
The substitution of macros is disabled.
|
||||||
|
Remember that on end-of-line EOF is returned.
|
||||||
|
*/
|
||||||
|
int tmp = UnknownIdIsZero;
|
||||||
|
int tok;
|
||||||
|
struct token tk;
|
||||||
|
|
||||||
|
UnknownIdIsZero = ReplaceMacros = 0;
|
||||||
|
tok = GetToken(&tk);
|
||||||
|
ReplaceMacros = 1;
|
||||||
|
UnknownIdIsZero = tmp;
|
||||||
|
if (tok != IDENTIFIER) {
|
||||||
|
if (skiponerr && tok != EOF) SkipToNewLine(0);
|
||||||
|
return (char *)0;
|
||||||
|
}
|
||||||
|
return tk.tk_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
Return 1 if the preprocessing directive is done. This is to leave
|
||||||
|
pragma's in the input.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
domacro()
|
||||||
|
{
|
||||||
|
struct token tk; /* the token itself */
|
||||||
|
register struct idf *id;
|
||||||
|
int toknum;
|
||||||
|
|
||||||
|
ReplaceMacros = 0;
|
||||||
|
toknum = GetToken(&tk);
|
||||||
|
ReplaceMacros = 1;
|
||||||
|
switch(toknum) { /* select control line action */
|
||||||
|
case IDENTIFIER: /* is it a macro keyword? */
|
||||||
|
id = findidf(tk.tk_str);
|
||||||
|
if (!id) {
|
||||||
|
error("%s: unknown control", tk.tk_str);
|
||||||
|
SkipToNewLine(0);
|
||||||
|
free(tk.tk_str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(tk.tk_str);
|
||||||
|
switch (id->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) {
|
||||||
|
error("bad #line syntax");
|
||||||
|
SkipToNewLine(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
do_line((unsigned int)tk.tk_val);
|
||||||
|
break;
|
||||||
|
case K_ERROR: /* "error" */
|
||||||
|
do_error();
|
||||||
|
break;
|
||||||
|
case K_PRAGMA: /* "pragma" */
|
||||||
|
return 0; /* this is for the compiler */
|
||||||
|
break;
|
||||||
|
case K_UNDEF: /* "undef" */
|
||||||
|
do_undef();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* invalid word seen after the '#' */
|
||||||
|
error("%s: unknown control", id->id_text);
|
||||||
|
SkipToNewLine(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INTEGER: /* # <integer> [<filespecifier>]? */
|
||||||
|
do_line((unsigned int)tk.tk_val);
|
||||||
|
break;
|
||||||
|
case EOF: /* only `#' on this line: do nothing, ignore */
|
||||||
|
break;
|
||||||
|
default: /* invalid token following '#' */
|
||||||
|
error("illegal # line");
|
||||||
|
SkipToNewLine(0);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_block(to_endif)
|
||||||
|
int to_endif;
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
int toknum;
|
||||||
|
struct idf *id;
|
||||||
|
|
||||||
|
NoUnstack++;
|
||||||
|
for (;;) {
|
||||||
|
ch = GetChar(); /* read first character after newline */
|
||||||
|
while (class(ch) == STSKIP)
|
||||||
|
ch = GetChar();
|
||||||
|
if (ch != '#') {
|
||||||
|
if (ch == EOI) {
|
||||||
|
NoUnstack--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
SkipToNewLine(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ReplaceMacros = 0;
|
||||||
|
toknum = GetToken(&tk);
|
||||||
|
ReplaceMacros = 1;
|
||||||
|
if (toknum != 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.
|
||||||
|
*/
|
||||||
|
id = findidf(tk.tk_str);
|
||||||
|
free(tk.tk_str);
|
||||||
|
switch(id->id_resmac) {
|
||||||
|
default:
|
||||||
|
SkipToNewLine(0);
|
||||||
|
break;
|
||||||
|
case K_IF:
|
||||||
|
case K_IFDEF:
|
||||||
|
case K_IFNDEF:
|
||||||
|
push_if();
|
||||||
|
SkipToNewLine(0);
|
||||||
|
break;
|
||||||
|
case K_ELIF:
|
||||||
|
if (ifstack[nestlevel])
|
||||||
|
error("#elif after #else");
|
||||||
|
if (!to_endif && nestlevel == skiplevel) {
|
||||||
|
nestlevel--;
|
||||||
|
push_if();
|
||||||
|
if (ifexpr()) {
|
||||||
|
NoUnstack--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else SkipToNewLine(0); /* otherwise done in ifexpr() */
|
||||||
|
break;
|
||||||
|
case K_ELSE:
|
||||||
|
if (ifstack[nestlevel])
|
||||||
|
error("#else after #else");
|
||||||
|
++(ifstack[nestlevel]);
|
||||||
|
if (!to_endif && nestlevel == skiplevel) {
|
||||||
|
if (SkipToNewLine(1))
|
||||||
|
strict("garbage following #else");
|
||||||
|
NoUnstack--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else SkipToNewLine(0);
|
||||||
|
break;
|
||||||
|
case K_ENDIF:
|
||||||
|
assert(nestlevel > svnestlevel[nestcount]);
|
||||||
|
if (nestlevel == skiplevel) {
|
||||||
|
if (SkipToNewLine(1))
|
||||||
|
strict("garbage following #endif");
|
||||||
|
nestlevel--;
|
||||||
|
NoUnstack--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else SkipToNewLine(0);
|
||||||
|
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;
|
||||||
|
DOT = 0; /* tricky */
|
||||||
|
If_expr(); /* invoke constant expression 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_str;
|
||||||
|
else {
|
||||||
|
error("bad include syntax");
|
||||||
|
filenm = (char *)0;
|
||||||
|
}
|
||||||
|
AccFileSpecifier = 0;
|
||||||
|
SkipToNewLine(0);
|
||||||
|
inctable[0] = WorkingDir;
|
||||||
|
if (filenm) {
|
||||||
|
if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
|
||||||
|
error("cannot open include file \"%s\"", filenm);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WorkingDir = getwdir(result);
|
||||||
|
svnestlevel[++nestcount] = nestlevel;
|
||||||
|
FileName = result;
|
||||||
|
LineNumber = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_define()
|
||||||
|
{
|
||||||
|
/* do_define() interprets a #define control line.
|
||||||
|
*/
|
||||||
|
register char *str; /* 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 (!(str = GetIdentifier(1))) {
|
||||||
|
error("#define: illegal macro name");
|
||||||
|
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);
|
||||||
|
free(str);
|
||||||
|
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 = Malloc(1);
|
||||||
|
*repl_text = '\0';
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
UnGetChar();
|
||||||
|
repl_text = get_text((nformals > 0) ? formals : 0, &length);
|
||||||
|
}
|
||||||
|
macro_def(str2idf(str, 0), 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 <= svnestlevel[nestcount]) {
|
||||||
|
error("#elif without corresponding #if");
|
||||||
|
SkipToNewLine(0);
|
||||||
|
}
|
||||||
|
else { /* restart at this level as if a #if is detected. */
|
||||||
|
if (ifstack[nestlevel]) {
|
||||||
|
error("#elif after #else");
|
||||||
|
SkipToNewLine(0);
|
||||||
|
}
|
||||||
|
nestlevel--;
|
||||||
|
push_if();
|
||||||
|
skip_block(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_else()
|
||||||
|
{
|
||||||
|
if (SkipToNewLine(1))
|
||||||
|
strict("garbage following #else");
|
||||||
|
if (nestlevel <= svnestlevel[nestcount])
|
||||||
|
error("#else without corresponding #if");
|
||||||
|
else { /* mark this level as else-d */
|
||||||
|
if (ifstack[nestlevel]) {
|
||||||
|
error("#else after #else");
|
||||||
|
}
|
||||||
|
++(ifstack[nestlevel]);
|
||||||
|
skip_block(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_endif()
|
||||||
|
{
|
||||||
|
if (SkipToNewLine(1))
|
||||||
|
strict("garbage following #endif");
|
||||||
|
if (nestlevel <= svnestlevel[nestcount]) {
|
||||||
|
error("#endif without corresponding #if");
|
||||||
|
}
|
||||||
|
else nestlevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_if()
|
||||||
|
{
|
||||||
|
push_if();
|
||||||
|
if (!ifexpr()) /* a false #if/#elif expression */
|
||||||
|
skip_block(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_ifdef(how)
|
||||||
|
{
|
||||||
|
register struct idf *id;
|
||||||
|
register char *str;
|
||||||
|
|
||||||
|
/* how == 1 : ifdef; how == 0 : ifndef
|
||||||
|
*/
|
||||||
|
push_if();
|
||||||
|
if (!(str = GetIdentifier(1))) {
|
||||||
|
error("illegal #ifdef construction");
|
||||||
|
id = (struct idf *)0;
|
||||||
|
} else {
|
||||||
|
id = findidf(str);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The next test is a shorthand for:
|
||||||
|
(how && !id->id_macro) || (!how && id->id_macro)
|
||||||
|
*/
|
||||||
|
if (how ^ (id && id->id_macro != 0))
|
||||||
|
skip_block(0);
|
||||||
|
else
|
||||||
|
SkipToNewLine(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_undef()
|
||||||
|
{
|
||||||
|
register struct idf *id;
|
||||||
|
register char *str;
|
||||||
|
|
||||||
|
/* Forget a macro definition. */
|
||||||
|
if (str = GetIdentifier(1)) {
|
||||||
|
if ((id = findidf(str)) && id->id_macro) {
|
||||||
|
if (id->id_macro->mc_flag & NOUNDEF) {
|
||||||
|
error("it is not allowed to #undef %s", str);
|
||||||
|
} else {
|
||||||
|
free(id->id_macro->mc_text);
|
||||||
|
free_macro(id->id_macro);
|
||||||
|
id->id_macro = (struct macro *) 0;
|
||||||
|
}
|
||||||
|
} /* else: don't complain */
|
||||||
|
free(str);
|
||||||
|
SkipToNewLine(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error("illegal #undef construction");
|
||||||
|
}
|
||||||
|
|
||||||
|
do_error()
|
||||||
|
{
|
||||||
|
static char errbuf[512];
|
||||||
|
register char *bp = errbuf;
|
||||||
|
register int ch;
|
||||||
|
|
||||||
|
while ((ch = GetChar()) != '\n')
|
||||||
|
*bp++ = ch;
|
||||||
|
*bp = '\0';
|
||||||
|
UnGetChar();
|
||||||
|
error("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) {
|
||||||
|
error("#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 != ',') {
|
||||||
|
error("#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.
|
||||||
|
An error is given if there was already a definition
|
||||||
|
*/
|
||||||
|
if (newdef) { /* is there a redefinition? */
|
||||||
|
if (newdef->mc_flag & NOUNDEF) {
|
||||||
|
error("it is not allowed to redefine %s", id->id_text);
|
||||||
|
} else if (!macroeq(newdef->mc_text, text))
|
||||||
|
error("illegal redefine of \"%s\"", id->id_text);
|
||||||
|
free(text);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
#ifdef DOBITS
|
||||||
|
register char *p = id->id_text;
|
||||||
|
#define setbit(bx) if (!*p) goto go_on; bits[*p++] |= (bx)
|
||||||
|
setbit(bit0);
|
||||||
|
setbit(bit1);
|
||||||
|
setbit(bit2);
|
||||||
|
setbit(bit3);
|
||||||
|
setbit(bit4);
|
||||||
|
setbit(bit5);
|
||||||
|
setbit(bit6);
|
||||||
|
setbit(bit7);
|
||||||
|
|
||||||
|
go_on:
|
||||||
|
#endif
|
||||||
|
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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
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 unsigned 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 <<= 1);
|
||||||
|
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 <<= 1);
|
||||||
|
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 <<= 1);
|
||||||
|
text[pos++] = FORMALP | (char) n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
register char *ptr = &id_buf[0];
|
||||||
|
|
||||||
|
while (pos + id_size >= text_size)
|
||||||
|
text_size <<= 1;
|
||||||
|
text = Realloc(text, text_size);
|
||||||
|
while (text[pos++] = *ptr++)
|
||||||
|
/* EMPTY */ ;
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (pos+1 >= text_size)
|
||||||
|
text = Realloc(text, text_size <<= 1);
|
||||||
|
text[pos++] = c;
|
||||||
|
c = GetChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text[pos++] = '\0';
|
||||||
|
text = Realloc(text, pos);
|
||||||
|
*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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_str;
|
||||||
|
SkipToNewLine(0);
|
||||||
|
}
|
106
lang/cem/cpp.ansi/error.c
Normal file
106
lang/cem/cpp.ansi/error.c
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* (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 <system.h>
|
||||||
|
#include <varargs.h>
|
||||||
|
|
||||||
|
#include "arith.h"
|
||||||
|
#include "errout.h"
|
||||||
|
#include "LLlex.h"
|
||||||
|
|
||||||
|
/* This file contains the (non-portable) error-message and diagnostic
|
||||||
|
functions. Beware, they are called with a variable number of
|
||||||
|
arguments!
|
||||||
|
*/
|
||||||
|
|
||||||
|
int err_occurred;
|
||||||
|
|
||||||
|
err_hdr(s)
|
||||||
|
char *s;
|
||||||
|
{
|
||||||
|
if (FileName) {
|
||||||
|
fprint(ERROUT, "\"%s\", line %d: %s", FileName, LineNumber, s);
|
||||||
|
}
|
||||||
|
else fprint(ERROUT, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*VARARGS1*/
|
||||||
|
error(va_alist)
|
||||||
|
va_dcl
|
||||||
|
{
|
||||||
|
char *fmt;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
err_hdr("");
|
||||||
|
va_start(ap);
|
||||||
|
fmt = va_arg(ap, char *);
|
||||||
|
doprnt(ERROUT, fmt, ap);
|
||||||
|
fprint(ERROUT, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*VARARGS1*/
|
||||||
|
warning(va_alist)
|
||||||
|
va_dcl
|
||||||
|
{
|
||||||
|
char *fmt;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
err_hdr("(warning) ");
|
||||||
|
va_start(ap);
|
||||||
|
fmt = va_arg(ap, char *);
|
||||||
|
doprnt(ERROUT, fmt, ap);
|
||||||
|
fprint(ERROUT, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*VARARGS1*/
|
||||||
|
strict(va_alist)
|
||||||
|
va_dcl
|
||||||
|
{
|
||||||
|
char *fmt;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
err_hdr("(strict) ");
|
||||||
|
va_start(ap);
|
||||||
|
fmt = va_arg(ap, char *);
|
||||||
|
doprnt(ERROUT, fmt, ap);
|
||||||
|
fprint(ERROUT, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*VARARGS1*/
|
||||||
|
crash(va_alist)
|
||||||
|
va_dcl
|
||||||
|
{
|
||||||
|
char *fmt;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
err_hdr("CRASH\007 ");
|
||||||
|
va_start(ap);
|
||||||
|
fmt = va_arg(ap, char *);
|
||||||
|
doprnt(ERROUT, fmt, ap);
|
||||||
|
fprint(ERROUT, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
sys_stop(S_ABORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*VARARGS1*/
|
||||||
|
fatal(va_alist)
|
||||||
|
va_dcl
|
||||||
|
{
|
||||||
|
char *fmt;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
err_hdr("fatal error -- ");
|
||||||
|
va_start(ap);
|
||||||
|
fmt = va_arg(ap, char *);
|
||||||
|
doprnt(ERROUT, fmt, ap);
|
||||||
|
fprint(ERROUT, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
sys_stop(S_EXIT);
|
||||||
|
}
|
58
lang/cem/cpp.ansi/expr.c
Normal file
58
lang/cem/cpp.ansi/expr.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||||
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||||
|
*/
|
||||||
|
/* $Header$ */
|
||||||
|
/* OPERATOR HANDLING */
|
||||||
|
|
||||||
|
#include "Lpars.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
rank_of(oper)
|
||||||
|
int oper;
|
||||||
|
{
|
||||||
|
/* The rank of the operator oper is returned.
|
||||||
|
*/
|
||||||
|
switch (oper) {
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
case '(':
|
||||||
|
return 1;
|
||||||
|
case '!':
|
||||||
|
return 2;
|
||||||
|
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 ',':
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
129
lang/cem/cpp.ansi/expression.g
Normal file
129
lang/cem/cpp.ansi/expression.g
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||||
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||||
|
*/
|
||||||
|
/* EXPRESSION SYNTAX PARSER */
|
||||||
|
|
||||||
|
%lexical LLlex;
|
||||||
|
%start If_expr, if_expression;
|
||||||
|
|
||||||
|
{
|
||||||
|
#include "arith.h"
|
||||||
|
#include "LLlex.h"
|
||||||
|
|
||||||
|
extern arith ifval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if_expression
|
||||||
|
:
|
||||||
|
constant_expression(&ifval)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* 7.1 */
|
||||||
|
primary(arith *pval;)
|
||||||
|
:
|
||||||
|
constant(pval)
|
||||||
|
|
|
||||||
|
'(' expression(pval) ')'
|
||||||
|
;
|
||||||
|
|
||||||
|
unary(arith *pval;)
|
||||||
|
{int oper;}
|
||||||
|
:
|
||||||
|
unop(&oper)
|
||||||
|
unary(pval)
|
||||||
|
{ ch7mon(oper, pval); }
|
||||||
|
|
|
||||||
|
primary(pval)
|
||||||
|
;
|
||||||
|
|
||||||
|
binary_expression(int maxrank; arith *pval;)
|
||||||
|
{int oper; arith val1;}
|
||||||
|
:
|
||||||
|
unary(pval)
|
||||||
|
[%while (rank_of(DOT) <= maxrank)
|
||||||
|
binop(&oper)
|
||||||
|
binary_expression(rank_of(oper)-1, &val1)
|
||||||
|
{
|
||||||
|
ch7bin(pval, oper, val1);
|
||||||
|
}
|
||||||
|
]*
|
||||||
|
;
|
||||||
|
|
||||||
|
/* 7.13 */
|
||||||
|
conditional_expression(arith *pval;)
|
||||||
|
{arith val1 = 0, val2 = 0;}
|
||||||
|
:
|
||||||
|
/* allow all binary operators */
|
||||||
|
binary_expression(rank_of('?') - 1, pval)
|
||||||
|
[ '?'
|
||||||
|
expression(&val1)
|
||||||
|
':'
|
||||||
|
assignment_expression(&val2)
|
||||||
|
{ *pval = (*pval ? val1 : val2); }
|
||||||
|
]?
|
||||||
|
;
|
||||||
|
|
||||||
|
/* 7.14 */
|
||||||
|
assignment_expression(arith *pval;)
|
||||||
|
:
|
||||||
|
conditional_expression(pval)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* 7.15 */
|
||||||
|
expression(arith *pval;)
|
||||||
|
{arith val1;}
|
||||||
|
:
|
||||||
|
assignment_expression(pval)
|
||||||
|
[ ','
|
||||||
|
assignment_expression(&val1)
|
||||||
|
{
|
||||||
|
ch7bin(pval, ',', val1);
|
||||||
|
}
|
||||||
|
]*
|
||||||
|
;
|
||||||
|
|
||||||
|
unop(int *oper;) :
|
||||||
|
[ '-' | '!' | '~' ]
|
||||||
|
{*oper = DOT;}
|
||||||
|
;
|
||||||
|
|
||||||
|
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;}
|
||||||
|
;
|
||||||
|
|
||||||
|
constant(arith *pval;) :
|
||||||
|
INTEGER
|
||||||
|
{*pval = dot.tk_val;}
|
||||||
|
;
|
||||||
|
|
||||||
|
constant_expression (arith *pval;) :
|
||||||
|
assignment_expression(pval)
|
||||||
|
;
|
18
lang/cem/cpp.ansi/file_info.h
Normal file
18
lang/cem/cpp.ansi/file_info.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$ */
|
||||||
|
/* 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;
|
||||||
|
char *fil_name;
|
||||||
|
char *fil_wdir;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LineNumber finfo.fil_lino
|
||||||
|
#define FileName finfo.fil_name
|
||||||
|
#define WorkingDir finfo.fil_wdir
|
||||||
|
|
||||||
|
extern struct file_info finfo; /* input.c */
|
7
lang/cem/cpp.ansi/idf.c
Normal file
7
lang/cem/cpp.ansi/idf.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
* (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 "idf.h"
|
||||||
|
#include <idf_pkg.body>
|
16
lang/cem/cpp.ansi/idf.h
Normal file
16
lang/cem/cpp.ansi/idf.h
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$ */
|
||||||
|
struct id_usr {
|
||||||
|
struct macro *idu_macro;
|
||||||
|
int idu_resmac;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IDF_TYPE struct id_usr
|
||||||
|
#define IDF_HSIZE 6
|
||||||
|
#define id_macro id_user.idu_macro
|
||||||
|
#define id_resmac id_user.idu_resmac
|
||||||
|
|
||||||
|
#include <idf_pkg.spec>
|
92
lang/cem/cpp.ansi/init.c
Normal file
92
lang/cem/cpp.ansi/init.c
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* (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 <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);
|
||||||
|
if (tp->tm_mday < 10) dbuf[5] = ' '; /* hack */
|
||||||
|
macro_def(str2idf("__DATE__", 0), dbuf, -1, strlen(dbuf), NOUNDEF);
|
||||||
|
|
||||||
|
/* __TIME__ */
|
||||||
|
sprintf(tbuf, "\"%.2d:%.2d:%.2d\"", tp->tm_hour, tp->tm_min, tp->tm_sec);
|
||||||
|
macro_def(str2idf("__TIME__", 0), tbuf, -1, strlen(tbuf), NOUNDEF);
|
||||||
|
|
||||||
|
/* __LINE__ */
|
||||||
|
macro_def(str2idf("__LINE__", 0), "0", -1, 1, NOUNDEF | FUNC);
|
||||||
|
|
||||||
|
/* __FILE__ */
|
||||||
|
macro_def(str2idf("__FILE__", 0), "", -1, 1, NOUNDEF | FUNC);
|
||||||
|
|
||||||
|
/* __STDC__ */
|
||||||
|
macro_def(str2idf("__STDC__", 0), "1", -1, 1, NOUNDEF);
|
||||||
|
|
||||||
|
/* defined(??) */
|
||||||
|
macro_def(str2idf("defined", 0), "", 1, 1, NOUNDEF | FUNC);
|
||||||
|
}
|
61
lang/cem/cpp.ansi/input.c
Normal file
61
lang/cem/cpp.ansi/input.c
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* (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 "file_info.h"
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
#define INP_PUSHBACK 3
|
||||||
|
#define INP_TYPE struct file_info
|
||||||
|
#define INP_VAR finfo
|
||||||
|
struct file_info finfo;
|
||||||
|
#include <inp_pkg.body>
|
||||||
|
|
||||||
|
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 ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
int NoUnstack;
|
||||||
|
int InputLevel;
|
||||||
|
|
||||||
|
AtEoIT()
|
||||||
|
{
|
||||||
|
InputLevel--;
|
||||||
|
/* if (NoUnstack) warning("unexpected EOF"); ??? */
|
||||||
|
unstackrepl();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtEoIF()
|
||||||
|
{
|
||||||
|
extern int nestlevel;
|
||||||
|
extern int nestcount;
|
||||||
|
extern int svnestlevel[];
|
||||||
|
|
||||||
|
if (nestlevel > svnestlevel[nestcount]) warning("missing #endif");
|
||||||
|
else if (NoUnstack) warning("unexpected EOF");
|
||||||
|
nestlevel = svnestlevel[nestcount--];
|
||||||
|
return 0;
|
||||||
|
}
|
15
lang/cem/cpp.ansi/input.h
Normal file
15
lang/cem/cpp.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 "inputtype.h"
|
||||||
|
#include <inp_pkg.spec>
|
||||||
|
|
||||||
|
/* Note: The following macro only garuantees one PushBack.
|
||||||
|
*/
|
||||||
|
#define UnGetChar() ((LexSave != EOI) ? ChPushBack(LexSave) : 0)
|
||||||
|
|
||||||
|
extern int LexSave; /* last character read by GetChar */
|
||||||
|
extern int GetChar(); /* character input, with trigraph parsing */
|
56
lang/cem/cpp.ansi/macro.str
Normal file
56
lang/cem/cpp.ansi/macro.str
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* (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 */
|
||||||
|
|
||||||
|
/* 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 0x1 /* function attached */
|
||||||
|
#define NOUNDEF 0x2 /* reserved macro */
|
||||||
|
#define NOREPLACE 0x4 /* prevent recursion */
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
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
|
84
lang/cem/cpp.ansi/main.c
Normal file
84
lang/cem/cpp.ansi/main.c
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* (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 <alloc.h>
|
||||||
|
#include <system.h>
|
||||||
|
#include "arith.h"
|
||||||
|
#include "file_info.h"
|
||||||
|
#include "idfsize.h"
|
||||||
|
|
||||||
|
extern char *symbol2str();
|
||||||
|
extern char *getwdir();
|
||||||
|
extern int err_occurred;
|
||||||
|
int idfsize = IDFSIZE;
|
||||||
|
|
||||||
|
arith ifval;
|
||||||
|
|
||||||
|
char *prog_name;
|
||||||
|
|
||||||
|
extern char **inctable;
|
||||||
|
extern int inc_max, inc_total;
|
||||||
|
|
||||||
|
main(argc, argv)
|
||||||
|
char *argv[];
|
||||||
|
{
|
||||||
|
/* parse and interpret the command line options */
|
||||||
|
prog_name = argv[0];
|
||||||
|
|
||||||
|
init_idf();
|
||||||
|
|
||||||
|
inctable = (char **) Malloc(10 * sizeof(char *));
|
||||||
|
inc_max = 10;
|
||||||
|
inc_total = 2;
|
||||||
|
inctable[0] = ".";
|
||||||
|
inctable[1] = "/usr/include";
|
||||||
|
init_pp(); /* initialise the preprocessor macros */
|
||||||
|
|
||||||
|
/* Note: source file "-" indicates that the source is supplied
|
||||||
|
as standard input. This is only allowed if INP_READ_IN_ONE is
|
||||||
|
not defined!
|
||||||
|
*/
|
||||||
|
while (argc > 1 && *argv[1] == '-' && argv[1][1] != '\0') {
|
||||||
|
char *par = &argv[1][1];
|
||||||
|
|
||||||
|
if (*par == '-')
|
||||||
|
par++;
|
||||||
|
do_option(par);
|
||||||
|
argc--, argv++;
|
||||||
|
}
|
||||||
|
compile(argc - 1, &argv[1]);
|
||||||
|
sys_stop(err_occurred ? S_EXIT : S_END);
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
|
||||||
|
compile(argc, argv)
|
||||||
|
char *argv[];
|
||||||
|
{
|
||||||
|
register char *source = 0;
|
||||||
|
char *dummy;
|
||||||
|
|
||||||
|
switch (argc) {
|
||||||
|
case 1:
|
||||||
|
source = argv[0];
|
||||||
|
FileName = source;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
FileName = "";
|
||||||
|
WorkingDir = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FileName = argv[0];
|
||||||
|
fatal("use: %s [options] [source]", prog_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!InsertFile(source, (char **) 0, &dummy)) /* read the source file */
|
||||||
|
fatal("%s: no source file %s\n", prog_name,
|
||||||
|
source ? source : "stdin");
|
||||||
|
if (source) WorkingDir = getwdir(dummy);
|
||||||
|
preprocess(source);
|
||||||
|
}
|
8
lang/cem/cpp.ansi/make.allocd
Executable file
8
lang/cem/cpp.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/cpp.ansi/make.hfiles
Executable file
35
lang/cem/cpp.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/cpp.ansi/make.next
Executable file
3
lang/cem/cpp.ansi/make.next
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
sed -n '
|
||||||
|
s:^.*ALLOCDEF.*"\(.*\)".*$:struct \1 *h_\1 = 0;:p
|
||||||
|
' $*
|
34
lang/cem/cpp.ansi/make.tokcase
Executable file
34
lang/cem/cpp.ansi/make.tokcase
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
cat <<'--EOT--'
|
||||||
|
#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--
|
6
lang/cem/cpp.ansi/make.tokfile
Executable file
6
lang/cem/cpp.ansi/make.tokfile
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
sed '
|
||||||
|
/{[A-Z]/!d
|
||||||
|
s/.*{//
|
||||||
|
s/,.*//
|
||||||
|
s/.*/%token &;/
|
||||||
|
'
|
74
lang/cem/cpp.ansi/nccp.6
Normal file
74
lang/cem/cpp.ansi/nccp.6
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
.TH NCPP 6ACK
|
||||||
|
.ad
|
||||||
|
.SH NAME
|
||||||
|
ncpp \- New C Pre-Processor
|
||||||
|
.SH SYNOPSIS
|
||||||
|
ncpp [\-options] [ file ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.I Ncpp
|
||||||
|
reads a file, expands macros and include
|
||||||
|
files, and writes an input file for the C compiler.
|
||||||
|
All output is to standard output.
|
||||||
|
.br
|
||||||
|
The following options are supported.
|
||||||
|
.IP -\fBI\fIdirectory\fR
|
||||||
|
.br
|
||||||
|
add this directory to the list of
|
||||||
|
directories searched for #include "..." and #include <...>
|
||||||
|
commands. Note that there is no space between the
|
||||||
|
"-I" and the directory string. More than one -I command
|
||||||
|
is permitted.
|
||||||
|
.IP -\fBI\fR
|
||||||
|
end the list of directories to be searched, and also do not look in
|
||||||
|
default places.
|
||||||
|
.IP -\fBD\fIname\fR=\fItext\fR
|
||||||
|
.br
|
||||||
|
define
|
||||||
|
.I name
|
||||||
|
as a macro with
|
||||||
|
.I text
|
||||||
|
as its replacement text.
|
||||||
|
.IP -\fBD\fIname\fR
|
||||||
|
the same as -\fBD\fIname\fR=1.
|
||||||
|
.IP
|
||||||
|
.IP -\fBU\fIname\fR
|
||||||
|
.br
|
||||||
|
undefine the macro name
|
||||||
|
.IR name .
|
||||||
|
.IP -\fBC\fR
|
||||||
|
leave comments in. By default, C-comments are deleted.
|
||||||
|
.IP -\fBP\fR
|
||||||
|
do not generate line directives
|
||||||
|
.IP -\fBM\fIn\fR
|
||||||
|
set maximum identifier length to
|
||||||
|
.IR n .
|
||||||
|
.PP
|
||||||
|
The following names are always available unless undefined:
|
||||||
|
.RS
|
||||||
|
.IP __STDC__
|
||||||
|
A decimal constant 1, indicating that this is an ANSI C conforming
|
||||||
|
implementation.
|
||||||
|
.IP __FILE__
|
||||||
|
The input (or #include) file being compiled
|
||||||
|
(as a quoted string).
|
||||||
|
.IP __LINE__
|
||||||
|
The line number being compiled.
|
||||||
|
.IP __DATE__
|
||||||
|
The date of translation of the source file. This is a string
|
||||||
|
literal of the form "\fBMmm dd yyyy\fP".
|
||||||
|
.IP __TIME__
|
||||||
|
The time of translation of the source file. This is a string
|
||||||
|
literal of the form "\fBhh:mm:ss\fP".
|
||||||
|
.RE
|
||||||
|
.SH BUGS
|
||||||
|
The output may contain extra spaces, this prevents unintended
|
||||||
|
pasting of tokens.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
L. Rosler,
|
||||||
|
.I
|
||||||
|
Draft Proposed Standard - Programming Language C,
|
||||||
|
.R
|
||||||
|
ANSI X3J11 Language Subcommittee
|
||||||
|
.SH AUTHOR
|
||||||
|
Leendert van Doorn
|
||||||
|
|
133
lang/cem/cpp.ansi/options.c
Normal file
133
lang/cem/cpp.ansi/options.c
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||||
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||||
|
*/
|
||||||
|
/* $Header$ */
|
||||||
|
/* USER-OPTION HANDLING */
|
||||||
|
|
||||||
|
#include <alloc.h>
|
||||||
|
#include "idfsize.h"
|
||||||
|
#include "class.h"
|
||||||
|
#include "macro.h"
|
||||||
|
#include "idf.h"
|
||||||
|
|
||||||
|
char options[128]; /* one for every char */
|
||||||
|
int inc_pos = 1; /* place where next -I goes */
|
||||||
|
int inc_max;
|
||||||
|
int inc_total;
|
||||||
|
int debug;
|
||||||
|
char **inctable;
|
||||||
|
|
||||||
|
extern int idfsize;
|
||||||
|
int txt2int();
|
||||||
|
|
||||||
|
do_option(text)
|
||||||
|
char *text;
|
||||||
|
{
|
||||||
|
switch(*text++) {
|
||||||
|
case '-':
|
||||||
|
options[*text] = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("illegal option: %c", text[-1]);
|
||||||
|
break;
|
||||||
|
case 'C' : /* comment output */
|
||||||
|
options['C'] = 1;
|
||||||
|
break;
|
||||||
|
case 'D' : /* -Dname : predefine name */
|
||||||
|
{
|
||||||
|
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, 0), mactext, -1, strlen(mactext), NOFLAG);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'I' : /* -Ipath : insert "path" into include list */
|
||||||
|
if (*text) {
|
||||||
|
register 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) {
|
||||||
|
register char *tmp = inctable[i];
|
||||||
|
|
||||||
|
inctable[i++] = new;
|
||||||
|
new = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else inctable[inc_pos] = 0;
|
||||||
|
break;
|
||||||
|
case 'M': /* maximum identifier length */
|
||||||
|
idfsize = txt2int(&text);
|
||||||
|
if (*text)
|
||||||
|
error("malformed -M option");
|
||||||
|
if (idfsize > IDFSIZE) {
|
||||||
|
warning("maximum identifier length is %d", IDFSIZE);
|
||||||
|
idfsize = IDFSIZE;
|
||||||
|
}
|
||||||
|
if (idfsize < 8) {
|
||||||
|
warning("minimum identifier length is 8");
|
||||||
|
idfsize = 8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'P' : /* run preprocessor stand-alone, without #'s */
|
||||||
|
options['P'] = 1;
|
||||||
|
break;
|
||||||
|
case 'U' : /* -Uname : undefine predefined */
|
||||||
|
if (*text) {
|
||||||
|
register struct idf *idef = findidf(text);
|
||||||
|
|
||||||
|
if (idef && idef->id_macro) {
|
||||||
|
free_macro(idef->id_macro);
|
||||||
|
idef->id_macro = (struct macro *) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
txt2int(tp)
|
||||||
|
char **tp;
|
||||||
|
{
|
||||||
|
/* the integer pointed to by *tp is read, while increasing
|
||||||
|
*tp; the resulting value is yielded.
|
||||||
|
*/
|
||||||
|
register int val = 0;
|
||||||
|
register int ch;
|
||||||
|
|
||||||
|
while (ch = **tp, ch >= '0' && ch <= '9') {
|
||||||
|
val = val * 10 + ch - '0';
|
||||||
|
(*tp)++;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
326
lang/cem/cpp.ansi/preprocess.c
Normal file
326
lang/cem/cpp.ansi/preprocess.c
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
/*
|
||||||
|
* (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 DRIVER */
|
||||||
|
|
||||||
|
#include <system.h>
|
||||||
|
#include "input.h"
|
||||||
|
#include "obufsize.h"
|
||||||
|
#include "arith.h"
|
||||||
|
#include "LLlex.h"
|
||||||
|
#include "class.h"
|
||||||
|
#include "macro.h"
|
||||||
|
#include "idf.h"
|
||||||
|
#include "idfsize.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "line_prefix.h"
|
||||||
|
|
||||||
|
char _obuf[OBUFSIZE];
|
||||||
|
#ifdef DOBITS
|
||||||
|
char bits[128];
|
||||||
|
#endif
|
||||||
|
extern int InputLevel;
|
||||||
|
|
||||||
|
Xflush()
|
||||||
|
{
|
||||||
|
sys_write(STDOUT, _obuf, OBUFSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
preprocess(fn)
|
||||||
|
char *fn;
|
||||||
|
{
|
||||||
|
register int c;
|
||||||
|
register char *op = _obuf;
|
||||||
|
register char *ob = &_obuf[OBUFSIZE];
|
||||||
|
char Xbuf[256];
|
||||||
|
int lineno = 0;
|
||||||
|
extern char options[];
|
||||||
|
|
||||||
|
#define flush(X) (sys_write(STDOUT,_obuf,X))
|
||||||
|
#define echo(ch) if (op == ob) { Xflush(); op = _obuf; } *op++ = (ch);
|
||||||
|
#define newline() echo('\n')
|
||||||
|
|
||||||
|
if (!options['P']) {
|
||||||
|
/* Generate a line directive communicating the
|
||||||
|
source filename
|
||||||
|
*/
|
||||||
|
register char *p = Xbuf;
|
||||||
|
|
||||||
|
sprint(p, "%s 1 \"%s\"\n",
|
||||||
|
LINE_PREFIX,
|
||||||
|
FileName);
|
||||||
|
while (*p) {
|
||||||
|
echo(*p++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define do_line(lineno, fn) \
|
||||||
|
if (lineno != LineNumber || fn != FileName) { \
|
||||||
|
fn = FileName; \
|
||||||
|
lineno = LineNumber; \
|
||||||
|
if (! options['P']) { \
|
||||||
|
register char *p = Xbuf; \
|
||||||
|
\
|
||||||
|
sprint(p, "%s %d \"%s\"\n", \
|
||||||
|
LINE_PREFIX, \
|
||||||
|
LineNumber, \
|
||||||
|
FileName); \
|
||||||
|
while (*p) { \
|
||||||
|
echo(*p++); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
LineNumber++;
|
||||||
|
lineno++;
|
||||||
|
c = GetChar();
|
||||||
|
while (class(c) == STSKIP) {
|
||||||
|
echo(c);
|
||||||
|
c = GetChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (c == '#') {
|
||||||
|
if (!domacro()) { /* pass pragma's to compiler */
|
||||||
|
register char *p = "#pragma";
|
||||||
|
|
||||||
|
do_line(lineno, fn);
|
||||||
|
|
||||||
|
while(*p) {
|
||||||
|
echo(*p++);
|
||||||
|
}
|
||||||
|
while ((c = GetChar()) != EOI) {
|
||||||
|
if (class(c) == STNL) break;
|
||||||
|
echo(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineno++;
|
||||||
|
newline();
|
||||||
|
c = GetChar();
|
||||||
|
while (class(c) == STSKIP) {
|
||||||
|
echo(c);
|
||||||
|
c = GetChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_line(lineno, fn);
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
/* illegal character */
|
||||||
|
if (c & 0200) {
|
||||||
|
if (c == EOI) {
|
||||||
|
newline();
|
||||||
|
flush(op-_obuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fatal("non-ascii character read");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* comments */
|
||||||
|
if (c == '/' && !InputLevel) {
|
||||||
|
c = GetChar();
|
||||||
|
if (c == '*') {
|
||||||
|
NoUnstack++;
|
||||||
|
if (options['C']) {
|
||||||
|
echo('/');
|
||||||
|
echo('*');
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
c = GetChar();
|
||||||
|
if (c == '\n') {
|
||||||
|
++LineNumber;
|
||||||
|
++lineno;
|
||||||
|
echo(c);
|
||||||
|
}
|
||||||
|
else if (c == EOI) {
|
||||||
|
newline();
|
||||||
|
flush(op - _obuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (c == '*') {
|
||||||
|
if (options['C']) {
|
||||||
|
echo(c);
|
||||||
|
}
|
||||||
|
c = GetChar();
|
||||||
|
if (c == '/') {
|
||||||
|
if (options['C']) {
|
||||||
|
echo(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
UnGetChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (options['C']) {
|
||||||
|
echo(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NoUnstack--;
|
||||||
|
c = GetChar();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
echo('/');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* switch on character */
|
||||||
|
switch(class(c)) {
|
||||||
|
case STNL:
|
||||||
|
echo(c);
|
||||||
|
break;
|
||||||
|
case STSTR:
|
||||||
|
case STCHAR:
|
||||||
|
{
|
||||||
|
register int stopc = c;
|
||||||
|
int escaped;
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
escaped = 0;
|
||||||
|
echo(c);
|
||||||
|
c = GetChar();
|
||||||
|
if (c == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (c == EOI) {
|
||||||
|
newline();
|
||||||
|
flush(op-_obuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (c == '\\') {
|
||||||
|
echo(c);
|
||||||
|
c = GetChar();
|
||||||
|
if (c == '\n') {
|
||||||
|
++LineNumber;
|
||||||
|
lineno++;
|
||||||
|
}
|
||||||
|
else if (c == '\'') escaped = 1;
|
||||||
|
}
|
||||||
|
} while (escaped || c != stopc);
|
||||||
|
echo(c);
|
||||||
|
if (c == '\n')
|
||||||
|
break; /* Don't eat # */
|
||||||
|
c = GetChar();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case STNUM:
|
||||||
|
echo(c);
|
||||||
|
if (c == '.') {
|
||||||
|
c = GetChar();
|
||||||
|
if (c == '.') {
|
||||||
|
if ((c = GetChar()) == '.') {
|
||||||
|
echo('.'); echo('.');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
c = '.';
|
||||||
|
continue;
|
||||||
|
} else if (!is_dig(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = GetChar();
|
||||||
|
while (in_idf(c) || c == '.') {
|
||||||
|
echo(c);
|
||||||
|
if (c == 'e' || c == 'E') {
|
||||||
|
c = GetChar();
|
||||||
|
if (c == '+' || c == '-') {
|
||||||
|
echo(c);
|
||||||
|
c = GetChar();
|
||||||
|
}
|
||||||
|
} else c = GetChar();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case STELL:
|
||||||
|
if (c == '"' || c == '\'') {
|
||||||
|
echo(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
c = 'L';
|
||||||
|
case STIDF: {
|
||||||
|
extern int idfsize; /* ??? */
|
||||||
|
char buf[IDFSIZE + 1];
|
||||||
|
register char *tg = &buf[0];
|
||||||
|
register char *maxpos = &buf[idfsize];
|
||||||
|
register struct idf *idef;
|
||||||
|
int NoExpandNext = 0;
|
||||||
|
|
||||||
|
#define tstmac(bx) if (!(bits[c] & bx)) goto nomac
|
||||||
|
#define cpy *tg++ = c
|
||||||
|
#define load c = GetChar(); if (!in_idf(c)) goto endidf
|
||||||
|
|
||||||
|
/* unstack macro's when allowed. */
|
||||||
|
if (Unstacked)
|
||||||
|
EnableMacros();
|
||||||
|
if (c == NOEXPM) {
|
||||||
|
NoExpandNext = 1;
|
||||||
|
c = GetChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DOBITS
|
||||||
|
cpy; tstmac(bit0); load;
|
||||||
|
cpy; tstmac(bit1); load;
|
||||||
|
cpy; tstmac(bit2); load;
|
||||||
|
cpy; tstmac(bit3); load;
|
||||||
|
cpy; tstmac(bit4); load;
|
||||||
|
cpy; tstmac(bit5); load;
|
||||||
|
cpy; tstmac(bit6); load;
|
||||||
|
cpy; tstmac(bit7); load;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
if (tg < maxpos) {
|
||||||
|
cpy;
|
||||||
|
}
|
||||||
|
load;
|
||||||
|
}
|
||||||
|
endidf:
|
||||||
|
if (c != EOF) UnGetChar();
|
||||||
|
*tg = '\0'; /* mark the end of the identifier */
|
||||||
|
if ((idef = findidf(buf))
|
||||||
|
&& idef->id_macro
|
||||||
|
&& ReplaceMacros && !NoExpandNext) {
|
||||||
|
if (replace(idef)) {
|
||||||
|
c = GetChar();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tg = buf;
|
||||||
|
while (*tg) {
|
||||||
|
echo(*tg++);
|
||||||
|
}
|
||||||
|
c = GetChar();
|
||||||
|
if (in_idf(c)) echo(' ');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nomac:
|
||||||
|
*tg = '\0';
|
||||||
|
tg = buf;
|
||||||
|
while (*tg) {
|
||||||
|
echo(*tg++);
|
||||||
|
}
|
||||||
|
c = GetChar();
|
||||||
|
while (in_idf(c)) {
|
||||||
|
echo(c);
|
||||||
|
c = GetChar();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case STMSPEC:
|
||||||
|
if (InputLevel) {
|
||||||
|
echo(' '); /* seperate tokens */
|
||||||
|
c = GetChar();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* else fallthrough */
|
||||||
|
default:
|
||||||
|
echo(c);
|
||||||
|
c = GetChar();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
703
lang/cem/cpp.ansi/replace.c
Normal file
703
lang/cem/cpp.ansi/replace.c
Normal file
|
@ -0,0 +1,703 @@
|
||||||
|
/*
|
||||||
|
* (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 "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 "lapbuf.h"
|
||||||
|
#include "argbuf.h"
|
||||||
|
#include "replace.h"
|
||||||
|
|
||||||
|
extern char *GetIdentifier();
|
||||||
|
extern int InputLevel;
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!(idf->id_macro)) return 0;
|
||||||
|
if (idf->id_macro->mc_flag & NOREPLACE)
|
||||||
|
return 0;
|
||||||
|
repl = new_repl();
|
||||||
|
repl->r_ptr = repl->r_text;
|
||||||
|
repl->r_args = new_args();
|
||||||
|
repl->r_idf = idf;
|
||||||
|
if (!expand_macro(repl, idf))
|
||||||
|
return 0;
|
||||||
|
InputLevel++;
|
||||||
|
InsertText(repl->r_text, repl->r_ptr - repl->r_text);
|
||||||
|
idf->id_macro->mc_flag |= NOREPLACE;
|
||||||
|
repl->r_level = InputLevel;
|
||||||
|
repl->next = ReplaceList;
|
||||||
|
ReplaceList = repl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unstackrepl()
|
||||||
|
{
|
||||||
|
Unstacked++;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnableMacros()
|
||||||
|
{
|
||||||
|
register struct repl *r = ReplaceList, *prev = 0;
|
||||||
|
|
||||||
|
assert(Unstacked > 0);
|
||||||
|
while(r) {
|
||||||
|
struct repl *nxt = r->next;
|
||||||
|
|
||||||
|
if (r->r_level > InputLevel) {
|
||||||
|
r->r_idf->id_macro->mc_flag &= ~NOREPLACE;
|
||||||
|
if (!prev) ReplaceList = nxt;
|
||||||
|
else prev->next = nxt;
|
||||||
|
free_args(r->r_args);
|
||||||
|
free_repl(r);
|
||||||
|
}
|
||||||
|
else prev = r;
|
||||||
|
r = nxt;
|
||||||
|
}
|
||||||
|
Unstacked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
expand_macro(repl, idf)
|
||||||
|
register struct repl *repl;
|
||||||
|
register struct idf *idf;
|
||||||
|
{
|
||||||
|
/* 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.
|
||||||
|
|
||||||
|
A special case is "defined". This acts as a unary operator
|
||||||
|
on a single, unexpanded identifier, which may be surrounded
|
||||||
|
by parenthesis. The function expand_defined() handles this.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
expand_defined(repl);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = GetChar();
|
||||||
|
ch = skipspaces(ch,1);
|
||||||
|
if (ch != '(') { /* no replacement if no () */
|
||||||
|
UnGetChar();
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
getactuals(repl, idf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mac->mc_flag & FUNC) /* this macro leads to special action */
|
||||||
|
macro_func(idf);
|
||||||
|
|
||||||
|
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.
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^ tsk tsk tsk
|
||||||
|
*/
|
||||||
|
if (*repl->r_ptr != TOKSEP) *repl->r_ptr++ = TOKSEP;
|
||||||
|
*repl->r_ptr = '\0';
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
expand_defined(repl)
|
||||||
|
register struct repl *repl;
|
||||||
|
{
|
||||||
|
register int ch = GetChar();
|
||||||
|
struct idf *id;
|
||||||
|
char *str;
|
||||||
|
int parens = 0;
|
||||||
|
|
||||||
|
ch = skipspaces(ch, 0);
|
||||||
|
|
||||||
|
if (ch == '(') {
|
||||||
|
parens++;
|
||||||
|
ch = GetChar();
|
||||||
|
ch = skipspaces(ch, 0);
|
||||||
|
}
|
||||||
|
if ((class(ch) != STIDF) && (class(ch) != STELL)) {
|
||||||
|
error("identifier missing");
|
||||||
|
if (parens && ch != ')') error(") missing");
|
||||||
|
if (!parens || ch != ')') UnGetChar();
|
||||||
|
*repl->r_ptr++ = '0';
|
||||||
|
*repl->r_ptr = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
str = GetIdentifier(0);
|
||||||
|
if (str)
|
||||||
|
id = str2idf(str, 0);
|
||||||
|
else id = 0;
|
||||||
|
assert(id || class(ch) == STELL);
|
||||||
|
ch = GetChar();
|
||||||
|
ch = skipspaces(ch, 0);
|
||||||
|
if (parens && ch != ')') error(") missing");
|
||||||
|
if (!parens || ch != ')') UnGetChar();
|
||||||
|
*repl->r_ptr++ = (id && id->id_macro) ? '1' : '0';
|
||||||
|
*repl->r_ptr = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
getactuals(repl, idf)
|
||||||
|
struct repl *repl;
|
||||||
|
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 struct args *args = repl->r_args;
|
||||||
|
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()) != ')') {
|
||||||
|
UnGetChar();
|
||||||
|
while ((ch = actual(repl)) != ')' ) {
|
||||||
|
if (ch != ',') {
|
||||||
|
error("illegal macro call");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stash(repl, '\0', 1);
|
||||||
|
++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(repl, '\0', 1);
|
||||||
|
++argcnt;
|
||||||
|
}
|
||||||
|
if (argcnt < nps)
|
||||||
|
error("too few macro arguments");
|
||||||
|
else if (argcnt > nps)
|
||||||
|
error("too many macro arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
saveraw(repl)
|
||||||
|
struct repl *repl;
|
||||||
|
{
|
||||||
|
register struct repl *nrepl = ReplaceList;
|
||||||
|
register struct args *ap = nrepl->r_args;
|
||||||
|
struct args *args = repl->r_args;
|
||||||
|
register char *p;
|
||||||
|
|
||||||
|
/* stash identifier name */
|
||||||
|
for (p = nrepl->r_idf->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-1) = ')'; /* delete last ',' */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
actual(repl)
|
||||||
|
struct repl *repl;
|
||||||
|
{
|
||||||
|
/* This routine deals with the scanning of an actual parameter.
|
||||||
|
It keeps in account the opening and closing brackets,
|
||||||
|
preprocessor numbers, strings and character constants.
|
||||||
|
*/
|
||||||
|
register int ch;
|
||||||
|
register int level = 0, nostashraw = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ch = GetChar();
|
||||||
|
|
||||||
|
if (Unstacked) {
|
||||||
|
nostashraw -= Unstacked;
|
||||||
|
if (nostashraw < 0) nostashraw = 0;
|
||||||
|
EnableMacros();
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
extern int idfsize;
|
||||||
|
int NoExpandMacro;
|
||||||
|
|
||||||
|
if (ch == NOEXPM) {
|
||||||
|
NoExpandMacro= 1;
|
||||||
|
ch = GetChar();
|
||||||
|
} else NoExpandMacro = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (++pos < idfsize) {
|
||||||
|
*p++ = ch;
|
||||||
|
}
|
||||||
|
ch = GetChar();
|
||||||
|
} while (in_idf(ch));
|
||||||
|
*p++ = '\0';
|
||||||
|
UnGetChar();
|
||||||
|
|
||||||
|
/* When the identifier has an associated macro
|
||||||
|
replacement list, it's expanded.
|
||||||
|
*/
|
||||||
|
idef = findidf(buf);
|
||||||
|
if (!idef || NoExpandMacro || !replace(idef)) {
|
||||||
|
if (NoExpandMacro
|
||||||
|
|| (idef && idef->id_macro
|
||||||
|
&& (idef->id_macro->mc_flag & NOREPLACE)))
|
||||||
|
stash(repl, NOEXPM, !nostashraw);
|
||||||
|
for (p = buf; *p != '\0'; p++)
|
||||||
|
stash(repl, *p, !nostashraw);
|
||||||
|
} else {
|
||||||
|
if (!nostashraw) saveraw(repl);
|
||||||
|
nostashraw++;
|
||||||
|
}
|
||||||
|
} else if (class(ch) == STNUM) {
|
||||||
|
/* a preprocessing number has the following
|
||||||
|
regular expression:
|
||||||
|
[0-9|"."[0-9]]{[0-9"."a-zA-Z_]|{[Ee][+-]}}*
|
||||||
|
*/
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
if (ch == '.') {
|
||||||
|
ch = GetChar();
|
||||||
|
if (class(ch) != STNUM) {
|
||||||
|
UnGetChar();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else stash(repl, ch, !nostashraw);
|
||||||
|
}
|
||||||
|
ch = GetChar();
|
||||||
|
while (in_idf(ch) || ch == '.') {
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
if ((ch = GetChar()) == 'e' || ch == 'E') {
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
ch = GetChar();
|
||||||
|
if (ch == '+' || ch == '-') {
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
ch = GetChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
} else if (ch == '(' || ch == '[' || ch == '{') {
|
||||||
|
/* a comma may occur within these constructions ???
|
||||||
|
*/
|
||||||
|
level++;
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
} else if (ch == ')' || ch == ']' || ch == '}') {
|
||||||
|
level--;
|
||||||
|
/* clossing parenthesis of macro call */
|
||||||
|
if (ch == ')' && level < 0)
|
||||||
|
return ')';
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
} else if (ch == ',') {
|
||||||
|
if (level <= 0) { /* comma separator for next argument */
|
||||||
|
if (level)
|
||||||
|
error("unbalanced parenthesis");
|
||||||
|
if (!nostashraw)
|
||||||
|
return ','; /* ??? */
|
||||||
|
}
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
} else if (ch == '\n') {
|
||||||
|
/* newlines are accepted as white spaces */
|
||||||
|
LineNumber++;
|
||||||
|
while ((ch = GetChar()), class(ch) == STSKIP)
|
||||||
|
/* EMPTY */;
|
||||||
|
|
||||||
|
/* 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();
|
||||||
|
else if (ch == EOI) {
|
||||||
|
error("unterminated macro call");
|
||||||
|
return ')';
|
||||||
|
}
|
||||||
|
UnGetChar();
|
||||||
|
stash(repl, ' ', !nostashraw);
|
||||||
|
} else if (ch == '/') {
|
||||||
|
/* comments are treated as one white space token */
|
||||||
|
if ((ch = GetChar()) == '*' && !InputLevel) {
|
||||||
|
skipcomment();
|
||||||
|
stash(repl, ' ', !nostashraw);
|
||||||
|
} else {
|
||||||
|
UnGetChar();
|
||||||
|
stash(repl, '/', !nostashraw);
|
||||||
|
}
|
||||||
|
} else if (ch == '\'' || ch == '"') {
|
||||||
|
/* Strings are considered as ONE token, thus no
|
||||||
|
replacement within strings.
|
||||||
|
*/
|
||||||
|
register int match = ch;
|
||||||
|
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
while ((ch = GetChar()) != EOI) {
|
||||||
|
if (ch == match)
|
||||||
|
break;
|
||||||
|
if (ch == '\\') {
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
ch = GetChar();
|
||||||
|
} else if (ch == '\n') {
|
||||||
|
error("newline in string");
|
||||||
|
LineNumber++;
|
||||||
|
stash(repl, match, !nostashraw);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
}
|
||||||
|
if (ch != match) {
|
||||||
|
error("unterminated macro call");
|
||||||
|
return ')';
|
||||||
|
}
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
} else
|
||||||
|
stash(repl, ch, !nostashraw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = strlen(mac->mc_text);
|
||||||
|
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;
|
||||||
|
register char *tmpptr;
|
||||||
|
int err = 0;
|
||||||
|
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') {
|
||||||
|
error("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
|
||||||
|
&& is_wsp(*repl->r_text)) {
|
||||||
|
err = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(*repl->r_ptr == TOKSEP
|
||||||
|
&& repl->r_ptr >= repl->r_text)
|
||||||
|
--repl->r_ptr;
|
||||||
|
|
||||||
|
tmpptr = repl->r_ptr;
|
||||||
|
++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];
|
||||||
|
if (p) { /* else macro argument missing */
|
||||||
|
while (is_wsp(*p))
|
||||||
|
p++;
|
||||||
|
if (*p == NOEXPM) p++;
|
||||||
|
while (*p)
|
||||||
|
*repl->r_ptr++ = *p++;
|
||||||
|
}
|
||||||
|
if (in_idf(*tmpptr + 1)) {
|
||||||
|
while (in_idf(*tmpptr)
|
||||||
|
&& tmpptr >= repl->r_text)
|
||||||
|
tmpptr--;
|
||||||
|
if (*tmpptr == NOEXPM) *tmpptr = TOKSEP;
|
||||||
|
}
|
||||||
|
} else if (*ptr == '\0') {
|
||||||
|
err = 1;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (in_idf(*ptr)) {
|
||||||
|
while (in_idf(*tmpptr)
|
||||||
|
&& tmpptr >= repl->r_text)
|
||||||
|
tmpptr--;
|
||||||
|
if (*tmpptr == NOEXPM) *tmpptr = TOKSEP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else /* # operator */
|
||||||
|
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++)
|
||||||
|
/* EMPTY */;
|
||||||
|
if (*p == '#' && p[1] == '#')
|
||||||
|
q = args->a_rawvec[n-1];
|
||||||
|
else
|
||||||
|
q = args->a_expvec[n-1];
|
||||||
|
|
||||||
|
p = repl->r_ptr;
|
||||||
|
if (q) /* else macro argument missing */
|
||||||
|
while (*q)
|
||||||
|
*repl->r_ptr++ = *q++;
|
||||||
|
|
||||||
|
if (*repl->r_ptr != TOKSEP)
|
||||||
|
*repl->r_ptr++ = TOKSEP;
|
||||||
|
} else
|
||||||
|
*repl->r_ptr++ = *ptr++;
|
||||||
|
}
|
||||||
|
*repl->r_ptr = '\0';
|
||||||
|
if (err)
|
||||||
|
error("illegal use of ## operator");
|
||||||
|
}
|
||||||
|
|
||||||
|
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_rawvec[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++ = '\\';
|
||||||
|
if (*p == TOKSEP || *p == NOEXPM) p++;
|
||||||
|
else *repl->r_ptr++ = *p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* trim spaces in the replacement list */
|
||||||
|
for (--repl->r_ptr; is_wsp(*repl->r_ptr); repl->r_ptr--)
|
||||||
|
/* EMPTY */;
|
||||||
|
*++repl->r_ptr = '"';
|
||||||
|
++repl->r_ptr; /* oops, one to far */
|
||||||
|
} else
|
||||||
|
error("illegal use of # operator");
|
||||||
|
*repl->r_ptr = '\0';
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
stash(repl, ch, stashraw)
|
||||||
|
struct repl *repl;
|
||||||
|
register int ch;
|
||||||
|
int stashraw;
|
||||||
|
{
|
||||||
|
/* Stash characters into the macro expansion buffer.
|
||||||
|
*/
|
||||||
|
register struct args *args = repl->r_args;
|
||||||
|
|
||||||
|
if (args->a_expptr >= &(args->a_expbuf[ARGBUF]))
|
||||||
|
fatal("macro argument buffer overflow");
|
||||||
|
*args->a_expptr++ = ch;
|
||||||
|
|
||||||
|
if (stashraw) {
|
||||||
|
if (args->a_rawptr >= &(args->a_rawbuf[ARGBUF]))
|
||||||
|
fatal("raw macro argument buffer overflow");
|
||||||
|
*args->a_rawptr++ = ch;
|
||||||
|
}
|
||||||
|
}
|
48
lang/cem/cpp.ansi/replace.str
Normal file
48
lang/cem/cpp.ansi/replace.str
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||||
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||||
|
*/
|
||||||
|
/* $Header$ */
|
||||||
|
/* DEFINITIONS FOR THE MACRO REPLACEMENT ROUTINES */
|
||||||
|
|
||||||
|
struct repl {
|
||||||
|
struct repl *next;
|
||||||
|
struct idf *r_idf; /* name of the macro */
|
||||||
|
struct args *r_args; /* replacement parameters */
|
||||||
|
int r_level; /* level of insertion */
|
||||||
|
char *r_ptr; /* replacement text pointer */
|
||||||
|
char r_text[LAPBUF]; /* replacement text */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
77
lang/cem/cpp.ansi/skip.c
Normal file
77
lang/cem/cpp.ansi/skip.c
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* (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 "arith.h"
|
||||||
|
#include "LLlex.h"
|
||||||
|
#include "class.h"
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
extern int InputLevel;
|
||||||
|
|
||||||
|
int
|
||||||
|
skipspaces(ch, skipnl)
|
||||||
|
register int ch;
|
||||||
|
{
|
||||||
|
/* skipspaces() skips any white space and returns the first
|
||||||
|
non-space character.
|
||||||
|
*/
|
||||||
|
register int nlseen = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
while (class(ch) == STSKIP)
|
||||||
|
ch = GetChar();
|
||||||
|
if (skipnl && class(ch) == STNL) {
|
||||||
|
ch = GetChar();
|
||||||
|
LineNumber++;
|
||||||
|
nlseen++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch == TOKSEP && InputLevel) {
|
||||||
|
ch = GetChar();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* \\\n are handled by trigraph */
|
||||||
|
|
||||||
|
if (ch == '/') {
|
||||||
|
ch = GetChar();
|
||||||
|
if (ch == '*' && !InputLevel) {
|
||||||
|
skipcomment();
|
||||||
|
ch = GetChar();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
UnGetChar();
|
||||||
|
return '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (nlseen && ch == '#') {
|
||||||
|
domacro();
|
||||||
|
ch = GetChar();
|
||||||
|
} else
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SkipToNewLine(garbage)
|
||||||
|
int garbage;
|
||||||
|
{
|
||||||
|
register int ch;
|
||||||
|
register int pstrict = 0;
|
||||||
|
|
||||||
|
while ((ch = GetChar()) != '\n') {
|
||||||
|
if (ch == '/') {
|
||||||
|
if ((ch = GetChar()) == '*' && !InputLevel) {
|
||||||
|
skipcomment();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (garbage && !is_wsp(ch))
|
||||||
|
pstrict = 1;
|
||||||
|
}
|
||||||
|
++LineNumber;
|
||||||
|
return pstrict;
|
||||||
|
}
|
72
lang/cem/cpp.ansi/tokenname.c
Normal file
72
lang/cem/cpp.ansi/tokenname.c
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||||
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||||
|
*/
|
||||||
|
/* $Header$ */
|
||||||
|
/* TOKEN NAME DEFINITIONS */
|
||||||
|
|
||||||
|
#include "idf.h"
|
||||||
|
#include "arith.h"
|
||||||
|
#include "LLlex.h"
|
||||||
|
#include "Lpars.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct tokenname { /* Used for defining the name of a
|
||||||
|
token as identified by its symbol
|
||||||
|
*/
|
||||||
|
int tn_symbol;
|
||||||
|
char *tn_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* To centralize the declaration of %tokens, their presence in this
|
||||||
|
file is taken as their declaration. The Makefile will produce
|
||||||
|
a grammar file (tokenfile.g) from this file.
|
||||||
|
Moreover, rather than looking up a symbol in all these lists
|
||||||
|
to find its printable name, a fast version of symbol2str() is
|
||||||
|
generated from these tables.
|
||||||
|
Consequenty some of these tables are not referenced explicitly
|
||||||
|
in the C text any more. To save space and to avoid lint confusion,
|
||||||
|
these have been made pseudo-invisible by #ifdefs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef ____
|
||||||
|
struct tokenname tkspec[] = { /* the names of the special tokens */
|
||||||
|
{IDENTIFIER, "identifier"},
|
||||||
|
{STRING, "string"},
|
||||||
|
{FILESPECIFIER, "filespecifier"},
|
||||||
|
{INTEGER, "integer"},
|
||||||
|
{0, ""}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tokenname tkcomp[] = { /* names of the composite tokens */
|
||||||
|
{PLUSAB, "+="},
|
||||||
|
{MINAB, "-="},
|
||||||
|
{TIMESAB, "*="},
|
||||||
|
{DIVAB, "/="},
|
||||||
|
{MODAB, "%="},
|
||||||
|
{LEFTAB, "<<="},
|
||||||
|
{RIGHTAB, ">>="},
|
||||||
|
{ANDAB, "&="},
|
||||||
|
{XORAB, "^="},
|
||||||
|
{ORAB, "|="},
|
||||||
|
{NOTEQUAL, "!="},
|
||||||
|
{AND, "&&"},
|
||||||
|
{PLUSPLUS, "++"},
|
||||||
|
{MINMIN, "--"},
|
||||||
|
{ARROW, "->"},
|
||||||
|
{LEFT, "<<"},
|
||||||
|
{LESSEQ, "<="},
|
||||||
|
{EQUAL, "=="},
|
||||||
|
{GREATEREQ, ">="},
|
||||||
|
{RIGHT, ">>"},
|
||||||
|
{OR, "||"},
|
||||||
|
{ELLIPSIS, "..."},
|
||||||
|
{0, ""}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tokenname tkfunny[] = { /* internal keywords */
|
||||||
|
{ERRONEOUS, "erroneous"},
|
||||||
|
{0, ""}
|
||||||
|
};
|
||||||
|
#endif ____
|
Loading…
Reference in a new issue