Merge pull request #120 from davidgiven/dtrg-no
Remove the built-in preprocessor in cemcom.ansi
This commit is contained in:
commit
2eaca39322
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,6 @@ int tk_nmb_at_last_syn_err = -5 /*ERR_SHADOW*/;
|
||||||
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,33 +41,6 @@ extern arith full_mask[];
|
||||||
extern int lint_skip_comment;
|
extern int lint_skip_comment;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NOPP
|
|
||||||
static struct token LexStack[MAX_LL_DEPTH];
|
|
||||||
static LexSP = 0;
|
|
||||||
|
|
||||||
void skipcomment();
|
|
||||||
void skiplinecomment();
|
|
||||||
|
|
||||||
/* 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()
|
int LLlex()
|
||||||
{
|
{
|
||||||
/* LLlex() plays the role of Lexical Analyzer for the C parser.
|
/* LLlex() plays the role of Lexical Analyzer for the C parser.
|
||||||
|
@ -152,9 +118,6 @@ go_on: /* rescan, the following character has been read */
|
||||||
return ptok->tk_symb = EOI;
|
return ptok->tk_symb = EOI;
|
||||||
|
|
||||||
while ((ch = GetChar()), (ch == '#'
|
while ((ch = GetChar()), (ch == '#'
|
||||||
#ifndef NOPP
|
|
||||||
|| ch == '/'
|
|
||||||
#endif
|
|
||||||
|| class(ch) == STSKIP))
|
|| class(ch) == STSKIP))
|
||||||
{
|
{
|
||||||
/* blanks are allowed before hashes */
|
/* blanks are allowed before hashes */
|
||||||
|
@ -162,26 +125,6 @@ go_on: /* rescan, the following character has been read */
|
||||||
{
|
{
|
||||||
/* a control line follows */
|
/* a control line follows */
|
||||||
domacro();
|
domacro();
|
||||||
#ifndef NOPP
|
|
||||||
if (File_Inserted)
|
|
||||||
{
|
|
||||||
File_Inserted = 0;
|
|
||||||
goto firstline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((ch == '/') && !InputLevel)
|
|
||||||
{
|
|
||||||
int nch = GetChar();
|
|
||||||
if (nch == '*')
|
|
||||||
skipcomment();
|
|
||||||
else if (nch == '/')
|
|
||||||
skiplinecomment();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UnGetChar();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif /* NOPP */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* We have to loop here, because in
|
/* We have to loop here, because in
|
||||||
|
@ -192,9 +135,6 @@ go_on: /* rescan, the following character has been read */
|
||||||
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
|
|
||||||
garbage:
|
|
||||||
#endif
|
|
||||||
if (040 < ch && ch < 0177)
|
if (040 < ch && ch < 0177)
|
||||||
{
|
{
|
||||||
return ptok->tk_symb = ch;
|
return ptok->tk_symb = ch;
|
||||||
|
@ -285,21 +225,6 @@ go_on: /* rescan, the following character has been read */
|
||||||
return ptok->tk_symb = XORAB;
|
return ptok->tk_symb = XORAB;
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
#ifndef NOPP
|
|
||||||
if (!InputLevel)
|
|
||||||
{
|
|
||||||
if (nch == '*')
|
|
||||||
{
|
|
||||||
skipcomment();
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
else if (nch == '/')
|
|
||||||
{
|
|
||||||
skiplinecomment();
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (nch == '=')
|
if (nch == '=')
|
||||||
return ptok->tk_symb = DIVAB;
|
return ptok->tk_symb = DIVAB;
|
||||||
break;
|
break;
|
||||||
|
@ -339,17 +264,6 @@ go_on: /* rescan, the following character has been read */
|
||||||
register int pos = -1;
|
register int pos = -1;
|
||||||
register struct idf* idef;
|
register struct idf* idef;
|
||||||
extern int idfsize; /* ??? */
|
extern int idfsize; /* ??? */
|
||||||
#ifndef NOPP
|
|
||||||
int NoExpandNext = 0;
|
|
||||||
|
|
||||||
if (Unstacked)
|
|
||||||
EnableMacros(); /* unstack macro's when allowed. */
|
|
||||||
if (ch == NOEXPM)
|
|
||||||
{
|
|
||||||
NoExpandNext = 1;
|
|
||||||
ch = GetChar();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
do
|
do
|
||||||
{ /* read the identifier */
|
{ /* read the identifier */
|
||||||
if (++pos < idfsize)
|
if (++pos < idfsize)
|
||||||
|
@ -366,19 +280,6 @@ go_on: /* rescan, the following character has been read */
|
||||||
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
|
|
||||||
if (idef->id_macro && ReplaceMacros && !NoExpandNext)
|
|
||||||
{
|
|
||||||
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
|
ptok->tk_symb
|
||||||
= (idef->id_reserved
|
= (idef->id_reserved
|
||||||
? idef->id_reserved
|
? idef->id_reserved
|
||||||
|
@ -472,101 +373,12 @@ go_on: /* rescan, the following character has been read */
|
||||||
}
|
}
|
||||||
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
|
|
||||||
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--;
|
|
||||||
}
|
|
||||||
|
|
||||||
void skiplinecomment(void)
|
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* NOPP */
|
|
||||||
|
|
||||||
arith char_constant(nm) char* nm;
|
arith char_constant(nm) char* nm;
|
||||||
{
|
{
|
||||||
register arith val = 0;
|
register arith val = 0;
|
||||||
|
@ -710,78 +522,10 @@ int GetChar()
|
||||||
*/
|
*/
|
||||||
register int ch;
|
register int ch;
|
||||||
|
|
||||||
#ifndef NOPP
|
|
||||||
again:
|
|
||||||
#endif
|
|
||||||
LoadChar(ch);
|
LoadChar(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);
|
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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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" */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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,859 +22,6 @@ 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;
|
|
||||||
|
|
||||||
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 == '/')
|
|
||||||
{
|
|
||||||
skiplinecomment();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (ch == '*')
|
|
||||||
{
|
|
||||||
skipcomment();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
UnGetChar();
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
else if (c == '/')
|
|
||||||
{
|
|
||||||
skiplinecomment();
|
|
||||||
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 */
|
struct idf* GetIdentifier(skiponerr) int skiponerr; /* skip the rest of the line on error */
|
||||||
{
|
{
|
||||||
|
@ -927,7 +69,6 @@ domacro()
|
||||||
EoiForNewline = 0;
|
EoiForNewline = 0;
|
||||||
SkipToNewLine();
|
SkipToNewLine();
|
||||||
}
|
}
|
||||||
#endif /* NOPP */
|
|
||||||
|
|
||||||
do_line(l) unsigned int l;
|
do_line(l) unsigned int l;
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 */
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
|
|
@ -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
|
|
||||||
|
|
|
@ -11,125 +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 if (ch == '/' && !InputLevel)
|
|
||||||
{
|
|
||||||
skiplinecomment();
|
|
||||||
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 (!InputLevel)
|
|
||||||
{
|
|
||||||
int nch = GetChar();
|
|
||||||
if (nch == '*')
|
|
||||||
{
|
|
||||||
skipcomment();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (nch == '/')
|
|
||||||
{
|
|
||||||
skiplinecomment();
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,7 @@ void skip_block(to_endif) int to_endif;
|
||||||
}
|
}
|
||||||
if (ch == '/')
|
if (ch == '/')
|
||||||
{
|
{
|
||||||
|
ch = GetChar();
|
||||||
if (ch == '*')
|
if (ch == '*')
|
||||||
{
|
{
|
||||||
skipcomment();
|
skipcomment();
|
||||||
|
|
12
lib/descr/fe
12
lib/descr/fe
|
@ -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?} < >
|
||||||
|
|
Loading…
Reference in a new issue