Merge from default.

This commit is contained in:
David Given 2018-09-09 18:58:07 +02:00
commit ee328a0572
28 changed files with 2054 additions and 4025 deletions

15
.drone.yml Normal file
View file

@ -0,0 +1,15 @@
clone:
depth: 10
build:
image: teaci/msys32
pull: true
shell: $$arch
commands:
- if [ $$arch = sh ]; then apt update; apt install build-essential bison flex; fi
- make PREFIX=/tmp/acki +ack
matrix:
arch:
- sh
#- msys32

View file

@ -15,8 +15,8 @@ ACK_TEMP_DIR = /tmp
# install it and just want to run the ACK from the build directory # install it and just want to run the ACK from the build directory
# (/tmp/ack-build/staging, by default), leave this as $(INSDIR). # (/tmp/ack-build/staging, by default), leave this as $(INSDIR).
#PREFIX = /usr/local PREFIX = /usr/local
PREFIX = $(INSDIR) #PREFIX = $(INSDIR)
# Where do you want to put the object files used when building? # Where do you want to put the object files used when building?

View file

@ -111,10 +111,6 @@
#define INP_READ_IN_ONE 1 /* read input file in one */ #define INP_READ_IN_ONE 1 /* read input file in one */
!File: nopp.h
/*#define NOPP 1 /* if NOT defined, use built-int preprocessor */
!File: nobitfield.h !File: nobitfield.h
/*#define NOBITFIELD 1 /* if NOT defined, implement bitfields */ /*#define NOBITFIELD 1 /* if NOT defined, implement bitfields */

View file

@ -22,18 +22,11 @@
/* Data about the token yielded */ /* Data about the token yielded */
struct token dot, ahead, aside; struct token dot, ahead, aside;
int token_nmb = 0; /* number of the ahead token */ int token_nmb = 0; /* number of the ahead token */
int tk_nmb_at_last_syn_err = -5/*ERR_SHADOW*/; int tk_nmb_at_last_syn_err = -5 /*ERR_SHADOW*/;
/* token number at last syntax error */ /* token number at last syntax error */
int idfsize = IDFSIZE; int idfsize = IDFSIZE;
char sp_occurred[SP_TOTAL+1]; char sp_occurred[SP_TOTAL + 1];
#ifndef NOPP
int ReplaceMacros = 1; /* replacing macros */
int AccDefined = 0; /* accept "defined(...)" */
int UnknownIdIsZero = 0; /* interpret unknown id as integer 0 */
int Unstacked = 0; /* an unstack is done */
extern int InputLevel;
#endif
int AccFileSpecifier = 0; /* return filespecifier <...> */ int AccFileSpecifier = 0; /* return filespecifier <...> */
int EoiForNewline = 0; /* return EOI upon encountering newline */ int EoiForNewline = 0; /* return EOI upon encountering newline */
int File_Inserted = 0; /* a file has just been inserted */ int File_Inserted = 0; /* a file has just been inserted */
@ -48,44 +41,19 @@ extern arith full_mask[];
extern int lint_skip_comment; extern int lint_skip_comment;
#endif #endif
#ifndef NOPP int LLlex()
static struct token LexStack[MAX_LL_DEPTH];
static LexSP = 0;
void skipcomment();
/* In PushLex() the actions are taken in order to initialise or
re-initialise the lexical scanner.
E.g. at the invocation of a sub-parser that uses LLlex(), the
state of the current parser should be saved.
*/
PushLex()
{
assert(LexSP < MAX_LL_DEPTH);
assert(ASIDE == 0); /* ASIDE = 0; */
GetToken(&ahead);
LexStack[LexSP++] = dot;
}
PopLex()
{
assert(LexSP > 0);
dot = LexStack[--LexSP];
}
#endif /* NOPP */
int
LLlex()
{ {
/* LLlex() plays the role of Lexical Analyzer for the C parser. /* LLlex() plays the role of Lexical Analyzer for the C parser.
The look-ahead and putting aside of tokens are taken into The look-ahead and putting aside of tokens are taken into
account. account.
*/ */
if (ASIDE) { /* a token is put aside */ if (ASIDE)
{ /* a token is put aside */
dot = aside; dot = aside;
ASIDE = 0; ASIDE = 0;
} }
else { /* read ahead and return the old one */ else
{ /* read ahead and return the old one */
#ifdef LINT #ifdef LINT
lint_comment_ahead(); lint_comment_ahead();
#endif /* LINT */ #endif /* LINT */
@ -104,13 +72,10 @@ LLlex()
return DOT; return DOT;
} }
char* string_token();
char *string_token();
arith char_constant(); arith char_constant();
int int GetToken(ptok) register struct token* ptok;
GetToken(ptok)
register struct token *ptok;
{ {
/* GetToken() is the actual token recognizer. It calls the /* GetToken() is the actual token recognizer. It calls the
control line interpreter if it encounters a "\n{w}*#" control line interpreter if it encounters a "\n{w}*#"
@ -122,7 +87,8 @@ GetToken(ptok)
token_nmb++; token_nmb++;
if (File_Inserted) { if (File_Inserted)
{
File_Inserted = 0; File_Inserted = 0;
goto firstline; goto firstline;
} }
@ -138,9 +104,10 @@ go_on: /* rescan, the following character has been read */
ptok->tk_file = FileName; ptok->tk_file = FileName;
ptok->tk_line = LineNumber; ptok->tk_line = LineNumber;
switch (class(ch)) { /* detect character class */ switch (class(ch))
{ /* detect character class */
case STNL: /* newline, vertical space or formfeed */ case STNL: /* newline, vertical space or formfeed */
firstline: firstline:
LineNumber++; /* also at vs and ff */ LineNumber++; /* also at vs and ff */
ptok->tk_file = FileName; ptok->tk_file = FileName;
ptok->tk_line = LineNumber; ptok->tk_line = LineNumber;
@ -150,29 +117,14 @@ firstline:
*/ */
return ptok->tk_symb = EOI; return ptok->tk_symb = EOI;
while ((ch = GetChar()), while ((ch = GetChar()), (ch == '#'
(ch == '#' || class(ch) == STSKIP))
#ifndef NOPP {
|| ch == '/'
#endif
|| class(ch) == STSKIP)) {
/* blanks are allowed before hashes */ /* blanks are allowed before hashes */
if (ch == '#') { if (ch == '#')
{
/* a control line follows */ /* a control line follows */
domacro(); domacro();
#ifndef NOPP
if (File_Inserted) {
File_Inserted = 0;
goto firstline;
}
} else if (ch == '/') {
if ((GetChar() == '*') && !InputLevel) {
skipcomment();
} else {
UnGetChar();
break;
}
#endif /* NOPP */
} }
} }
/* We have to loop here, because in /* We have to loop here, because in
@ -183,12 +135,12 @@ firstline:
case STSKIP: /* just skip the skip characters */ case STSKIP: /* just skip the skip characters */
goto again; goto again;
case STGARB: /* garbage character */ case STGARB: /* garbage character */
#ifndef NOPP if (040 < ch && ch < 0177)
garbage: {
#endif
if (040 < ch && ch < 0177) {
return ptok->tk_symb = ch; return ptok->tk_symb = ch;
} else { }
else
{
lexerror("garbage char \\%03o", ch); lexerror("garbage char \\%03o", ch);
} }
goto again; goto again;
@ -196,7 +148,8 @@ garbage:
return ptok->tk_symb = ch; return ptok->tk_symb = ch;
case STCOMP: /* maybe the start of a compound token */ case STCOMP: /* maybe the start of a compound token */
nch = GetChar(); /* character lookahead */ nch = GetChar(); /* character lookahead */
switch (ch) { switch (ch)
{
case '!': case '!':
if (nch == '=') if (nch == '=')
return ptok->tk_symb = NOTEQUAL; return ptok->tk_symb = NOTEQUAL;
@ -222,13 +175,14 @@ garbage:
return ptok->tk_symb = MINAB; return ptok->tk_symb = MINAB;
break; break;
case '<': case '<':
if (AccFileSpecifier) { if (AccFileSpecifier)
{
UnGetChar(); /* pushback nch */ UnGetChar(); /* pushback nch */
ptok->tk_bts = string_token("file specifier", ptok->tk_bts = string_token("file specifier", '>', &(ptok->tk_len));
'>', &(ptok->tk_len));
return ptok->tk_symb = FILESPECIFIER; return ptok->tk_symb = FILESPECIFIER;
} }
if (nch == '<') { if (nch == '<')
{
if ((nch = GetChar()) == '=') if ((nch = GetChar()) == '=')
return ptok->tk_symb = LEFTAB; return ptok->tk_symb = LEFTAB;
UnGetChar(); UnGetChar();
@ -244,7 +198,8 @@ garbage:
case '>': case '>':
if (nch == '=') if (nch == '=')
return ptok->tk_symb = GREATEREQ; return ptok->tk_symb = GREATEREQ;
if (nch == '>') { if (nch == '>')
{
if ((nch = GetChar()) == '=') if ((nch = GetChar()) == '=')
return ptok->tk_symb = RIGHTAB; return ptok->tk_symb = RIGHTAB;
UnGetChar(); UnGetChar();
@ -270,12 +225,6 @@ garbage:
return ptok->tk_symb = XORAB; return ptok->tk_symb = XORAB;
break; break;
case '/': case '/':
#ifndef NOPP
if (nch == '*' && !InputLevel) {
skipcomment();
goto again;
}
#endif
if (nch == '=') if (nch == '=')
return ptok->tk_symb = DIVAB; return ptok->tk_symb = DIVAB;
break; break;
@ -295,12 +244,14 @@ garbage:
return ptok->tk_symb = STRING; return ptok->tk_symb = STRING;
case STELL: /* wide character constant/string prefix */ case STELL: /* wide character constant/string prefix */
nch = GetChar(); nch = GetChar();
if (nch == '"') { if (nch == '"')
ptok->tk_bts = string_token("wide character string", {
'"', &(ptok->tk_len)); ptok->tk_bts = string_token("wide character string", '"', &(ptok->tk_len));
ptok->tk_fund = WCHAR; /* string of wide characters */ ptok->tk_fund = WCHAR; /* string of wide characters */
return ptok->tk_symb = STRING; return ptok->tk_symb = STRING;
} else if (nch == '\'') { }
else if (nch == '\'')
{
ptok->tk_ival = char_constant("wide character"); ptok->tk_ival = char_constant("wide character");
ptok->tk_fund = INT; ptok->tk_fund = INT;
return ptok->tk_symb = INTEGER; return ptok->tk_symb = INTEGER;
@ -309,21 +260,14 @@ garbage:
/* fallthrough */ /* fallthrough */
case STIDF: case STIDF:
{ {
register char *tg = &buf[0]; register char* tg = &buf[0];
register int pos = -1; register int pos = -1;
register struct idf *idef; register struct idf* idef;
extern int idfsize; /* ??? */ extern int idfsize; /* ??? */
#ifndef NOPP do
int NoExpandNext = 0; { /* read the identifier */
if (++pos < idfsize)
if (Unstacked) EnableMacros(); /* unstack macro's when allowed. */ {
if (ch == NOEXPM) {
NoExpandNext = 1;
ch = GetChar();
}
#endif
do { /* read the identifier */
if (++pos < idfsize) {
*tg++ = ch; *tg++ = ch;
} }
ch = GetChar(); ch = GetChar();
@ -336,48 +280,40 @@ garbage:
sp_occurred[idef->id_special] = 1; sp_occurred[idef->id_special] = 1;
idef->id_file = ptok->tk_file; idef->id_file = ptok->tk_file;
idef->id_line = ptok->tk_line; idef->id_line = ptok->tk_line;
#ifndef NOPP ptok->tk_symb
if (idef->id_macro && ReplaceMacros && !NoExpandNext) { = (idef->id_reserved
if (replace(idef))
goto again;
}
if (UnknownIdIsZero && idef->id_reserved != SIZEOF) {
ptok->tk_ival = (arith)0;
ptok->tk_fund = INT;
return ptok->tk_symb = INTEGER;
}
#endif /* NOPP */
ptok->tk_symb = (
idef->id_reserved
? idef->id_reserved ? idef->id_reserved
: idef->id_def && idef->id_def->df_sc == TYPEDEF : idef->id_def && idef->id_def->df_sc == TYPEDEF ? TYPE_IDENTIFIER
? TYPE_IDENTIFIER : IDENTIFIER);
: IDENTIFIER
);
return IDENTIFIER; return IDENTIFIER;
} }
case STNUM: /* a numeric constant */ case STNUM: /* a numeric constant */
{ {
register int siz_left = NUMSIZE - 1; register int siz_left = NUMSIZE - 1;
register char *np = &buf[0]; register char* np = &buf[0];
int flags = 0; int flags = 0;
#define store(ch) if (--siz_left >= 0) \ #define store(ch) \
if (--siz_left >= 0) \
*np++ = ch; *np++ = ch;
if (ch == '.') { if (ch == '.')
{
/* An embarrasing ambiguity. We have either a /* An embarrasing ambiguity. We have either a
pp-number, a field operator, an ELLIPSIS or pp-number, a field operator, an ELLIPSIS or
an error (..). an error (..).
*/ */
ch = GetChar(); ch = GetChar();
if (!is_dig(ch)) { /* . or ... */ if (!is_dig(ch))
if (ch == '.') { { /* . or ... */
if (ch == '.')
{
if ((ch = GetChar()) == '.') if ((ch = GetChar()) == '.')
return ptok->tk_symb = ELLIPSIS; return ptok->tk_symb = ELLIPSIS;
UnGetChar(); /* not '.' */ UnGetChar(); /* not '.' */
ChPushBack('.'); /* sigh ... */ ChPushBack('.'); /* sigh ... */
} else }
else
UnGetChar(); /* not '.' */ UnGetChar(); /* not '.' */
return ptok->tk_symb = '.'; return ptok->tk_symb = '.';
} }
@ -387,31 +323,37 @@ garbage:
} }
store(ch); store(ch);
ch = GetChar(); ch = GetChar();
while(in_idf(ch) || ch == '.') { while (in_idf(ch) || ch == '.')
{
store(ch); store(ch);
if (ch == '.') flags |= FLG_DOTSEEN; if (ch == '.')
if (ch == 'e' || ch == 'E') { flags |= FLG_DOTSEEN;
if (ch == 'e' || ch == 'E')
{
flags |= FLG_ESEEN; flags |= FLG_ESEEN;
ch = GetChar(); ch = GetChar();
if (ch == '+' || ch == '-') { if (ch == '+' || ch == '-')
{
flags |= FLG_DOTSEEN; /* trick */ flags |= FLG_DOTSEEN; /* trick */
store(ch); store(ch);
ch = GetChar(); ch = GetChar();
} }
} else ch = GetChar(); }
else
ch = GetChar();
} }
store('\0'); store('\0');
UnGetChar(); UnGetChar();
np = &buf[0]; np = &buf[0];
ch = *np++; ch = *np++;
if (siz_left < 0) { if (siz_left < 0)
{
lexerror("number too long"); lexerror("number too long");
if ((flags & FLG_DOTSEEN) if ((flags & FLG_DOTSEEN)
|| (flags & FLG_ESEEN || (flags & FLG_ESEEN && !(ch == '0' && (*np == 'x' || *np == 'X'))))
&& !(ch == '0' {
&& (*np == 'x' || *np == 'X')))) { ptok->tk_fval = Salloc("0.0", (unsigned)4);
ptok->tk_fval = Salloc("0.0", (unsigned) 4);
ptok->tk_fund = DOUBLE; ptok->tk_fund = DOUBLE;
return ptok->tk_symb = FLOATING; return ptok->tk_symb = FLOATING;
} }
@ -421,8 +363,8 @@ garbage:
} }
/* Now, the pp-number must be converted into a token */ /* Now, the pp-number must be converted into a token */
if ((flags & FLG_DOTSEEN) if ((flags & FLG_DOTSEEN)
|| (flags & FLG_ESEEN || (flags & FLG_ESEEN && !(ch == '0' && (*np == 'x' || *np == 'X'))))
&& !(ch == '0' && (*np == 'x' || *np == 'X')))) { {
strflt2tok(&buf[0], ptok); strflt2tok(&buf[0], ptok);
return ptok->tk_symb = FLOATING; return ptok->tk_symb = FLOATING;
} }
@ -431,77 +373,13 @@ garbage:
} }
case STEOI: /* end of text on source file */ case STEOI: /* end of text on source file */
return ptok->tk_symb = EOI; return ptok->tk_symb = EOI;
#ifndef NOPP
case STMSPEC:
if (!InputLevel) goto garbage;
if (ch == TOKSEP) goto again;
/* fallthrough shouldn't happen */
#endif
default: /* this cannot happen */ default: /* this cannot happen */
crash("bad class for char 0%o", ch); crash("bad class for char 0%o", ch);
} }
/*NOTREACHED*/ /*NOTREACHED*/
} }
#ifndef NOPP arith char_constant(nm) char* nm;
void
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, oldc = '\0';
NoUnstack++;
c = GetChar();
#ifdef LINT
if (! lint_skip_comment) {
lint_start_comment();
lint_comment_char(c);
}
#endif /* LINT */
do {
while (c != '*') {
if (class(c) == STNL) {
++LineNumber;
} else if (c == EOI) {
NoUnstack--;
#ifdef LINT
if (! lint_skip_comment) lint_end_comment();
#endif /* LINT */
return;
}
oldc = c;
c = GetChar();
#ifdef LINT
if (! lint_skip_comment) lint_comment_char(c);
#endif /* LINT */
} /* last Character seen was '*' */
c = GetChar();
if ( c != '/' && oldc == '/')
lexwarning("comment inside comment ?");
oldc = '*';
#ifdef LINT
if (! lint_skip_comment) lint_comment_char(c);
#endif /* LINT */
} while (c != '/');
#ifdef LINT
if (! lint_skip_comment) lint_end_comment();
#endif /* LINT */
NoUnstack--;
}
#endif /* NOPP */
arith
char_constant(nm)
char *nm;
{ {
register arith val = 0; register arith val = 0;
register int ch; register int ch;
@ -511,15 +389,18 @@ char_constant(nm)
if (ch == '\'') if (ch == '\'')
lexerror("%s constant too short", nm); lexerror("%s constant too short", nm);
else else
while (ch != '\'') { while (ch != '\'')
if (ch == '\n') { {
if (ch == '\n')
{
lexerror("newline in %s constant", nm); lexerror("newline in %s constant", nm);
LineNumber++; LineNumber++;
break; break;
} }
if (ch == '\\') if (ch == '\\')
ch = quoted(GetChar()); ch = quoted(GetChar());
if (ch >= 128) ch -= 256; if (ch >= 128)
ch -= 256;
if (size < (int)int_size) if (size < (int)int_size)
val |= ch << 8 * size; val |= ch << 8 * size;
size++; size++;
@ -532,24 +413,25 @@ char_constant(nm)
return val; return val;
} }
char * char* string_token(nm, stop_char, plen) char* nm;
string_token(nm, stop_char, plen) int* plen;
char *nm;
int *plen;
{ {
register int ch; register int ch;
register int str_size; register int str_size;
register char *str = Malloc((unsigned) (str_size = ISTRSIZE)); register char* str = Malloc((unsigned)(str_size = ISTRSIZE));
register int pos = 0; register int pos = 0;
ch = GetChar(); ch = GetChar();
while (ch != stop_char) { while (ch != stop_char)
if (ch == '\n') { {
if (ch == '\n')
{
lexerror("newline in %s", nm); lexerror("newline in %s", nm);
LineNumber++; LineNumber++;
break; break;
} }
if (ch == EOI) { if (ch == EOI)
{
lexerror("end-of-file inside %s", nm); lexerror("end-of-file inside %s", nm);
break; break;
} }
@ -557,7 +439,7 @@ string_token(nm, stop_char, plen)
ch = quoted(GetChar()); ch = quoted(GetChar());
str[pos++] = ch; str[pos++] = ch;
if (pos == str_size) if (pos == str_size)
str = Realloc(str, (unsigned) (str_size += RSTRSIZE)); str = Realloc(str, (unsigned)(str_size += RSTRSIZE));
ch = GetChar(); ch = GetChar();
} }
str[pos++] = '\0'; /* for filenames etc. */ str[pos++] = '\0'; /* for filenames etc. */
@ -565,16 +447,16 @@ string_token(nm, stop_char, plen)
return str; return str;
} }
int int quoted(ch) register int ch;
quoted(ch)
register int ch;
{ {
/* quoted() replaces an escaped character sequence by the /* quoted() replaces an escaped character sequence by the
character meant. character meant.
*/ */
/* first char after backslash already in ch */ /* first char after backslash already in ch */
if (!is_oct(ch)) { /* a quoted char */ if (!is_oct(ch))
switch (ch) { { /* a quoted char */
switch (ch)
{
case 'n': case 'n':
ch = '\n'; ch = '\n';
break; break;
@ -601,7 +483,8 @@ quoted(ch)
register int hex = 0; register int hex = 0;
register int vch; register int vch;
for (;;) { for (;;)
{
ch = GetChar(); ch = GetChar();
if ((vch = hex_val(ch)) == -1) if ((vch = hex_val(ch)) == -1)
break; break;
@ -612,166 +495,115 @@ quoted(ch)
} }
} }
} }
else { /* a quoted octal */ else
{ /* a quoted octal */
register int oct = 0, cnt = 0; register int oct = 0, cnt = 0;
do { do
oct = oct*8 + (ch-'0'); {
oct = oct * 8 + (ch - '0');
ch = GetChar(); ch = GetChar();
} while (is_oct(ch) && ++cnt < 3); } while (is_oct(ch) && ++cnt < 3);
UnGetChar(); UnGetChar();
ch = oct; ch = oct;
} }
return ch&0377; return ch & 0377;
} }
int hex_val(ch) register int ch;
int
hex_val(ch)
register int ch;
{ {
return is_dig(ch) ? ch - '0' return is_dig(ch) ? ch - '0' : is_hex(ch) ? (ch - 'a' + 10) & 017 : -1;
: is_hex(ch) ? (ch - 'a' + 10) & 017
: -1;
} }
int GetChar()
int
GetChar()
{ {
/* The routines GetChar and trigraph parses the trigraph /* The routines GetChar and trigraph parses the trigraph
sequences and removes occurences of \\\n. sequences and removes occurences of \\\n.
*/ */
register int ch; register int ch;
#ifndef NOPP
again:
#endif
LoadChar(ch); LoadChar(ch);
return (LexSave = ch);
#ifndef NOPP
/* possible trigraph sequence */
if (ch == '?')
ch = trigraph();
/* \<newline> is removed from the input stream */
if (ch == '\\') {
LoadChar(ch);
if (ch == '\n') {
++LineNumber;
goto again;
}
PushBack();
ch = '\\';
}
#endif
return(LexSave = ch);
} }
#ifndef NOPP
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('?');
}
#endif
/* strflt2tok only checks the syntax of the floating-point number and /* strflt2tok only checks the syntax of the floating-point number and
* selects the right type for the number. * selects the right type for the number.
*/ */
strflt2tok(fltbuf, ptok) strflt2tok(fltbuf, ptok) char fltbuf[];
char fltbuf[]; struct token* ptok;
struct token *ptok;
{ {
register char *cp = fltbuf; register char* cp = fltbuf;
int malformed = 0; int malformed = 0;
while (is_dig(*cp)) cp++; while (is_dig(*cp))
if (*cp == '.') { cp++;
if (*cp == '.')
{
cp++;
while (is_dig(*cp))
cp++; cp++;
while (is_dig(*cp)) cp++;
} }
if (*cp == 'e' || *cp == 'E') { if (*cp == 'e' || *cp == 'E')
{
cp++; cp++;
if (*cp == '+' || *cp == '-') if (*cp == '+' || *cp == '-')
cp++; cp++;
if (!is_dig(*cp)) malformed++; if (!is_dig(*cp))
while (is_dig(*cp)) cp++; malformed++;
while (is_dig(*cp))
cp++;
} }
if (*cp == 'f' || *cp == 'F') { if (*cp == 'f' || *cp == 'F')
if (*(cp + 1)) malformed++; {
if (*(cp + 1))
malformed++;
*cp = '\0'; *cp = '\0';
ptok->tk_fund = FLOAT; ptok->tk_fund = FLOAT;
} else if (*cp == 'l' || *cp == 'L') { }
if (*(cp + 1)) malformed++; else if (*cp == 'l' || *cp == 'L')
{
if (*(cp + 1))
malformed++;
*cp = '\0'; *cp = '\0';
ptok->tk_fund = LNGDBL; ptok->tk_fund = LNGDBL;
} else { }
if (*cp) malformed++; else
{
if (*cp)
malformed++;
ptok->tk_fund = DOUBLE; ptok->tk_fund = DOUBLE;
} }
if (malformed) { if (malformed)
{
lexerror("malformed floating constant"); lexerror("malformed floating constant");
ptok->tk_fval = Salloc("0.0", (unsigned) 4); ptok->tk_fval = Salloc("0.0", (unsigned)4);
} else { }
ptok->tk_fval = Salloc(fltbuf, (unsigned) (cp - fltbuf + 1)); else
{
ptok->tk_fval = Salloc(fltbuf, (unsigned)(cp - fltbuf + 1));
} }
} }
strint2tok(intbuf, ptok) strint2tok(intbuf, ptok) char intbuf[];
char intbuf[]; struct token* ptok;
struct token *ptok;
{ {
register char *cp = intbuf; register char* cp = intbuf;
int base = 10; int base = 10;
arith val = 0, dig, ubound; arith val = 0, dig, ubound;
int uns_flg = 0, lng_flg = 0, malformed = 0, ovfl = 0; int uns_flg = 0, lng_flg = 0, malformed = 0, ovfl = 0;
int fund; int fund;
assert(*cp != '-'); assert(*cp != '-');
if (*cp == '0') { if (*cp == '0')
{
cp++; cp++;
if (*cp == 'x' || *cp == 'X') { if (*cp == 'x' || *cp == 'X')
{
cp++; cp++;
base = 16; base = 16;
} else base = 8; }
else
base = 8;
} }
/* The upperbound will be the same as when computed with /* The upperbound will be the same as when computed with
* max_unsigned_arith / base (since base is even). The problem here * max_unsigned_arith / base (since base is even). The problem here
@ -779,68 +611,99 @@ struct token *ptok;
*/ */
ubound = max_arith / (base / 2); ubound = max_arith / (base / 2);
while (is_hex(*cp)) { while (is_hex(*cp))
{
dig = hex_val(*cp); dig = hex_val(*cp);
if (dig >= base) { if (dig >= base)
{
malformed++; /* ignore */ malformed++; /* ignore */
} }
else { else
if (val < 0 || val > ubound) ovfl++; {
if (val < 0 || val > ubound)
ovfl++;
val *= base; val *= base;
if (val < 0 && val + dig >= 0) ovfl++; if (val < 0 && val + dig >= 0)
ovfl++;
val += dig; val += dig;
} }
cp++; cp++;
} }
while (*cp) { while (*cp)
if (*cp == 'l' || *cp == 'L') lng_flg++; {
else if (*cp == 'u' || *cp == 'U') uns_flg++; if (*cp == 'l' || *cp == 'L')
else break; lng_flg++;
else if (*cp == 'u' || *cp == 'U')
uns_flg++;
else
break;
cp++; cp++;
} }
if (*cp) { if (*cp)
{
malformed++; malformed++;
} }
if (malformed) { if (malformed)
lexerror("malformed %s integer constant", {
(base == 10 ? "decimal" lexerror(
: (base == 8 ? "octal" "malformed %s integer constant",
: "hexadecimal"))); (base == 10 ? "decimal" : (base == 8 ? "octal" : "hexadecimal")));
} else { }
else
{
if (lng_flg > 1) if (lng_flg > 1)
lexerror("only one long suffix allowed"); lexerror("only one long suffix allowed");
if (uns_flg > 1) if (uns_flg > 1)
lexerror("only one unsigned suffix allowed"); lexerror("only one unsigned suffix allowed");
} }
if (ovfl) { if (ovfl)
{
lexwarning("overflow in constant"); lexwarning("overflow in constant");
fund = ULONG; fund = ULONG;
} else if (!lng_flg && (val & full_mask[(int)int_size]) == val) { }
if (val >= 0 && val <= max_int) { else if (!lng_flg && (val & full_mask[(int)int_size]) == val)
{
if (val >= 0 && val <= max_int)
{
fund = INT; fund = INT;
} else if (int_size == long_size) { }
else if (int_size == long_size)
{
fund = UNSIGNED; fund = UNSIGNED;
} else if (base == 10 && !uns_flg) }
else if (base == 10 && !uns_flg)
fund = LONG; fund = LONG;
else fund = UNSIGNED; else
} else if((val & full_mask[(int)long_size]) == val) { fund = UNSIGNED;
if (val >= 0) fund = LONG; }
else fund = ULONG; else if ((val & full_mask[(int)long_size]) == val)
} else { /* sizeof(arith) is greater than long_size */ {
if (val >= 0)
fund = LONG;
else
fund = ULONG;
}
else
{ /* sizeof(arith) is greater than long_size */
assert(arith_size > long_size); assert(arith_size > long_size);
lexwarning("constant too large for target machine"); lexwarning("constant too large for target machine");
/* cut the size to prevent further complaints */ /* cut the size to prevent further complaints */
val &= full_mask[(int)long_size]; val &= full_mask[(int)long_size];
fund = ULONG; fund = ULONG;
} }
if (lng_flg) { if (lng_flg)
{
/* fund can't be INT */ /* fund can't be INT */
if (fund == UNSIGNED) fund = ULONG; if (fund == UNSIGNED)
fund = ULONG;
} }
if (uns_flg) { if (uns_flg)
if (fund == INT) fund = UNSIGNED; {
else if (fund == LONG) fund = ULONG; if (fund == INT)
fund = UNSIGNED;
else if (fund == LONG)
fund = ULONG;
} }
ptok->tk_fund = fund; ptok->tk_fund = fund;
ptok->tk_ival = val; ptok->tk_ival = val;

View file

@ -43,12 +43,6 @@ extern struct token dot, ahead, aside;
extern int token_nmb; /* number of the ahead token */ extern int token_nmb; /* number of the ahead token */
extern int tk_nmb_at_last_syn_err; /* token number at last syntax error */ extern int tk_nmb_at_last_syn_err; /* token number at last syntax error */
#ifndef NOPP
extern int ReplaceMacros; /* "LLlex.c" */
extern int AccDefined; /* "LLlex.c" */
extern int Unstacked; /* "LLlex.c" */
extern int UnknownIdIsZero; /* "LLlex.c" */
#endif /* NOPP */
extern int EoiForNewline; /* "LLlex.c" */ extern int EoiForNewline; /* "LLlex.c" */
extern int AccFileSpecifier; /* "LLlex.c" */ extern int AccFileSpecifier; /* "LLlex.c" */
extern int File_Inserted; /* "LLlex.c" */ extern int File_Inserted; /* "LLlex.c" */

View file

@ -111,10 +111,6 @@
/*#define INP_READ_IN_ONE 1 /* read input file in one */ /*#define INP_READ_IN_ONE 1 /* read input file in one */
!File: nopp.h
#define NOPP 1 /* if NOT defined, use built-int preprocessor */
!File: nobitfield.h !File: nobitfield.h
/*#define NOBITFIELD 1 /* if NOT defined, implement bitfields */ /*#define NOBITFIELD 1 /* if NOT defined, implement bitfields */

View file

@ -111,7 +111,6 @@ cprogram {
"./field.c", "./field.c",
"./fltcstoper.c", "./fltcstoper.c",
"./idf.c", "./idf.c",
"./init.c",
"./input.c", "./input.c",
"./l_comment.c", "./l_comment.c",
"./l_ev_ord.c", "./l_ev_ord.c",
@ -124,7 +123,6 @@ cprogram {
"./options.c", "./options.c",
"./pragma.c", "./pragma.c",
"./proto.c", "./proto.c",
"./replace.c",
"./skip.c", "./skip.c",
"./stab.c", "./stab.c",
"./stack.c", "./stack.c",

View file

@ -14,12 +14,7 @@
#include "LLlex.h" #include "LLlex.h"
#include "Lpars.h" #include "Lpars.h"
#include "input.h" #include "input.h"
#include "replace.h"
#ifndef NOPP
#include <alloc.h>
#include "class.h"
#include "macro.h"
#ifdef DBSYMTAB #ifdef DBSYMTAB
#include <stb.h> #include <stb.h>
#include <em.h> #include <em.h>
@ -27,775 +22,8 @@ int IncludeLevel = 0;
#endif #endif
extern char options[]; extern char options[];
extern char **inctable; /* list of include directories */
extern char *getwdir();
char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */
/* 1 if a corresponding ELSE has been */
/* encountered. */
int nestlevel = -1; struct idf* GetIdentifier(skiponerr) int skiponerr; /* skip the rest of the line on error */
void macro_def();
void do_define();
struct idf *
GetIdentifier(skiponerr)
int skiponerr; /* skip the rest of the line on error */
{
/* returns a pointer to the descriptor of the identifier that is
read from the input stream. When the input doe 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.
*/
int tmp = UnknownIdIsZero;
int tok;
struct token tk;
UnknownIdIsZero = ReplaceMacros = 0;
tok = GetToken(&tk);
ReplaceMacros = 1;
UnknownIdIsZero = tmp;
if (tok != IDENTIFIER) {
if (skiponerr && tok != EOI) SkipToNewLine();
return (struct idf *)0;
}
return tk.tk_idf;
}
/* domacro() is the control line interpreter. The '#' has already
been read by the lexical analyzer by which domacro() is called.
The token appearing directly after the '#' is obtained by calling
the basic lexical analyzing function GetToken() and is interpreted
to perform the action belonging to that token.
An error message is produced when the token is not recognized,
i.e. it is not one of "define" .. "undef" , integer or newline.
*/
domacro()
{
struct token tk; /* the token itself */
int toknum;
EoiForNewline = 1;
ReplaceMacros = 0;
toknum = GetToken(&tk);
ReplaceMacros = 1;
switch(toknum) { /* select control line action */
case IDENTIFIER: /* is it a macro keyword? */
switch (tk.tk_idf->id_resmac) {
case K_DEFINE: /* "define" */
do_define();
break;
case K_ELIF: /* "elif" */
do_elif();
break;
case K_ELSE: /* "else" */
do_else();
break;
case K_ENDIF: /* "endif" */
do_endif();
break;
case K_IF: /* "if" */
do_if();
break;
case K_IFDEF: /* "ifdef" */
do_ifdef(1);
break;
case K_IFNDEF: /* "ifndef" */
do_ifdef(0);
break;
case K_INCLUDE: /* "include" */
do_include();
break;
case K_LINE: /* "line" */
/* set LineNumber and FileName according to
the arguments.
*/
if (GetToken(&tk) != INTEGER) {
lexerror("bad #line syntax");
SkipToNewLine();
}
else
do_line((unsigned int)tk.tk_ival);
break;
case K_ERROR: /* "error" */
do_error();
break;
case K_PRAGMA: /* "pragma" */
do_pragma();
break;
case K_UNDEF: /* "undef" */
do_undef((struct idf *) 0);
break;
default:
/* invalid word seen after the '#' */
lexerror("%s: unknown control", tk.tk_idf->id_text);
SkipToNewLine();
}
break;
case INTEGER: /* # <integer> [<filespecifier>]? */
do_line((unsigned int)tk.tk_ival);
break;
case EOI: /* only `#' on this line: do nothing, ignore */
break;
default: /* invalid token following '#' */
lexerror("illegal # line");
SkipToNewLine();
}
EoiForNewline = 0;
}
#ifdef LINT
int lint_skip_comment;
#endif
void
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;
#ifdef LINT
lint_skip_comment++;
#endif
NoUnstack++;
for (;;) {
ch = GetChar(); /* read first character after newline */
while (class(ch) == STSKIP)
ch = GetChar();
if (ch != '#') {
if (ch == EOI) {
NoUnstack--;
#ifdef LINT
lint_skip_comment--;
#endif
return;
}
/* A possible '/' is not pushed back */
if (ch == '/') {
ch = GetChar();
if (ch != '*') UnGetChar();
else {
skipcomment();
continue;
}
} else UnGetChar();
SkipToNewLine();
continue;
}
ReplaceMacros = 0;
toknum = GetToken(&tk);
ReplaceMacros = 1;
if (toknum != IDENTIFIER) {
if (toknum != INTEGER) {
lexerror("illegal # line");
}
SkipToNewLine();
continue;
}
/* an IDENTIFIER: look for #if, #ifdef and #ifndef
without interpreting them.
Interpret #else, #elif and #endif if they occur
on the same level.
*/
switch(tk.tk_idf->id_resmac) {
default:
case K_UNKNOWN:
/* invalid word seen after the '#' */
lexwarning("%s: unknown control", tk.tk_idf->id_text);
/* fallthrough */
case K_DEFINE:
case K_ERROR:
case K_INCLUDE:
case K_LINE:
case K_PRAGMA:
case K_UNDEF:
case K_FILE:
SkipToNewLine();
break;
case K_IF:
case K_IFDEF:
case K_IFNDEF:
push_if();
SkipToNewLine();
break;
case K_ELIF:
if (ifstack[nestlevel])
lexerror("#elif after #else");
if (!to_endif && nestlevel == skiplevel) {
nestlevel--;
push_if();
if (ifexpr()) {
NoUnstack--;
#ifdef LINT
lint_skip_comment--;
#endif
return;
}
}
else SkipToNewLine(); /* otherwise done in ifexpr() */
break;
case K_ELSE:
if (ifstack[nestlevel])
lexerror("#else after #else");
++(ifstack[nestlevel]);
if (!to_endif && nestlevel == skiplevel) {
if (SkipToNewLine()) {
if (!options['o'])
lexstrict("garbage following #else");
}
NoUnstack--;
#ifdef LINT
lint_skip_comment--;
#endif
return;
}
else SkipToNewLine();
break;
case K_ENDIF:
assert(nestlevel > nestlow);
if (nestlevel == skiplevel) {
if (SkipToNewLine()) {
if (!options['o'])
lexstrict("garbage following #endif");
}
nestlevel--;
NoUnstack--;
#ifdef LINT
lint_skip_comment--;
#endif
return;
}
else SkipToNewLine();
nestlevel--;
break;
}
}
}
ifexpr()
{
/* ifexpr() returns whether the restricted constant
expression following #if or #elif evaluates to true. This
is done by calling the LLgen generated subparser for
constant expressions. The result of this expression will
be given in the extern long variable "ifval".
*/
extern arith ifval;
int errors = err_occurred;
ifval = (arith)0;
AccDefined = 1;
UnknownIdIsZero = 1;
PushLex(); /* NEW parser */
If_expr(); /* invoke constant expression parser */
PopLex(); /* OLD parser */
AccDefined = 0;
UnknownIdIsZero = 0;
return (errors == err_occurred) && (ifval != (arith)0);
}
do_include()
{
/* do_include() performs the inclusion of a file.
*/
char *filenm;
char *result;
int tok;
struct token tk;
AccFileSpecifier = 1;
if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
filenm = tk.tk_bts;
else {
lexerror("bad include syntax");
filenm = (char *)0;
}
AccFileSpecifier = 0;
if (SkipToNewLine()) {
lexerror("bad include syntax");
}
inctable[0] = WorkingDir;
if (filenm) {
if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
lexerror("cannot open include file \"%s\"", filenm);
add_dependency(filenm);
free(filenm);
}
else {
add_dependency(result);
WorkingDir = getwdir(result);
File_Inserted = 1;
FileName = result;
LineNumber = 0;
nestlow = nestlevel;
#ifdef DBSYMTAB
IncludeLevel++;
if (options['g']) {
C_ms_stb_cst(FileName, N_BINCL, 0, (arith) 0);
}
#endif /* DBSYMTAB */
if (result != filenm) free(filenm);
}
}
}
void
do_define()
{
/* do_define() interprets a #define control line.
*/
struct idf *id; /* the #defined identifier's descriptor */
int nformals = -1; /* keep track of the number of formals */
char *formals[NPARAMS]; /* pointers to the names of the formals */
char parbuf[PARBUFSIZE]; /* names of formals */
char *repl_text; /* start of the replacement text */
int length; /* length of the replacement text */
register ch;
char *get_text();
/* read the #defined macro's name */
if (!(id = GetIdentifier(1))) {
lexerror("illegal #define line");
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();
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);
/* UnGetChar() is not right when replacement starts with a '/' */
ChPushBack(ch);
repl_text = get_text((nformals > 0) ? formals : 0, &length);
macro_def(id, repl_text, nformals, length, NOFLAG);
LineNumber++;
}
push_if()
{
if (nestlevel >= IFDEPTH)
fatal("too many nested #if/#ifdef/#ifndef");
else
ifstack[++nestlevel] = 0;
}
do_elif()
{
if (nestlevel <= nestlow) {
lexerror("#elif without corresponding #if");
SkipToNewLine();
}
else { /* restart at this level as if a #if is detected. */
if (ifstack[nestlevel]) {
lexerror("#elif after #else");
SkipToNewLine();
}
nestlevel--;
push_if();
skip_block(1);
}
}
do_else()
{
if (SkipToNewLine())
if (!options['o'])
lexstrict("garbage following #else");
if (nestlevel <= nestlow)
lexerror("#else without corresponding #if");
else { /* mark this level as else-d */
if (ifstack[nestlevel]) {
lexerror("#else after #else");
}
++(ifstack[nestlevel]);
skip_block(1);
}
}
do_endif()
{
if (SkipToNewLine()) {
if (!options['o'])
lexstrict("garbage following #endif");
}
if (nestlevel <= nestlow) {
lexerror("#endif without corresponding #if");
}
else nestlevel--;
}
do_if()
{
push_if();
if (!ifexpr()) /* a false #if/#elif expression */
skip_block(0);
}
do_ifdef(how)
{
register struct idf *id;
/* how == 1 : ifdef; how == 0 : ifndef
*/
push_if();
if (!(id = GetIdentifier(1)))
lexerror("illegal #ifdef construction");
else if (SkipToNewLine())
if (!options['o'])
lexstrict("garbage following #%s <identifier>",
how ? "ifdef" : "ifndef");
/* 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);
}
/* argidf != NULL when the undef came from a -U option */
do_undef(argidf)
struct idf *argidf;
{
register struct idf *id = argidf;
/* Forget a macro definition. */
if (id || (id = GetIdentifier(1))) {
if (id->id_macro) { /* forget the macro */
if (id->id_macro->mc_flag & NOUNDEF) {
lexerror("it is not allowed to undef %s", id->id_text);
} else {
free(id->id_macro->mc_text);
free_macro(id->id_macro);
id->id_macro = (struct macro *) 0;
}
} /* else: don't complain */
if (!argidf) {
if (SkipToNewLine())
if (!options['o'])
lexstrict("garbage following #undef");
}
}
else
lexerror("illegal #undef construction");
}
do_error()
{
int len;
char *get_text();
char *bp = get_text((char **) 0, &len);
lexerror("user error: %s", bp);
free(bp);
LineNumber++;
}
int
getparams(buf, parbuf)
char *buf[];
char parbuf[];
{
/* getparams() reads the formal parameter list of a macro
definition.
The number of parameters is returned.
As a formal parameter list is expected when calling this
routine, -1 is returned if an error is detected, for
example:
#define one(1), where 1 is not an identifier.
Note that the '(' has already been eaten.
The names of the formal parameters are stored into parbuf.
*/
register char **pbuf = &buf[0];
register int c;
register char *ptr = &parbuf[0];
register char **pbuf2;
c = GetChar();
c = skipspaces(c,0);
if (c == ')') { /* no parameters: #define name() */
*pbuf = (char *) 0;
return 0;
}
for (;;) { /* eat the formal parameter list */
if (class(c) != STIDF && class(c) != STELL) {
lexerror("#define: bad formal parameter");
return -1;
}
*pbuf = ptr; /* name of the formal */
*ptr++ = c;
if (ptr >= &parbuf[PARBUFSIZE])
fatal("formal parameter buffer overflow");
do { /* eat the identifier name */
c = GetChar();
*ptr++ = c;
if (ptr >= &parbuf[PARBUFSIZE])
fatal("formal parameter buffer overflow");
} while (in_idf(c));
*(ptr - 1) = '\0'; /* mark end of the name */
/* Check if this formal parameter is already used.
Usually, macros do not have many parameters, so ...
*/
for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--) {
if (!strcmp(*pbuf2, *pbuf)) {
lexerror("formal parameter \"%s\" already used",
*pbuf);
}
}
pbuf++;
c = skipspaces(c,0);
if (c == ')') { /* end of the formal parameter list */
*pbuf = (char *) 0;
return pbuf - buf;
}
if (c != ',') {
lexerror("#define: bad formal parameter list");
return -1;
}
c = GetChar();
c = skipspaces(c,0);
}
/*NOTREACHED*/
}
void
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) {
lexerror("it is not allowed to redefine %s", id->id_text);
} else if (!macroeq(newdef->mc_text, text))
lexerror("illegal redefine of \"%s\"", id->id_text);
free(text);
return;
}
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;
}
#define BLANK(ch) ((ch == ' ') || (ch == '\t'))
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 interested in
1- white space, sequences must be mapped onto 1 single
blank.
2- identifiers, since they might be replaced by some
actual parameter.
3- strings and character constants, since replacing
variables within them is illegal, and white-space is
significant.
4- comment, same as for 1
Other tokens will not be seen as such.
*/
register int c;
struct repl repls;
register struct repl *repl = &repls;
int blank = 0;
c = GetChar();
repl->r_ptr = repl->r_text = Malloc(repl->r_size = ITEXTSIZE);
*repl->r_ptr = '\0';
while ((c != EOI) && (class(c) != STNL)) {
if (BLANK(c)) {
blank++;
c = GetChar();
continue;
}
if (c == '\'' || c == '"') {
register int delim = c;
if (blank) {
blank = 0;
add2repl(repl, ' ');
}
do {
add2repl(repl, c);
if (c == '\\') add2repl(repl, GetChar());
c = GetChar();
} while (c != delim && c != EOI && class(c) != STNL);
if (c == EOI || class(c) == STNL) {
lexstrict("unclosed opening %c", delim);
break;
}
add2repl(repl, c);
c = GetChar();
} else if (c == '/') {
c = GetChar();
if (c == '*') {
skipcomment();
blank++;
c = GetChar();
continue;
}
if (blank) {
blank = 0;
add2repl(repl, ' ');
}
add2repl(repl, '/');
} else if (formals
&& (class(c) == STIDF || class(c) == STELL)) {
char id_buf[IDFSIZE + 1];
register char *idp = id_buf;
int n;
/* read identifier: it may be a formal parameter */
*idp++ = c;
do {
c = GetChar();
if (idp <= &id_buf[IDFSIZE])
*idp++ = c;
} while (in_idf(c));
*--idp = '\0';
if (blank) {
blank = 0;
add2repl(repl, ' ');
}
/* construct the formal parameter mark or identifier */
if (n = find_name(id_buf, formals))
add2repl(repl, FORMALP | (char) n);
else {
idp = id_buf;
while (*idp) add2repl(repl, *idp++);
}
} else if (class(c) == STNUM) {
if (blank) {
blank = 0;
add2repl(repl, ' ');
}
add2repl(repl, c);
if (c == '.') {
c = GetChar();
if (class(c) != STNUM) {
continue;
}
add2repl(repl, c);
}
c = GetChar();
while(in_idf(c) || c == '.') {
add2repl(repl, c);
if((c = GetChar()) == 'e' || c == 'E') {
add2repl(repl, c);
c = GetChar();
if (c == '+' || c == '-') {
add2repl(repl, c);
c = GetChar();
}
}
}
} else {
if (blank) {
blank = 0;
add2repl(repl, ' ');
}
add2repl(repl, c);
c = GetChar();
}
}
*length = repl->r_ptr - repl->r_text;
return Realloc(repl->r_text, (unsigned)(repl->r_ptr - repl->r_text +1));
}
/* macroeq() decides whether two macro replacement texts are
identical. This version compares the texts, which occur
as strings, without taking care of the leading and trailing
blanks (spaces and tabs).
*/
macroeq(s, t)
register char *s, *t;
{
/* skip leading spaces */
while (BLANK(*s)) s++;
while (BLANK(*t)) t++;
/* first non-blank encountered in both strings */
/* The actual comparison loop: */
while (*s && *s == *t)
s++, t++;
/* two cases are possible when arrived here: */
if (*s == '\0') { /* *s == '\0' */
while (BLANK(*t)) t++;
return *t == '\0';
}
else { /* *s != *t */
while (BLANK(*s)) s++;
while (BLANK(*t)) t++;
return (*s == '\0') && (*t == '\0');
}
}
#else /* NOPP */
struct idf *
GetIdentifier(skiponerr)
int skiponerr; /* skip the rest of the line on error */
{ {
/* returns a pointer to the descriptor of the identifier that is /* returns a pointer to the descriptor of the identifier that is
read from the input stream. When the input does not contain read from the input stream. When the input does not contain
@ -807,9 +35,11 @@ GetIdentifier(skiponerr)
struct token tk; struct token tk;
tok = GetToken(&tk); tok = GetToken(&tk);
if (tok != IDENTIFIER) { if (tok != IDENTIFIER)
if (skiponerr && tok != EOI) SkipToNewLine(); {
return (struct idf *)0; if (skiponerr && tok != EOI)
SkipToNewLine();
return (struct idf*)0;
} }
return tk.tk_idf; return tk.tk_idf;
} }
@ -820,14 +50,18 @@ domacro()
struct token tk; struct token tk;
EoiForNewline = 1; EoiForNewline = 1;
if ((tok = GetToken(&tk)) == IDENTIFIER) { if ((tok = GetToken(&tk)) == IDENTIFIER)
if (! strcmp(tk.tk_idf->id_text, "pragma")) { {
if (!strcmp(tk.tk_idf->id_text, "pragma"))
{
do_pragma(); do_pragma();
EoiForNewline = 0; EoiForNewline = 0;
return; return;
} }
} else if (tok == INTEGER) { }
do_line((unsigned int) tk.tk_ival); else if (tok == INTEGER)
{
do_line((unsigned int)tk.tk_ival);
EoiForNewline = 0; EoiForNewline = 0;
return; return;
} }
@ -835,24 +69,24 @@ domacro()
EoiForNewline = 0; EoiForNewline = 0;
SkipToNewLine(); SkipToNewLine();
} }
#endif /* NOPP */
do_line(l) unsigned int l;
do_line(l)
unsigned int l;
{ {
struct token tk; struct token tk;
int t = GetToken(&tk); int t = GetToken(&tk);
if (t != EOI) SkipToNewLine(); if (t != EOI)
SkipToNewLine();
LineNumber = l; /* the number of the next input line */ LineNumber = l; /* the number of the next input line */
if (t == STRING) { /* is there a filespecifier? */ if (t == STRING)
/* { /* is there a filespecifier? */
/*
* Do not attempt to free the old string, since it might * Do not attempt to free the old string, since it might
* be used in a def structure. * be used in a def structure.
*/ */
#ifdef DBSYMTAB #ifdef DBSYMTAB
if (options['g'] && strcmp(FileName, tk.tk_bts) != 0) { if (options['g'] && strcmp(FileName, tk.tk_bts) != 0)
{
C_ms_std(tk.tk_bts, N_SOL, 0); C_ms_std(tk.tk_bts, N_SOL, 0);
} }
#endif /* DBSYMTAB */ #endif /* DBSYMTAB */

View file

@ -106,15 +106,6 @@ dumpidf(idf, opt)
if (!idf) if (!idf)
return; return;
#ifndef NOPP
if ((opt&1) && idf->id_macro) {
if (!started++) {
newline();
print("%s:", idf->id_text);
}
print(" macro");
}
#endif /* NOPP */
if ((opt&2) && idf->id_reserved) { if ((opt&2) && idf->id_reserved) {
if (!started++) { if (!started++) {
newline(); newline();

View file

@ -8,10 +8,6 @@
#include "parameters.h" #include "parameters.h"
struct id_u { struct id_u {
#ifndef NOPP
struct macro *idd_macro;
int idd_resmac; /* if nonzero: keyword of macroproc. */
#endif /* NOPP */
int idd_reserved; /* non-zero for reserved words */ int idd_reserved; /* non-zero for reserved words */
char *idd_file; /* file containing the occurrence */ char *idd_file; /* file containing the occurrence */
unsigned int idd_line; /* line number of the occurrence */ unsigned int idd_line; /* line number of the occurrence */
@ -36,14 +32,5 @@ struct id_u {
#include <idf_pkg.spec> #include <idf_pkg.spec>
#ifndef NOPP
struct dependency {
struct dependency *next;
struct idf *dep_idf;
};
/* ALLOCDEF "dependency" 10 */
#endif /* NOPP */
extern int level; extern int level;
extern struct idf *gen_idf(); extern struct idf *gen_idf();

View file

@ -1,99 +0,0 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Id$ */
/* PREPROCESSOR: INITIALIZATION ROUTINES */
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "parameters.h"
#ifndef NOPP
#include <system.h>
#include <alloc.h>
#include <time.h>
#include "idf.h"
#include "class.h"
#include "macro.h"
extern char *sprint();
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}
};
init_pp()
{
static char *months[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
time_t clock;
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, 0);
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 = time(NULL);
tp = localtime(&clock);
/* __DATE__ */
sprint(dbuf, "\"%s %02d %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__ */
sprint(tbuf, "\"%02d:%02d:%02d\"", 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);
}
#endif /* NOPP */

View file

@ -18,50 +18,10 @@ struct file_info finfo;
#include <inp_pkg.body> #include <inp_pkg.body>
#include <alloc.h> #include <alloc.h>
#ifndef NOPP
#ifdef DBSYMTAB
#include <stb.h>
#include <em.h>
extern int IncludeLevel;
extern char options[];
#endif
char *
getwdir(fn)
register char *fn;
{
register char *p;
char *strrchr();
p = strrchr(fn, '/');
while (p && *(p + 1) == '\0') { /* remove trailing /'s */
*p = '\0';
p = strrchr(fn, '/');
}
if (fn[0] == '\0' || (fn[0] == '/' && p == &fn[0])) /* absolute path */
return "";
if (p) {
*p = '\0';
fn = Salloc(fn,(unsigned) (p - &fn[0] + 1));
*p = '/';
return fn;
}
return "";
}
int InputLevel;
extern int nestlevel;
#endif /* NOPP */
int NoUnstack; int NoUnstack;
AtEoIT() AtEoIT()
{ {
#ifndef NOPP
InputLevel--;
unstackrepl();
#endif /* NOPP */
return 0; return 0;
} }
@ -69,22 +29,6 @@ extern char *source;
AtEoIF() AtEoIF()
{ {
#ifndef NOPP
if (nestlevel != nestlow) lexwarning("missing #endif");
else
#endif /* NOPP */
if (NoUnstack) lexerror("unexpected EOF"); if (NoUnstack) lexerror("unexpected EOF");
#ifndef NOPP
nestlevel = nestlow;
#ifdef DBSYMTAB
if (options['g'] && IncludeLevel > 0) {
C_ms_stb_cst(FileName, N_EINCL, 0, (arith) 0);
}
IncludeLevel--;
#endif
/* We don't free WorkingDir and FileName here because the rest of the
* compiler may be holding pointers to them for displaying error messages.
*/
#endif /* NOPP */
return 0; return 0;
} }

View file

@ -6,47 +6,3 @@
/* PREPROCESSOR: DEFINITION OF MACRO DESCRIPTOR */ /* PREPROCESSOR: DEFINITION OF MACRO DESCRIPTOR */
#include "parameters.h" #include "parameters.h"
#ifndef NOPP
/* The flags of the mc_flag field of the macro structure. Note that
these flags can be set simultaneously.
*/
#define NOFLAG 0 /* no special flags */
#define FUNC 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 */
/* `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
#define K_FILE 100 /* for dependency generator */
#endif /* NOPP */

View file

@ -29,19 +29,6 @@ extern struct tokenname tkidf[];
extern char *symbol2str(); extern char *symbol2str();
extern char options[128]; extern char options[128];
#ifndef NOPP
int inc_pos = 1; /* place where next -I goes */
int inc_total = 0;
int inc_max;
char **inctable;
extern int do_dependencies;
extern char *dep_file;
static File *dep_fd = STDOUT;
extern char *getwdir();
#endif /* NOPP */
struct sp_id special_ids[] = { struct sp_id special_ids[] = {
{"__setjmp", SP_SETJMP}, /* non-local goto's are registered */ {"__setjmp", SP_SETJMP}, /* non-local goto's are registered */
{0, 0} {0, 0}
@ -74,10 +61,6 @@ int
union_align = AL_UNION; union_align = AL_UNION;
#endif /* NOCROSS */ #endif /* NOCROSS */
#ifndef NOPP
arith ifval; /* ifval will contain the result of the #if expression */
#endif /* NOPP */
char *prog_name; char *prog_name;
main(argc, argv) main(argc, argv)
@ -86,17 +69,6 @@ main(argc, argv)
/* parse and interpret the command line options */ /* parse and interpret the command line options */
prog_name = argv[0]; prog_name = argv[0];
#ifndef NOPP
inctable = (char **) Malloc(10 * sizeof(char *));
inctable[0] = "";
inctable[1] = 0;
inctable[2] = 0;
inc_total = 3;
inc_max = 10;
init_pp(); /* initialise the preprocessor macros */
#endif /* NOPP */
/* Note: source file "-" indicates that the source is supplied /* Note: source file "-" indicates that the source is supplied
as standard input. This is only allowed if INP_READ_IN_ONE is as standard input. This is only allowed if INP_READ_IN_ONE is
not defined! not defined!
@ -122,83 +94,10 @@ main(argc, argv)
if (options['m']) Info(); if (options['m']) Info();
#endif /* DEBUG */ #endif /* DEBUG */
#ifndef NOPP
if (do_dependencies) {
extern char *source;
list_dependencies(source);
}
#endif
sys_stop(err_occurred ? S_EXIT : S_END); sys_stop(err_occurred ? S_EXIT : S_END);
/*NOTREACHED*/ /*NOTREACHED*/
} }
#ifndef NOPP
struct dependency *file_head;
extern char *strrchr();
list_dependencies(source)
char *source;
{
register struct dependency *p = file_head;
if (source) {
register char *s = strrchr(source, '.');
if (s && *(s+1)) {
s++;
*s++ = 'o';
*s = '\0';
/* the source may be in another directory than the
* object generated, so don't include the pathname
* leading to it.
*/
if (s = strrchr(source, '/')) {
source = s + 1;
}
}
else source = 0;
}
if (dep_file && !sys_open(dep_file, OP_WRITE, &dep_fd)) {
fatal("could not open %s", dep_file);
}
while (p) {
dependency(p->dep_idf->id_text, source);
p = p->next;
}
}
add_dependency(s)
char *s;
{
register struct idf *p = str2idf(s, 1);
if (! p->id_resmac) {
register struct dependency *q = new_dependency();
p->id_resmac = K_FILE;
q->dep_idf = p;
q->next = file_head;
file_head = q;
}
}
void
dependency(s, source)
char *s, *source;
{
if (options['i'] && !strncmp(s, "/usr/include/", 13)) {
return;
}
if (options['m'] && source) {
fprint(dep_fd, "%s: %s\n", source, s);
}
else fprint(dep_fd, "%s\n", s);
}
#endif /* NOPP */
char *source = 0; char *source = 0;
#ifdef GEN_NM_LIST #ifdef GEN_NM_LIST
@ -213,19 +112,10 @@ compile(argc, argv)
register char *destination = 0; register char *destination = 0;
#endif /* LINT */ #endif /* LINT */
#ifdef DEBUG
#ifndef NOPP
int pp_only = options['E'] || options['P'] || options['C'];
#endif /* NOPP */
#endif
switch (argc) { switch (argc) {
case 1: case 1:
#ifndef LINT #ifndef LINT
#ifdef DEBUG #ifdef DEBUG
#ifndef NOPP
if (!pp_only)
#endif /* NOPP */
#endif #endif
fatal("%s: destination file not specified", prog_name); fatal("%s: destination file not specified", prog_name);
#endif /* LINT */ #endif /* LINT */
@ -277,20 +167,7 @@ compile(argc, argv)
: 0); : 0);
#endif /* LINT */ #endif /* LINT */
#ifndef NOPP
WorkingDir = getwdir(source);
PushLex(); /* initialize lex machine */
#else /* NOPP */
GetToken(&ahead); GetToken(&ahead);
#endif /* NOPP */
#ifdef DEBUG
#ifndef NOPP
if (pp_only) /* run the preprocessor as if it is stand-alone */
preprocess();
else
#endif /* NOPP */
#endif /* DEBUG */
{ {
/* compile the source text */ /* compile the source text */
C_program(); C_program();
@ -311,9 +188,6 @@ compile(argc, argv)
dumpidftab("end of main", options['f'] ? 7 : 0); dumpidftab("end of main", options['f'] ? 7 : 0);
#endif /* DEBUG */ #endif /* DEBUG */
} }
#ifndef NOPP
PopLex();
#endif /* NOPP */
} }
init() init()
@ -395,76 +269,6 @@ init_specials(si)
} }
#ifdef DEBUG #ifdef DEBUG
#ifndef NOPP
preprocess()
{
/* preprocess() is the "stand-alone" preprocessor which
consecutively calls the lexical analyzer LLlex() to get
the tokens and prints them in a suitable way.
*/
static unsigned int lastlineno = 0;
static char *lastfilenm = "";
while (LLlex() != EOI) {
if (lastlineno != dot.tk_line) {
if (strcmp(lastfilenm, dot.tk_file) == 0) {
if (dot.tk_line - lastlineno <= 1) {
lastlineno++;
print("\n");
}
else {
lastlineno = dot.tk_line;
if (!options['P'])
print("\n#line %ld \"%s\"\n",
lastlineno,
lastfilenm
);
}
}
else {
lastfilenm = dot.tk_file;
lastlineno = dot.tk_line;
if (!options['P'])
print("\n#line %ld \"%s\"\n",
lastlineno, lastfilenm);
}
}
else
if (strcmp(lastfilenm, dot.tk_file) != 0) {
lastfilenm = dot.tk_file;
if (!options['P'])
print("\n#line %ld \"%s\"\n",
lastlineno, lastfilenm);
}
switch (DOT) {
case IDENTIFIER:
case TYPE_IDENTIFIER:
print("%s ", dot.tk_idf->id_text);
break;
case STRING:
{
char sbuf[1024]; /* a transient buffer */
print("\"%s\" ", bts2str(dot.tk_bts, dot.tk_len -
1, sbuf));
break;
}
case INTEGER:
print("%ld ", dot.tk_ival);
break;
case FLOATING:
print("%s ", dot.tk_fval);
break;
case EOI:
case EOF:
return;
default: /* very expensive... */
print("%s ", symbol2str(DOT));
}
}
}
#endif /* NOPP */
Info() Info()
{ {
extern int cnt_string_cst, cnt_formal, extern int cnt_string_cst, cnt_formal,

View file

@ -16,16 +16,6 @@
#include "sizes.h" #include "sizes.h"
#include "align.h" #include "align.h"
#ifndef NOPP
extern char **inctable;
extern int inc_pos;
extern int inc_max;
extern int inc_total;
int do_dependencies = 0;
char *dep_file = 0;
#endif /* NOPP */
char options[128]; /* one for every char */ char options[128]; /* one for every char */
#ifdef LINT #ifdef LINT
char loptions[128]; /* one for every char */ char loptions[128]; /* one for every char */
@ -60,18 +50,6 @@ next_option: /* to allow combined one-char options */
goto next_option; goto next_option;
#ifndef LINT #ifndef LINT
#ifndef NOPP
case 'A' : /* Amake dependency generation */
do_dependencies = 1;
if (*text) {
dep_file = text;
}
break;
case 'i':
case 'm':
options[opt] = 1;
break;
#endif /* NOPP */
#endif /* LINT */ #endif /* LINT */
#ifdef DBSYMTAB #ifdef DBSYMTAB
case 'g': /* symbol table for debugger */ case 'g': /* symbol table for debugger */
@ -110,64 +88,6 @@ next_option: /* to allow combined one-char options */
goto next_option; goto next_option;
#endif /* LINT */ #endif /* LINT */
#ifndef NOPP
case 'D' : { /* -Dname : predefine name */
register char *cp = text, *name, *mactext;
unsigned maclen;
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 */
maclen = 1;
mactext = Salloc("1", 2);
}
else
if (*cp == '=') { /* -Dname=text */
*cp++ = '\0'; /* end of name */
maclen = (unsigned) strlen(cp);
mactext = Salloc(cp, maclen + 1);
}
else { /* -Dname?? */
error("malformed option -D%s", text);
break;
}
macro_def(str2idf(name, 0), mactext, -1, (int)maclen, NOFLAG);
break;
}
case 'I' : /* -Ipath : insert "path" into include list */
if (*text) {
int i;
register char *new = text;
if (inc_total >= inc_max) {
inctable = (char **)
Realloc((char *)inctable,
(unsigned)((inc_max+=10)*sizeof(char *)));
}
for (i = inc_pos++; i < inc_total ; i++) {
char *tmp = inctable[i];
inctable[i] = new;
new = tmp;
}
inc_total++;
}
else inctable[inc_pos] = 0;
break;
#endif /* NOPP */
case 'M': /* maximum identifier length */ case 'M': /* maximum identifier length */
idfsize = txt2int(&text); idfsize = txt2int(&text);
if (*text || idfsize <= 0) if (*text || idfsize <= 0)
@ -197,12 +117,6 @@ next_option: /* to allow combined one-char options */
break; break;
} }
#ifndef NOPP
case 'U' : /* -Uname : undefine predefined */
if (*text) do_undef(str2idf(text, 0));
break;
#endif /* NOPP */
#ifndef LINT #ifndef LINT
#ifndef NOCROSS #ifndef NOCROSS
case 'V' : /* set object sizes and alignment requirements */ case 'V' : /* set object sizes and alignment requirements */

View file

@ -61,10 +61,6 @@
#include "l_lint.h" #include "l_lint.h"
#endif /* LINT */ #endif /* LINT */
#ifndef NOPP
extern arith ifval;
#endif /* NOPP */
extern error(); extern error();
} }
@ -75,14 +71,6 @@ control_if_expression
: :
constant_expression(&exprX) constant_expression(&exprX)
{ {
#ifndef NOPP
register struct expr *expr = exprX;
if (expr->ex_flags & EX_SIZEOF)
expr_error(expr,
"sizeof not allowed in preprocessor");
ifval = expr->VL_VALUE;
free_expression(expr);
#endif /* NOPP */
} }
; ;

View file

@ -1,808 +0,0 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Id$ */
/* M A C R O R E P L A C E M E N T */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "parameters.h"
#ifndef NOPP
#include <ack_string.h>
#include <alloc.h>
#include "idf.h"
#include "input.h"
#include "macro.h"
#include "arith.h"
#include "LLlex.h"
#include "class.h"
#include "replace.h"
extern struct idf *GetIdentifier();
extern int InputLevel;
struct repl *ReplaceList; /* list of currently active macros */
void macro2buffer();
void getactuals();
void expand_defined();
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 = Malloc(repl->r_size = LAPBUF);
repl->r_args = new_args();
repl->r_idf = idf;
if (!expand_macro(repl, idf))
return 0;
InputLevel++;
InsertText(repl->r_text, (int)(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++;
}
freeargs(args)
struct args *args;
{
register int i;
/* We must don't know how many parameters were specified, so be
* prepared to free all NPARAMS parameters.
* When an expvec is !0, the rawvec will also be !0.
* When an expvec is 0, all remaining vectors will also be 0.
*/
for (i = 0; i < NPARAMS; i++) {
if (args->a_expvec[i]) {
free(args->a_expvec[i]);
free(args->a_rawvec[i]);
} else break;
}
free_args(args);
}
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(r->r_text);
freeargs(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));
expand the assert macro by hand (??? dirty, temporary)
*/
#ifdef DEBUG
if (strcmp("defined", idf->id_text))
crash("in %s, %u: assertion %s failed",
__FILE__, __LINE__ - 2,
"strcmp(\"defined\", idf->id_text)");
#endif
if (!AccDefined) return 0;
expand_defined(repl);
return 1;
}
ch = GetChar();
ch = skipspaces(ch,1);
if (ch != '(') { /* no replacement if no () */
ChPushBack(ch);
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. Therefore a token separator is
inserted after the replacement.
*/
if (repl->r_text == repl->r_ptr || *(repl->r_ptr - 1) != TOKSEP) {
add2repl(repl, TOKSEP);
}
return 1;
}
void
expand_defined(repl)
register struct repl *repl;
{
register int ch = GetChar();
struct idf *id;
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 != ')') ChPushBack(ch);
add2repl(repl, '0');
return;
}
ChPushBack(ch);
id = GetIdentifier(0);
assert(id || class(ch) == STELL);
ch = GetChar();
ch = skipspaces(ch, 0);
if (parens && ch != ')') error(") missing");
if (!parens || ch != ')') ChPushBack(ch);
add2repl(repl, (id && id->id_macro) ? '1' : '0');
add2repl(repl, ' ');
}
newarg(args)
struct args *args;
{
args->a_expptr = args->a_expbuf = Malloc(args->a_expsize = ARGBUF);
args->a_rawptr = args->a_rawbuf = Malloc(args->a_rawsize = ARGBUF);
}
void
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;
newarg(args);
if ((ch = GetChar()) != ')') {
UnGetChar();
while ((ch = actual(repl)) != ')' ) {
if (ch != ',') {
lexerror("illegal macro call");
return;
}
stash(repl, '\0', 1);
args->a_expvec[argcnt] = args->a_expbuf;
args->a_rawvec[argcnt] = args->a_rawbuf;
++argcnt;
if (argcnt == STDC_NPARAMS)
lexstrict("number of parameters exceeds ANSI standard");
if (argcnt >= NPARAMS)
fatal("argument vector overflow");
newarg(args);
}
stash(repl, '\0', 1);
args->a_expvec[argcnt] = args->a_expbuf;
args->a_rawvec[argcnt] = args->a_rawbuf;
++argcnt;
}
if (argcnt < nps)
lexerror("too few macro arguments");
else if (argcnt > nps)
lexerror("too many macro arguments");
}
saveraw(repl)
struct repl *repl;
{
register struct repl *nrepl = ReplaceList;
register struct args *ap = nrepl->r_args;
register char *p;
/* stash identifier name */
for (p = nrepl->r_idf->id_text; *p != '\0'; p++)
stash(repl, *p, -1);
/* 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;
for (i = 0; ap->a_rawvec[i] != (char *)0; i++) {
if (i == 0) stash(repl, '(', -1);
else stash(repl, ',', -1);
for (p = ap->a_rawvec[i]; *p != '\0'; p++)
stash(repl, *p, -1);
}
stash(repl, ')', -1);
}
}
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 = 0;
register int level = 0, nostashraw = 0;
int lastch;
static int Unstacked_missed;
while (1) {
lastch = ch;
ch = GetChar();
if (nostashraw
&& nostashraw >= Unstacked_missed) {
nostashraw -= Unstacked_missed;
Unstacked_missed = 0;
}
if (Unstacked) {
nostashraw -= Unstacked;
if (nostashraw < 0) {
Unstacked_missed = -nostashraw;
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';
ch = '\0'; /* It could be an unstashed TOKSEP */
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) {
ch = '\0'; /* It could be an unstashed TOKSEP */
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();
}
}
}
ch = '\0'; /* It could be an unstashed TOKSEP */
UnGetChar();
} else if (ch == '(') {
/* a comma may occur between parentheses */
level++;
stash(repl, ch, !nostashraw);
} else if (ch == ')') {
level--;
/* closing parenthesis of macro call */
if (level < 0) return ')';
stash(repl, ch, !nostashraw);
} else if (ch == ',') {
if (level <= 0) { /* comma separator for next argument */
if (level)
lexerror("unbalanced parenthesis");
if (!nostashraw)
return ','; /* ??? */
}
stash(repl, ch, !nostashraw);
} else if (ch == '\n') {
/* newlines are accepted as white spaces */
LineNumber++;
/* 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(
/_* comment *_/ #include phone_number
,2);
in which case the include must be handled
interpreted as such.
*/
a_new_line: ch = GetChar();
while (class(ch) == STSKIP || ch == '/') {
if (ch == '/') {
if ((ch = GetChar()) == '*' && !InputLevel) {
skipcomment();
stash(repl, ' ', !nostashraw);
ch = GetChar();
continue;
} else {
UnGetChar();
ch = '/';
}
stash(repl, '/', !nostashraw);
break;
} else ch = GetChar();
}
if (ch == '#') {
domacro();
/* Clear File_Inserted since domacro could
* be called again, which calls GetToken().
*/
File_Inserted = 0;
goto a_new_line;
} else if (ch == EOI) {
lexerror("unterminated macro call");
return ')';
}
if (ch != '/') {
UnGetChar();
ch = ' ';
stash(repl, ' ', !nostashraw);
}
} else if (ch == '/') {
/* comments are treated as one white space token */
if ((ch = GetChar()) == '*' && !InputLevel) {
skipcomment();
stash(repl, ' ', !nostashraw);
} else {
UnGetChar();
ch = '/';
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') {
lexerror("newline in string");
LineNumber++;
stash(repl, match, !nostashraw);
break;
}
stash(repl, ch, !nostashraw);
}
if (ch != match) {
lexerror("unterminated macro call");
return ')';
}
stash(repl, ch, !nostashraw);
} else {
if (lastch == TOKSEP && ch == TOKSEP) continue;
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];
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*/
}
}
void
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;
int err = 0;
int func = idf->id_macro->mc_nps != -1;
char *stringify();
assert(ptr[idf->id_macro->mc_length] == '\0');
while (*ptr) {
if (*ptr == '\'' || *ptr == '"') {
register int delim = *ptr;
do {
add2repl(repl, *ptr);
if (*ptr == '\\')
add2repl(repl, *++ptr);
if (*ptr == '\0') {
lexerror("unterminated string");
return;
}
ptr++;
} while (*ptr != delim || *ptr == '\0');
add2repl(repl, *ptr++);
} else if (*ptr == '#' && (func || *(ptr+1) == '#')) {
if (*++ptr == '#') {
register int tmpindex;
/* ## - paste operator */
ptr++;
/* trim the actual replacement list */
--repl->r_ptr;
while (repl->r_ptr >= repl->r_text
&& is_wsp(*repl->r_ptr))
--repl->r_ptr;
/* ## occurred at the beginning of the replacement list.
*/
if (repl->r_ptr < repl->r_text) {
err = 1;
break;
}
if (repl->r_ptr >= repl->r_text
&& *repl->r_ptr == TOKSEP)
--repl->r_ptr;
++repl->r_ptr;
tmpindex = repl->r_ptr - repl->r_text;
/* tmpindex can be 0 */
/* 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)
add2repl(repl, *p++);
}
while (tmpindex > 0
&& in_idf(repl->r_text[tmpindex]))
tmpindex--;
if (tmpindex >= 0
&& repl->r_text[tmpindex] == NOEXPM)
repl->r_text[tmpindex] = TOKSEP;
} else if (*ptr == '\0') {
err = 1;
break;
} else {
if (in_idf(*ptr)) {
tmpindex--;
while (tmpindex > 0
&& in_idf(repl->r_text[tmpindex]))
tmpindex--;
if (tmpindex >= 0
&& repl->r_text[tmpindex] == NOEXPM)
repl->r_text[tmpindex] = 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
## operator. 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];
if (q) /* else macro argument missing */
while (*q)
add2repl(repl, *q++);
if (repl->r_text == repl->r_ptr || *(repl->r_ptr - 1) != TOKSEP)
add2repl(repl, TOKSEP);
} else {
add2repl(repl, *ptr++);
}
}
if (err)
lexerror("illegal use of the ## 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];
add2repl(repl, '"');
while (*p) {
if (is_wsp(*p)) {
if (!space) {
space = 1;
add2repl(repl, ' ');
}
p++;
continue;
}
space = 0;
if (!delim && (*p == '"' || *p == '\''))
delim = *p;
else if (*p == delim && !backslash)
delim = 0;
backslash = *p == '\\';
if (*p == '"' || (delim && *p == '\\'))
add2repl(repl, '\\');
if (*p == TOKSEP || *p == NOEXPM) p++;
else add2repl(repl, *p++);
}
/* trim spaces in the replacement list */
for (--repl->r_ptr; is_wsp(*repl->r_ptr); repl->r_ptr--)
/* EMPTY */;
++repl->r_ptr; /* oops, one to far */
add2repl(repl, '"');
} else
error("illegal use of # operator");
return ptr;
}
/* The following routine is also called from domacro.c.
*/
add2repl(repl, ch)
register struct repl *repl;
int ch;
{
register int index = repl->r_ptr - repl->r_text;
assert(index < repl->r_size);
if (index + 2 >= repl->r_size) {
repl->r_text = Realloc(repl->r_text, (unsigned) (repl->r_size <<= 1));
repl->r_ptr = repl->r_text + index;
}
*repl->r_ptr++ = ch;
*repl->r_ptr = '\0';
}
/* If the variable stashraw is negative, we must only stash into the raw
* buffer. If the variable is zero, we must only stash into the expanded
* buffer. Otherwise, we must use both buffers.
*/
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;
register int index = args->a_expptr - args->a_expbuf;
if (stashraw >= 0) {
assert(index < args->a_expsize);
if (index + 1 >= args->a_expsize) {
args->a_expbuf = Realloc(args->a_expbuf,
(unsigned) (args->a_expsize <<= 1));
args->a_expptr = args->a_expbuf + index;
}
*args->a_expptr++ = ch;
}
if (stashraw) {
index = args->a_rawptr - args->a_rawbuf;
assert(index < args->a_rawsize);
if (index + 1 >= args->a_rawsize) {
args->a_rawbuf = Realloc(args->a_rawbuf,
(unsigned)(args->a_rawsize <<= 1));
args->a_rawptr = args->a_rawbuf + index;
}
*args->a_rawptr++ = ch;
}
}
#endif /* NOPP */

View file

@ -1,51 +0,0 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Id$ */
/* 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 */
int r_size; /* current size of replacement buffer */
char *r_ptr; /* replacement text index pointer */
char *r_text; /* 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); // gives: 2 + h(f())
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 index pointer */
char *a_expbuf; /* expanded argument buffer pointer */
int a_expsize; /* current size of expanded buffer */
char *a_expvec[NPARAMS]; /* expanded argument vector */
char *a_rawptr; /* raw argument index pointer */
char *a_rawbuf; /* raw argument buffer pointer */
int a_rawsize; /* current size of raw buffer */
char *a_rawvec[NPARAMS]; /* raw argument vector */
};
/* ALLOCDEF "args" 2 */
#define NO_ARGS (struct args *)0

View file

@ -11,94 +11,17 @@
#include "class.h" #include "class.h"
#include "input.h" #include "input.h"
#ifndef NOPP
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;
}
}
#endif /* NOPP */
SkipToNewLine() SkipToNewLine()
{ {
register int ch; register int ch;
register int garbage = 0; register int garbage = 0;
#ifndef NOPP
register int delim = 0;
#endif
while ((ch = GetChar()) != '\n') { while ((ch = GetChar()) != '\n')
#ifndef NOPP {
if (delim) {
if (ch == '\\') {
if (GetChar() == '\n') break;
} else if (ch == delim) {
delim = 0;
}
continue;
}
else if (ch == '\'' || ch == '\"') {
delim = ch;
garbage = 1;
} else if (ch == '/') {
if (GetChar() == '*'
&& !InputLevel
) {
skipcomment();
continue;
}
else UnGetChar();
}
else if (ch == TOKSEP && InputLevel) {
continue;
}
#endif
if (!is_wsp(ch)) if (!is_wsp(ch))
garbage = 1; garbage = 1;
} }
#ifndef NOPP
if (delim) strict("unclosed opening %c", delim);
#endif
++LineNumber; ++LineNumber;
return garbage; return garbage;
} }

View file

@ -30,23 +30,20 @@ int AccFileSpecifier = 0; /* return filespecifier <...> */
int LexSave = 0; /* last character read by GetChar */ int LexSave = 0; /* last character read by GetChar */
extern int InputLevel; /* # of current macro expansions */ extern int InputLevel; /* # of current macro expansions */
extern char *string_token(); extern char* string_token();
extern arith char_constant(); extern arith char_constant();
#define FLG_ESEEN 0x01 /* possibly a floating point number */ #define FLG_ESEEN 0x01 /* possibly a floating point number */
#define FLG_DOTSEEN 0x02 /* certainly a floating point number */ #define FLG_DOTSEEN 0x02 /* certainly a floating point number */
void skipcomment(); void skipcomment();
void skiplinecomment(void);
int int LLlex()
LLlex()
{ {
return (DOT != EOF) ? GetToken(&dot) : EOF; return (DOT != EOF) ? GetToken(&dot) : EOF;
} }
int GetToken(ptok) register struct token* ptok;
int
GetToken(ptok)
register struct token *ptok;
{ {
/* GetToken() is the actual token recognizer. It calls the /* GetToken() is the actual token recognizer. It calls the
control line interpreter if it encounters a "\n{w}*#" control line interpreter if it encounters a "\n{w}*#"
@ -63,14 +60,15 @@ again: /* rescan the input after an error or replacement */
fatal("non-ascii '\\%03o' read", ch & 0377); fatal("non-ascii '\\%03o' read", ch & 0377);
/* keep track of the place of the token in the file */ /* keep track of the place of the token in the file */
switch (class(ch)) { /* detect character class */ switch (class(ch))
{ /* detect character class */
case STNL: /* newline, vertical space or formfeed */ case STNL: /* newline, vertical space or formfeed */
LineNumber++; LineNumber++;
return ptok->tk_symb = EOF; return ptok->tk_symb = EOF;
case STSKIP: /* just skip the skip characters */ case STSKIP: /* just skip the skip characters */
goto again; goto again;
case STGARB: /* garbage character */ case STGARB: /* garbage character */
garbage: garbage:
if (040 < ch && ch < 0177) if (040 < ch && ch < 0177)
error("garbage char %c", ch); error("garbage char %c", ch);
else else
@ -80,7 +78,8 @@ garbage:
return ptok->tk_symb = ch; return ptok->tk_symb = ch;
case STCOMP: /* maybe the start of a compound token */ case STCOMP: /* maybe the start of a compound token */
nch = GetChar(); /* character lookahead */ nch = GetChar(); /* character lookahead */
switch (ch) { switch (ch)
{
case '!': case '!':
if (nch == '=') if (nch == '=')
return ptok->tk_symb = NOTEQUAL; return ptok->tk_symb = NOTEQUAL;
@ -110,17 +109,20 @@ garbage:
UnGetChar(); UnGetChar();
return ptok->tk_symb = ch; return ptok->tk_symb = ch;
case '<': case '<':
if (AccFileSpecifier) { if (AccFileSpecifier)
{
UnGetChar(); /* pushback nch */ UnGetChar(); /* pushback nch */
ptok->tk_str = ptok->tk_str = string_token("file specifier", '>');
string_token("file specifier", '>');
return ptok->tk_symb = FILESPECIFIER; return ptok->tk_symb = FILESPECIFIER;
} else if (nch == '<') { }
else if (nch == '<')
{
if ((nch = GetChar()) == '=') if ((nch = GetChar()) == '=')
return ptok->tk_symb = LEFTAB; return ptok->tk_symb = LEFTAB;
UnGetChar(); UnGetChar();
return ptok->tk_symb = LEFT; return ptok->tk_symb = LEFT;
} else if (nch == '=') }
else if (nch == '=')
return ptok->tk_symb = LESSEQ; return ptok->tk_symb = LESSEQ;
UnGetChar(); UnGetChar();
return ptok->tk_symb = ch; return ptok->tk_symb = ch;
@ -132,7 +134,8 @@ garbage:
case '>': case '>':
if (nch == '=') if (nch == '=')
return ptok->tk_symb = GREATEREQ; return ptok->tk_symb = GREATEREQ;
else if (nch == '>') { else if (nch == '>')
{
if ((nch = GetChar()) == '=') if ((nch = GetChar()) == '=')
return ptok->tk_symb = RIGHTAB; return ptok->tk_symb = RIGHTAB;
UnGetChar(); UnGetChar();
@ -163,10 +166,19 @@ garbage:
UnGetChar(); UnGetChar();
return ptok->tk_symb = ch; return ptok->tk_symb = ch;
case '/': case '/':
if (nch == '*' && !InputLevel) { if (!InputLevel)
{
if (nch == '*')
{
skipcomment(); skipcomment();
goto again; goto again;
} }
else if (nch == '/')
{
skiplinecomment();
goto again;
}
}
else if (nch == '=') else if (nch == '=')
return ptok->tk_symb = DIVAB; return ptok->tk_symb = DIVAB;
UnGetChar(); UnGetChar();
@ -183,11 +195,13 @@ garbage:
return ptok->tk_symb = STRING; return ptok->tk_symb = STRING;
case STELL: /* wide character constant/string prefix */ case STELL: /* wide character constant/string prefix */
nch = GetChar(); nch = GetChar();
if (nch == '"') { if (nch == '"')
ptok->tk_str = {
string_token("wide character string", '"'); ptok->tk_str = string_token("wide character string", '"');
return ptok->tk_symb = STRING; return ptok->tk_symb = STRING;
} else if (nch == '\'') { }
else if (nch == '\'')
{
ptok->tk_val = char_constant("wide character"); ptok->tk_val = char_constant("wide character");
return ptok->tk_symb = INTEGER; return ptok->tk_symb = INTEGER;
} }
@ -196,33 +210,57 @@ garbage:
case STIDF: case STIDF:
{ {
extern int idfsize; /* ??? */ extern int idfsize; /* ??? */
register char *tg = &buf[0]; register char* tg = &buf[0];
register char *maxpos = &buf[idfsize]; register char* maxpos = &buf[idfsize];
int NoExpandNext = 0; int NoExpandNext = 0;
#define tstmac(bx) if (!(bits[ch] & bx)) goto nomac #define tstmac(bx) \
if (!(bits[ch] & bx)) \
goto nomac
#define cpy *tg++ = ch #define cpy *tg++ = ch
#define load (ch = GetChar()); if (!in_idf(ch)) goto endidf #define load \
(ch = GetChar()); \
if (!in_idf(ch)) \
goto endidf
if (Unstacked) EnableMacros(); /* unstack macro's when allowed. */ if (Unstacked)
if (ch == NOEXPM) { EnableMacros(); /* unstack macro's when allowed. */
if (ch == NOEXPM)
{
NoExpandNext = 1; NoExpandNext = 1;
ch = GetChar(); ch = GetChar();
} }
#ifdef DOBITS #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; 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; load;
} }
@ -230,10 +268,12 @@ garbage:
/*if (ch != EOI) UnGetChar();*/ /*if (ch != EOI) UnGetChar();*/
UnGetChar(); UnGetChar();
*tg++ = '\0'; /* mark the end of the identifier */ *tg++ = '\0'; /* mark the end of the identifier */
if (ReplaceMacros) { if (ReplaceMacros)
register struct idf *idef = findidf(buf); {
register struct idf* idef = findidf(buf);
if (idef && idef->id_macro && !NoExpandNext) { if (idef && idef->id_macro && !NoExpandNext)
{
if (replace(idef)) if (replace(idef))
goto again; goto again;
} }
@ -241,15 +281,18 @@ garbage:
nomac: /* buf can already be null-terminated. soit */ nomac: /* buf can already be null-terminated. soit */
ch = GetChar(); ch = GetChar();
while (in_idf(ch)) { while (in_idf(ch))
if (tg < maxpos) *tg++ = ch; {
if (tg < maxpos)
*tg++ = ch;
ch = GetChar(); ch = GetChar();
} }
UnGetChar(); UnGetChar();
*tg++ = '\0'; /* mark the end of the identifier */ *tg++ = '\0'; /* mark the end of the identifier */
NoExpandNext = 0; NoExpandNext = 0;
if (UnknownIdIsZero) { if (UnknownIdIsZero)
{
ptok->tk_val = (arith)0; ptok->tk_val = (arith)0;
return ptok->tk_symb = INTEGER; return ptok->tk_symb = INTEGER;
} }
@ -262,52 +305,65 @@ garbage:
register int base = 10, vch; register int base = 10, vch;
register arith val = 0; register arith val = 0;
int ovfl = 0; int ovfl = 0;
arith ubound = max_arith/(base/2); arith ubound = max_arith / (base / 2);
/* Since the preprocessor only knows integers and has /* Since the preprocessor only knows integers and has
* nothing to do with ellipsis we just return when the * nothing to do with ellipsis we just return when the
* pp-number starts with a '.' * pp-number starts with a '.'
*/ */
if (ch == '.') { if (ch == '.')
{
return ptok->tk_symb = ch; return ptok->tk_symb = ch;
} }
if (ch == '0') { if (ch == '0')
{
ch = GetChar(); ch = GetChar();
if (ch == 'x' || ch == 'X') { if (ch == 'x' || ch == 'X')
{
base = 16; base = 16;
ch = GetChar(); ch = GetChar();
} else { }
else
{
base = 8; base = 8;
} }
} }
while ((vch = val_in_base(ch, base)) >= 0) { while ((vch = val_in_base(ch, base)) >= 0)
if (val < 0 || val > ubound) ovfl++; {
if (val < 0 || val > ubound)
ovfl++;
val *= base; val *= base;
if (val < 0 && val + vch >= 0) ovfl++; if (val < 0 && val + vch >= 0)
ovfl++;
val += vch; val += vch;
ch = GetChar(); ch = GetChar();
} }
ptok->tk_unsigned = 0; ptok->tk_unsigned = 0;
if (ch == 'u' || ch == 'U') { if (ch == 'u' || ch == 'U')
{
ptok->tk_unsigned = 1; ptok->tk_unsigned = 1;
ch = GetChar(); ch = GetChar();
if (ch == 'l' || ch == 'L') { if (ch == 'l' || ch == 'L')
{
ch = GetChar(); ch = GetChar();
} }
} }
else if (ch == 'l' || ch == 'L') { else if (ch == 'l' || ch == 'L')
{
ch = GetChar(); ch = GetChar();
if (ch == 'u' || ch == 'U') { if (ch == 'u' || ch == 'U')
{
ptok->tk_unsigned = 1; ptok->tk_unsigned = 1;
ch = GetChar(); ch = GetChar();
} }
} }
if (ovfl) { if (ovfl)
{
warning("overflow in constant"); warning("overflow in constant");
ptok->tk_unsigned = 1; ptok->tk_unsigned = 1;
} }
else if (val < 0) { else if (val < 0)
{
/* give warning??? */ /* give warning??? */
ptok->tk_unsigned = 1; ptok->tk_unsigned = 1;
} }
@ -318,8 +374,10 @@ garbage:
case STEOI: /* end of text on source file */ case STEOI: /* end of text on source file */
return ptok->tk_symb = EOF; return ptok->tk_symb = EOF;
case STMSPEC: case STMSPEC:
if (!InputLevel) goto garbage; if (!InputLevel)
if (ch == TOKSEP) goto again; goto garbage;
if (ch == TOKSEP)
goto again;
/* fallthrough shouldn't happen */ /* fallthrough shouldn't happen */
default: /* this cannot happen */ default: /* this cannot happen */
crash("bad class for char 0%o", ch); crash("bad class for char 0%o", ch);
@ -327,8 +385,7 @@ garbage:
/*NOTREACHED*/ /*NOTREACHED*/
} }
void void skipcomment()
skipcomment()
{ {
/* The last character read has been the '*' of '/_*'. The /* The last character read has been the '*' of '/_*'. The
characters, except NL and EOI, between '/_*' and the first characters, except NL and EOI, between '/_*' and the first
@ -344,11 +401,16 @@ skipcomment()
NoUnstack++; NoUnstack++;
c = GetChar(); c = GetChar();
do { do
while (c != '*') { {
if (class(c) == STNL) { while (c != '*')
{
if (class(c) == STNL)
{
++LineNumber; ++LineNumber;
} else if (c == EOI) { }
else if (c == EOI)
{
NoUnstack--; NoUnstack--;
return; return;
} }
@ -359,9 +421,23 @@ skipcomment()
NoUnstack--; NoUnstack--;
} }
arith void skiplinecomment(void)
char_constant(nm) {
char *nm; /* The last character read has been the '/' of '//'. We read
and discard all characters up to but not including the next
NL. */
for (;;) {
int c = GetChar();
if ((class(c) == STNL) || (c == EOI))
{
UnGetChar();
break;
}
}
}
arith char_constant(nm) char* nm;
{ {
register arith val = 0; register arith val = 0;
register int ch; register int ch;
@ -371,15 +447,18 @@ char_constant(nm)
if (ch == '\'') if (ch == '\'')
error("%s constant too short", nm); error("%s constant too short", nm);
else else
while (ch != '\'') { while (ch != '\'')
if (ch == '\n') { {
if (ch == '\n')
{
error("newline in %s constant", nm); error("newline in %s constant", nm);
LineNumber++; LineNumber++;
break; break;
} }
if (ch == '\\') if (ch == '\\')
ch = quoted(GetChar()); ch = quoted(GetChar());
if (ch >= 128) ch -= 256; if (ch >= 128)
ch -= 256;
if (size < sizeof(arith)) if (size < sizeof(arith))
val |= ch << (8 * size); val |= ch << (8 * size);
size++; size++;
@ -392,23 +471,24 @@ char_constant(nm)
return val; return val;
} }
char * char* string_token(nm, stop_char) char* nm;
string_token(nm, stop_char)
char *nm;
{ {
register int ch; register int ch;
register int str_size; register int str_size;
register char *str = Malloc((unsigned) (str_size = ISTRSIZE)); register char* str = Malloc((unsigned)(str_size = ISTRSIZE));
register int pos = 0; register int pos = 0;
ch = GetChar(); ch = GetChar();
while (ch != stop_char) { while (ch != stop_char)
if (ch == '\n') { {
if (ch == '\n')
{
error("newline in %s", nm); error("newline in %s", nm);
LineNumber++; LineNumber++;
break; break;
} }
if (ch == EOI) { if (ch == EOI)
{
error("end-of-file inside %s", nm); error("end-of-file inside %s", nm);
break; break;
} }
@ -424,16 +504,16 @@ string_token(nm, stop_char)
return str; return str;
} }
int int quoted(ch) register int ch;
quoted(ch)
register int ch;
{ {
/* quoted() replaces an escaped character sequence by the /* quoted() replaces an escaped character sequence by the
character meant. character meant.
*/ */
/* first char after backslash already in ch */ /* first char after backslash already in ch */
if (!is_oct(ch)) { /* a quoted char */ if (!is_oct(ch))
switch (ch) { { /* a quoted char */
switch (ch)
{
case 'n': case 'n':
ch = '\n'; ch = '\n';
break; break;
@ -460,7 +540,8 @@ quoted(ch)
register int hex = 0; register int hex = 0;
register int vch; register int vch;
for (;;) { for (;;)
{
ch = GetChar(); ch = GetChar();
if (vch = val_in_base(ch, 16), vch == -1) if (vch = val_in_base(ch, 16), vch == -1)
break; break;
@ -470,42 +551,39 @@ quoted(ch)
ch = hex; ch = hex;
} }
} }
} else { /* a quoted octal */ }
else
{ /* a quoted octal */
register int oct = 0, cnt = 0; register int oct = 0, cnt = 0;
do { do
oct = oct*8 + (ch-'0'); {
oct = oct * 8 + (ch - '0');
ch = GetChar(); ch = GetChar();
} while (is_oct(ch) && ++cnt < 3); } while (is_oct(ch) && ++cnt < 3);
UnGetChar(); UnGetChar();
ch = oct; ch = oct;
} }
return ch&0377; return ch & 0377;
} }
int val_in_base(ch, base) register int ch;
int
val_in_base(ch, base)
register int ch;
{ {
switch (base) { switch (base)
{
case 8: case 8:
return (is_dig(ch) && ch < '9') ? ch - '0' : -1; return (is_dig(ch) && ch < '9') ? ch - '0' : -1;
case 10: case 10:
return is_dig(ch) ? ch - '0' : -1; return is_dig(ch) ? ch - '0' : -1;
case 16: case 16:
return is_dig(ch) ? ch - '0' return is_dig(ch) ? ch - '0' : is_hex(ch) ? (ch - 'a' + 10) & 017 : -1;
: is_hex(ch) ? (ch - 'a' + 10) & 017
: -1;
default: default:
fatal("(val_in_base) illegal base value %d", base); fatal("(val_in_base) illegal base value %d", base);
/* NOTREACHED */ /* NOTREACHED */
} }
} }
int GetChar()
int
GetChar()
{ {
/* The routines GetChar and trigraph parses the trigraph /* The routines GetChar and trigraph parses the trigraph
sequences and removes occurences of \\\n. sequences and removes occurences of \\\n.
@ -520,58 +598,60 @@ again:
ch = trigraph(); ch = trigraph();
/* \\\n are removed from the input stream */ /* \\\n are removed from the input stream */
if (ch == '\\') { if (ch == '\\')
{
LoadChar(ch); LoadChar(ch);
if (ch == '\n') { if (ch == '\n')
{
++LineNumber; ++LineNumber;
goto again; goto again;
} }
PushBack(); PushBack();
ch = '\\'; ch = '\\';
} }
return(LexSave = ch); return (LexSave = ch);
} }
int trigraph()
int
trigraph()
{ {
register int ch; register int ch;
LoadChar(ch); LoadChar(ch);
if (ch == '?') { if (ch == '?')
{
LoadChar(ch); LoadChar(ch);
switch (ch) { /* its a trigraph */ switch (ch)
{ /* its a trigraph */
case '=': case '=':
ch = '#'; ch = '#';
return(ch); return (ch);
case '(': case '(':
ch = '['; ch = '[';
return(ch); return (ch);
case '/': case '/':
ch = '\\'; ch = '\\';
return(ch); return (ch);
case ')': case ')':
ch = ']'; ch = ']';
return(ch); return (ch);
case '\'': case '\'':
ch = '^'; ch = '^';
return(ch); return (ch);
case '<': case '<':
ch = '{'; ch = '{';
return(ch); return (ch);
case '!': case '!':
ch = '|'; ch = '|';
return(ch); return (ch);
case '>': case '>':
ch = '}'; ch = '}';
return(ch); return (ch);
case '-': case '-':
ch = '~'; ch = '~';
return(ch); return (ch);
} }
PushBack(); PushBack();
} }
PushBack(); PushBack();
return('?'); return ('?');
} }

View file

@ -22,23 +22,21 @@
#include "replace.h" #include "replace.h"
extern char options[]; extern char options[];
extern char **inctable; /* list of include directories */ extern char** inctable; /* list of include directories */
extern char *getwdir(); extern char* getwdir();
char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */ char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */
/* 1 if a corresponding ELSE has been */ /* 1 if a corresponding ELSE has been */
/* encountered. */ /* encountered. */
int nestlevel = -1; int nestlevel = -1;
int svnestlevel[30] = {-1}; int svnestlevel[30] = { -1 };
int nestcount; int nestcount;
extern int do_preprocess; extern int do_preprocess;
void macro_def(); void macro_def();
void do_define(); void do_define();
char * char* GetIdentifier(skiponerr) int skiponerr; /* skip the rest of the line on error */
GetIdentifier(skiponerr)
int skiponerr; /* skip the rest of the line on error */
{ {
/* Returns a pointer to the identifier that is read from the /* Returns a pointer to the identifier that is read from the
input stream. When the input does not contain an input stream. When the input does not contain an
@ -55,9 +53,11 @@ GetIdentifier(skiponerr)
tok = GetToken(&tk); tok = GetToken(&tk);
ReplaceMacros = 1; ReplaceMacros = 1;
UnknownIdIsZero = tmp; UnknownIdIsZero = tmp;
if (tok != IDENTIFIER) { if (tok != IDENTIFIER)
if (skiponerr && tok != EOF) SkipToNewLine(); {
return (char *)0; if (skiponerr && tok != EOF)
SkipToNewLine();
return (char*)0;
} }
return tk.tk_str; return tk.tk_str;
} }
@ -74,23 +74,26 @@ GetIdentifier(skiponerr)
domacro() domacro()
{ {
struct token tk; /* the token itself */ struct token tk; /* the token itself */
register struct idf *id; register struct idf* id;
int toknum; int toknum;
ReplaceMacros = 0; ReplaceMacros = 0;
toknum = GetToken(&tk); toknum = GetToken(&tk);
ReplaceMacros = 1; ReplaceMacros = 1;
switch(toknum) { /* select control line action */ switch (toknum)
{ /* select control line action */
case IDENTIFIER: /* is it a macro keyword? */ case IDENTIFIER: /* is it a macro keyword? */
id = findidf(tk.tk_str); id = findidf(tk.tk_str);
if (!id) { if (!id)
{
error("%s: unknown control", tk.tk_str); error("%s: unknown control", tk.tk_str);
SkipToNewLine(); SkipToNewLine();
free(tk.tk_str); free(tk.tk_str);
break; break;
} }
free(tk.tk_str); free(tk.tk_str);
switch (id->id_resmac) { switch (id->id_resmac)
{
case K_DEFINE: /* "define" */ case K_DEFINE: /* "define" */
do_define(); do_define();
break; break;
@ -119,7 +122,8 @@ domacro()
/* set LineNumber and FileName according to /* set LineNumber and FileName according to
the arguments. the arguments.
*/ */
if (GetToken(&tk) != INTEGER) { if (GetToken(&tk) != INTEGER)
{
error("bad #line syntax"); error("bad #line syntax");
SkipToNewLine(); SkipToNewLine();
} }
@ -133,7 +137,7 @@ domacro()
do_pragma(); do_pragma();
break; break;
case K_UNDEF: /* "undef" */ case K_UNDEF: /* "undef" */
do_undef((char *)0); do_undef((char*)0);
break; break;
default: default:
/* invalid word seen after the '#' */ /* invalid word seen after the '#' */
@ -152,9 +156,7 @@ domacro()
} }
} }
void void skip_block(to_endif) int to_endif;
skip_block(to_endif)
int to_endif;
{ {
/* skip_block() skips the input from /* skip_block() skips the input from
1) a false #if, #ifdef, #ifndef or #elif until the 1) a false #if, #ifdef, #ifndef or #elif until the
@ -168,33 +170,49 @@ int to_endif;
register int skiplevel = nestlevel; /* current nesting level */ register int skiplevel = nestlevel; /* current nesting level */
struct token tk; struct token tk;
int toknum; int toknum;
struct idf *id; struct idf* id;
NoUnstack++; NoUnstack++;
for (;;) { for (;;)
{
ch = GetChar(); /* read first character after newline */ ch = GetChar(); /* read first character after newline */
while (class(ch) == STSKIP) while (class(ch) == STSKIP)
ch = GetChar(); ch = GetChar();
if (ch != '#') { if (ch != '#')
if (ch == EOI) { {
if (ch == EOI)
{
NoUnstack--; NoUnstack--;
return; return;
} }
if (ch == '/') { if (ch == '/')
if (ch != '*') UnGetChar(); {
else { ch = GetChar();
if (ch == '*')
{
skipcomment(); skipcomment();
continue; continue;
} }
} else UnGetChar(); else if (ch == '/')
{
skiplinecomment();
continue;
}
else
UnGetChar();
}
else
UnGetChar();
SkipToNewLine(); SkipToNewLine();
continue; continue;
} }
ReplaceMacros = 0; ReplaceMacros = 0;
toknum = GetToken(&tk); toknum = GetToken(&tk);
ReplaceMacros = 1; ReplaceMacros = 1;
if (toknum != IDENTIFIER) { if (toknum != IDENTIFIER)
if (toknum != INTEGER) { {
if (toknum != INTEGER)
{
error("illegal # line"); error("illegal # line");
} }
SkipToNewLine(); SkipToNewLine();
@ -206,13 +224,16 @@ int to_endif;
on the same level. on the same level.
*/ */
id = findidf(tk.tk_str); id = findidf(tk.tk_str);
if (id == (struct idf *)0) { if (id == (struct idf*)0)
{
/* invalid word seen after the '#' */ /* invalid word seen after the '#' */
warning("%s: unknown control", tk.tk_str); warning("%s: unknown control", tk.tk_str);
} }
free(tk.tk_str); free(tk.tk_str);
if (id == (struct idf *)0) continue; if (id == (struct idf*)0)
switch(id->id_resmac) { continue;
switch (id->id_resmac)
{
case K_DEFINE: case K_DEFINE:
case K_ERROR: case K_ERROR:
case K_INCLUDE: case K_INCLUDE:
@ -231,34 +252,42 @@ int to_endif;
case K_ELIF: case K_ELIF:
if (ifstack[nestlevel]) if (ifstack[nestlevel])
error("#elif after #else"); error("#elif after #else");
if (!to_endif && nestlevel == skiplevel) { if (!to_endif && nestlevel == skiplevel)
{
nestlevel--; nestlevel--;
push_if(); push_if();
if (ifexpr()) { if (ifexpr())
{
NoUnstack--; NoUnstack--;
return; return;
} }
} }
else SkipToNewLine(); /* otherwise done in ifexpr() */ else
SkipToNewLine(); /* otherwise done in ifexpr() */
break; break;
case K_ELSE: case K_ELSE:
if (ifstack[nestlevel]) if (ifstack[nestlevel])
error("#else after #else"); error("#else after #else");
++(ifstack[nestlevel]); ++(ifstack[nestlevel]);
if (!to_endif && nestlevel == skiplevel) { if (!to_endif && nestlevel == skiplevel)
if (SkipToNewLine()) { {
if (SkipToNewLine())
{
if (!options['o']) if (!options['o'])
strict("garbage following #else"); strict("garbage following #else");
} }
NoUnstack--; NoUnstack--;
return; return;
} }
else SkipToNewLine(); else
SkipToNewLine();
break; break;
case K_ENDIF: case K_ENDIF:
assert(nestlevel > svnestlevel[nestcount]); assert(nestlevel > svnestlevel[nestcount]);
if (nestlevel == skiplevel) { if (nestlevel == skiplevel)
if (SkipToNewLine()) { {
if (SkipToNewLine())
{
if (!options['o']) if (!options['o'])
strict("garbage following #endif"); strict("garbage following #endif");
} }
@ -266,14 +295,14 @@ int to_endif;
NoUnstack--; NoUnstack--;
return; return;
} }
else SkipToNewLine(); else
SkipToNewLine();
nestlevel--; nestlevel--;
break; break;
} }
} }
} }
ifexpr() ifexpr()
{ {
/* ifexpr() returns whether the restricted constant /* ifexpr() returns whether the restricted constant
@ -299,30 +328,37 @@ do_include()
{ {
/* do_include() performs the inclusion of a file. /* do_include() performs the inclusion of a file.
*/ */
char *filenm; char* filenm;
char *result; char* result;
int tok; int tok;
struct token tk; struct token tk;
AccFileSpecifier = 1; AccFileSpecifier = 1;
if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING) if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
filenm = tk.tk_str; filenm = tk.tk_str;
else { else
{
error("bad include syntax"); error("bad include syntax");
filenm = (char *)0; filenm = (char*)0;
} }
AccFileSpecifier = 0; AccFileSpecifier = 0;
if (SkipToNewLine()) { if (SkipToNewLine())
{
error("bad include syntax"); error("bad include syntax");
} }
inctable[0] = WorkingDir; inctable[0] = WorkingDir;
if (filenm) { if (filenm)
if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){ {
if (do_preprocess) error("cannot open include file \"%s\"", filenm); if (!InsertFile(filenm, &inctable[tok == FILESPECIFIER], &result))
else warning("cannot open include file \"%s\"", filenm); {
if (do_preprocess)
error("cannot open include file \"%s\"", filenm);
else
warning("cannot open include file \"%s\"", filenm);
add_dependency(filenm); add_dependency(filenm);
} }
else { else
{
add_dependency(result); add_dependency(result);
WorkingDir = getwdir(result); WorkingDir = getwdir(result);
svnestlevel[++nestcount] = nestlevel; svnestlevel[++nestcount] = nestlevel;
@ -332,22 +368,22 @@ do_include()
} }
} }
void void do_define()
do_define()
{ {
/* do_define() interprets a #define control line. /* do_define() interprets a #define control line.
*/ */
register char *str; /* the #defined identifier's descriptor */ register char* str; /* the #defined identifier's descriptor */
int nformals = -1; /* keep track of the number of formals */ int nformals = -1; /* keep track of the number of formals */
char *formals[NPARAMS]; /* pointers to the names of the formals */ char* formals[NPARAMS]; /* pointers to the names of the formals */
char parbuf[PARBUFSIZE]; /* names of formals */ char parbuf[PARBUFSIZE]; /* names of formals */
char *repl_text; /* start of the replacement text */ char* repl_text; /* start of the replacement text */
int length; /* length of the replacement text */ int length; /* length of the replacement text */
register ch; register ch;
char *get_text(); char* get_text();
/* read the #defined macro's name */ /* read the #defined macro's name */
if (!(str = GetIdentifier(1))) { if (!(str = GetIdentifier(1)))
{
error("#define: illegal macro name"); error("#define: illegal macro name");
return; return;
} }
@ -355,8 +391,10 @@ do_define()
followed immediately by a '('. followed immediately by a '('.
*/ */
ch = GetChar(); ch = GetChar();
if (ch == '(') { if (ch == '(')
if ((nformals = getparams(formals, parbuf)) == -1) { {
if ((nformals = getparams(formals, parbuf)) == -1)
{
SkipToNewLine(); SkipToNewLine();
free(str); free(str);
return; /* an error occurred */ return; /* an error occurred */
@ -364,7 +402,7 @@ do_define()
ch = GetChar(); ch = GetChar();
} }
/* read the replacement text if there is any */ /* read the replacement text if there is any */
ch = skipspaces(ch,0); /* find first character of the text */ ch = skipspaces(ch, 0); /* find first character of the text */
assert(ch != EOI); assert(ch != EOI);
/* UnGetChar() is not right when replacement starts with a '/' */ /* UnGetChar() is not right when replacement starts with a '/' */
ChPushBack(ch); ChPushBack(ch);
@ -383,12 +421,15 @@ push_if()
do_elif() do_elif()
{ {
if (nestlevel <= svnestlevel[nestcount]) { if (nestlevel <= svnestlevel[nestcount])
{
error("#elif without corresponding #if"); error("#elif without corresponding #if");
SkipToNewLine(); SkipToNewLine();
} }
else { /* restart at this level as if a #if is detected. */ else
if (ifstack[nestlevel]) { { /* restart at this level as if a #if is detected. */
if (ifstack[nestlevel])
{
error("#elif after #else"); error("#elif after #else");
SkipToNewLine(); SkipToNewLine();
} }
@ -400,14 +441,17 @@ do_elif()
do_else() do_else()
{ {
if (SkipToNewLine()) { if (SkipToNewLine())
{
if (!options['o']) if (!options['o'])
strict("garbage following #else"); strict("garbage following #else");
} }
if (nestlevel <= svnestlevel[nestcount]) if (nestlevel <= svnestlevel[nestcount])
error("#else without corresponding #if"); error("#else without corresponding #if");
else { /* mark this level as else-d */ else
if (ifstack[nestlevel]) { { /* mark this level as else-d */
if (ifstack[nestlevel])
{
error("#else after #else"); error("#else after #else");
} }
++(ifstack[nestlevel]); ++(ifstack[nestlevel]);
@ -417,14 +461,17 @@ do_else()
do_endif() do_endif()
{ {
if (SkipToNewLine()) { if (SkipToNewLine())
{
if (!options['o']) if (!options['o'])
strict("garbage following #endif"); strict("garbage following #endif");
} }
if (nestlevel <= svnestlevel[nestcount]) { if (nestlevel <= svnestlevel[nestcount])
{
error("#endif without corresponding #if"); error("#endif without corresponding #if");
} }
else nestlevel--; else
nestlevel--;
} }
do_if() do_if()
@ -436,23 +483,26 @@ do_if()
do_ifdef(how) do_ifdef(how)
{ {
register struct idf *id; register struct idf* id;
register char *str; register char* str;
/* how == 1 : ifdef; how == 0 : ifndef /* how == 1 : ifdef; how == 0 : ifndef
*/ */
push_if(); push_if();
if (!(str = GetIdentifier(1))) { if (!(str = GetIdentifier(1)))
{
error("illegal #ifdef construction"); error("illegal #ifdef construction");
id = (struct idf *)0; id = (struct idf*)0;
} else { }
else
{
id = findidf(str); id = findidf(str);
free(str); free(str);
} }
if (SkipToNewLine()) { if (SkipToNewLine())
{
if (str && !options['o']) if (str && !options['o'])
strict("garbage following #%s <identifier>", strict("garbage following #%s <identifier>", how ? "ifdef" : "ifndef");
how ? "ifdef" : "ifndef");
} }
/* The next test is a shorthand for: /* The next test is a shorthand for:
@ -463,26 +513,32 @@ do_ifdef(how)
} }
/* argstr != NULL when the undef came from a -U option */ /* argstr != NULL when the undef came from a -U option */
do_undef(argstr) do_undef(argstr) char* argstr;
char *argstr;
{ {
register struct idf *id; register struct idf* id;
register char *str = argstr; register char* str = argstr;
/* Forget a macro definition. */ /* Forget a macro definition. */
if (str || (str = GetIdentifier(1))) { if (str || (str = GetIdentifier(1)))
if ((id = findidf(str)) && id->id_macro) { {
if (id->id_macro->mc_flag & NOUNDEF) { if ((id = findidf(str)) && id->id_macro)
{
if (id->id_macro->mc_flag & NOUNDEF)
{
error("it is not allowed to #undef %s", str); error("it is not allowed to #undef %s", str);
} else { }
else
{
free(id->id_macro->mc_text); free(id->id_macro->mc_text);
free_macro(id->id_macro); free_macro(id->id_macro);
id->id_macro = (struct macro *) 0; id->id_macro = (struct macro*)0;
} }
} /* else: don't complain */ } /* else: don't complain */
if (!argstr){ if (!argstr)
{
free(str); free(str);
if (SkipToNewLine()) { if (SkipToNewLine())
{
if (!options['o']) if (!options['o'])
strict("garbage following #undef"); strict("garbage following #undef");
} }
@ -495,18 +551,16 @@ do_undef(argstr)
do_error() do_error()
{ {
int len; int len;
char *get_text(); char* get_text();
char *bp = get_text((char **) 0, &len); char* bp = get_text((char**)0, &len);
error("user error: %s", bp); error("user error: %s", bp);
free(bp); free(bp);
LineNumber++; LineNumber++;
} }
int int getparams(buf, parbuf) char* buf[];
getparams(buf, parbuf) char parbuf[];
char *buf[];
char parbuf[];
{ {
/* getparams() reads the formal parameter list of a macro /* getparams() reads the formal parameter list of a macro
definition. definition.
@ -518,19 +572,22 @@ getparams(buf, parbuf)
Note that the '(' has already been eaten. Note that the '(' has already been eaten.
The names of the formal parameters are stored into parbuf. The names of the formal parameters are stored into parbuf.
*/ */
register char **pbuf = &buf[0]; register char** pbuf = &buf[0];
register int c; register int c;
register char *ptr = &parbuf[0]; register char* ptr = &parbuf[0];
register char **pbuf2; register char** pbuf2;
c = GetChar(); c = GetChar();
c = skipspaces(c,0); c = skipspaces(c, 0);
if (c == ')') { /* no parameters: #define name() */ if (c == ')')
*pbuf = (char *) 0; { /* no parameters: #define name() */
*pbuf = (char*)0;
return 0; return 0;
} }
for (;;) { /* eat the formal parameter list */ for (;;)
if (class(c) != STIDF && class(c) != STELL) { { /* eat the formal parameter list */
if (class(c) != STIDF && class(c) != STELL)
{
error("#define: bad formal parameter"); error("#define: bad formal parameter");
return -1; return -1;
} }
@ -538,7 +595,8 @@ getparams(buf, parbuf)
*ptr++ = c; *ptr++ = c;
if (ptr >= &parbuf[PARBUFSIZE]) if (ptr >= &parbuf[PARBUFSIZE])
fatal("formal parameter buffer overflow"); fatal("formal parameter buffer overflow");
do { /* eat the identifier name */ do
{ /* eat the identifier name */
c = GetChar(); c = GetChar();
*ptr++ = c; *ptr++ = c;
if (ptr >= &parbuf[PARBUFSIZE]) if (ptr >= &parbuf[PARBUFSIZE])
@ -549,52 +607,61 @@ getparams(buf, parbuf)
/* Check if this formal parameter is already used. /* Check if this formal parameter is already used.
Usually, macros do not have many parameters, so ... Usually, macros do not have many parameters, so ...
*/ */
for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--) { for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--)
if (!strcmp(*pbuf2, *pbuf)) { {
warning("formal parameter \"%s\" already used", if (!strcmp(*pbuf2, *pbuf))
*pbuf); {
warning("formal parameter \"%s\" already used", *pbuf);
} }
} }
pbuf++; pbuf++;
c = skipspaces(c,0); c = skipspaces(c, 0);
if (c == ')') { /* end of the formal parameter list */ if (c == ')')
*pbuf = (char *) 0; { /* end of the formal parameter list */
*pbuf = (char*)0;
return pbuf - buf; return pbuf - buf;
} }
if (c != ',') { if (c != ',')
{
error("#define: bad formal parameter list"); error("#define: bad formal parameter list");
return -1; return -1;
} }
c = GetChar(); c = GetChar();
c = skipspaces(c,0); c = skipspaces(c, 0);
} }
/*NOTREACHED*/ /*NOTREACHED*/
} }
void void macro_def(id, text, nformals, length, flags) register struct idf* id;
macro_def(id, text, nformals, length, flags) char* text;
register struct idf *id;
char *text;
{ {
register struct macro *newdef = id->id_macro; register struct macro* newdef = id->id_macro;
/* macro_def() puts the contents and information of a macro /* macro_def() puts the contents and information of a macro
definition into a structure and stores it into the symbol definition into a structure and stores it into the symbol
table entry belonging to the name of the macro. table entry belonging to the name of the macro.
An error is given if there was already a definition An error is given if there was already a definition
*/ */
if (newdef) { /* is there a redefinition? */ if (newdef)
if (newdef->mc_flag & NOUNDEF) { { /* is there a redefinition? */
if (newdef->mc_flag & NOUNDEF)
{
error("it is not allowed to redefine %s", id->id_text); error("it is not allowed to redefine %s", id->id_text);
} else if (!macroeq(newdef->mc_text, text)) }
else if (!macroeq(newdef->mc_text, text))
error("illegal redefine of \"%s\"", id->id_text); error("illegal redefine of \"%s\"", id->id_text);
free(text); free(text);
return; return;
} else { }
else
{
#ifdef DOBITS #ifdef DOBITS
register char *p = id->id_text; register char* p = id->id_text;
#define setbit(bx) if (!*p) goto go_on; bits[*p++] |= (bx) #define setbit(bx) \
if (!*p) \
goto go_on; \
bits[*p++] |= (bx)
setbit(bit0); setbit(bit0);
setbit(bit1); setbit(bit1);
setbit(bit2); setbit(bit2);
@ -614,15 +681,13 @@ macro_def(id, text, nformals, length, flags)
newdef->mc_flag = flags; /* special flags */ newdef->mc_flag = flags; /* special flags */
} }
int int find_name(nm, index) char *nm, *index[];
find_name(nm, index)
char *nm, *index[];
{ {
/* find_name() returns the index of "nm" in the namelist /* find_name() returns the index of "nm" in the namelist
"index" if it can be found there. 0 is returned if it is "index" if it can be found there. 0 is returned if it is
not there. not there.
*/ */
register char **ip = &index[0]; register char** ip = &index[0];
while (*ip) while (*ip)
if (strcmp(nm, *ip++) == 0) if (strcmp(nm, *ip++) == 0)
@ -633,10 +698,8 @@ find_name(nm, index)
#define BLANK(ch) ((ch == ' ') || (ch == '\t')) #define BLANK(ch) ((ch == ' ') || (ch == '\t'))
char * char* get_text(formals, length) char* formals[];
get_text(formals, length) int* length;
char *formals[];
int *length;
{ {
/* get_text() copies the replacement text of a macro /* get_text() copies the replacement text of a macro
definition with zero, one or more parameters, thereby definition with zero, one or more parameters, thereby
@ -662,104 +725,138 @@ get_text(formals, length)
*/ */
register int c; register int c;
struct repl repls; struct repl repls;
register struct repl *repl = &repls; register struct repl* repl = &repls;
int blank = 0; int blank = 0;
c = GetChar(); c = GetChar();
repl->r_ptr = repl->r_text = Malloc((unsigned)(repl->r_size = ITEXTSIZE)); repl->r_ptr = repl->r_text = Malloc((unsigned)(repl->r_size = ITEXTSIZE));
*repl->r_ptr = '\0'; *repl->r_ptr = '\0';
while ((c != EOI) && (class(c) != STNL)) { while ((c != EOI) && (class(c) != STNL))
if (BLANK(c)) { {
if (BLANK(c))
{
blank++; blank++;
c = GetChar(); c = GetChar();
continue; continue;
} }
if (c == '\'' || c == '"') { if (c == '\'' || c == '"')
{
register int delim = c; register int delim = c;
if (blank) { if (blank)
{
blank = 0; blank = 0;
add2repl(repl, ' '); add2repl(repl, ' ');
} }
do { do
{
add2repl(repl, c); add2repl(repl, c);
if (c == '\\') add2repl(repl, GetChar()); if (c == '\\')
add2repl(repl, GetChar());
c = GetChar(); c = GetChar();
} while (c != delim && c != EOI && class(c) != STNL); } while (c != delim && c != EOI && class(c) != STNL);
if (c != delim) { if (c != delim)
{
strict("unclosed opening %c", delim); strict("unclosed opening %c", delim);
break; break;
} }
add2repl(repl, c); add2repl(repl, c);
c = GetChar(); c = GetChar();
} else if (c == '/') { }
else if (c == '/')
{
c = GetChar(); c = GetChar();
if (c == '*') { if (c == '*')
{
skipcomment(); skipcomment();
blank++; blank++;
c = GetChar(); c = GetChar();
continue; continue;
} }
if (blank) { else if (c == '/')
{
skiplinecomment();
blank++;
c = GetChar();
continue;
}
if (blank)
{
blank = 0; blank = 0;
add2repl(repl, ' '); add2repl(repl, ' ');
} }
add2repl(repl, '/'); add2repl(repl, '/');
} else if (formals }
&& (class(c) == STIDF || class(c) == STELL)) { else if (formals && (class(c) == STIDF || class(c) == STELL))
{
char id_buf[IDFSIZE + 1]; char id_buf[IDFSIZE + 1];
register char *idp = id_buf; register char* idp = id_buf;
int n; int n;
/* read identifier: it may be a formal parameter */ /* read identifier: it may be a formal parameter */
*idp++ = c; *idp++ = c;
do { do
{
c = GetChar(); c = GetChar();
if (idp <= &id_buf[IDFSIZE]) if (idp <= &id_buf[IDFSIZE])
*idp++ = c; *idp++ = c;
} while (in_idf(c)); } while (in_idf(c));
*--idp = '\0'; *--idp = '\0';
if (blank) { if (blank)
{
blank = 0; blank = 0;
add2repl(repl, ' '); add2repl(repl, ' ');
} }
/* construct the formal parameter mark or identifier */ /* construct the formal parameter mark or identifier */
if (n = find_name(id_buf, formals)) if (n = find_name(id_buf, formals))
add2repl(repl, FORMALP | (char) n); add2repl(repl, FORMALP | (char)n);
else { else
{
idp = id_buf; idp = id_buf;
while (*idp) add2repl(repl, *idp++); while (*idp)
add2repl(repl, *idp++);
} }
} else if (class(c) == STNUM) { }
if (blank) { else if (class(c) == STNUM)
{
if (blank)
{
blank = 0; blank = 0;
add2repl(repl, ' '); add2repl(repl, ' ');
} }
add2repl(repl, c); add2repl(repl, c);
if (c == '.') { if (c == '.')
{
c = GetChar(); c = GetChar();
if (class(c) != STNUM) { if (class(c) != STNUM)
{
continue; continue;
} }
add2repl(repl, c); add2repl(repl, c);
} }
c = GetChar(); c = GetChar();
while(in_idf(c) || c == '.') { while (in_idf(c) || c == '.')
{
add2repl(repl, c); add2repl(repl, c);
if((c = GetChar()) == 'e' || c == 'E') { if ((c = GetChar()) == 'e' || c == 'E')
{
add2repl(repl, c); add2repl(repl, c);
c = GetChar(); c = GetChar();
if (c == '+' || c == '-') { if (c == '+' || c == '-')
{
add2repl(repl, c); add2repl(repl, c);
c = GetChar(); c = GetChar();
} }
} }
} }
} else { }
if (blank) { else
{
if (blank)
{
blank = 0; blank = 0;
add2repl(repl, ' '); add2repl(repl, ' ');
} }
@ -768,7 +865,7 @@ get_text(formals, length)
} }
} }
*length = repl->r_ptr - repl->r_text; *length = repl->r_ptr - repl->r_text;
return Realloc(repl->r_text, (unsigned)(repl->r_ptr - repl->r_text +1)); return Realloc(repl->r_text, (unsigned)(repl->r_ptr - repl->r_text + 1));
} }
/* macroeq() decides whether two macro replacement texts are /* macroeq() decides whether two macro replacement texts are
@ -776,36 +873,42 @@ get_text(formals, length)
as strings, without taking care of the leading and trailing as strings, without taking care of the leading and trailing
blanks (spaces and tabs). blanks (spaces and tabs).
*/ */
macroeq(s, t) macroeq(s, t) register char* s, *t;
register char *s, *t;
{ {
/* skip leading spaces */ /* skip leading spaces */
while (BLANK(*s)) s++; while (BLANK(*s))
while (BLANK(*t)) t++; s++;
while (BLANK(*t))
t++;
/* first non-blank encountered in both strings */ /* first non-blank encountered in both strings */
/* The actual comparison loop: */ /* The actual comparison loop: */
while (*s && *s == *t) while (*s && *s == *t)
s++, t++; s++, t++;
/* two cases are possible when arrived here: */ /* two cases are possible when arrived here: */
if (*s == '\0') { /* *s == '\0' */ if (*s == '\0')
while (BLANK(*t)) t++; { /* *s == '\0' */
while (BLANK(*t))
t++;
return *t == '\0'; return *t == '\0';
} }
else { /* *s != *t */ else
while (BLANK(*s)) s++; { /* *s != *t */
while (BLANK(*t)) t++; while (BLANK(*s))
s++;
while (BLANK(*t))
t++;
return (*s == '\0') && (*t == '\0'); return (*s == '\0') && (*t == '\0');
} }
} }
do_line(l) do_line(l) unsigned int l;
unsigned int l;
{ {
struct token tk; struct token tk;
int t = GetToken(&tk); int t = GetToken(&tk);
if (t != EOF) SkipToNewLine(); if (t != EOF)
SkipToNewLine();
LineNumber = l; /* the number of the next input line */ LineNumber = l; /* the number of the next input line */
if (t == STRING) /* is there a filespecifier? */ if (t == STRING) /* is there a filespecifier? */
FileName = tk.tk_str; FileName = tk.tk_str;

View file

@ -24,73 +24,94 @@ char bits[128];
#endif #endif
extern int InputLevel; extern int InputLevel;
extern char *sprint(); extern char* sprint();
Xflush() Xflush()
{ {
sys_write(STDOUT, _obuf, OBUFSIZE); sys_write(STDOUT, _obuf, OBUFSIZE);
} }
static char *SkipComment(); static char* SkipComment();
extern char options[]; extern char options[];
/* #pragma directives are saved here and passed to the compiler later on. /* #pragma directives are saved here and passed to the compiler later on.
*/ */
struct prag_info { struct prag_info
{
int pr_linnr; int pr_linnr;
char *pr_fil; char* pr_fil;
char *pr_text; char* pr_text;
}; };
static struct prag_info *pragma_tab; static struct prag_info* pragma_tab;
static int pragma_nr; static int pragma_nr;
do_pragma() do_pragma()
{ {
register int size = ITEXTSIZE; register int size = ITEXTSIZE;
char *cur_line = Malloc((unsigned)size); char* cur_line = Malloc((unsigned)size);
register char *c_ptr = cur_line; register char* c_ptr = cur_line;
register int c = GetChar(); register int c = GetChar();
register int delim = 0; register int delim = 0;
while(c != '\n') { while (c != '\n')
if (c_ptr + 1 - cur_line == size) { {
if (c_ptr + 1 - cur_line == size)
{
cur_line = Realloc(cur_line, (unsigned)(size + ITEXTSIZE)); cur_line = Realloc(cur_line, (unsigned)(size + ITEXTSIZE));
c_ptr = cur_line + size - 1; c_ptr = cur_line + size - 1;
size += ITEXTSIZE; size += ITEXTSIZE;
} }
if (delim) { if (delim)
if (c == delim) { {
if (c == delim)
{
delim = 0; delim = 0;
} }
else if (c == '\\') { else if (c == '\\')
{
*c_ptr++ = c; *c_ptr++ = c;
c = GetChar(); c = GetChar();
if (c == '\n') break; if (c == '\n')
break;
} }
} }
else if (c == '\'' || c == '"') { else if (c == '\'' || c == '"')
{
delim = c; delim = c;
} }
else if (c == '/') { else if (c == '/')
if ((c = GetChar()) != '*' || InputLevel) { {
*c_ptr++ = '/'; if (!InputLevel)
} {
else { c = GetChar();
if (c == '*')
{
skipcomment(); skipcomment();
continue; continue;
} }
else if (c == '/')
{
skiplinecomment();
continue;
}
*c_ptr++ = '/';
}
} }
*c_ptr++ = c; *c_ptr++ = c;
c = GetChar(); c = GetChar();
} }
*c_ptr = '\0'; *c_ptr = '\0';
if (!pragma_nr) { if (!pragma_nr)
pragma_tab = (struct prag_info *)Malloc(sizeof(struct prag_info)); {
} else { pragma_tab = (struct prag_info*)Malloc(sizeof(struct prag_info));
pragma_tab = (struct prag_info *)Realloc((char *)pragma_tab
, (unsigned)(sizeof(struct prag_info) * (pragma_nr+1)));
} }
if (delim) { else
{
pragma_tab = (struct prag_info*)Realloc(
(char*)pragma_tab, (unsigned)(sizeof(struct prag_info) * (pragma_nr + 1)));
}
if (delim)
{
error("unclosed opening %c", delim); error("unclosed opening %c", delim);
} }
pragma_tab[pragma_nr].pr_linnr = LineNumber; pragma_tab[pragma_nr].pr_linnr = LineNumber;
@ -102,98 +123,130 @@ do_pragma()
char Xbuf[256]; char Xbuf[256];
void void preprocess(fn) char* fn;
preprocess(fn)
char *fn;
{ {
register int c; register int c;
register char *op = _obuf; register char* op = _obuf;
register char *ob = &_obuf[OBUFSIZE]; register char* ob = &_obuf[OBUFSIZE];
int lineno = 0; int lineno = 0;
int startline; int startline;
#define flush(X) (sys_write(STDOUT,_obuf,X)) #define flush(X) (sys_write(STDOUT, _obuf, X))
#define echo(ch) if (op == ob) { Xflush(); op = _obuf; } *op++ = (ch); #define echo(ch) \
#define newline() op--; while (op >= _obuf && (*op == ' ' || *op == '\t')) op--; op++; echo('\n') if (op == ob) \
{ \
Xflush(); \
op = _obuf; \
} \
*op++ = (ch);
#define newline() \
op--; \
while (op >= _obuf && (*op == ' ' || *op == '\t')) \
op--; \
op++; \
echo('\n')
if (!options['P']) { if (!options['P'])
{
/* Generate a line directive communicating the /* Generate a line directive communicating the
source filename source filename
*/ */
register char *p = Xbuf; register char* p = Xbuf;
sprint(p, "%s 1 \"%s\"\n", sprint(p, "%s 1 \"%s\"\n", LINE_PREFIX, FileName);
LINE_PREFIX, while (*p)
FileName); {
while (*p) {
echo(*p++); echo(*p++);
} }
} }
#define do_line_dir(lineno, fn) \ #define do_line_dir(lineno, fn) \
if (lineno != LineNumber || fn != FileName) { \ if (lineno != LineNumber || fn != FileName) \
{ \
fn = FileName; \ fn = FileName; \
lineno = LineNumber; \ lineno = LineNumber; \
if (! options['P']) { \ if (!options['P']) \
register char *p = Xbuf; \ { \
sprint(Xbuf, "%s %d \"%s\"\n", \ register char* p = Xbuf; \
LINE_PREFIX, \ sprint(Xbuf, "%s %d \"%s\"\n", LINE_PREFIX, (int)LineNumber, FileName); \
(int)LineNumber, \ op--; \
FileName); \ while (op >= _obuf && (class(*op) == STSKIP || *op == '\n')) \
op--; \ op--; \
while (op >= _obuf \
&& (class(*op) == STSKIP \
|| *op == '\n')) op--; \
op++; \ op++; \
newline(); \ newline(); \
while (*p) { \ while (*p) \
{ \
echo(*p++); \ echo(*p++); \
} \ } \
} \ } \
} }
for (;;) { for (;;)
{
LineNumber++; LineNumber++;
lineno++; lineno++;
startline = 1; startline = 1;
c = GetChar(); c = GetChar();
while (startline) { while (startline)
{
/* first flush the saved pragma's */ /* first flush the saved pragma's */
if (pragma_nr) { if (pragma_nr)
{
register int i = 0; register int i = 0;
int LiNo = LineNumber; int LiNo = LineNumber;
char *FiNam = FileName; char* FiNam = FileName;
while (i < pragma_nr) { while (i < pragma_nr)
register char *c_ptr = "#pragma"; {
register char* c_ptr = "#pragma";
LineNumber = pragma_tab[i].pr_linnr; LineNumber = pragma_tab[i].pr_linnr;
FileName = pragma_tab[i].pr_fil; FileName = pragma_tab[i].pr_fil;
do_line_dir(lineno, fn); do_line_dir(lineno, fn);
while (*c_ptr) { echo(*c_ptr++); } while (*c_ptr)
{
echo(*c_ptr++);
}
c_ptr = pragma_tab[i].pr_text; c_ptr = pragma_tab[i].pr_text;
while (*c_ptr) { echo(*c_ptr++); } while (*c_ptr)
newline(); lineno++; {
echo(*c_ptr++);
}
newline();
lineno++;
free(pragma_tab[i].pr_text); free(pragma_tab[i].pr_text);
i++; i++;
} }
free((char *) pragma_tab); free((char*)pragma_tab);
pragma_tab = (struct prag_info *)0; pragma_tab = (struct prag_info*)0;
pragma_nr = 0; pragma_nr = 0;
LineNumber = LiNo; LineNumber = LiNo;
FileName = FiNam; FileName = FiNam;
do_line_dir(lineno, fn); do_line_dir(lineno, fn);
} }
while (class(c) == STSKIP || c == '/')
while (class(c) == STSKIP || c == '/') { {
if (c == '/') { if (c == '/')
if (!InputLevel) { {
if (!InputLevel)
{
c = GetChar(); c = GetChar();
if (c == '*') { if (c == '*')
{
op = SkipComment(op, &lineno); op = SkipComment(op, &lineno);
if (!op) return; if (!op)
if (!options['C']) { echo(' '); } return;
if (!options['C'])
{
echo(' ');
}
c = GetChar();
continue;
}
else if (c == '/')
{
skiplinecomment();
c = GetChar(); c = GetChar();
continue; continue;
} }
@ -206,34 +259,52 @@ preprocess(fn)
c = GetChar(); c = GetChar();
} }
if (c == '#') { if (c == '#')
{
domacro(); domacro();
lineno++; lineno++;
newline(); newline();
do_line_dir(lineno, fn); do_line_dir(lineno, fn);
c = GetChar(); c = GetChar();
} else startline = 0; }
else
startline = 0;
} }
do_line_dir(lineno, fn); do_line_dir(lineno, fn);
for (;;) { for (;;)
{
/* illegal character */ /* illegal character */
if (c & 0200) { if (c & 0200)
if (c == EOI) { {
if (c == EOI)
{
newline(); newline();
flush((int)(op-_obuf)); flush((int)(op - _obuf));
return; return;
} }
fatal("non-ascii character read"); fatal("non-ascii character read");
} }
/* comments */ /* comments */
if (c == '/' && !InputLevel) { if (c == '/' && !InputLevel)
{
c = GetChar(); c = GetChar();
if (c == '*') { if (c == '*')
{
op = SkipComment(op, &lineno); op = SkipComment(op, &lineno);
if (!op) return; if (!op)
if (!options['C']) { echo(' '); } return;
if (!options['C'])
{
echo(' ');
}
c = GetChar();
continue;
}
else if (c == '/')
{
skiplinecomment();
c = GetChar(); c = GetChar();
continue; continue;
} }
@ -242,7 +313,8 @@ preprocess(fn)
} }
/* switch on character */ /* switch on character */
switch(class(c)) { switch (class(c))
{
case STNL: case STNL:
newline(); newline();
break; break;
@ -252,26 +324,33 @@ preprocess(fn)
register int stopc = c; register int stopc = c;
int escaped; int escaped;
do { do
{
escaped = 0; escaped = 0;
echo(c); echo(c);
c = GetChar(); c = GetChar();
if (c == '\n') { if (c == '\n')
{
/* the compiler will complain */ /* the compiler will complain */
break; break;
} }
else if (c == EOI) { else if (c == EOI)
{
newline(); newline();
flush((int)(op-_obuf)); flush((int)(op - _obuf));
return; return;
} }
if (c == '\\') { if (c == '\\')
{
echo(c); echo(c);
c = GetChar(); c = GetChar();
if (c == '\n') { if (c == '\n')
{
++LineNumber; ++LineNumber;
lineno++; lineno++;
} else escaped = 1; }
else
escaped = 1;
} }
} while (escaped || c != stopc); } while (escaped || c != stopc);
echo(c); echo(c);
@ -285,112 +364,161 @@ preprocess(fn)
* ..3 == . .3 , whereas ...3 == ... 3 * ..3 == . .3 , whereas ...3 == ... 3
*/ */
echo(c); echo(c);
if (c == '.') { if (c == '.')
{
c = GetChar(); c = GetChar();
if (c == '.') { if (c == '.')
if ((c = GetChar()) == '.') { {
echo('.'); echo('.'); if ((c = GetChar()) == '.')
{
echo('.');
echo('.');
c = GetChar(); c = GetChar();
continue; continue;
} }
UnGetChar(); UnGetChar();
c = '.'; c = '.';
continue; continue;
} else if (!is_dig(c)) { }
else if (!is_dig(c))
{
continue; continue;
} else { echo(c); } }
else
{
echo(c);
}
} }
c = GetChar(); c = GetChar();
while (in_idf(c) || c == '.') { while (in_idf(c) || c == '.')
{
echo(c); echo(c);
if (c == 'e' || c == 'E') { if (c == 'e' || c == 'E')
{
c = GetChar(); c = GetChar();
if (c == '+' || c == '-') { if (c == '+' || c == '-')
{
echo(c); echo(c);
c = GetChar(); c = GetChar();
} }
} else c = GetChar(); }
else
c = GetChar();
} }
continue; continue;
case STELL: case STELL:
c = GetChar(); c = GetChar();
UnGetChar(); UnGetChar();
if (c == '"' || c == '\'') { if (c == '"' || c == '\'')
{
echo('L'); echo('L');
continue; continue;
} }
c = 'L'; c = 'L';
case STIDF: { case STIDF:
{
extern int idfsize; /* ??? */ extern int idfsize; /* ??? */
char buf[IDFSIZE + 1]; char buf[IDFSIZE + 1];
register char *tg = &buf[0]; register char* tg = &buf[0];
register char *maxpos = &buf[idfsize]; register char* maxpos = &buf[idfsize];
register struct idf *idef; register struct idf* idef;
int NoExpandNext = 0; int NoExpandNext = 0;
#define tstmac(bx) if (!(bits[c] & bx)) goto nomac #define tstmac(bx) \
if (!(bits[c] & bx)) \
goto nomac
#define cpy *tg++ = c #define cpy *tg++ = c
#define load c = GetChar(); if (!in_idf(c)) goto endidf #define load \
c = GetChar(); \
if (!in_idf(c)) \
goto endidf
/* unstack macro's when allowed. */ /* unstack macro's when allowed. */
if (Unstacked) if (Unstacked)
EnableMacros(); EnableMacros();
if (c == NOEXPM) { if (c == NOEXPM)
{
NoExpandNext = 1; NoExpandNext = 1;
c = GetChar(); c = GetChar();
} }
#ifdef DOBITS #ifdef DOBITS
cpy; tstmac(bit0); load; cpy;
cpy; tstmac(bit1); load; tstmac(bit0);
cpy; tstmac(bit2); load; load;
cpy; tstmac(bit3); load; cpy;
cpy; tstmac(bit4); load; tstmac(bit1);
cpy; tstmac(bit5); load; load;
cpy; tstmac(bit6); load; cpy;
cpy; tstmac(bit7); load; tstmac(bit2);
load;
cpy;
tstmac(bit3);
load;
cpy;
tstmac(bit4);
load;
cpy;
tstmac(bit5);
load;
cpy;
tstmac(bit6);
load;
cpy;
tstmac(bit7);
load;
#endif #endif
for(;;) { for (;;)
if (tg < maxpos) { {
if (tg < maxpos)
{
cpy; cpy;
} }
load; load;
} }
endidf: endidf:
if (c != EOF) UnGetChar(); if (c != EOF)
UnGetChar();
*tg = '\0'; /* mark the end of the identifier */ *tg = '\0'; /* mark the end of the identifier */
if ((idef = findidf(buf)) if ((idef = findidf(buf)) && idef->id_macro && ReplaceMacros && !NoExpandNext)
&& idef->id_macro {
&& ReplaceMacros && !NoExpandNext) { if (replace(idef))
if (replace(idef)) { {
echo(' '); echo(' ');
c = GetChar(); c = GetChar();
continue; continue;
} }
tg = buf; tg = buf;
while (*tg) { while (*tg)
{
echo(*tg++); echo(*tg++);
} }
c = GetChar(); c = GetChar();
if (in_idf(c)) { echo(' '); } if (in_idf(c))
{
echo(' ');
}
continue; continue;
} }
nomac: nomac:
*tg = '\0'; *tg = '\0';
tg = buf; tg = buf;
while (*tg) { while (*tg)
{
echo(*tg++); echo(*tg++);
} }
c = GetChar(); c = GetChar();
while (in_idf(c)) { while (in_idf(c))
{
echo(c); echo(c);
c = GetChar(); c = GetChar();
} }
continue; continue;
} }
case STMSPEC: case STMSPEC:
if (InputLevel) { if (InputLevel)
{
echo(' '); /* seperate tokens */ echo(' '); /* seperate tokens */
c = GetChar(); c = GetChar();
continue; continue;
@ -407,49 +535,60 @@ preprocess(fn)
/*NOTREACHED*/ /*NOTREACHED*/
} }
static char * static char* SkipComment(op, lineno) char* op;
SkipComment(op, lineno) int* lineno;
char *op;
int *lineno;
{ {
char *ob = &_obuf[OBUFSIZE]; char* ob = &_obuf[OBUFSIZE];
register int c, oldc = '\0'; register int c, oldc = '\0';
NoUnstack++; NoUnstack++;
if (options['C']) { if (options['C'])
{
echo('/'); echo('/');
echo('*'); echo('*');
} }
c = GetChar(); c = GetChar();
for(;;) { for (;;)
if (c == EOI) { {
if (c == EOI)
{
newline(); newline();
flush((int)(op - _obuf)); flush((int)(op - _obuf));
op = 0; op = 0;
break; break;
} }
if (options['C']) { if (options['C'])
{
echo(c); echo(c);
} }
if (c == '\n') { if (c == '\n')
{
++LineNumber; ++LineNumber;
++*lineno; ++*lineno;
if (!options['C']) { if (!options['C'])
{
echo(c); echo(c);
} }
} }
if (c == '*') { if (c == '*')
{
c = GetChar(); c = GetChar();
if (c == '/') { if (c == '/')
if (options['C']) { {
if (options['C'])
{
echo(c); echo(c);
} }
break; /* for(;;) */ break; /* for(;;) */
} else if (oldc == '/') { }
else if (oldc == '/')
{
warning("comment inside comment ?"); warning("comment inside comment ?");
} }
oldc = '*'; oldc = '*';
} else { }
else
{
oldc = c; oldc = c;
c = GetChar(); c = GetChar();
} }

View file

@ -12,46 +12,57 @@
extern int InputLevel; extern int InputLevel;
int int skipspaces(ch, skipnl) register int ch;
skipspaces(ch, skipnl)
register int ch;
{ {
/* skipspaces() skips any white space and returns the first /* skipspaces() skips any white space and returns the first
non-space character. non-space character.
*/ */
register int nlseen = 0; register int nlseen = 0;
for (;;) { for (;;)
{
while (class(ch) == STSKIP) while (class(ch) == STSKIP)
ch = GetChar(); ch = GetChar();
if (skipnl && class(ch) == STNL) { if (skipnl && class(ch) == STNL)
{
ch = GetChar(); ch = GetChar();
LineNumber++; LineNumber++;
nlseen++; nlseen++;
continue; continue;
} }
if (ch == TOKSEP && InputLevel) { if (ch == TOKSEP && InputLevel)
{
ch = GetChar(); ch = GetChar();
continue; continue;
} }
/* \\\n are handled by trigraph */ /* \\\n are handled by trigraph */
if (ch == '/') { if (ch == '/')
{
ch = GetChar(); ch = GetChar();
if (ch == '*' && !InputLevel) { if (ch == '*' && !InputLevel)
{
skipcomment(); skipcomment();
ch = GetChar(); ch = GetChar();
} }
else { else if (ch == '/' && !InputLevel)
{
skiplinecomment();
ch = GetChar();
}
else
{
UnGetChar(); UnGetChar();
return '/'; return '/';
} }
} }
else if (nlseen && ch == '#') { else if (nlseen && ch == '#')
{
domacro(); domacro();
ch = GetChar(); ch = GetChar();
} else }
else
return ch; return ch;
} }
} }
@ -62,31 +73,54 @@ SkipToNewLine()
register int garbage = 0; register int garbage = 0;
register int delim = 0; register int delim = 0;
while ((ch = GetChar()) != '\n') { while ((ch = GetChar()) != '\n')
if (delim) { {
if (ch == '\\') { if (delim)
if (GetChar() == '\n') break; {
} else if (ch == delim) { if (ch == '\\')
{
if (GetChar() == '\n')
break;
}
else if (ch == delim)
{
delim = 0; delim = 0;
} }
continue; continue;
} else if (ch == '\'' || ch == '\"') { }
else if (ch == '\'' || ch == '\"')
{
delim = ch; delim = ch;
garbage = 1; garbage = 1;
} else if (ch == '/') { }
if (GetChar() == '*' && !InputLevel) { else if (ch == '/')
{
if (!InputLevel)
{
int nch = GetChar();
if (nch == '*')
{
skipcomment(); skipcomment();
continue; continue;
} }
else UnGetChar(); else if (nch == '/')
{
skiplinecomment();
continue;
} }
else if (ch == TOKSEP && InputLevel) { else
UnGetChar();
}
}
else if (ch == TOKSEP && InputLevel)
{
continue; continue;
} }
if (!is_wsp(ch)) if (!is_wsp(ch))
garbage = 1; garbage = 1;
} }
if (delim) strict("unclosed opening %c", delim); if (delim)
strict("unclosed opening %c", delim);
++LineNumber; ++LineNumber;
return garbage; return garbage;
} }

View file

@ -15,8 +15,8 @@ int __funccnt = 0;
void exit(int status) void exit(int status)
{ {
/* "Called in reversed order of their registration" */ /* "Called in reversed order of their registration" */
while (__funccnt >= 0) while (__funccnt)
(*__functab[__funccnt])(); (*__functab[--__funccnt])();
_exit(status); _exit(status);
} }

View file

@ -72,18 +72,8 @@ name cem
mapflag -V* CEM_F={CEM_F?} -V* mapflag -V* CEM_F={CEM_F?} -V*
rts .c rts .c
need .c need .c
prep always
args \ args \
{CPP_F?} \
-D__{ARCH} -D__{PLATFORM} \
-D__ACK \
{SYSINCLUDES?} \
{C_INCLUDES} \
{INCLUDES?} \
({ANSI_C?.xx}:.xx=-D{ARCH} \
-DEM_WSIZE={w} -DEM_PSIZE={p} \
-DEM_SSIZE={s} -DEM_LSIZE={l} -DEM_FSIZE={f} -DEM_DSIZE={d}) \
-D_EM_WSIZE={w} -D_EM_PSIZE={p} \
-D_EM_SSIZE={s} -D_EM_LSIZE={l} -D_EM_FSIZE={f} -D_EM_DSIZE={d} \
-Vw{w}.{wa}i{w}.{wa}p{p}.{pa}f{f}.{fa}s{s}.{sa}l{l}.{la}d{d}.{da}x{x}.{xa} \ -Vw{w}.{wa}i{w}.{wa}p{p}.{pa}f{f}.{fa}s{s}.{sa}l{l}.{la}d{d}.{da}x{x}.{xa} \
{CC_ALIGN?} \ {CC_ALIGN?} \
{CEM_F?} {LFLAG?} < > {CEM_F?} {LFLAG?} < >

View file

@ -340,6 +340,28 @@ InsertText(text, length)
return 1; return 1;
} }
#define RAWLOAD(dest) \
((void)((dest = *_ipp++) || (dest = loadbuf())))
/* Reads the next character, converting CRLF into LF. */
int
loadchar(void)
{
int ch;
RAWLOAD(ch);
if (ch == '\r')
{
RAWLOAD(ch);
if (ch != '\n')
{
/* Oops, this isn't a CRLF; put back the char we just read. */
ChPushBack(ch);
}
ch = '\n';
}
return ch;
}
/* loadbuf() is called if LoadChar meets a '\0' character /* loadbuf() is called if LoadChar meets a '\0' character
which may be the end-of-buffer mark of the current input which may be the end-of-buffer mark of the current input
buffer. The '\0' could be genuine although not likely. buffer. The '\0' could be genuine although not likely.

View file

@ -20,7 +20,7 @@
/* INPUT PRIMITIVES */ /* INPUT PRIMITIVES */
#define LoadChar(dest) ((void)((dest = *_ipp++) || (dest = loadbuf()))) #define LoadChar(dest) (dest = loadchar())
#define PushBack() (--_ipp) #define PushBack() (--_ipp)
#define ChPushBack(ch) (*--_ipp = (ch)) #define ChPushBack(ch) (*--_ipp = (ch))
@ -31,6 +31,7 @@
extern char *_ipp; extern char *_ipp;
_PROTOTYPE(int loadchar, (void));
_PROTOTYPE(int loadbuf, (void)); _PROTOTYPE(int loadbuf, (void));
_PROTOTYPE(int AtEoIT, (void)); _PROTOTYPE(int AtEoIT, (void));
_PROTOTYPE(int AtEoIF, (void)); _PROTOTYPE(int AtEoIF, (void));

View file

@ -47,6 +47,14 @@ struct timeb { /* non-existing; we use an ad-hoc definition */
#include "warn.h" #include "warn.h"
#include "mem.h" #include "mem.h"
/* Detect supported system calls. */
#if !defined __CYGWIN__
#define HAS_ACCT 1
#else
#define HAS_ACCT 0
#endif
#define INPUT 0 #define INPUT 0
#define OUTPUT 1 #define OUTPUT 1
@ -914,6 +922,7 @@ moncall()
case 51: /* Acct */ case 51: /* Acct */
dsp1 = pop_ptr(); dsp1 = pop_ptr();
#if HAS_ACCT
if (!savestr(0, dsp1) || acct(buf[0]) == -1) { if (!savestr(0, dsp1) || acct(buf[0]) == -1) {
push_err(); push_err();
LOG(("@m4 Acct: failed, dsp1 = %lu, errno = %d", LOG(("@m4 Acct: failed, dsp1 = %lu, errno = %d",
@ -923,6 +932,12 @@ moncall()
push_int(0); push_int(0);
LOG(("@m9 Acct: succeeded, dsp1 = %lu", dsp1)); LOG(("@m9 Acct: succeeded, dsp1 = %lu", dsp1));
} }
#else
einval(WMPXIMP);
push_err();
LOG(("@m4 Acct: failed, request = %d, dsp1 = %lu, errno = %d",
request, dsp1, errno));
#endif
break; break;
case 54: /* Ioctl */ case 54: /* Ioctl */