ack/lang/cem/cpp.ansi/domacro.c

931 lines
20 KiB
C
Raw Permalink Normal View History

1989-10-23 10:35:56 +00:00
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
1994-06-24 14:02:31 +00:00
/* $Id$ */
1989-10-23 10:35:56 +00:00
/* PREPROCESSOR: CONTROLLINE INTERPRETER */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "domacro.h"
#include "arith.h"
#include "LLlex.h"
#include "Lpars.h"
#include "idf.h"
#include "input.h"
#include "error.h"
#include "parameters.h"
#include "preprocess.h"
#include <alloc.h>
#include "class.h"
#include "macro.h"
#include "LLlex.h"
#include "bits.h"
#include "skip.h"
#include "replace.h"
1989-10-23 10:35:56 +00:00
1989-10-31 10:02:48 +00:00
extern char options[];
extern char** inctable; /* list of include directories */
char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */
/* 1 if a corresponding ELSE has been */
/* encountered. */
int nestlevel = -1;
int svnestlevel[30] = { -1 };
int nestcount;
extern int do_preprocess;
1989-10-23 10:35:56 +00:00
/* Internal declarations */
static void do_define(void);
static void do_elif(void);
static void do_else(void);
static void push_if(void);
static void do_endif(void);
static void do_if(void);
static void do_ifdef(int);
static void do_include(void);
static void do_line(unsigned int);
static int find_name(char* , char* []);
static char* get_text(char* [], int* );
static int getparams(char* [], char []);
static int ifexpr(void);
static int macroeq(register char*, register char *);
static void skip_block(int);
static void do_error(void);
/* External dependencies to C files with no include files */
extern void If_expr(void);
extern void add_dependency(char *);
char* GetIdentifier(int skiponerr /* skip the rest of the line on error */
)
1989-10-23 10:35:56 +00:00
{
/* Returns a pointer to the identifier that is read from the
input stream. When the input does not contain an
identifier, the rest of the line is skipped when skiponerr
is on, and a null-pointer is returned.
The substitution of macros is disabled.
Remember that on end-of-line EOF is returned.
1989-10-23 10:35:56 +00:00
*/
int tmp = UnknownIdIsZero;
int tok;
struct token tk;
UnknownIdIsZero = ReplaceMacros = 0;
tok = GetToken(&tk);
ReplaceMacros = 1;
UnknownIdIsZero = tmp;
if (tok != IDENTIFIER)
{
if (skiponerr && tok != EOF)
SkipToNewLine();
return (char*)0;
1989-10-23 10:35:56 +00:00
}
return tk.tk_str;
}
void domacro(void)
1989-10-23 10:35:56 +00:00
{
struct token tk; /* the token itself */
register struct idf* id;
1989-10-23 10:35:56 +00:00
int toknum;
ReplaceMacros = 0;
toknum = GetToken(&tk);
ReplaceMacros = 1;
switch (toknum)
{ /* select control line action */
case IDENTIFIER: /* is it a macro keyword? */
id = findidf(tk.tk_str);
if (!id)
{
error("%s: unknown control", tk.tk_str);
SkipToNewLine();
free(tk.tk_str);
break;
}
free(tk.tk_str);
switch (id->id_resmac)
{
case K_DEFINE: /* "define" */
do_define();
break;
case K_ELIF: /* "elif" */
do_elif();
break;
case K_ELSE: /* "else" */
do_else();
break;
case K_ENDIF: /* "endif" */
do_endif();
break;
case K_IF: /* "if" */
do_if();
break;
case K_IFDEF: /* "ifdef" */
do_ifdef(1);
break;
case K_IFNDEF: /* "ifndef" */
do_ifdef(0);
break;
case K_INCLUDE: /* "include" */
do_include();
break;
case K_LINE: /* "line" */
/* set LineNumber and FileName according to
the arguments.
*/
if (GetToken(&tk) != INTEGER)
{
error("bad #line syntax");
SkipToNewLine();
}
else
do_line((unsigned int)tk.tk_val);
break;
case K_ERROR: /* "error" */
do_error();
break;
case K_PRAGMA: /* "pragma" */
do_pragma();
break;
case K_UNDEF: /* "undef" */
do_undef((char*)0);
break;
default:
/* invalid word seen after the '#' */
error("%s: unknown control", id->id_text);
SkipToNewLine();
1989-10-23 10:35:56 +00:00
}
break;
case INTEGER: /* # <integer> [<filespecifier>]? */
do_line((unsigned int)tk.tk_val);
break;
case EOF: /* only `#' on this line: do nothing, ignore */
1989-10-23 10:35:56 +00:00
break;
default: /* invalid token following '#' */
error("illegal # line");
SkipToNewLine();
1989-10-23 10:35:56 +00:00
}
}
static void skip_block(int to_endif)
1989-10-23 10:35:56 +00:00
{
/* 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.
1989-10-23 10:35:56 +00:00
*/
register int ch;
register int skiplevel = nestlevel; /* current nesting level */
struct token tk;
int toknum;
struct idf* id;
1989-10-23 10:35:56 +00:00
NoUnstack++;
for (;;)
{
ch = GetChar(); /* read first character after newline */
1989-10-23 10:35:56 +00:00
while (class(ch) == STSKIP)
ch = GetChar();
if (ch != '#')
{
if (ch == EOI)
{
1989-10-23 10:35:56 +00:00
NoUnstack--;
return;
}
if (ch == '/')
{
ch = GetChar();
if (ch == '*')
{
skipcomment();
continue;
}
else if (ch == '/')
{
skiplinecomment();
continue;
}
else
UnGetChar();
}
else
UnGetChar();
SkipToNewLine();
1989-10-23 10:35:56 +00:00
continue;
}
ReplaceMacros = 0;
toknum = GetToken(&tk);
ReplaceMacros = 1;
if (toknum != IDENTIFIER)
{
if (toknum != INTEGER)
{
error("illegal # line");
}
SkipToNewLine();
1989-10-23 10:35:56 +00:00
continue;
}
/* an IDENTIFIER: look for #if, #ifdef and #ifndef
without interpreting them.
Interpret #else, #elif and #endif if they occur
on the same level.
1989-10-23 10:35:56 +00:00
*/
id = findidf(tk.tk_str);
if (id == (struct idf*)0)
{
1990-08-31 10:27:12 +00:00
/* invalid word seen after the '#' */
warning("%s: unknown control", tk.tk_str);
1990-08-31 10:27:12 +00:00
}
1989-10-23 10:35:56 +00:00
free(tk.tk_str);
if (id == (struct idf*)0)
continue;
switch (id->id_resmac)
{
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:
1989-10-23 10:35:56 +00:00
push_if();
SkipToNewLine();
break;
case K_ELIF:
if (ifstack[nestlevel])
error("#elif after #else");
if (!to_endif && nestlevel == skiplevel)
{
nestlevel--;
push_if();
if (ifexpr())
{
NoUnstack--;
return;
}
}
else
SkipToNewLine(); /* otherwise done in ifexpr() */
break;
case K_ELSE:
if (ifstack[nestlevel])
error("#else after #else");
++(ifstack[nestlevel]);
if (!to_endif && nestlevel == skiplevel)
{
if (SkipToNewLine())
{
if (!options['o'])
strict("garbage following #else");
}
1989-10-23 10:35:56 +00:00
NoUnstack--;
return;
}
else
SkipToNewLine();
break;
case K_ENDIF:
assert(nestlevel > svnestlevel[nestcount]);
if (nestlevel == skiplevel)
{
if (SkipToNewLine())
{
if (!options['o'])
strict("garbage following #endif");
}
nestlevel--;
NoUnstack--;
return;
1989-10-31 10:02:48 +00:00
}
else
SkipToNewLine();
1989-10-23 10:35:56 +00:00
nestlevel--;
break;
1989-10-23 10:35:56 +00:00
}
}
}
static int ifexpr(void)
1989-10-23 10:35:56 +00:00
{
/* 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".
1989-10-23 10:35:56 +00:00
*/
extern arith ifval;
int errors = err_occurred;
ifval = (arith)0;
AccDefined = 1;
UnknownIdIsZero = 1;
DOT = 0; /* tricky */
If_expr(); /* invoke constant expression parser */
1989-10-23 10:35:56 +00:00
AccDefined = 0;
UnknownIdIsZero = 0;
return (errors == err_occurred) && (ifval != (arith)0);
}
static void do_include(void)
1989-10-23 10:35:56 +00:00
{
/* do_include() performs the inclusion of a file.
*/
char* filenm;
char* result;
1989-10-23 10:35:56 +00:00
int tok;
struct token tk;
AccFileSpecifier = 1;
if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
filenm = tk.tk_str;
else
{
1989-10-23 10:35:56 +00:00
error("bad include syntax");
filenm = (char*)0;
1989-10-23 10:35:56 +00:00
}
AccFileSpecifier = 0;
if (SkipToNewLine())
{
error("bad include syntax");
}
1989-10-23 10:35:56 +00:00
inctable[0] = WorkingDir;
if (filenm)
{
if (!InsertFile(filenm, &inctable[tok == FILESPECIFIER], &result))
{
if (do_preprocess)
error("cannot open include file \"%s\"", filenm);
else
warning("cannot open include file \"%s\"", filenm);
add_dependency(filenm);
1989-10-23 10:35:56 +00:00
}
else
{
add_dependency(result);
1989-10-23 10:35:56 +00:00
WorkingDir = getwdir(result);
svnestlevel[++nestcount] = nestlevel;
FileName = result;
LineNumber = 1;
}
}
}
static void do_define(void)
1989-10-23 10:35:56 +00:00
{
/* do_define() interprets a #define control line.
*/
register char* str; /* the #defined identifier's descriptor */
int nformals = -1; /* keep track of the number of formals */
char* formals[NPARAMS]; /* pointers to the names of the formals */
char parbuf[PARBUFSIZE]; /* names of formals */
char* repl_text; /* start of the replacement text */
int length; /* length of the replacement text */
register int ch;
1989-10-23 10:35:56 +00:00
/* read the #defined macro's name */
if (!(str = GetIdentifier(1)))
{
1989-10-23 10:35:56 +00:00
error("#define: illegal macro name");
return;
}
/* there is a formal parameter list if the identifier is
followed immediately by a '('.
1989-10-23 10:35:56 +00:00
*/
ch = GetChar();
if (ch == '(')
{
if ((nformals = getparams(formals, parbuf)) == -1)
{
SkipToNewLine();
1989-10-23 10:35:56 +00:00
free(str);
return; /* an error occurred */
1989-10-23 10:35:56 +00:00
}
ch = GetChar();
}
/* read the replacement text if there is any */
ch = skipspaces(ch, 0); /* find first character of the text */
1989-10-23 10:35:56 +00:00
assert(ch != EOI);
/* UnGetChar() is not right when replacement starts with a '/' */
ChPushBack(ch);
repl_text = get_text((nformals > 0) ? formals : 0, &length);
1989-10-23 10:35:56 +00:00
macro_def(str2idf(str, 0), repl_text, nformals, length, NOFLAG);
LineNumber++;
}
static void push_if(void)
1989-10-23 10:35:56 +00:00
{
if (nestlevel >= IFDEPTH)
fatal("too many nested #if/#ifdef/#ifndef");
else
ifstack[++nestlevel] = 0;
}
static void do_elif(void)
1989-10-23 10:35:56 +00:00
{
if (nestlevel <= svnestlevel[nestcount])
{
1989-10-23 10:35:56 +00:00
error("#elif without corresponding #if");
SkipToNewLine();
1989-10-23 10:35:56 +00:00
}
else
{ /* restart at this level as if a #if is detected. */
if (ifstack[nestlevel])
{
1989-10-23 10:35:56 +00:00
error("#elif after #else");
SkipToNewLine();
1989-10-23 10:35:56 +00:00
}
nestlevel--;
push_if();
skip_block(1);
}
}
static void do_else(void)
1989-10-23 10:35:56 +00:00
{
if (SkipToNewLine())
{
1989-10-31 10:02:48 +00:00
if (!options['o'])
strict("garbage following #else");
}
1989-10-23 10:35:56 +00:00
if (nestlevel <= svnestlevel[nestcount])
error("#else without corresponding #if");
else
{ /* mark this level as else-d */
if (ifstack[nestlevel])
{
1989-10-23 10:35:56 +00:00
error("#else after #else");
}
++(ifstack[nestlevel]);
skip_block(1);
}
}
static void do_endif(void)
1989-10-23 10:35:56 +00:00
{
if (SkipToNewLine())
{
1989-10-31 10:02:48 +00:00
if (!options['o'])
strict("garbage following #endif");
}
if (nestlevel <= svnestlevel[nestcount])
{
1989-10-23 10:35:56 +00:00
error("#endif without corresponding #if");
}
else
nestlevel--;
1989-10-23 10:35:56 +00:00
}
static void do_if(void)
1989-10-23 10:35:56 +00:00
{
push_if();
if (!ifexpr()) /* a false #if/#elif expression */
1989-10-23 10:35:56 +00:00
skip_block(0);
}
static void do_ifdef(int how)
1989-10-23 10:35:56 +00:00
{
register struct idf* id;
register char* str;
1989-10-23 10:35:56 +00:00
/* how == 1 : ifdef; how == 0 : ifndef
*/
push_if();
if (!(str = GetIdentifier(1)))
{
1989-10-23 10:35:56 +00:00
error("illegal #ifdef construction");
id = (struct idf*)0;
}
else
{
1989-10-23 10:35:56 +00:00
id = findidf(str);
free(str);
}
if (SkipToNewLine())
{
if (str && !options['o'])
strict("garbage following #%s <identifier>", how ? "ifdef" : "ifndef");
}
1989-10-23 10:35:56 +00:00
/* The next test is a shorthand for:
(how && !id->id_macro) || (!how && id->id_macro)
1989-10-23 10:35:56 +00:00
*/
if (how ^ (id && id->id_macro != 0))
skip_block(0);
}
/* argstr != NULL when the undef came from a -U option */
void do_undef(char* argstr)
1989-10-23 10:35:56 +00:00
{
register struct idf* id;
register char* str = argstr;
1989-10-23 10:35:56 +00:00
/* Forget a macro definition. */
if (str || (str = GetIdentifier(1)))
{
if ((id = findidf(str)) && id->id_macro)
{
if (id->id_macro->mc_flag & NOUNDEF)
{
1989-10-23 10:35:56 +00:00
error("it is not allowed to #undef %s", str);
}
else
{
1989-10-23 10:35:56 +00:00
free(id->id_macro->mc_text);
free_macro(id->id_macro);
id->id_macro = (struct macro*)0;
1989-10-23 10:35:56 +00:00
}
} /* else: don't complain */
if (!argstr)
{
free(str);
if (SkipToNewLine())
{
1991-12-16 14:06:09 +00:00
if (!options['o'])
1995-03-27 11:22:57 +00:00
strict("garbage following #undef");
1991-12-16 14:06:09 +00:00
}
}
1989-10-23 10:35:56 +00:00
}
else
error("illegal #undef construction");
}
static void do_error(void)
1989-10-23 10:35:56 +00:00
{
1991-04-11 10:52:52 +00:00
int len;
char* get_text();
char* bp = get_text((char**)0, &len);
1989-10-23 10:35:56 +00:00
1991-04-11 10:52:52 +00:00
error("user error: %s", bp);
free(bp);
LineNumber++;
1989-10-23 10:35:56 +00:00
}
static int getparams(char* buf[], char parbuf[])
1989-10-23 10:35:56 +00:00
{
/* 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.
1989-10-23 10:35:56 +00:00
*/
register char** pbuf = &buf[0];
1989-10-23 10:35:56 +00:00
register int c;
register char* ptr = &parbuf[0];
register char** pbuf2;
1989-10-23 10:35:56 +00:00
c = GetChar();
c = skipspaces(c, 0);
if (c == ')')
{ /* no parameters: #define name() */
*pbuf = (char*)0;
1989-10-23 10:35:56 +00:00
return 0;
}
for (;;)
{ /* eat the formal parameter list */
if (class(c) != STIDF && class(c) != STELL)
{
1989-10-23 10:35:56 +00:00
error("#define: bad formal parameter");
return -1;
}
*pbuf = ptr; /* name of the formal */
1989-10-23 10:35:56 +00:00
*ptr++ = c;
if (ptr >= &parbuf[PARBUFSIZE])
fatal("formal parameter buffer overflow");
do
{ /* eat the identifier name */
1989-10-23 10:35:56 +00:00
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 */
1989-10-23 10:35:56 +00:00
/* Check if this formal parameter is already used.
Usually, macros do not have many parameters, so ...
1989-10-23 10:35:56 +00:00
*/
for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--)
{
if (!strcmp(*pbuf2, *pbuf))
{
warning("formal parameter \"%s\" already used", *pbuf);
1989-10-23 10:35:56 +00:00
}
}
pbuf++;
c = skipspaces(c, 0);
if (c == ')')
{ /* end of the formal parameter list */
*pbuf = (char*)0;
1989-10-23 10:35:56 +00:00
return pbuf - buf;
}
if (c != ',')
{
1989-10-23 10:35:56 +00:00
error("#define: bad formal parameter list");
return -1;
}
c = GetChar();
c = skipspaces(c, 0);
1989-10-23 10:35:56 +00:00
}
/*NOTREACHED*/
}
void macro_def(register struct idf* id, char* text, int nformals, int length, int flags)
1989-10-23 10:35:56 +00:00
{
register struct macro* newdef = id->id_macro;
1989-10-23 10:35:56 +00:00
/* 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
1989-10-23 10:35:56 +00:00
*/
if (newdef)
{ /* is there a redefinition? */
if (newdef->mc_flag & NOUNDEF)
{
1989-10-23 10:35:56 +00:00
error("it is not allowed to redefine %s", id->id_text);
}
else if (!macroeq(newdef->mc_text, text))
1989-10-23 10:35:56 +00:00
error("illegal redefine of \"%s\"", id->id_text);
free(text);
return;
}
else
{
1989-10-23 10:35:56 +00:00
#ifdef DOBITS
register char* p = id->id_text;
#define setbit(bx) \
if (!*p) \
goto go_on; \
bits[*p++] |= (bx)
1989-10-23 10:35:56 +00:00
setbit(bit0);
setbit(bit1);
setbit(bit2);
setbit(bit3);
setbit(bit4);
setbit(bit5);
setbit(bit6);
setbit(bit7);
go_on:
#endif
id->id_macro = newdef = new_macro();
}
newdef->mc_text = text; /* replacement text */
newdef->mc_nps = nformals; /* nr of formals */
newdef->mc_length = length; /* length of repl. text */
newdef->mc_flag = flags; /* special flags */
1989-10-23 10:35:56 +00:00
}
static int find_name(char* nm, char *index[])
1989-10-23 10:35:56 +00:00
{
/* 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.
1989-10-23 10:35:56 +00:00
*/
register char** ip = &index[0];
1989-10-23 10:35:56 +00:00
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'))
static char* get_text(char* formals[], int* length)
1989-10-23 10:35:56 +00:00
{
/* 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.
1989-10-23 10:35:56 +00:00
*/
register int c;
struct repl repls;
register struct repl* repl = &repls;
int blank = 0;
1989-10-23 10:35:56 +00:00
c = GetChar();
repl->r_ptr = repl->r_text = Malloc((unsigned)(repl->r_size = ITEXTSIZE));
1989-11-27 11:40:58 +00:00
*repl->r_ptr = '\0';
while ((c != EOI) && (class(c) != STNL))
{
if (BLANK(c))
{
blank++;
c = GetChar();
continue;
}
if (c == '\'' || c == '"')
{
1989-10-23 10:35:56 +00:00
register int delim = c;
if (blank)
{
blank = 0;
add2repl(repl, ' ');
}
do
{
add2repl(repl, c);
if (c == '\\')
add2repl(repl, GetChar());
1989-10-23 10:35:56 +00:00
c = GetChar();
} while (c != delim && c != EOI && class(c) != STNL);
if (c != delim)
{
1991-04-11 10:52:52 +00:00
strict("unclosed opening %c", delim);
break;
}
add2repl(repl, c);
1989-10-23 10:35:56 +00:00
c = GetChar();
}
else if (c == '/')
{
1989-10-23 10:35:56 +00:00
c = GetChar();
if (c == '*')
{
1989-10-23 10:35:56 +00:00
skipcomment();
blank++;
1989-10-23 10:35:56 +00:00
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))
{
1989-10-23 10:35:56 +00:00
char id_buf[IDFSIZE + 1];
register char* idp = id_buf;
int n;
1989-10-23 10:35:56 +00:00
/* read identifier: it may be a formal parameter */
*idp++ = c;
do
{
1989-10-23 10:35:56 +00:00
c = GetChar();
if (idp <= &id_buf[IDFSIZE])
*idp++ = c;
1989-10-23 10:35:56 +00:00
} 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);
1989-10-23 10:35:56 +00:00
}
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);
1989-10-23 10:35:56 +00:00
c = GetChar();
}
}
*length = repl->r_ptr - repl->r_text;
return Realloc(repl->r_text, (unsigned)(repl->r_ptr - repl->r_text + 1));
1989-10-23 10:35:56 +00:00
}
/* 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).
1989-10-23 10:35:56 +00:00
*/
static int macroeq(register char* s, register char *t)
1989-10-23 10:35:56 +00:00
{
1989-10-23 10:35:56 +00:00
/* skip leading spaces */
while (BLANK(*s))
s++;
while (BLANK(*t))
t++;
1989-10-23 10:35:56 +00:00
/* 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++;
1989-10-23 10:35:56 +00:00
return *t == '\0';
}
else
{ /* *s != *t */
while (BLANK(*s))
s++;
while (BLANK(*t))
t++;
1989-10-23 10:35:56 +00:00
return (*s == '\0') && (*t == '\0');
}
}
static void do_line(unsigned int l)
1989-10-23 10:35:56 +00:00
{
struct token tk;
int t = GetToken(&tk);
1989-10-23 10:35:56 +00:00
if (t != EOF)
SkipToNewLine();
LineNumber = l; /* the number of the next input line */
if (t == STRING) /* is there a filespecifier? */
1989-10-23 10:35:56 +00:00
FileName = tk.tk_str;
}