blob: 50ef8caae34fda34167e0bddafa4ab7d544650b9 [file] [log] [blame]
/* CPP Library.
Copyright (C) 1986, 87, 89, 92-6, 1997 Free Software Foundation, Inc.
Contributed by Per Bothner, 1994-95.
Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
#ifdef EMACS
#define NO_SHORTNAMES
#include "../src/config.h"
#ifdef open
#undef open
#undef read
#undef write
#endif /* open */
#endif /* EMACS */
/* The macro EMACS is defined when cpp is distributed as part of Emacs,
for the sake of machines with limited C compilers. */
#ifndef EMACS
#include "config.h"
#endif /* not EMACS */
#ifndef STANDARD_INCLUDE_DIR
#define STANDARD_INCLUDE_DIR "/usr/include"
#endif
#if 0 /* We can't get ptrdiff_t, so I arranged not to need PTR_INT_TYPE. */
#ifdef __STDC__
#define PTR_INT_TYPE ptrdiff_t
#else
#define PTR_INT_TYPE long
#endif
#endif /* 0 */
#include "cpplib.h"
#include "cpphash.h"
#ifndef STDC_VALUE
#define STDC_VALUE 1
#endif
/* By default, colon separates directories in a path. */
#ifndef PATH_SEPARATOR
#define PATH_SEPARATOR ':'
#endif
#include <ctype.h>
#include <stdio.h>
#include <signal.h>
#ifdef __STDC__
#include <stdlib.h>
#endif
#ifndef VMS
#ifndef USG
#include <sys/time.h> /* for __DATE__ and __TIME__ */
#include <sys/resource.h>
#else
#include <sys/times.h>
#include <time.h>
#include <fcntl.h>
#endif /* USG */
#endif /* not VMS */
/* This defines "errno" properly for VMS, and gives us EACCES. */
#include <errno.h>
extern char *index ();
extern char *rindex ();
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
#undef MIN
#undef MAX
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
/* Find the largest host integer type and set its size and type. */
#ifndef HOST_BITS_PER_WIDE_INT
#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
#define HOST_WIDE_INT long
#else
#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
#define HOST_WIDE_INT int
#endif
#endif
#ifndef S_ISREG
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#ifndef S_ISDIR
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
/* Define a generic NULL if one hasn't already been defined. */
#ifndef NULL
#define NULL 0
#endif
#ifndef GENERIC_PTR
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
#define GENERIC_PTR void *
#else
#define GENERIC_PTR char *
#endif
#endif
#ifndef NULL_PTR
#define NULL_PTR ((GENERIC_PTR) 0)
#endif
#ifndef INCLUDE_LEN_FUDGE
#define INCLUDE_LEN_FUDGE 0
#endif
/* Symbols to predefine. */
#ifdef CPP_PREDEFINES
static char *predefs = CPP_PREDEFINES;
#else
static char *predefs = "";
#endif
/* We let tm.h override the types used here, to handle trivial differences
such as the choice of unsigned int or long unsigned int for size_t.
When machines start needing nontrivial differences in the size type,
it would be best to do something here to figure out automatically
from other information what type to use. */
/* The string value for __SIZE_TYPE__. */
#ifndef SIZE_TYPE
#define SIZE_TYPE "long unsigned int"
#endif
/* The string value for __PTRDIFF_TYPE__. */
#ifndef PTRDIFF_TYPE
#define PTRDIFF_TYPE "long int"
#endif
/* The string value for __WCHAR_TYPE__. */
#ifndef WCHAR_TYPE
#define WCHAR_TYPE "int"
#endif
#define CPP_WCHAR_TYPE(PFILE) \
(CPP_OPTIONS (PFILE)->cplusplus ? "__wchar_t" : WCHAR_TYPE)
/* The string value for __USER_LABEL_PREFIX__ */
#ifndef USER_LABEL_PREFIX
#define USER_LABEL_PREFIX ""
#endif
/* The string value for __REGISTER_PREFIX__ */
#ifndef REGISTER_PREFIX
#define REGISTER_PREFIX ""
#endif
/* In the definition of a #assert name, this structure forms
a list of the individual values asserted.
Each value is itself a list of "tokens".
These are strings that are compared by name. */
struct tokenlist_list {
struct tokenlist_list *next;
struct arglist *tokens;
};
struct assertion_hashnode {
struct assertion_hashnode *next; /* double links for easy deletion */
struct assertion_hashnode *prev;
/* also, a back pointer to this node's hash
chain is kept, in case the node is the head
of the chain and gets deleted. */
struct assertion_hashnode **bucket_hdr;
int length; /* length of token, for quick comparison */
U_CHAR *name; /* the actual name */
/* List of token-sequences. */
struct tokenlist_list *value;
};
#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
#define PEEKN(N) (CPP_BUFFER (pfile)->rlimit - CPP_BUFFER (pfile)->cur >= (N) ? CPP_BUFFER (pfile)->cur[N] : EOF)
#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
#define GETC() CPP_BUF_GET (CPP_BUFFER (pfile))
#define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile))
/* CPP_IS_MACRO_BUFFER is true if the buffer contains macro expansion.
(Note that it is false while we're expanding marco *arguments*.) */
#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->cleanup == macro_cleanup)
/* Move all backslash-newline pairs out of embarrassing places.
Exchange all such pairs following BP
with any potentially-embarrassing characters that follow them.
Potentially-embarrassing characters are / and *
(because a backslash-newline inside a comment delimiter
would cause it not to be recognized). */
#define NEWLINE_FIX \
do {while (PEEKC() == '\\' && PEEKN(1) == '\n') FORWARD(2); } while(0)
/* Same, but assume we've already read the potential '\\' into C. */
#define NEWLINE_FIX1(C) do { \
while ((C) == '\\' && PEEKC() == '\n') { FORWARD(1); (C) = GETC(); }\
} while(0)
struct cpp_pending {
struct cpp_pending *next;
char *cmd;
char *arg;
};
/* Forward declarations. */
extern char *xmalloc ();
static void add_import ();
static void append_include_chain ();
static void make_undef ();
static void make_assertion ();
static void path_include ();
static void initialize_builtins ();
static void initialize_char_syntax ();
static void dump_arg_n ();
static void dump_defn_1 ();
extern void delete_macro ();
static void trigraph_pcp ();
static int finclude ();
static void validate_else ();
static int comp_def_part ();
#ifdef abort
extern void fancy_abort ();
#endif
static void pipe_closed ();
static void print_containing_files ();
static int lookup_import ();
static int redundant_include_p ();
static is_system_include ();
static struct file_name_map *read_name_map ();
static char *read_filename_string ();
static int open_include_file ();
static int check_preconditions ();
static void pcfinclude ();
static void pcstring_used ();
static int check_macro_name ();
static int compare_defs ();
static int compare_token_lists ();
static HOST_WIDE_INT eval_if_expression ();
static int change_newlines ();
extern int hashf ();
static int file_size_and_mode ();
static struct arglist *read_token_list ();
static void free_token_list ();
static int safe_read ();
static void push_macro_expansion PARAMS ((cpp_reader *,
U_CHAR *, int, HASHNODE *));
static struct cpp_pending *nreverse_pending PARAMS ((struct cpp_pending *));
extern char *xrealloc ();
static char *xcalloc ();
static char *savestring ();
static void conditional_skip ();
static void skip_if_group ();
/* Last arg to output_line_command. */
enum file_change_code {same_file, enter_file, leave_file};
/* External declarations. */
extern HOST_WIDE_INT cpp_parse_expr PARAMS ((cpp_reader *));
extern char *getenv ();
extern FILE *fdopen ();
extern char *version_string;
extern struct tm *localtime ();
/* These functions are declared to return int instead of void since they
are going to be placed in a table and some old compilers have trouble with
pointers to functions returning void. */
static int do_define ();
static int do_line ();
static int do_include ();
static int do_undef ();
static int do_error ();
static int do_pragma ();
static int do_ident ();
static int do_if ();
static int do_xifdef ();
static int do_else ();
static int do_elif ();
static int do_endif ();
static int do_sccs ();
static int do_once ();
static int do_assert ();
static int do_unassert ();
static int do_warning ();
struct file_name_list
{
struct file_name_list *next;
char *fname;
/* If the following is nonzero, it is a macro name.
Don't include the file again if that macro is defined. */
U_CHAR *control_macro;
/* If the following is nonzero, it is a C-language system include
directory. */
int c_system_include_path;
/* Mapping of file names for this directory. */
struct file_name_map *name_map;
/* Non-zero if name_map is valid. */
int got_name_map;
};
/* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found
via the same directory as the file that #included it. */
#define SELF_DIR_DUMMY ((struct file_name_list *) (~0))
/* #include "file" looks in source file dir, then stack. */
/* #include <file> just looks in the stack. */
/* -I directories are added to the end, then the defaults are added. */
/* The */
static struct default_include {
char *fname; /* The name of the directory. */
int cplusplus; /* Only look here if we're compiling C++. */
int cxx_aware; /* Includes in this directory don't need to
be wrapped in extern "C" when compiling
C++. */
} include_defaults_array[]
#ifdef INCLUDE_DEFAULTS
= INCLUDE_DEFAULTS;
#else
= {
/* Pick up GNU C++ specific include files. */
{ GPLUSPLUS_INCLUDE_DIR, 1, 1 },
{ OLD_GPLUSPLUS_INCLUDE_DIR, 1, 1 },
#ifdef CROSS_COMPILE
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
{ GCC_INCLUDE_DIR, 0, 0 },
/* For cross-compilation, this dir name is generated
automatically in Makefile.in. */
{ CROSS_INCLUDE_DIR, 0, 0 },
#ifdef TOOL_INCLUDE_DIR
/* This is another place that the target system's headers might be. */
{ TOOL_INCLUDE_DIR, 0, 1 },
#endif
#else /* not CROSS_COMPILE */
#ifdef LOCAL_INCLUDE_DIR
/* This should be /usr/local/include and should come before
the fixincludes-fixed header files. */
{ LOCAL_INCLUDE_DIR, 0, 1 },
#endif
#ifdef TOOL_INCLUDE_DIR
/* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.
Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */
{ TOOL_INCLUDE_DIR, 0, 1 },
#endif
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
{ GCC_INCLUDE_DIR, 0, 0 },
/* Some systems have an extra dir of include files. */
#ifdef SYSTEM_INCLUDE_DIR
{ SYSTEM_INCLUDE_DIR, 0, 0 },
#endif
{ STANDARD_INCLUDE_DIR, 0, 0 },
#endif /* not CROSS_COMPILE */
{ 0, 0, 0 }
};
#endif /* no INCLUDE_DEFAULTS */
/* `struct directive' defines one #-directive, including how to handle it. */
struct directive {
int length; /* Length of name */
int (*func)(); /* Function to handle directive */
char *name; /* Name of directive */
enum node_type type; /* Code which describes which directive. */
char command_reads_line; /* One if rest of line is read by func. */
char traditional_comments; /* Nonzero: keep comments if -traditional. */
char pass_thru; /* Copy preprocessed directive to output file.*/
};
/* Here is the actual list of #-directives, most-often-used first.
The initialize_builtins function assumes #define is the very first. */
static struct directive directive_table[] = {
{ 6, do_define, "define", T_DEFINE, 0, 1},
{ 5, do_xifdef, "ifdef", T_IFDEF, 1},
{ 6, do_xifdef, "ifndef", T_IFNDEF, 1},
{ 7, do_include, "include", T_INCLUDE, 1},
{ 12, do_include, "include_next", T_INCLUDE_NEXT, 1},
{ 6, do_include, "import", T_IMPORT, 1},
{ 5, do_endif, "endif", T_ENDIF, 1},
{ 4, do_else, "else", T_ELSE, 1},
{ 2, do_if, "if", T_IF, 1},
{ 4, do_elif, "elif", T_ELIF, 1},
{ 5, do_undef, "undef", T_UNDEF},
{ 5, do_error, "error", T_ERROR},
{ 7, do_warning, "warning", T_WARNING},
{ 6, do_pragma, "pragma", T_PRAGMA, 0, 0, 1},
{ 4, do_line, "line", T_LINE, 1},
{ 5, do_ident, "ident", T_IDENT, 1, 0, 1},
#ifdef SCCS_DIRECTIVE
{ 4, do_sccs, "sccs", T_SCCS},
#endif
{ 6, do_assert, "assert", T_ASSERT, 1},
{ 8, do_unassert, "unassert", T_UNASSERT, 1},
{ -1, 0, "", T_UNUSED},
};
/* table to tell if char can be part of a C identifier. */
U_CHAR is_idchar[256];
/* table to tell if char can be first char of a c identifier. */
U_CHAR is_idstart[256];
/* table to tell if c is horizontal space. */
U_CHAR is_hor_space[256];
/* table to tell if c is horizontal or vertical space. */
static U_CHAR is_space[256];
/* Initialize syntactic classifications of characters. */
static void
initialize_char_syntax (opts)
struct cpp_options *opts;
{
register int i;
/*
* Set up is_idchar and is_idstart tables. These should be
* faster than saying (is_alpha (c) || c == '_'), etc.
* Set up these things before calling any routines tthat
* refer to them.
*/
for (i = 'a'; i <= 'z'; i++) {
is_idchar[i - 'a' + 'A'] = 1;
is_idchar[i] = 1;
is_idstart[i - 'a' + 'A'] = 1;
is_idstart[i] = 1;
}
for (i = '0'; i <= '9'; i++)
is_idchar[i] = 1;
is_idchar['_'] = 1;
is_idstart['_'] = 1;
is_idchar['$'] = opts->dollars_in_ident;
is_idstart['$'] = opts->dollars_in_ident;
/* horizontal space table */
is_hor_space[' '] = 1;
is_hor_space['\t'] = 1;
is_hor_space['\v'] = 1;
is_hor_space['\f'] = 1;
is_hor_space['\r'] = 1;
is_space[' '] = 1;
is_space['\t'] = 1;
is_space['\v'] = 1;
is_space['\f'] = 1;
is_space['\n'] = 1;
is_space['\r'] = 1;
}
/* Place into PFILE a quoted string representing the string SRC.
Caller must reserve enough space in pfile->token_buffer. */
static void
quote_string (pfile, src)
cpp_reader *pfile;
char *src;
{
U_CHAR c;
CPP_PUTC_Q (pfile, '\"');
for (;;)
switch ((c = *src++))
{
default:
if (isprint (c))
CPP_PUTC_Q (pfile, c);
else
{
sprintf (CPP_PWRITTEN (pfile), "\\%03o", c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
break;
case '\"':
case '\\':
CPP_PUTC_Q (pfile, '\\');
CPP_PUTC_Q (pfile, c);
break;
case '\0':
CPP_PUTC_Q (pfile, '\"');
CPP_NUL_TERMINATE_Q (pfile);
return;
}
}
/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */
void
cpp_grow_buffer (pfile, n)
cpp_reader *pfile;
long n;
{
long old_written = CPP_WRITTEN (pfile);
pfile->token_buffer_size = n + 2 * pfile->token_buffer_size;
pfile->token_buffer = (U_CHAR *)
xrealloc(pfile->token_buffer, pfile->token_buffer_size);
CPP_SET_WRITTEN (pfile, old_written);
}
/*
* process a given definition string, for initialization
* If STR is just an identifier, define it with value 1.
* If STR has anything after the identifier, then it should
* be identifier=definition.
*/
void
cpp_define (pfile, str)
cpp_reader *pfile;
U_CHAR *str;
{
U_CHAR *buf, *p;
buf = str;
p = str;
if (!is_idstart[*p])
{
cpp_error (pfile, "malformed option `-D %s'", str);
return;
}
while (is_idchar[*++p])
;
if (*p == 0)
{
buf = (U_CHAR *) alloca (p - buf + 4);
strcpy ((char *)buf, str);
strcat ((char *)buf, " 1");
}
else if (*p != '=')
{
cpp_error (pfile, "malformed option `-D %s'", str);
return;
}
else
{
U_CHAR *q;
/* Copy the entire option so we can modify it. */
buf = (U_CHAR *) alloca (2 * strlen (str) + 1);
strncpy (buf, str, p - str);
/* Change the = to a space. */
buf[p - str] = ' ';
/* Scan for any backslash-newline and remove it. */
p++;
q = &buf[p - str];
while (*p)
{
if (*p == '\\' && p[1] == '\n')
p += 2;
else
*q++ = *p++;
}
*q = 0;
}
do_define (pfile, NULL, buf, buf + strlen (buf));
}
/* Process the string STR as if it appeared as the body of a #assert.
OPTION is the option name for which STR was the argument. */
static void
make_assertion (pfile, option, str)
cpp_reader *pfile;
char *option;
U_CHAR *str;
{
struct directive *kt;
U_CHAR *buf, *p, *q;
/* Copy the entire option so we can modify it. */
buf = (U_CHAR *) alloca (strlen (str) + 1);
strcpy ((char *) buf, str);
/* Scan for any backslash-newline and remove it. */
p = q = buf;
while (*p) {
#if 0
if (*p == '\\' && p[1] == '\n')
p += 2;
else
#endif
*q++ = *p++;
}
*q = 0;
p = buf;
if (!is_idstart[*p]) {
cpp_error (pfile, "malformed option `%s %s'", option, str);
return;
}
while (is_idchar[*++p])
;
while (*p == ' ' || *p == '\t') p++;
if (! (*p == 0 || *p == '(')) {
cpp_error (pfile, "malformed option `%s %s'", option, str);
return;
}
if (cpp_push_buffer (pfile, buf, strlen (buf)) != NULL)
{
do_assert (pfile, NULL, NULL, NULL);
cpp_pop_buffer (pfile);
}
}
/* Append a chain of `struct file_name_list's
to the end of the main include chain.
FIRST is the beginning of the chain to append, and LAST is the end. */
static void
append_include_chain (pfile, first, last)
cpp_reader *pfile;
struct file_name_list *first, *last;
{
struct cpp_options *opts = CPP_OPTIONS (pfile);
struct file_name_list *dir;
if (!first || !last)
return;
if (opts->include == 0)
opts->include = first;
else
opts->last_include->next = first;
if (opts->first_bracket_include == 0)
opts->first_bracket_include = first;
for (dir = first; ; dir = dir->next) {
int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE;
if (len > pfile->max_include_len)
pfile->max_include_len = len;
if (dir == last)
break;
}
last->next = NULL;
opts->last_include = last;
}
/* Add output to `deps_buffer' for the -M switch.
STRING points to the text to be output.
SPACER is ':' for targets, ' ' for dependencies, zero for text
to be inserted literally. */
static void
deps_output (pfile, string, spacer)
cpp_reader *pfile;
char *string;
int spacer;
{
int size = strlen (string);
if (size == 0)
return;
#ifndef MAX_OUTPUT_COLUMNS
#define MAX_OUTPUT_COLUMNS 72
#endif
if (spacer
&& pfile->deps_column > 0
&& (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS)
{
deps_output (pfile, " \\\n ", 0);
pfile->deps_column = 0;
}
if (pfile->deps_size + size + 8 > pfile->deps_allocated_size)
{
pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2;
pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer,
pfile->deps_allocated_size);
}
if (spacer == ' ' && pfile->deps_column > 0)
pfile->deps_buffer[pfile->deps_size++] = ' ';
bcopy (string, &pfile->deps_buffer[pfile->deps_size], size);
pfile->deps_size += size;
pfile->deps_column += size;
if (spacer == ':')
pfile->deps_buffer[pfile->deps_size++] = ':';
pfile->deps_buffer[pfile->deps_size] = 0;
}
/* Given a colon-separated list of file names PATH,
add all the names to the search path for include files. */
static void
path_include (pfile, path)
cpp_reader *pfile;
char *path;
{
char *p;
p = path;
if (*p)
while (1) {
char *q = p;
char *name;
struct file_name_list *dirtmp;
/* Find the end of this name. */
while (*q != 0 && *q != PATH_SEPARATOR) q++;
if (p == q) {
/* An empty name in the path stands for the current directory. */
name = (char *) xmalloc (2);
name[0] = '.';
name[1] = 0;
} else {
/* Otherwise use the directory that is named. */
name = (char *) xmalloc (q - p + 1);
bcopy (p, name, q - p);
name[q - p] = 0;
}
dirtmp = (struct file_name_list *)
xmalloc (sizeof (struct file_name_list));
dirtmp->next = 0; /* New one goes on the end */
dirtmp->control_macro = 0;
dirtmp->c_system_include_path = 0;
dirtmp->fname = name;
dirtmp->got_name_map = 0;
append_include_chain (pfile, dirtmp, dirtmp);
/* Advance past this name. */
p = q;
if (*p == 0)
break;
/* Skip the colon. */
p++;
}
}
void
cpp_options_init (opts)
cpp_options *opts;
{
bzero ((char *) opts, sizeof *opts);
opts->in_fname = NULL;
opts->out_fname = NULL;
/* Initialize is_idchar to allow $. */
opts->dollars_in_ident = 1;
initialize_char_syntax (opts);
opts->no_line_commands = 0;
opts->no_trigraphs = 1;
opts->put_out_comments = 0;
opts->print_include_names = 0;
opts->dump_macros = dump_none;
opts->no_output = 0;
opts->cplusplus = 0;
opts->cplusplus_comments = 0;
opts->verbose = 0;
opts->objc = 0;
opts->lang_asm = 0;
opts->for_lint = 0;
opts->chill = 0;
opts->pedantic_errors = 0;
opts->inhibit_warnings = 0;
opts->warn_comments = 0;
opts->warn_import = 1;
opts->warnings_are_errors = 0;
}
enum cpp_token
null_underflow (pfile)
cpp_reader *pfile;
{
return CPP_EOF;
}
int
null_cleanup (pbuf, pfile)
cpp_buffer *pbuf;
cpp_reader *pfile;
{
return 0;
}
int
macro_cleanup (pbuf, pfile)
cpp_buffer *pbuf;
cpp_reader *pfile;
{
HASHNODE *macro = (HASHNODE *) pbuf->data;
if (macro->type == T_DISABLED)
macro->type = T_MACRO;
if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion)
free (pbuf->buf);
return 0;
}
int
file_cleanup (pbuf, pfile)
cpp_buffer *pbuf;
cpp_reader *pfile;
{
if (pbuf->buf)
{
free (pbuf->buf);
pbuf->buf = 0;
}
return 0;
}
/* Assuming we have read '/'.
If this is the start of a comment (followed by '*' or '/'),
skip to the end of the comment, and return ' '.
Return EOF if we reached the end of file before the end of the comment.
If not the start of a comment, return '/'. */
static int
skip_comment (pfile, linep)
cpp_reader *pfile;
long *linep;
{
int c = 0;
while (PEEKC() == '\\' && PEEKN(1) == '\n')
{
if (linep)
(*linep)++;
FORWARD(2);
}
if (PEEKC() == '*')
{
FORWARD(1);
for (;;)
{
int prev_c = c;
c = GETC ();
if (c == EOF)
return EOF;
while (c == '\\' && PEEKC() == '\n')
{
if (linep)
(*linep)++;
FORWARD(1), c = GETC();
}
if (prev_c == '*' && c == '/')
return ' ';
if (c == '\n' && linep)
(*linep)++;
}
}
else if (PEEKC() == '/' && CPP_OPTIONS (pfile)->cplusplus_comments)
{
FORWARD(1);
for (;;)
{
c = GETC ();
if (c == EOF)
return ' '; /* Allow // to be terminated by EOF. */
while (c == '\\' && PEEKC() == '\n')
{
FORWARD(1);
c = GETC();
if (linep)
(*linep)++;
}
if (c == '\n')
{
/* Don't consider final '\n' to be part of comment. */
FORWARD(-1);
return ' ';
}
}
}
else
return '/';
}
/* Skip whitespace \-newline and comments. Does not macro-expand. */
void
cpp_skip_hspace (pfile)
cpp_reader *pfile;
{
while (1)
{
int c = PEEKC();
if (c == EOF)
return; /* FIXME */
if (is_hor_space[c])
{
if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "%s in preprocessing directive",
c == '\f' ? "formfeed" : "vertical tab");
FORWARD(1);
}
else if (c == '/')
{
FORWARD (1);
c = skip_comment (pfile, NULL);
if (c == '/')
FORWARD(-1);
if (c == EOF || c == '/')
return;
}
else if (c == '\\' && PEEKN(1) == '\n') {
FORWARD(2);
}
else if (c == '@' && CPP_BUFFER (pfile)->has_escapes
&& is_hor_space[PEEKN(1)])
FORWARD(2);
else return;
}
}
/* Read the rest of the current line.
The line is appended to PFILE's output buffer. */
static void
copy_rest_of_line (pfile)
cpp_reader *pfile;
{
struct cpp_options *opts = CPP_OPTIONS (pfile);
for (;;)
{
int c = GETC();
int nextc;
switch (c)
{
case EOF:
goto end_directive;
case '\\':
if (PEEKC() == '\n')
{
FORWARD (1);
continue;
}
case '\'':
case '\"':
goto scan_directive_token;
break;
case '/':
nextc = PEEKC();
if (nextc == '*' || (opts->cplusplus_comments && nextc == '*'))
goto scan_directive_token;
break;
case '\f':
case '\v':
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "%s in preprocessing directive",
c == '\f' ? "formfeed" : "vertical tab");
break;
case '\n':
FORWARD(-1);
goto end_directive;
scan_directive_token:
FORWARD(-1);
cpp_get_token (pfile);
continue;
}
CPP_PUTC (pfile, c);
}
end_directive: ;
CPP_NUL_TERMINATE (pfile);
}
void
skip_rest_of_line (pfile)
cpp_reader *pfile;
{
long old = CPP_WRITTEN (pfile);
copy_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old);
}
/* Handle a possible # directive.
'#' has already been read. */
int
handle_directive (pfile)
cpp_reader *pfile;
{ int c;
register struct directive *kt;
int ident_length;
long after_ident;
U_CHAR *ident, *line_end;
long old_written = CPP_WRITTEN (pfile);
cpp_skip_hspace (pfile);
c = PEEKC ();
if (c >= '0' && c <= '9')
{
/* Handle # followed by a line number. */
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "`#' followed by integer");
do_line (pfile, NULL);
goto done_a_directive;
}
/* Now find the directive name. */
CPP_PUTC (pfile, '#');
parse_name (pfile, GETC());
ident = pfile->token_buffer + old_written + 1;
ident_length = CPP_PWRITTEN (pfile) - ident;
if (ident_length == 0 && PEEKC() == '\n')
{
/* A line of just `#' becomes blank. */
goto done_a_directive;
}
#if 0
if (ident_length == 0 || !is_idstart[*ident]) {
U_CHAR *p = ident;
while (is_idchar[*p]) {
if (*p < '0' || *p > '9')
break;
p++;
}
/* Avoid error for `###' and similar cases unless -pedantic. */
if (p == ident) {
while (*p == '#' || is_hor_space[*p]) p++;
if (*p == '\n') {
if (pedantic && !lang_asm)
cpp_warning (pfile, "invalid preprocessor directive");
return 0;
}
}
if (!lang_asm)
cpp_error (pfile, "invalid preprocessor directive name");
return 0;
}
#endif
/*
* Decode the keyword and call the appropriate expansion
* routine, after moving the input pointer up to the next line.
*/
for (kt = directive_table; ; kt++) {
if (kt->length <= 0)
goto not_a_directive;
if (kt->length == ident_length && !strncmp (kt->name, ident, ident_length))
break;
}
if (kt->command_reads_line)
after_ident = 0;
else
{
/* Nonzero means do not delete comments within the directive.
#define needs this when -traditional. */
int comments = CPP_TRADITIONAL (pfile) && kt->traditional_comments;
int save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments;
CPP_OPTIONS (pfile)->put_out_comments = comments;
after_ident = CPP_WRITTEN (pfile);
copy_rest_of_line (pfile);
CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments;
}
/* For #pragma and #define, we may want to pass through the directive.
Other directives may create output, but we don't want the directive
itself out, so we pop it now. For example #include may write a #line
command (see comment in do_include), and conditionals may emit
#failed ... #endfailed stuff. But note that popping the buffer
means the parameters to kt->func may point after pfile->limit
so these parameters are invalid as soon as something gets appended
to the token_buffer. */
line_end = CPP_PWRITTEN (pfile);
if (!kt->pass_thru && kt->type != T_DEFINE)
CPP_SET_WRITTEN (pfile, old_written);
(*kt->func) (pfile, kt, pfile->token_buffer + after_ident, line_end);
if (kt->pass_thru
|| (kt->type == T_DEFINE
&& CPP_OPTIONS (pfile)->dump_macros == dump_definitions))
{
/* Just leave the entire #define in the output stack. */
}
else if (kt->type == T_DEFINE
&& CPP_OPTIONS (pfile)->dump_macros == dump_names)
{
U_CHAR *p = pfile->token_buffer + old_written + 7; /* Skip "#define". */
SKIP_WHITE_SPACE (p);
while (is_idchar[*p]) p++;
pfile->limit = p;
CPP_PUTC (pfile, '\n');
}
else if (kt->type == T_DEFINE)
CPP_SET_WRITTEN (pfile, old_written);
done_a_directive:
return 1;
not_a_directive:
return 0;
}
/* Pass a directive through to the output file.
BUF points to the contents of the directive, as a contiguous string.
LIMIT points to the first character past the end of the directive.
KEYWORD is the keyword-table entry for the directive. */
static void
pass_thru_directive (buf, limit, pfile, keyword)
U_CHAR *buf, *limit;
cpp_reader *pfile;
struct directive *keyword;
{
register unsigned keyword_length = keyword->length;
CPP_RESERVE (pfile, 1 + keyword_length + (limit - buf));
CPP_PUTC_Q (pfile, '#');
CPP_PUTS_Q (pfile, keyword->name, keyword_length);
if (limit != buf && buf[0] != ' ')
CPP_PUTC_Q (pfile, ' ');
CPP_PUTS_Q (pfile, buf, limit - buf);
#if 0
CPP_PUTS_Q (pfile, '\n');
/* Count the line we have just made in the output,
to get in sync properly. */
pfile->lineno++;
#endif
}
/* The arglist structure is built by do_define to tell
collect_definition where the argument names begin. That
is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist
would contain pointers to the strings x, y, and z.
Collect_definition would then build a DEFINITION node,
with reflist nodes pointing to the places x, y, and z had
appeared. So the arglist is just convenience data passed
between these two routines. It is not kept around after
the current #define has been processed and entered into the
hash table. */
struct arglist {
struct arglist *next;
U_CHAR *name;
int length;
int argno;
char rest_args;
};
/* Read a replacement list for a macro with parameters.
Build the DEFINITION structure.
Reads characters of text starting at BUF until END.
ARGLIST specifies the formal parameters to look for
in the text of the definition; NARGS is the number of args
in that list, or -1 for a macro name that wants no argument list.
MACRONAME is the macro name itself (so we can avoid recursive expansion)
and NAMELEN is its length in characters.
Note that comments, backslash-newlines, and leading white space
have already been deleted from the argument. */
static DEFINITION *
collect_expansion (pfile, buf, limit, nargs, arglist)
cpp_reader *pfile;
U_CHAR *buf, *limit;
int nargs;
struct arglist *arglist;
{
DEFINITION *defn;
register U_CHAR *p, *lastp, *exp_p;
struct reflist *endpat = NULL;
/* Pointer to first nonspace after last ## seen. */
U_CHAR *concat = 0;
/* Pointer to first nonspace after last single-# seen. */
U_CHAR *stringify = 0;
int maxsize;
int expected_delimiter = '\0';
/* Scan thru the replacement list, ignoring comments and quoted
strings, picking up on the macro calls. It does a linear search
thru the arg list on every potential symbol. Profiling might say
that something smarter should happen. */
if (limit < buf)
abort ();
/* Find the beginning of the trailing whitespace. */
p = buf;
while (p < limit && is_space[limit[-1]]) limit--;
/* Allocate space for the text in the macro definition.
Leading and trailing whitespace chars need 2 bytes each.
Each other input char may or may not need 1 byte,
so this is an upper bound. The extra 5 are for invented
leading and trailing newline-marker and final null. */
maxsize = (sizeof (DEFINITION)
+ (limit - p) + 5);
/* Occurrences of '@' get doubled, so allocate extra space for them. */
while (p < limit)
if (*p++ == '@')
maxsize++;
defn = (DEFINITION *) xcalloc (1, maxsize);
defn->nargs = nargs;
exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION);
lastp = exp_p;
p = buf;
/* Add one initial space escape-marker to prevent accidental
token-pasting (often removed by macroexpand). */
*exp_p++ = '@';
*exp_p++ = ' ';
if (limit - p >= 2 && p[0] == '#' && p[1] == '#') {
cpp_error (pfile, "`##' at start of macro definition");
p += 2;
}
/* Process the main body of the definition. */
while (p < limit) {
int skipped_arg = 0;
register U_CHAR c = *p++;
*exp_p++ = c;
if (!CPP_TRADITIONAL (pfile)) {
switch (c) {
case '\'':
case '\"':
if (expected_delimiter != '\0') {
if (c == expected_delimiter)
expected_delimiter = '\0';
} else
expected_delimiter = c;
break;
case '\\':
if (p < limit && expected_delimiter) {
/* In a string, backslash goes through
and makes next char ordinary. */
*exp_p++ = *p++;
}
break;
case '@':
/* An '@' in a string or character constant stands for itself,
and does not need to be escaped. */
if (!expected_delimiter)
*exp_p++ = c;
break;
case '#':
/* # is ordinary inside a string. */
if (expected_delimiter)
break;
if (p < limit && *p == '#') {
/* ##: concatenate preceding and following tokens. */
/* Take out the first #, discard preceding whitespace. */
exp_p--;
while (exp_p > lastp && is_hor_space[exp_p[-1]])
--exp_p;
/* Skip the second #. */
p++;
/* Discard following whitespace. */
SKIP_WHITE_SPACE (p);
concat = p;
if (p == limit)
cpp_error (pfile, "`##' at end of macro definition");
} else if (nargs >= 0) {
/* Single #: stringify following argument ref.
Don't leave the # in the expansion. */
exp_p--;
SKIP_WHITE_SPACE (p);
if (p == limit || ! is_idstart[*p]
|| (*p == 'L' && p + 1 < limit && (p[1] == '\'' || p[1] == '"')))
cpp_error (pfile,
"`#' operator is not followed by a macro argument name");
else
stringify = p;
}
break;
}
} else {
/* In -traditional mode, recognize arguments inside strings and
and character constants, and ignore special properties of #.
Arguments inside strings are considered "stringified", but no
extra quote marks are supplied. */
switch (c) {
case '\'':
case '\"':
if (expected_delimiter != '\0') {
if (c == expected_delimiter)
expected_delimiter = '\0';
} else
expected_delimiter = c;
break;
case '\\':
/* Backslash quotes delimiters and itself, but not macro args. */
if (expected_delimiter != 0 && p < limit
&& (*p == expected_delimiter || *p == '\\')) {
*exp_p++ = *p++;
continue;
}
break;
case '/':
if (expected_delimiter != '\0') /* No comments inside strings. */
break;
if (*p == '*') {
/* If we find a comment that wasn't removed by handle_directive,
this must be -traditional. So replace the comment with
nothing at all. */
exp_p--;
p += 1;
while (p < limit && !(p[-2] == '*' && p[-1] == '/'))
p++;
#if 0
/* Mark this as a concatenation-point, as if it had been ##. */
concat = p;
#endif
}
break;
}
}
/* Handle the start of a symbol. */
if (is_idchar[c] && nargs > 0) {
U_CHAR *id_beg = p - 1;
int id_len;
--exp_p;
while (p != limit && is_idchar[*p]) p++;
id_len = p - id_beg;
if (is_idstart[c]
&& ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) {
register struct arglist *arg;
for (arg = arglist; arg != NULL; arg = arg->next) {
struct reflist *tpat;
if (arg->name[0] == c
&& arg->length == id_len
&& strncmp (arg->name, id_beg, id_len) == 0) {
if (expected_delimiter && CPP_OPTIONS (pfile)->warn_stringify) {
if (CPP_TRADITIONAL (pfile)) {
cpp_warning (pfile, "macro argument `%.*s' is stringified.",
id_len, arg->name);
} else {
cpp_warning (pfile,
"macro arg `%.*s' would be stringified with -traditional.",
id_len, arg->name);
}
}
/* If ANSI, don't actually substitute inside a string. */
if (!CPP_TRADITIONAL (pfile) && expected_delimiter)
break;
/* make a pat node for this arg and append it to the end of
the pat list */
tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
tpat->next = NULL;
tpat->raw_before = concat == id_beg;
tpat->raw_after = 0;
tpat->rest_args = arg->rest_args;
tpat->stringify = (CPP_TRADITIONAL (pfile)
? expected_delimiter != '\0'
: stringify == id_beg);
if (endpat == NULL)
defn->pattern = tpat;
else
endpat->next = tpat;
endpat = tpat;
tpat->argno = arg->argno;
tpat->nchars = exp_p - lastp;
{
register U_CHAR *p1 = p;
SKIP_WHITE_SPACE (p1);
if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#')
tpat->raw_after = 1;
}
lastp = exp_p; /* place to start copying from next time */
skipped_arg = 1;
break;
}
}
}
/* If this was not a macro arg, copy it into the expansion. */
if (! skipped_arg) {
register U_CHAR *lim1 = p;
p = id_beg;
while (p != lim1)
*exp_p++ = *p++;
if (stringify == id_beg)
cpp_error (pfile,
"`#' operator should be followed by a macro argument name");
}
}
}
if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0)
{
/* If ANSI, put in a "@ " marker to prevent token pasting.
But not if "inside a string" (which in ANSI mode
happens only for -D option). */
*exp_p++ = '@';
*exp_p++ = ' ';
}
*exp_p = '\0';
defn->length = exp_p - defn->expansion;
/* Crash now if we overrun the allocated size. */
if (defn->length + 1 > maxsize)
abort ();
#if 0
/* This isn't worth the time it takes. */
/* give back excess storage */
defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1);
#endif
return defn;
}
/*
* special extension string that can be added to the last macro argument to
* allow it to absorb the "rest" of the arguments when expanded. Ex:
* #define wow(a, b...) process (b, a, b)
* { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); }
* { wow (one, two); } -> { process (two, one, two); }
* if this "rest_arg" is used with the concat token '##' and if it is not
* supplied then the token attached to with ## will not be outputted. Ex:
* #define wow (a, b...) process (b ## , a, ## b)
* { wow (1, 2); } -> { process (2, 1, 2); }
* { wow (one); } -> { process (one); {
*/
static char rest_extension[] = "...";
#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)
/* Create a DEFINITION node from a #define directive. Arguments are
as for do_define. */
static MACRODEF
create_definition (buf, limit, pfile, predefinition)
U_CHAR *buf, *limit;
cpp_reader *pfile;
int predefinition;
{
U_CHAR *bp; /* temp ptr into input buffer */
U_CHAR *symname; /* remember where symbol name starts */
int sym_length; /* and how long it is */
int rest_args = 0;
long line, col;
char *file = CPP_BUFFER (pfile) ? CPP_BUFFER (pfile)->nominal_fname : "";
DEFINITION *defn;
int arglengths = 0; /* Accumulate lengths of arg names
plus number of args. */
MACRODEF mdef;
cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
bp = buf;
while (is_hor_space[*bp])
bp++;
symname = bp; /* remember where it starts */
sym_length = check_macro_name (pfile, bp, "macro");
bp += sym_length;
/* Lossage will occur if identifiers or control keywords are broken
across lines using backslash. This is not the right place to take
care of that. */
if (*bp == '(') {
struct arglist *arg_ptrs = NULL;
int argno = 0;
bp++; /* skip '(' */
SKIP_WHITE_SPACE (bp);
/* Loop over macro argument names. */
while (*bp != ')') {
struct arglist *temp;
temp = (struct arglist *) alloca (sizeof (struct arglist));
temp->name = bp;
temp->next = arg_ptrs;
temp->argno = argno++;
temp->rest_args = 0;
arg_ptrs = temp;
if (rest_args)
cpp_pedwarn (pfile, "another parameter follows `%s'", rest_extension);
if (!is_idstart[*bp])
cpp_pedwarn (pfile, "invalid character in macro parameter name");
/* Find the end of the arg name. */
while (is_idchar[*bp]) {
bp++;
/* do we have a "special" rest-args extension here? */
if (limit - bp > REST_EXTENSION_LENGTH
&& strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) {
rest_args = 1;
temp->rest_args = 1;
break;
}
}
temp->length = bp - temp->name;
if (rest_args == 1)
bp += REST_EXTENSION_LENGTH;
arglengths += temp->length + 2;
SKIP_WHITE_SPACE (bp);
if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
cpp_error (pfile, "badly punctuated parameter list in `#define'");
goto nope;
}
if (*bp == ',') {
bp++;
SKIP_WHITE_SPACE (bp);
}
if (bp >= limit) {
cpp_error (pfile, "unterminated parameter list in `#define'");
goto nope;
}
{
struct arglist *otemp;
for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
if (temp->length == otemp->length
&& strncmp (temp->name, otemp->name, temp->length) == 0) {
U_CHAR *name;
name = (U_CHAR *) alloca (temp->length + 1);
(void) strncpy (name, temp->name, temp->length);
name[temp->length] = '\0';
cpp_error (pfile,
"duplicate argument name `%s' in `#define'", name);
goto nope;
}
}
}
++bp; /* skip paren */
SKIP_WHITE_SPACE (bp);
/* now everything from bp before limit is the definition. */
defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs);
defn->rest_args = rest_args;
/* Now set defn->args.argnames to the result of concatenating
the argument names in reverse order
with comma-space between them. */
defn->args.argnames = (U_CHAR *) xmalloc (arglengths + 1);
{
struct arglist *temp;
int i = 0;
for (temp = arg_ptrs; temp; temp = temp->next) {
bcopy (temp->name, &defn->args.argnames[i], temp->length);
i += temp->length;
if (temp->next != 0) {
defn->args.argnames[i++] = ',';
defn->args.argnames[i++] = ' ';
}
}
defn->args.argnames[i] = 0;
}
} else {
/* Simple expansion or empty definition. */
if (bp < limit)
{
if (is_hor_space[*bp]) {
bp++;
SKIP_WHITE_SPACE (bp);
} else {
switch (*bp) {
case '!': case '"': case '#': case '%': case '&': case '\'':
case ')': case '*': case '+': case ',': case '-': case '.':
case '/': case ':': case ';': case '<': case '=': case '>':
case '?': case '[': case '\\': case ']': case '^': case '{':
case '|': case '}': case '~':
cpp_warning (pfile, "missing white space after `#define %.*s'",
sym_length, symname);
break;
default:
cpp_pedwarn (pfile, "missing white space after `#define %.*s'",
sym_length, symname);
break;
}
}
}
/* now everything from bp before limit is the definition. */
defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR);
defn->args.argnames = (U_CHAR *) "";
}
defn->line = line;
defn->file = file;
/* OP is null if this is a predefinition */
defn->predefined = predefinition;
mdef.defn = defn;
mdef.symnam = symname;
mdef.symlen = sym_length;
return mdef;
nope:
mdef.defn = 0;
return mdef;
}
/* Check a purported macro name SYMNAME, and yield its length.
USAGE is the kind of name this is intended for. */
static int
check_macro_name (pfile, symname, usage)
cpp_reader *pfile;
U_CHAR *symname;
char *usage;
{
U_CHAR *p;
int sym_length;
for (p = symname; is_idchar[*p]; p++)
;
sym_length = p - symname;
if (sym_length == 0
|| (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
cpp_error (pfile, "invalid %s name", usage);
else if (!is_idstart[*symname]) {
U_CHAR *msg; /* what pain... */
msg = (U_CHAR *) alloca (sym_length + 1);
bcopy (symname, msg, sym_length);
msg[sym_length] = 0;
cpp_error (pfile, "invalid %s name `%s'", usage, msg);
} else {
if (! strncmp (symname, "defined", 7) && sym_length == 7)
cpp_error (pfile, "invalid %s name `defined'", usage);
}
return sym_length;
}
/* Return zero if two DEFINITIONs are isomorphic. */
static int
compare_defs (d1, d2)
DEFINITION *d1, *d2;
{
register struct reflist *a1, *a2;
register U_CHAR *p1 = d1->expansion;
register U_CHAR *p2 = d2->expansion;
int first = 1;
if (d1->nargs != d2->nargs)
return 1;
if (strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames))
return 1;
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
a1 = a1->next, a2 = a2->next) {
if (!((a1->nchars == a2->nchars && ! strncmp (p1, p2, a1->nchars))
|| ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
|| a1->argno != a2->argno
|| a1->stringify != a2->stringify
|| a1->raw_before != a2->raw_before
|| a1->raw_after != a2->raw_after)
return 1;
first = 0;
p1 += a1->nchars;
p2 += a2->nchars;
}
if (a1 != a2)
return 1;
if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
p2, d2->length - (p2 - d2->expansion), 1))
return 1;
return 0;
}
/* Return 1 if two parts of two macro definitions are effectively different.
One of the parts starts at BEG1 and has LEN1 chars;
the other has LEN2 chars at BEG2.
Any sequence of whitespace matches any other sequence of whitespace.
FIRST means these parts are the first of a macro definition;
so ignore leading whitespace entirely.
LAST means these parts are the last of a macro definition;
so ignore trailing whitespace entirely. */
static int
comp_def_part (first, beg1, len1, beg2, len2, last)
int first;
U_CHAR *beg1, *beg2;
int len1, len2;
int last;
{
register U_CHAR *end1 = beg1 + len1;
register U_CHAR *end2 = beg2 + len2;
if (first) {
while (beg1 != end1 && is_space[*beg1]) beg1++;
while (beg2 != end2 && is_space[*beg2]) beg2++;
}
if (last) {
while (beg1 != end1 && is_space[end1[-1]]) end1--;
while (beg2 != end2 && is_space[end2[-1]]) end2--;
}
while (beg1 != end1 && beg2 != end2) {
if (is_space[*beg1] && is_space[*beg2]) {
while (beg1 != end1 && is_space[*beg1]) beg1++;
while (beg2 != end2 && is_space[*beg2]) beg2++;
} else if (*beg1 == *beg2) {
beg1++; beg2++;
} else break;
}
return (beg1 != end1) || (beg2 != end2);
}
/* Process a #define command.
BUF points to the contents of the #define command, as a contiguous string.
LIMIT points to the first character past the end of the definition.
KEYWORD is the keyword-table entry for #define,
or NULL for a "predefined" macro. */
static int
do_define (pfile, keyword, buf, limit)
cpp_reader *pfile;
struct directive *keyword;
U_CHAR *buf, *limit;
{
int hashcode;
MACRODEF mdef;
HASHNODE *hp;
#if 0
/* If this is a precompiler run (with -pcp) pass thru #define commands. */
if (pcp_outfile && keyword)
pass_thru_directive (buf, limit, pfile, keyword);
#endif
mdef = create_definition (buf, limit, pfile, keyword == NULL);
if (mdef.defn == 0)
goto nope;
hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE);
if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen, hashcode)) != NULL)
{
int ok = 0;
/* Redefining a precompiled key is ok. */
if (hp->type == T_PCSTRING)
ok = 1;
/* Redefining a macro is ok if the definitions are the same. */
else if (hp->type == T_MACRO)
ok = ! compare_defs (mdef.defn, hp->value.defn);
/* Redefining a constant is ok with -D. */
else if (hp->type == T_CONST)
ok = ! CPP_OPTIONS (pfile)->done_initializing;
/* Print the warning if it's not ok. */
if (!ok)
{
U_CHAR *msg; /* what pain... */
/* If we are passing through #define and #undef directives, do
that for this re-definition now. */
if (CPP_OPTIONS (pfile)->debug_output && keyword)
pass_thru_directive (buf, limit, pfile, keyword);
msg = (U_CHAR *) alloca (mdef.symlen + 22);
*msg = '`';
bcopy (mdef.symnam, msg + 1, mdef.symlen);
strcpy ((char *) (msg + mdef.symlen + 1), "' redefined");
cpp_pedwarn (pfile, msg);
if (hp->type == T_MACRO)
cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file, hp->value.defn->line,
"this is the location of the previous definition");
}
/* Replace the old definition. */
hp->type = T_MACRO;
hp->value.defn = mdef.defn;
}
else
{
/* If we are passing through #define and #undef directives, do
that for this new definition now. */
if (CPP_OPTIONS (pfile)->debug_output && keyword)
pass_thru_directive (buf, limit, pfile, keyword);
install (mdef.symnam, mdef.symlen, T_MACRO, 0,
(char *) mdef.defn, hashcode);
}
return 0;
nope:
return 1;
}
/* This structure represents one parsed argument in a macro call.
`raw' points to the argument text as written (`raw_length' is its length).
`expanded' points to the argument's macro-expansion
(its length is `expand_length').
`stringified_length' is the length the argument would have
if stringified.
`use_count' is the number of times this macro arg is substituted
into the macro. If the actual use count exceeds 10,
the value stored is 10. */
/* raw and expanded are relative to ARG_BASE */
#define ARG_BASE ((pfile)->token_buffer)
struct argdata {
/* Strings relative to pfile->token_buffer */
long raw, expanded, stringified;
int raw_length, expand_length;
int stringified_length;
char newlines;
char use_count;
};
/* Allocate a new cpp_buffer for PFILE, and push it on the input buffer stack.
If BUFFER != NULL, then use the LENGTH characters in BUFFER
as the new input buffer.
Return the new buffer, or NULL on failure. */
cpp_buffer *
cpp_push_buffer (pfile, buffer, length)
cpp_reader *pfile;
U_CHAR *buffer;
long length;
{
register cpp_buffer *buf = CPP_BUFFER (pfile);
if (buf == pfile->buffer_stack)
{
cpp_fatal (pfile, "%s: macro or `#include' recursion too deep",
buf->fname);
return NULL;
}
buf--;
bzero ((char *) buf, sizeof (cpp_buffer));
CPP_BUFFER (pfile) = buf;
buf->if_stack = pfile->if_stack;
buf->cleanup = null_cleanup;
buf->underflow = null_underflow;
buf->buf = buf->cur = buffer;
buf->alimit = buf->rlimit = buffer + length;
return buf;
}
cpp_buffer *
cpp_pop_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *buf = CPP_BUFFER (pfile);
(*buf->cleanup) (buf, pfile);
return ++CPP_BUFFER (pfile);
}
/* Scan until CPP_BUFFER (PFILE) is exhausted into PFILE->token_buffer.
Pop the buffer when done. */
void
cpp_scan_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *buffer = CPP_BUFFER (pfile);
for (;;)
{
enum cpp_token token = cpp_get_token (pfile);
if (token == CPP_EOF) /* Should not happen ... */
break;
if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
{
cpp_pop_buffer (pfile);
break;
}
}
}
/*
* Rescan a string (which may have escape marks) into pfile's buffer.
* Place the result in pfile->token_buffer.
*
* The input is copied before it is scanned, so it is safe to pass
* it something from the token_buffer that will get overwritten
* (because it follows CPP_WRITTEN). This is used by do_include.
*/
static void
cpp_expand_to_buffer (pfile, buf, length)
cpp_reader *pfile;
U_CHAR *buf;
int length;
{
register cpp_buffer *ip;
cpp_buffer obuf;
U_CHAR *limit = buf + length;
U_CHAR *buf1;
#if 0
int odepth = indepth;
#endif
if (length < 0)
abort ();
/* Set up the input on the input stack. */
buf1 = (U_CHAR *) alloca (length + 1);
{
register U_CHAR *p1 = buf;
register U_CHAR *p2 = buf1;
while (p1 != limit)
*p2++ = *p1++;
}
buf1[length] = 0;
ip = cpp_push_buffer (pfile, buf1, length);
if (ip == NULL)
return;
ip->has_escapes = 1;
#if 0
ip->lineno = obuf.lineno = 1;
#endif
/* Scan the input, create the output. */
cpp_scan_buffer (pfile);
#if 0
if (indepth != odepth)
abort ();
#endif
CPP_NUL_TERMINATE (pfile);
}
static void
adjust_position (buf, limit, linep, colp)
U_CHAR *buf;
U_CHAR *limit;
long *linep;
long *colp;
{
while (buf < limit)
{
U_CHAR ch = *buf++;
if (ch == '\n')
(*linep)++, (*colp) = 1;
else
(*colp)++;
}
}
/* Move line_base forward, updating lineno and colno. */
static void
update_position (pbuf)
register cpp_buffer *pbuf;
{
unsigned char *old_pos = pbuf->buf + pbuf->line_base;
unsigned char *new_pos = pbuf->cur;
register struct parse_marker *mark;
for (mark = pbuf->marks; mark != NULL; mark = mark->next)
{
if (pbuf->buf + mark->position < new_pos)
new_pos = pbuf->buf + mark->position;
}
pbuf->line_base += new_pos - old_pos;
adjust_position (old_pos, new_pos, &pbuf->lineno, &pbuf->colno);
}
void
cpp_buf_line_and_col (pbuf, linep, colp)
register cpp_buffer *pbuf;
long *linep, *colp;
{
long dummy;
if (colp == NULL)
colp = &dummy;
if (pbuf)
{
*linep = pbuf->lineno;
*colp = pbuf->colno;
adjust_position (pbuf->buf + pbuf->line_base, pbuf->cur, linep, colp);
}
else
{
*linep = 0;
*colp = 0;
}
}
/* Return the cpp_buffer that corresponds to a file (not a macro). */
cpp_buffer *
cpp_file_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *ip = CPP_BUFFER (pfile);
for ( ; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip))
if (ip->fname != NULL)
return ip;
return NULL;
}
static long
count_newlines (buf, limit)
register U_CHAR *buf;
register U_CHAR *limit;
{
register long count = 0;
while (buf < limit)
{
U_CHAR ch = *buf++;
if (ch == '\n')
count++;
}
return count;
}
/*
* write out a #line command, for instance, after an #include file.
* If CONDITIONAL is nonzero, we can omit the #line if it would
* appear to be a no-op, and we can output a few newlines instead
* if we want to increase the line number by a small amount.
* FILE_CHANGE says whether we are entering a file, leaving, or neither.
*/
static void
output_line_command (pfile, conditional, file_change)
cpp_reader *pfile;
int conditional;
enum file_change_code file_change;
{
int len;
char *line_cmd_buf, *line_end;
long line, col;
cpp_buffer *ip = CPP_BUFFER (pfile);
if (ip->fname == NULL)
return;
update_position (ip);
if (CPP_OPTIONS (pfile)->no_line_commands
|| CPP_OPTIONS (pfile)->no_output)
return;
line = CPP_BUFFER (pfile)->lineno;
col = CPP_BUFFER (pfile)->colno;
adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col);
if (CPP_OPTIONS (pfile)->no_line_commands)
return;
if (conditional) {
if (line == pfile->lineno)
return;
/* If the inherited line number is a little too small,
output some newlines instead of a #line command. */
if (line > pfile->lineno && line < pfile->lineno + 8) {
CPP_RESERVE (pfile, 20);
while (line > pfile->lineno) {
CPP_PUTC_Q (pfile, '\n');
pfile->lineno++;
}
return;
}
}
#if 0
/* Don't output a line number of 0 if we can help it. */
if (ip->lineno == 0 && ip->bufp - ip->buf < ip->length
&& *ip->bufp == '\n') {
ip->lineno++;
ip->bufp++;
}
#endif
CPP_RESERVE (pfile, 4 * strlen (ip->nominal_fname) + 50);
{
#ifdef OUTPUT_LINE_COMMANDS
static char sharp_line[] = "#line ";
#else
static char sharp_line[] = "# ";
#endif
CPP_PUTS_Q (pfile, sharp_line, sizeof(sharp_line)-1);
}
sprintf (CPP_PWRITTEN (pfile), "%d ", line);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
quote_string (pfile, ip->nominal_fname);
if (file_change != same_file) {
CPP_PUTC_Q (pfile, ' ');
CPP_PUTC_Q (pfile, file_change == enter_file ? '1' : '2');
}
/* Tell cc1 if following text comes from a system header file. */
if (ip->system_header_p) {
CPP_PUTC_Q (pfile, ' ');
CPP_PUTC_Q (pfile, '3');
}
#ifndef NO_IMPLICIT_EXTERN_C
/* Tell cc1plus if following text should be treated as C. */
if (ip->system_header_p == 2 && CPP_OPTIONS (pfile)->cplusplus) {
CPP_PUTC_Q (pfile, ' ');
CPP_PUTC_Q (pfile, '4');
}
#endif
CPP_PUTC_Q (pfile, '\n');
pfile->lineno = line;
}
/*
* Parse a macro argument and append the info on PFILE's token_buffer.
* REST_ARGS means to absorb the rest of the args.
* Return nonzero to indicate a syntax error.
*/
static enum cpp_token
macarg (pfile, rest_args)
cpp_reader *pfile;
int rest_args;
{
int paren = 0;
enum cpp_token token;
long arg_start = CPP_WRITTEN (pfile);
char save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments;
CPP_OPTIONS (pfile)->put_out_comments = 0;
/* Try to parse as much of the argument as exists at this
input stack level. */
pfile->no_macro_expand++;
for (;;)
{
token = cpp_get_token (pfile);
switch (token)
{
case CPP_EOF:
goto done;
case CPP_POP:
/* If we've hit end of file, it's an error (reported by caller).
Ditto if it's the end of cpp_expand_to_buffer text.
If we've hit end of macro, just continue. */
if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
goto done;
break;
case CPP_LPAREN:
paren++;
break;
case CPP_RPAREN:
if (--paren < 0)
goto found;
break;
case CPP_COMMA:
/* if we've returned to lowest level and
we aren't absorbing all args */
if (paren == 0 && rest_args == 0)
goto found;
break;
found:
/* Remove ',' or ')' from argument buffer. */
CPP_ADJUST_WRITTEN (pfile, -1);
goto done;
default: ;
}
}
done:
CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments;
pfile->no_macro_expand--;
return token;
}
/* Turn newlines to spaces in the string of length LENGTH at START,
except inside of string constants.
The string is copied into itself with its beginning staying fixed. */
static int
change_newlines (start, length)
U_CHAR *start;
int length;
{
register U_CHAR *ibp;
register U_CHAR *obp;
register U_CHAR *limit;
register int c;
ibp = start;
limit = start + length;
obp = start;
while (ibp < limit) {
*obp++ = c = *ibp++;
switch (c) {
case '\'':
case '\"':
/* Notice and skip strings, so that we don't delete newlines in them. */
{
int quotec = c;
while (ibp < limit) {
*obp++ = c = *ibp++;
if (c == quotec)
break;
if (c == '\n' && quotec == '\'')
break;
}
}
break;
}
}
return obp - start;
}
static struct tm *
timestamp (pfile)
cpp_reader *pfile;
{
if (!pfile->timebuf) {
time_t t = time ((time_t *) 0);
pfile->timebuf = localtime (&t);
}
return pfile->timebuf;
}
static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
/*
* expand things like __FILE__. Place the expansion into the output
* buffer *without* rescanning.
*/
static void
special_symbol (hp, pfile)
HASHNODE *hp;
cpp_reader *pfile;
{
char *buf;
int i, len;
int true_indepth;
cpp_buffer *ip = NULL;
struct tm *timebuf;
int paren = 0; /* For special `defined' keyword */
#if 0
if (pcp_outfile && pcp_inside_if
&& hp->type != T_SPEC_DEFINED && hp->type != T_CONST)
cpp_error (pfile,
"Predefined macro `%s' used inside `#if' during precompilation",
hp->name);
#endif
for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip))
{
if (ip == CPP_NULL_BUFFER (pfile))
{
cpp_error (pfile, "cccp error: not in any file?!");
return; /* the show must go on */
}
if (ip->fname != NULL)
break;
}
switch (hp->type)
{
case T_FILE:
case T_BASE_FILE:
{
char *string;
if (hp->type == T_BASE_FILE)
{
while (CPP_PREV_BUFFER (ip) != CPP_NULL_BUFFER (pfile))
ip = CPP_PREV_BUFFER (ip);
}
string = ip->nominal_fname;
if (!string)
string = "";
CPP_RESERVE (pfile, 3 + 4 * strlen (string));
quote_string (pfile, string);
return;
}
case T_INCLUDE_LEVEL:
true_indepth = 0;
ip = CPP_BUFFER (pfile);
for (; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip))
if (ip->fname != NULL)
true_indepth++;
buf = (char *) alloca (8); /* Eight bytes ought to be more than enough */
sprintf (buf, "%d", true_indepth - 1);
break;
case T_VERSION:
buf = (char *) alloca (3 + strlen (version_string));
sprintf (buf, "\"%s\"", version_string);
break;
#ifndef NO_BUILTIN_SIZE_TYPE
case T_SIZE_TYPE:
buf = SIZE_TYPE;
break;
#endif
#ifndef NO_BUILTIN_PTRDIFF_TYPE
case T_PTRDIFF_TYPE:
buf = PTRDIFF_TYPE;
break;
#endif
case T_WCHAR_TYPE:
buf = CPP_WCHAR_TYPE (pfile);
break;
case T_USER_LABEL_PREFIX_TYPE:
buf = USER_LABEL_PREFIX;
break;
case T_REGISTER_PREFIX_TYPE:
buf = REGISTER_PREFIX;
break;
case T_CONST:
buf = (char *) alloca (4 * sizeof (int));
sprintf (buf, "%d", hp->value.ival);
#if 0
if (pcp_inside_if && pcp_outfile)
/* Output a precondition for this macro use */
fprintf (pcp_outfile, "#define %s %d\n", hp->name, hp->value.ival);
#endif
break;
case T_SPECLINE:
{
long line = ip->lineno;
long col = ip->colno;
adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col);
buf = (char *) alloca (10);
sprintf (buf, "%d", line);
}
break;
case T_DATE:
case T_TIME:
buf = (char *) alloca (20);
timebuf = timestamp (pfile);
if (hp->type == T_DATE)
sprintf (buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon],
timebuf->tm_mday, timebuf->tm_year + 1900);
else
sprintf (buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min,
timebuf->tm_sec);
break;
case T_SPEC_DEFINED:
buf = " 0 "; /* Assume symbol is not defined */
ip = CPP_BUFFER (pfile);
SKIP_WHITE_SPACE (ip->cur);
if (*ip->cur == '(')
{
paren++;
ip->cur++; /* Skip over the paren */
SKIP_WHITE_SPACE (ip->cur);
}
if (!is_idstart[*ip->cur])
goto oops;
if (ip->cur[0] == 'L' && (ip->cur[1] == '\'' || ip->cur[1] == '"'))
goto oops;
if (hp = cpp_lookup (pfile, ip->cur, -1, -1))
{
#if 0
if (pcp_outfile && pcp_inside_if
&& (hp->type == T_CONST
|| (hp->type == T_MACRO && hp->value.defn->predefined)))
/* Output a precondition for this macro use. */
fprintf (pcp_outfile, "#define %s\n", hp->name);
#endif
buf = " 1 ";
}
#if 0
else
if (pcp_outfile && pcp_inside_if)
{
/* Output a precondition for this macro use */
U_CHAR *cp = ip->bufp;
fprintf (pcp_outfile, "#undef ");
while (is_idchar[*cp]) /* Ick! */
fputc (*cp++, pcp_outfile);
putc ('\n', pcp_outfile);
}
#endif
while (is_idchar[*ip->cur])
++ip->cur;
SKIP_WHITE_SPACE (ip->cur);
if (paren)
{
if (*ip->cur != ')')
goto oops;
++ip->cur;
}
break;
oops:
cpp_error (pfile, "`defined' without an identifier");
break;
default:
cpp_error (pfile, "cccp error: invalid special hash type"); /* time for gdb */
abort ();
}
len = strlen (buf);
CPP_RESERVE (pfile, len + 1);
CPP_PUTS_Q (pfile, buf, len);
CPP_NUL_TERMINATE_Q (pfile);
return;
}
/* Write out a #define command for the special named MACRO_NAME
to PFILE's token_buffer. */
static void
dump_special_to_buffer (pfile, macro_name)
cpp_reader *pfile;
char *macro_name;
{
static char define_directive[] = "#define ";
int macro_name_length = strlen (macro_name);
output_line_command (pfile, 0, same_file);
CPP_RESERVE (pfile, sizeof(define_directive) + macro_name_length);
CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1);
CPP_PUTS_Q (pfile, macro_name, macro_name_length);
CPP_PUTC_Q (pfile, ' ');
cpp_expand_to_buffer (pfile, macro_name, macro_name_length);
CPP_PUTC (pfile, '\n');
}
/* Initialize the built-in macros. */
static void
initialize_builtins (pfile)
cpp_reader *pfile;
{
install ("__LINE__", -1, T_SPECLINE, 0, 0, -1);
install ("__DATE__", -1, T_DATE, 0, 0, -1);
install ("__FILE__", -1, T_FILE, 0, 0, -1);
install ("__BASE_FILE__", -1, T_BASE_FILE, 0, 0, -1);
install ("__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, 0, -1);
install ("__VERSION__", -1, T_VERSION, 0, 0, -1);
#ifndef NO_BUILTIN_SIZE_TYPE
install ("__SIZE_TYPE__", -1, T_SIZE_TYPE, 0, 0, -1);
#endif
#ifndef NO_BUILTIN_PTRDIFF_TYPE
install ("__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, 0, 0, -1);
#endif
install ("__WCHAR_TYPE__", -1, T_WCHAR_TYPE, 0, 0, -1);
install ("__USER_LABEL_PREFIX__", -1, T_USER_LABEL_PREFIX_TYPE, 0, 0, -1);
install ("__REGISTER_PREFIX__", -1, T_REGISTER_PREFIX_TYPE, 0, 0, -1);
install ("__TIME__", -1, T_TIME, 0, 0, -1);
if (!CPP_TRADITIONAL (pfile))
install ("__STDC__", -1, T_CONST, STDC_VALUE, 0, -1);
if (CPP_OPTIONS (pfile)->objc)
install ("__OBJC__", -1, T_CONST, 1, 0, -1);
/* This is supplied using a -D by the compiler driver
so that it is present only when truly compiling with GNU C. */
/* install ("__GNUC__", -1, T_CONST, 2, 0, -1); */
if (CPP_OPTIONS (pfile)->debug_output)
{
dump_special_to_buffer (pfile, "__BASE_FILE__");
dump_special_to_buffer (pfile, "__VERSION__");
#ifndef NO_BUILTIN_SIZE_TYPE
dump_special_to_buffer (pfile, "__SIZE_TYPE__");
#endif
#ifndef NO_BUILTIN_PTRDIFF_TYPE
dump_special_to_buffer (pfile, "__PTRDIFF_TYPE__");
#endif
dump_special_to_buffer (pfile, "__WCHAR_TYPE__");
dump_special_to_buffer (pfile, "__DATE__");
dump_special_to_buffer (pfile, "__TIME__");
if (!CPP_TRADITIONAL (pfile))
dump_special_to_buffer (pfile, "__STDC__");
if (CPP_OPTIONS (pfile)->objc)
dump_special_to_buffer (pfile, "__OBJC__");
}
}
/* Return 1 iff a token ending in C1 followed directly by a token C2
could cause mis-tokenization. */
static int
unsafe_chars (c1, c2)
int c1, c2;
{
switch (c1)
{
case '+': case '-':
if (c2 == c1 || c2 == '=')
return 1;
goto letter;
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'e': case 'E': case 'p': case 'P':
if (c2 == '-' || c2 == '+')
return 1; /* could extend a pre-processing number */
goto letter;
case 'L':
if (c2 == '\'' || c2 == '\"')
return 1; /* Could turn into L"xxx" or L'xxx'. */
goto letter;
letter:
case '_':
case 'a': case 'b': case 'c': case 'd': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K':
case 'M': case 'N': case 'O': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
/* We're in the middle of either a name or a pre-processing number. */
return (is_idchar[c2] || c2 == '.');
case '<': case '>': case '!': case '%': case '#': case ':':
case '^': case '&': case '|': case '*': case '/': case '=':
return (c2 == c1 || c2 == '=');
}
return 0;
}
/* Expand a macro call.
HP points to the symbol that is the macro being called.
Put the result of expansion onto the input stack
so that subsequent input by our caller will use it.
If macro wants arguments, caller has already verified that
an argument list follows; arguments come from the input stack. */
static void
macroexpand (pfile, hp)
cpp_reader *pfile;
HASHNODE *hp;
{
int nargs;
DEFINITION *defn = hp->value.defn;
register U_CHAR *xbuf;
long start_line, start_column;
int xbuf_len;
struct argdata *args;
long old_written = CPP_WRITTEN (pfile);
#if 0
int start_line = instack[indepth].lineno;
#endif
int rest_args, rest_zero;
register int i;
#if 0
CHECK_DEPTH (return;);
#endif
#if 0
/* This macro is being used inside a #if, which means it must be */
/* recorded as a precondition. */
if (pcp_inside_if && pcp_outfile && defn->predefined)
dump_single_macro (hp, pcp_outfile);
#endif
pfile->output_escapes++;
cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
nargs = defn->nargs;
if (nargs >= 0)
{
enum cpp_token token;
args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
for (i = 0; i < nargs; i++)
{
args[i].raw = args[i].expanded = 0;
args[i].raw_length = 0;
args[i].expand_length = args[i].stringified_length = -1;
args[i].use_count = 0;
}
/* Parse all the macro args that are supplied. I counts them.
The first NARGS args are stored in ARGS.
The rest are discarded. If rest_args is set then we assume
macarg absorbed the rest of the args. */
i = 0;
rest_args = 0;
rest_args = 0;
FORWARD(1); /* Discard the open-parenthesis before the first arg. */
do
{
if (rest_args)
continue;
if (i < nargs || (nargs == 0 && i == 0))
{
/* if we are working on last arg which absorbs rest of args... */
if (i == nargs - 1 && defn->rest_args)
rest_args = 1;
args[i].raw = CPP_WRITTEN (pfile);
token = macarg (pfile, rest_args);
args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw;
args[i].newlines = 0; /* FIXME */
}
else
token = macarg (pfile, 0);
if (token == CPP_EOF || token == CPP_POP)
{
cpp_error_with_line (pfile, start_line, start_column,
"unterminated macro call");
return;
}
i++;
} while (token == CPP_COMMA);
/* If we got one arg but it was just whitespace, call that 0 args. */
if (i == 1)
{
register U_CHAR *bp = ARG_BASE + args[0].raw;
register U_CHAR *lim = bp + args[0].raw_length;
/* cpp.texi says for foo ( ) we provide one argument.
However, if foo wants just 0 arguments, treat this as 0. */
if (nargs == 0)
while (bp != lim && is_space[*bp]) bp++;
if (bp == lim)
i = 0;
}
/* Don't output an error message if we have already output one for
a parse error above. */
rest_zero = 0;
if (nargs == 0 && i > 0)
{
cpp_error (pfile, "arguments given to macro `%s'", hp->name);
}
else if (i < nargs)
{
/* traditional C allows foo() if foo wants one argument. */
if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile))
;
/* the rest args token is allowed to absorb 0 tokens */
else if (i == nargs - 1 && defn->rest_args)
rest_zero = 1;
else if (i == 0)
cpp_error (pfile, "macro `%s' used without args", hp->name);
else if (i == 1)
cpp_error (pfile, "macro `%s' used with just one arg", hp->name);
else
cpp_error (pfile, "macro `%s' used with only %d args",
hp->name, i);
}
else if (i > nargs)
{
cpp_error (pfile,
"macro `%s' used with too many (%d) args", hp->name, i);
}
}
/* If macro wants zero args, we parsed the arglist for checking only.
Read directly from the macro definition. */
if (nargs <= 0)
{
xbuf = defn->expansion;
xbuf_len = defn->length;
}
else
{
register U_CHAR *exp = defn->expansion;
register int offset; /* offset in expansion,
copied a piece at a time */
register int totlen; /* total amount of exp buffer filled so far */
register struct reflist *ap, *last_ap;
/* Macro really takes args. Compute the expansion of this call. */
/* Compute length in characters of the macro's expansion.
Also count number of times each arg is used. */
xbuf_len = defn->length;
for (ap = defn->pattern; ap != NULL; ap = ap->next)
{
if (ap->stringify)
{
register struct argdata *arg = &args[ap->argno];
/* Stringify it it hasn't already been */
if (arg->stringified_length < 0)
{
int arglen = arg->raw_length;
int escaped = 0;
int in_string = 0;
int c;
/* Initially need_space is -1. Otherwise, 1 means the
previous character was a space, but we suppressed it;
0 means the previous character was a non-space. */
int need_space = -1;
i = 0;
arg->stringified = CPP_WRITTEN (pfile);
if (!CPP_TRADITIONAL (pfile))
CPP_PUTC (pfile, '\"'); /* insert beginning quote */
for (; i < arglen; i++)
{
c = (ARG_BASE + arg->raw)[i];
if (! in_string)
{
/* Internal sequences of whitespace are replaced by
one space except within an string or char token.*/
if (is_space[c])
{
if (CPP_WRITTEN (pfile) > arg->stringified
&& (CPP_PWRITTEN (pfile))[-1] == '@')
{
/* "@ " escape markers are removed */
CPP_ADJUST_WRITTEN (pfile, -1);
continue;
}
if (need_space == 0)
need_space = 1;
continue;
}
else if (need_space > 0)
CPP_PUTC (pfile, ' ');
need_space = 0;
}
if (escaped)
escaped = 0;
else
{
if (c == '\\')
escaped = 1;
if (in_string)
{
if (c == in_string)
in_string = 0;
}
else if (c == '\"' || c == '\'')
in_string = c;
}
/* Escape these chars */
if (c == '\"' || (in_string && c == '\\'))
CPP_PUTC (pfile, '\\');
if (isprint (c))
CPP_PUTC (pfile, c);
else
{
CPP_RESERVE (pfile, 4);
sprintf (CPP_PWRITTEN (pfile), "\\%03o",
(unsigned int) c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
}
if (!CPP_TRADITIONAL (pfile))
CPP_PUTC (pfile, '\"'); /* insert ending quote */
arg->stringified_length
= CPP_WRITTEN (pfile) - arg->stringified;
}
xbuf_len += args[ap->argno].stringified_length;
}
else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
/* Add 4 for two newline-space markers to prevent
token concatenation. */
xbuf_len += args[ap->argno].raw_length + 4;
else
{
/* We have an ordinary (expanded) occurrence of the arg.
So compute its expansion, if we have not already. */
if (args[ap->argno].expand_length < 0)
{
args[ap->argno].expanded = CPP_WRITTEN (pfile);
cpp_expand_to_buffer (pfile,
ARG_BASE + args[ap->argno].raw,
args[ap->argno].raw_length);
args[ap->argno].expand_length
= CPP_WRITTEN (pfile) - args[ap->argno].expanded;
}
/* Add 4 for two newline-space markers to prevent
token concatenation. */
xbuf_len += args[ap->argno].expand_length + 4;
}
if (args[ap->argno].use_count < 10)
args[ap->argno].use_count++;
}
xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
/* Generate in XBUF the complete expansion
with arguments substituted in.
TOTLEN is the total size generated so far.
OFFSET is the index in the definition
of where we are copying from. */
offset = totlen = 0;
for (last_ap = NULL, ap = defn->pattern; ap != NULL;
last_ap = ap, ap = ap->next)
{
register struct argdata *arg = &args[ap->argno];
int count_before = totlen;
/* Add chars to XBUF. */
for (i = 0; i < ap->nchars; i++, offset++)
xbuf[totlen++] = exp[offset];
/* If followed by an empty rest arg with concatenation,
delete the last run of nonwhite chars. */
if (rest_zero && totlen > count_before
&& ((ap->rest_args && ap->raw_before)
|| (last_ap != NULL && last_ap->rest_args
&& last_ap->raw_after)))
{
/* Delete final whitespace. */
while (totlen > count_before && is_space[xbuf[totlen - 1]])
totlen--;
/* Delete the nonwhites before them. */
while (totlen > count_before && ! is_space[xbuf[totlen - 1]])
totlen--;
}
if (ap->stringify != 0)
{
bcopy (ARG_BASE + arg->stringified,
xbuf + totlen, arg->stringified_length);
totlen += arg->stringified_length;
}
else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
{
U_CHAR *p1 = ARG_BASE + arg->raw;
U_CHAR *l1 = p1 + arg->raw_length;
if (ap->raw_before)
{
while (p1 != l1 && is_space[*p1]) p1++;
while (p1 != l1 && is_idchar[*p1])
xbuf[totlen++] = *p1++;
/* Delete any no-reexpansion marker that follows
an identifier at the beginning of the argument
if the argument is concatenated with what precedes it. */
if (p1[0] == '@' && p1[1] == '-')
p1 += 2;
}
if (ap->raw_after)
{
/* Arg is concatenated after: delete trailing whitespace,
whitespace markers, and no-reexpansion markers. */
while (p1 != l1)
{
if (is_space[l1[-1]]) l1--;
else if (l1[-1] == '-')
{
U_CHAR *p2 = l1 - 1;
/* If a `-' is preceded by an odd number of newlines then it
and the last newline are a no-reexpansion marker. */
while (p2 != p1 && p2[-1] == '\n') p2--;
if ((l1 - 1 - p2) & 1) {
l1 -= 2;
}
else break;
}
else break;
}
}
bcopy (p1, xbuf + totlen, l1 - p1);
totlen += l1 - p1;
}
else
{
U_CHAR *expanded = ARG_BASE + arg->expanded;
if (!ap->raw_before && totlen > 0 && arg->expand_length
&& !CPP_TRADITIONAL(pfile)
&& unsafe_chars (xbuf[totlen-1], expanded[0]))
{
xbuf[totlen++] = '@';
xbuf[totlen++] = ' ';
}
bcopy (expanded, xbuf + totlen, arg->expand_length);
totlen += arg->expand_length;
if (!ap->raw_after && totlen > 0 && offset < defn->length
&& !CPP_TRADITIONAL(pfile)
&& unsafe_chars (xbuf[totlen-1], exp[offset]))
{
xbuf[totlen++] = '@';
xbuf[totlen++] = ' ';
}
/* If a macro argument with newlines is used multiple times,
then only expand the newlines once. This avoids creating
output lines which don't correspond to any input line,
which confuses gdb and gcov. */
if (arg->use_count > 1 && arg->newlines > 0)
{
/* Don't bother doing change_newlines for subsequent
uses of arg. */
arg->use_count = 1;
arg->expand_length
= change_newlines (expanded, arg->expand_length);
}
}
if (totlen > xbuf_len)
abort ();
}
/* if there is anything left of the definition
after handling the arg list, copy that in too. */
for (i = offset; i < defn->length; i++)
{
/* if we've reached the end of the macro */
if (exp[i] == ')')
rest_zero = 0;
if (! (rest_zero && last_ap != NULL && last_ap->rest_args
&& last_ap->raw_after))
xbuf[totlen++] = exp[i];
}
xbuf[totlen] = 0;
xbuf_len = totlen;
}
pfile->output_escapes--;
/* Now put the expansion on the input stack
so our caller will commence reading from it. */
push_macro_expansion (pfile, xbuf, xbuf_len, hp);
CPP_BUFFER (pfile)->has_escapes = 1;
/* Pop the space we've used in the token_buffer for argument expansion. */
CPP_SET_WRITTEN (pfile, old_written);
/* Recursive macro use sometimes works traditionally.
#define foo(x,y) bar (x (y,0), y)
foo (foo, baz) */
if (!CPP_TRADITIONAL (pfile))
hp->type = T_DISABLED;
}
static void
push_macro_expansion (pfile, xbuf, xbuf_len, hp)
cpp_reader *pfile;
register U_CHAR *xbuf;
int xbuf_len;
HASHNODE *hp;
{
register cpp_buffer *mbuf = cpp_push_buffer (pfile, xbuf, xbuf_len);
if (mbuf == NULL)
return;
mbuf->cleanup = macro_cleanup;
mbuf->data = hp;
/* The first chars of the expansion should be a "@ " added by
collect_expansion. This is to prevent accidental token-pasting
between the text preceding the macro invocation, and the macro
expansion text.
We would like to avoid adding unneeded spaces (for the sake of
tools that use cpp, such as imake). In some common cases we can
tell that it is safe to omit the space.
The character before the macro invocation cannot have been an
idchar (or else it would have been pasted with the idchars of
the macro name). Therefore, if the first non-space character
of the expansion is an idchar, we do not need the extra space
to prevent token pasting.
Also, we don't need the extra space if the first char is '(',
or some other (less common) characters. */
if