#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
#include "obstack.h"
#ifdef PFE
#include "pfe/pfe.h"
#include "pfe/pfe-header.h"
#undef abort
extern void pfe_find_macro PARAMS ((const char *));
#endif
extern int flag_cpp_precomp;
#include "genindex.h"
struct answer
{
struct answer *next;
unsigned int count;
cpp_token first[1];
};
struct if_stack
{
struct if_stack *next;
unsigned int line;
const cpp_hashnode *mi_cmacro;
bool skip_elses;
bool was_skipping;
int type;
};
typedef void (*pragma_cb) PARAMS ((cpp_reader *));
struct pragma_entry
{
struct pragma_entry *next;
const cpp_hashnode *pragma;
int is_nspace;
union {
pragma_cb handler;
struct pragma_entry *space;
} u;
};
#define KANDR 0
#define STDC89 1
#define EXTENSION 2
#define COND (1 << 0)
#define IF_COND (1 << 1)
#define INCL (1 << 2)
#define IN_I (1 << 3)
typedef void (*directive_handler) PARAMS ((cpp_reader *));
typedef struct directive directive;
struct directive
{
directive_handler handler;
const U_CHAR *name;
unsigned short length;
unsigned char origin;
unsigned char flags;
};
static void skip_rest_of_line PARAMS ((cpp_reader *));
static void check_eol PARAMS ((cpp_reader *));
static void start_directive PARAMS ((cpp_reader *));
static void end_directive PARAMS ((cpp_reader *, int));
static void directive_diagnostics
PARAMS ((cpp_reader *, const directive *, int));
static void run_directive PARAMS ((cpp_reader *, int,
const char *, size_t));
static const cpp_token *glue_header_name PARAMS ((cpp_reader *));
static const cpp_token *parse_include PARAMS ((cpp_reader *));
static void push_conditional PARAMS ((cpp_reader *, int, int,
const cpp_hashnode *));
static unsigned int read_flag PARAMS ((cpp_reader *, unsigned int));
static U_CHAR *dequote_string PARAMS ((cpp_reader *, const U_CHAR *,
unsigned int));
static int strtoul_for_line PARAMS ((const U_CHAR *, unsigned int,
unsigned long *));
static void do_diagnostic PARAMS ((cpp_reader *, enum error_type, int));
static cpp_hashnode *lex_macro_node PARAMS ((cpp_reader *));
static void do_include_common PARAMS ((cpp_reader *, enum include_type));
static struct pragma_entry *lookup_pragma_entry
PARAMS ((struct pragma_entry *, const cpp_hashnode *pragma));
static struct pragma_entry *insert_pragma_entry
PARAMS ((cpp_reader *, struct pragma_entry **, const cpp_hashnode *,
pragma_cb));
static void do_pragma_once PARAMS ((cpp_reader *));
static void do_pragma_poison PARAMS ((cpp_reader *));
static void do_pragma_system_header PARAMS ((cpp_reader *));
static void do_pragma_dependency PARAMS ((cpp_reader *));
static void do_linemarker PARAMS ((cpp_reader *));
static const cpp_token *get_token_no_padding PARAMS ((cpp_reader *));
static const cpp_token *get__Pragma_string PARAMS ((cpp_reader *));
static void destringize_and_run PARAMS ((cpp_reader *, const cpp_string *));
static int parse_answer PARAMS ((cpp_reader *, struct answer **, int));
static cpp_hashnode *parse_assertion PARAMS ((cpp_reader *, struct answer **,
int));
static struct answer ** find_answer PARAMS ((cpp_hashnode *,
const struct answer *));
static void handle_assertion PARAMS ((cpp_reader *, const char *, int));
#define DIRECTIVE_TABLE \
D(define, T_DEFINE = 0, KANDR, IN_I) \
D(include, T_INCLUDE, KANDR, INCL) \
D(endif, T_ENDIF, KANDR, COND) \
D(ifdef, T_IFDEF, KANDR, COND | IF_COND) \
D(if, T_IF, KANDR, COND | IF_COND) \
D(else, T_ELSE, KANDR, COND) \
D(ifndef, T_IFNDEF, KANDR, COND | IF_COND) \
D(undef, T_UNDEF, KANDR, IN_I) \
D(line, T_LINE, KANDR, 0) \
D(elif, T_ELIF, STDC89, COND) \
D(error, T_ERROR, STDC89, 0) \
D(pragma, T_PRAGMA, STDC89, IN_I) \
D(warning, T_WARNING, EXTENSION, 0) \
D(include_next, T_INCLUDE_NEXT, EXTENSION, INCL) \
D(ident, T_IDENT, EXTENSION, IN_I) \
D(import, T_IMPORT, EXTENSION, INCL) \
D(assert, T_ASSERT, EXTENSION, 0) \
D(unassert, T_UNASSERT, EXTENSION, 0) \
SCCS_ENTRY
#ifdef SCCS_DIRECTIVE
# define SCCS_ENTRY D(sccs, T_SCCS, EXTENSION, 0)
#else
# define SCCS_ENTRY
#endif
#define D(name, t, o, f) static void CONCAT2(do_,name) PARAMS ((cpp_reader *));
DIRECTIVE_TABLE
#undef D
#define D(n, tag, o, f) tag,
enum
{
DIRECTIVE_TABLE
N_DIRECTIVES
};
#undef D
#define D(name, t, origin, flags) \
{ CONCAT2(do_,name), (const U_CHAR *) STRINGX(name), \
sizeof STRINGX(name) - 1, origin, flags },
static const directive dtable[] =
{
DIRECTIVE_TABLE
};
#undef D
#undef DIRECTIVE_TABLE
static const directive linemarker_dir =
{
do_linemarker, U"#", 1, KANDR, IN_I
};
#define SEEN_EOL() (pfile->cur_token[-1].type == CPP_EOF)
static void
skip_rest_of_line (pfile)
cpp_reader *pfile;
{
while (pfile->context != &pfile->base_context)
_cpp_pop_context (pfile);
if (! SEEN_EOL ())
while (_cpp_lex_token (pfile)->type != CPP_EOF)
;
}
static void
check_eol (pfile)
cpp_reader *pfile;
{
if (! SEEN_EOL () && _cpp_lex_token (pfile)->type != CPP_EOF
&& CPP_OPTION (pfile, warn_extra_tokens))
cpp_pedwarn (pfile, "extra tokens at end of #%s directive",
pfile->directive->name);
}
static void
start_directive (pfile)
cpp_reader *pfile;
{
pfile->state.in_directive = 1;
pfile->state.save_comments = 0;
pfile->directive_line = pfile->line;
}
static void
end_directive (pfile, skip_line)
cpp_reader *pfile;
int skip_line;
{
if (skip_line)
{
skip_rest_of_line (pfile);
if (!pfile->keep_tokens)
{
pfile->cur_run = &pfile->base_run;
pfile->cur_token = pfile->base_run.base;
}
}
pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
pfile->state.in_directive = 0;
pfile->state.angled_headers = 0;
pfile->directive = 0;
}
static void
directive_diagnostics (pfile, dir, indented)
cpp_reader *pfile;
const directive *dir;
int indented;
{
if (CPP_PEDANTIC (pfile)
&& ! pfile->state.skipping
&& dir->origin == EXTENSION)
if (!flag_cpp_precomp)
cpp_pedwarn (pfile, "#%s is a GCC extension", dir->name);
if (CPP_WTRADITIONAL (pfile))
{
if (dir == &dtable[T_ELIF])
cpp_warning (pfile, "suggest not using #elif in traditional C");
else if (indented && dir->origin == KANDR)
cpp_warning (pfile,
"traditional C ignores #%s with the # indented",
dir->name);
else if (!indented && dir->origin != KANDR)
cpp_warning (pfile,
"suggest hiding #%s from traditional C with an indented #",
dir->name);
}
}
int
_cpp_handle_directive (pfile, indented)
cpp_reader *pfile;
int indented;
{
const directive *dir = 0;
const cpp_token *dname;
int skip = 1;
start_directive (pfile);
dname = _cpp_lex_token (pfile);
if (dname->type == CPP_NAME)
{
if (dname->val.node->directive_index)
dir = &dtable[dname->val.node->directive_index - 1];
}
else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM)
{
dir = &linemarker_dir;
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed)
&& ! pfile->state.skipping)
cpp_pedwarn (pfile, "style of line directive is a GCC extension");
}
if (dir)
{
if (! (dir->flags & IF_COND))
pfile->mi_valid = false;
if (CPP_OPTION (pfile, preprocessed)
&& (indented || !(dir->flags & IN_I)))
{
skip = 0;
dir = 0;
}
else
{
pfile->state.angled_headers = dir->flags & INCL;
if (! CPP_OPTION (pfile, preprocessed))
directive_diagnostics (pfile, dir, indented);
if (pfile->state.skipping && !(dir->flags & COND))
dir = 0;
}
}
else if (dname->type == CPP_EOF)
;
else
{
if (CPP_OPTION (pfile, lang) == CLK_ASM)
skip = 0;
else if (!pfile->state.skipping)
cpp_error (pfile, "invalid preprocessing directive #%s",
cpp_token_as_text (pfile, dname));
}
if (dir)
{
pfile->directive = dir;
(*pfile->directive->handler) (pfile);
}
else if (skip == 0)
_cpp_backup_tokens (pfile, 1);
end_directive (pfile, skip);
return skip;
}
static void
run_directive (pfile, dir_no, buf, count)
cpp_reader *pfile;
int dir_no;
const char *buf;
size_t count;
{
cpp_push_buffer (pfile, (const U_CHAR *) buf, count,
true, 1);
start_directive (pfile);
pfile->buffer->saved_flags = 0;
pfile->directive = &dtable[dir_no];
(void) (*pfile->directive->handler) (pfile);
end_directive (pfile, 1);
_cpp_pop_buffer (pfile);
}
static cpp_hashnode *
lex_macro_node (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node;
const cpp_token *token = _cpp_lex_token (pfile);
if (token->type != CPP_NAME)
{
if (token->type == CPP_EOF)
cpp_error (pfile, "no macro name given in #%s directive",
pfile->directive->name);
else if (token->flags & NAMED_OP)
cpp_error (pfile,
"\"%s\" cannot be used as a macro name as it is an operator in C++",
NODE_NAME (token->val.node));
else
cpp_error (pfile, "macro names must be identifiers");
return 0;
}
node = token->val.node;
if (node->flags & NODE_POISONED)
return 0;
if (node == pfile->spec_nodes.n_defined)
{
cpp_error (pfile, "\"%s\" cannot be used as a macro name",
NODE_NAME (node));
return 0;
}
return node;
}
static void
do_define (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node = lex_macro_node (pfile);
if (node)
{
if (_cpp_create_definition (pfile, node))
if (pfile->cb.define)
(*pfile->cb.define) (pfile, pfile->directive_line, node);
}
}
static void
do_undef (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node = lex_macro_node (pfile);
if (node && node->type == NT_MACRO)
{
if (pfile->cb.undef)
(*pfile->cb.undef) (pfile, pfile->directive_line, node);
if (node->flags & NODE_WARN)
cpp_warning (pfile, "undefining \"%s\"", NODE_NAME (node));
_cpp_free_definition (node);
}
check_eol (pfile);
}
static const cpp_token *
glue_header_name (pfile)
cpp_reader *pfile;
{
cpp_token *header = NULL;
const cpp_token *token;
unsigned char *buffer;
size_t len, total_len = 0, capacity = 1024;
buffer = (unsigned char *) xmalloc (capacity);
for (;;)
{
token = cpp_get_token (pfile);
if (token->type == CPP_GREATER || token->type == CPP_EOF)
break;
len = cpp_token_len (token);
if (total_len + len > capacity)
{
capacity = (capacity + len) * 2;
buffer = (unsigned char *) xrealloc (buffer, capacity);
}
if (token->flags & PREV_WHITE)
buffer[total_len++] = ' ';
total_len = cpp_spell_token (pfile, token, &buffer[total_len]) - buffer;
}
if (token->type == CPP_EOF)
cpp_error (pfile, "missing terminating > character");
else
{
unsigned char *token_mem = _cpp_unaligned_alloc (pfile, total_len + 1);
memcpy (token_mem, buffer, total_len);
token_mem[total_len] = '\0';
header = _cpp_temp_token (pfile);
header->type = CPP_HEADER_NAME;
header->flags = 0;
header->val.str.len = total_len;
header->val.str.text = token_mem;
}
free ((PTR) buffer);
return header;
}
static const cpp_token *
parse_include (pfile)
cpp_reader *pfile;
{
const unsigned char *dir;
const cpp_token *header;
if (pfile->directive == &dtable[T_PRAGMA])
dir = U"pragma dependency";
else
dir = pfile->directive->name;
header = cpp_get_token (pfile);
if (header->type != CPP_STRING && header->type != CPP_HEADER_NAME)
{
if (header->type != CPP_LESS)
{
cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir);
return NULL;
}
header = glue_header_name (pfile);
if (header == NULL)
return header;
}
if (header->val.str.len == 0)
{
cpp_error (pfile, "empty file name in #%s", dir);
return NULL;
}
return header;
}
static void
do_include_common (pfile, type)
cpp_reader *pfile;
enum include_type type;
{
const cpp_token *header;
if (type == IT_INCLUDE_NEXT && ! pfile->buffer->prev)
{
cpp_warning (pfile, "#include_next in primary source file");
type = IT_INCLUDE;
}
else if (type == IT_IMPORT && CPP_OPTION (pfile, warn_import))
{
CPP_OPTION (pfile, warn_import) = 0;
cpp_warning (pfile,
"#import is obsolete, use an #ifndef wrapper in the header file");
}
header = parse_include (pfile);
if (header)
{
if (pfile->line_maps.depth >= CPP_STACK_MAX)
cpp_fatal (pfile, "#include nested too deeply");
else
{
check_eol (pfile);
skip_rest_of_line (pfile);
if (pfile->cb.include)
(*pfile->cb.include) (pfile, pfile->directive_line,
pfile->directive->name, header);
_cpp_execute_include (pfile, header, type);
}
}
}
static void
do_include (pfile)
cpp_reader *pfile;
{
do_include_common (pfile, IT_INCLUDE);
}
static void
do_import (pfile)
cpp_reader *pfile;
{
do_include_common (pfile, IT_IMPORT);
}
static void
do_include_next (pfile)
cpp_reader *pfile;
{
do_include_common (pfile, IT_INCLUDE_NEXT);
}
static unsigned int
read_flag (pfile, last)
cpp_reader *pfile;
unsigned int last;
{
const cpp_token *token = _cpp_lex_token (pfile);
if (token->type == CPP_NUMBER && token->val.str.len == 1)
{
unsigned int flag = token->val.str.text[0] - '0';
if (flag > last && flag <= 4
&& (flag != 4 || last == 3)
&& (flag != 2 || last == 0))
return flag;
}
if (token->type != CPP_EOF)
cpp_error (pfile, "invalid flag \"%s\" in line directive",
cpp_token_as_text (pfile, token));
return 0;
}
static U_CHAR *
dequote_string (pfile, str, len)
cpp_reader *pfile;
const U_CHAR *str;
unsigned int len;
{
U_CHAR *result = _cpp_unaligned_alloc (pfile, len + 1);
U_CHAR *dst = result;
const U_CHAR *limit = str + len;
unsigned int c;
unsigned HOST_WIDE_INT mask;
if (CHAR_BIT < HOST_BITS_PER_WIDE_INT)
mask = ((unsigned HOST_WIDE_INT) 1 << CHAR_BIT) - 1;
else
mask = ~(unsigned HOST_WIDE_INT)0;
while (str < limit)
{
c = *str++;
if (c != '\\')
*dst++ = c;
else
*dst++ = cpp_parse_escape (pfile, (const U_CHAR **)&str, limit, mask, 0);
}
*dst++ = '\0';
return result;
}
static int
strtoul_for_line (str, len, nump)
const U_CHAR *str;
unsigned int len;
unsigned long *nump;
{
unsigned long reg = 0;
U_CHAR c;
while (len--)
{
c = *str++;
if (!ISDIGIT (c))
return 1;
reg *= 10;
reg += c - '0';
}
*nump = reg;
return 0;
}
static void
do_line (pfile)
cpp_reader *pfile;
{
const cpp_token *token;
const char *new_file = pfile->map->to_file;
unsigned long new_lineno;
unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
token = cpp_get_token (pfile);
if (token->type != CPP_NUMBER
|| strtoul_for_line (token->val.str.text, token->val.str.len,
&new_lineno))
{
cpp_error (pfile, "\"%s\" after #line is not a positive integer",
cpp_token_as_text (pfile, token));
return;
}
if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap))
cpp_pedwarn (pfile, "line number out of range");
token = cpp_get_token (pfile);
if (token->type == CPP_STRING)
{
new_file = (const char *) dequote_string (pfile, token->val.str.text,
token->val.str.len);
check_eol (pfile);
}
else if (token->type != CPP_EOF)
{
cpp_error (pfile, "\"%s\" is not a valid filename",
cpp_token_as_text (pfile, token));
return;
}
skip_rest_of_line (pfile);
_cpp_do_file_change (pfile, LC_RENAME, new_file, new_lineno,
pfile->map->sysp);
}
static void
do_linemarker (pfile)
cpp_reader *pfile;
{
const cpp_token *token;
const char *new_file = pfile->map->to_file;
unsigned long new_lineno;
unsigned int new_sysp = pfile->map->sysp;
enum lc_reason reason = LC_RENAME;
int flag;
_cpp_backup_tokens (pfile, 1);
token = cpp_get_token (pfile);
if (token->type != CPP_NUMBER
|| strtoul_for_line (token->val.str.text, token->val.str.len,
&new_lineno))
{
cpp_error (pfile, "\"%s\" after # is not a positive integer",
cpp_token_as_text (pfile, token));
return;
}
token = cpp_get_token (pfile);
if (token->type == CPP_STRING)
{
new_file = (const char *) dequote_string (pfile, token->val.str.text,
token->val.str.len);
new_sysp = 0;
flag = read_flag (pfile, 0);
if (flag == 1)
{
reason = LC_ENTER;
_cpp_fake_include (pfile, new_file);
flag = read_flag (pfile, flag);
}
else if (flag == 2)
{
reason = LC_LEAVE;
flag = read_flag (pfile, flag);
}
if (flag == 3)
{
new_sysp = 1;
flag = read_flag (pfile, flag);
if (flag == 4)
new_sysp = 2;
}
if (flag == 0 && flag_gen_index_original && flag_gen_index_header)
{
if (new_file[0] != '/')
{
char *apath;
int alen = MAXPATHLEN + strlen (new_file) + 2;
apath = (char *) xmalloc (sizeof (char) * alen);
apath = getcwd (apath, alen);
strcat (apath, "/");
strcat (apath, new_file);
gen_indexing_header ((char *) apath);
push_cur_index_filename (apath);
free (apath);
}
else
{
gen_indexing_header ((char *) new_file);
push_cur_index_filename (new_file);
}
flag_gen_index_header = 0;
process_header_indexing ((char *) new_file, PB_INDEX_BEGIN);
}
check_eol (pfile);
}
else if (token->type != CPP_EOF)
{
cpp_error (pfile, "\"%s\" is not a valid filename",
cpp_token_as_text (pfile, token));
return;
}
if (flag_gen_index_original && (reason == LC_ENTER || reason == LC_LEAVE))
{
int index_begin_or_end = 0;
if (reason == LC_ENTER)
index_begin_or_end = PB_INDEX_BEGIN;
else if (reason == LC_LEAVE)
index_begin_or_end = PB_INDEX_END;
process_header_indexing ((char *)new_file, index_begin_or_end);
}
skip_rest_of_line (pfile);
_cpp_do_file_change (pfile, reason, new_file, new_lineno, new_sysp);
}
void
_cpp_do_file_change (pfile, reason, to_file, file_line, sysp)
cpp_reader *pfile;
enum lc_reason reason;
const char *to_file;
unsigned int file_line;
unsigned int sysp;
{
pfile->map = add_line_map (&pfile->line_maps, reason, sysp,
pfile->line, to_file, file_line);
if (pfile->cb.file_change)
(*pfile->cb.file_change) (pfile, pfile->map);
}
static void
do_diagnostic (pfile, code, print_dir)
cpp_reader *pfile;
enum error_type code;
int print_dir;
{
if (_cpp_begin_message (pfile, code, 0, 0))
{
if (print_dir)
fprintf (stderr, "#%s ", pfile->directive->name);
pfile->state.prevent_expansion++;
cpp_output_line (pfile, stderr);
pfile->state.prevent_expansion--;
}
}
static void
do_error (pfile)
cpp_reader *pfile;
{
do_diagnostic (pfile, ERROR, 1);
}
static void
do_warning (pfile)
cpp_reader *pfile;
{
if (!CPP_OPTION (pfile, no_pound_warnings))
if (!CPP_IN_SYSTEM_HEADER (pfile) || CPP_OPTION (pfile, warn_system_headers))
do_diagnostic (pfile, WARNING_SYSHDR, 1);
}
static void
do_ident (pfile)
cpp_reader *pfile;
{
const cpp_token *str = cpp_get_token (pfile);
if (str->type != CPP_STRING)
cpp_error (pfile, "invalid #ident directive");
else if (pfile->cb.ident)
(*pfile->cb.ident) (pfile, pfile->directive_line, &str->val.str);
check_eol (pfile);
}
static struct pragma_entry *
lookup_pragma_entry (chain, pragma)
struct pragma_entry *chain;
const cpp_hashnode *pragma;
{
while (chain && chain->pragma != pragma)
chain = chain->next;
return chain;
}
static struct pragma_entry *
insert_pragma_entry (pfile, chain, pragma, handler)
cpp_reader *pfile;
struct pragma_entry **chain;
const cpp_hashnode *pragma;
pragma_cb handler;
{
struct pragma_entry *new;
new = (struct pragma_entry *)
_cpp_aligned_alloc (pfile, sizeof (struct pragma_entry));
new->pragma = pragma;
if (handler)
{
new->is_nspace = 0;
new->u.handler = handler;
}
else
{
new->is_nspace = 1;
new->u.space = NULL;
}
new->next = *chain;
*chain = new;
return new;
}
void
cpp_register_pragma (pfile, space, name, handler)
cpp_reader *pfile;
const char *space;
const char *name;
pragma_cb handler;
{
struct pragma_entry **chain = &pfile->pragmas;
struct pragma_entry *entry;
const cpp_hashnode *node;
if (!handler)
abort ();
if (space)
{
node = cpp_lookup (pfile, U space, strlen (space));
entry = lookup_pragma_entry (*chain, node);
if (!entry)
entry = insert_pragma_entry (pfile, chain, node, NULL);
else if (!entry->is_nspace)
goto clash;
chain = &entry->u.space;
}
node = cpp_lookup (pfile, U name, strlen (name));
entry = lookup_pragma_entry (*chain, node);
if (entry)
{
if (entry->is_nspace)
clash:
cpp_ice (pfile,
"registering \"%s\" as both a pragma and a pragma namespace",
NODE_NAME (node));
else if (space)
cpp_ice (pfile, "#pragma %s %s is already registered", space, name);
else
cpp_ice (pfile, "#pragma %s is already registered", name);
}
else
insert_pragma_entry (pfile, chain, node, handler);
}
void
_cpp_init_internal_pragmas (pfile)
cpp_reader *pfile;
{
cpp_register_pragma (pfile, 0, "poison", do_pragma_poison);
cpp_register_pragma (pfile, 0, "once", do_pragma_once);
cpp_register_pragma (pfile, "GCC", "poison", do_pragma_poison);
cpp_register_pragma (pfile, "GCC", "system_header", do_pragma_system_header);
cpp_register_pragma (pfile, "GCC", "dependency", do_pragma_dependency);
}
static void
do_pragma (pfile)
cpp_reader *pfile;
{
const struct pragma_entry *p = NULL;
const cpp_token *token;
unsigned int count = 1;
pfile->state.prevent_expansion++;
token = cpp_get_token (pfile);
if (token->type == CPP_NAME)
{
p = lookup_pragma_entry (pfile->pragmas, token->val.node);
if (p && p->is_nspace)
{
count = 2;
token = cpp_get_token (pfile);
if (token->type == CPP_NAME)
p = lookup_pragma_entry (p->u.space, token->val.node);
else
p = NULL;
}
}
if (pfile->cb.line_change)
(*pfile->cb.line_change)(pfile, token, 1);
if (p)
(*p->u.handler) (pfile);
else if (pfile->cb.def_pragma)
{
_cpp_backup_tokens (pfile, count);
(*pfile->cb.def_pragma) (pfile, pfile->directive_line);
}
pfile->state.prevent_expansion--;
}
static void
do_pragma_once (pfile)
cpp_reader *pfile;
{
if (CPP_OPTION (pfile, warn_pragma_once))
cpp_warning (pfile, "#pragma once is obsolete");
if (pfile->buffer->prev == NULL && !flag_cpp_precomp)
cpp_warning (pfile, "#pragma once in main file");
else
_cpp_never_reread (pfile->buffer->inc);
check_eol (pfile);
}
static void
do_pragma_poison (pfile)
cpp_reader *pfile;
{
const cpp_token *tok;
cpp_hashnode *hp;
pfile->state.poisoned_ok = 1;
for (;;)
{
tok = _cpp_lex_token (pfile);
if (tok->type == CPP_EOF)
break;
if (tok->type != CPP_NAME)
{
cpp_error (pfile, "invalid #pragma GCC poison directive");
break;
}
hp = tok->val.node;
if (hp->flags & NODE_POISONED)
continue;
if (hp->type == NT_MACRO)
cpp_warning (pfile, "poisoning existing macro \"%s\"", NODE_NAME (hp));
_cpp_free_definition (hp);
hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
}
pfile->state.poisoned_ok = 0;
}
static void
do_pragma_system_header (pfile)
cpp_reader *pfile;
{
cpp_buffer *buffer = pfile->buffer;
if (buffer->prev == 0 && !flag_cpp_precomp)
cpp_warning (pfile, "#pragma system_header ignored outside include file");
else
{
check_eol (pfile);
skip_rest_of_line (pfile);
cpp_make_system_header (pfile, 1, 0);
}
}
static void
do_pragma_dependency (pfile)
cpp_reader *pfile;
{
const cpp_token *header;
int ordering;
header = parse_include (pfile);
if (!header)
return;
ordering = _cpp_compare_file_date (pfile, header);
if (ordering < 0)
cpp_warning (pfile, "cannot find source %s",
cpp_token_as_text (pfile, header));
else if (ordering > 0)
{
cpp_warning (pfile, "current file is older than %s",
cpp_token_as_text (pfile, header));
if (cpp_get_token (pfile)->type != CPP_EOF)
{
_cpp_backup_tokens (pfile, 1);
do_diagnostic (pfile, WARNING, 0);
}
}
}
static const cpp_token *
get_token_no_padding (pfile)
cpp_reader *pfile;
{
for (;;)
{
const cpp_token *result = cpp_get_token (pfile);
if (result->type != CPP_PADDING)
return result;
}
}
static const cpp_token *
get__Pragma_string (pfile)
cpp_reader *pfile;
{
const cpp_token *string;
if (get_token_no_padding (pfile)->type != CPP_OPEN_PAREN)
return NULL;
string = get_token_no_padding (pfile);
if (string->type != CPP_STRING && string->type != CPP_WSTRING)
return NULL;
if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN)
return NULL;
return string;
}
static void
destringize_and_run (pfile, in)
cpp_reader *pfile;
const cpp_string *in;
{
const unsigned char *src, *limit;
char *dest, *result;
dest = result = alloca (in->len + 1);
for (src = in->text, limit = src + in->len; src < limit;)
{
if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
src++;
*dest++ = *src++;
}
*dest = '\0';
run_directive (pfile, T_PRAGMA, result, dest - result);
}
void
_cpp_do__Pragma (pfile)
cpp_reader *pfile;
{
const cpp_token *string = get__Pragma_string (pfile);
if (!string)
cpp_error (pfile, "_Pragma takes a parenthesized string literal");
else
{
unsigned int orig_line = pfile->line;
destringize_and_run (pfile, &string->val.str);
pfile->line = orig_line;
pfile->buffer->saved_flags = BOL;
}
}
#ifdef SCCS_DIRECTIVE
static void
do_sccs (pfile)
cpp_reader *pfile ATTRIBUTE_UNUSED;
{
}
#endif
static void
do_ifdef (pfile)
cpp_reader *pfile;
{
int skip = 1;
if (! pfile->state.skipping)
{
const cpp_hashnode *node = lex_macro_node (pfile);
if (node)
skip = node->type != NT_MACRO;
if (node)
check_eol (pfile);
}
push_conditional (pfile, skip, T_IFDEF, 0);
}
static void
do_ifndef (pfile)
cpp_reader *pfile;
{
int skip = 1;
const cpp_hashnode *node = 0;
if (! pfile->state.skipping)
{
node = lex_macro_node (pfile);
if (node)
skip = node->type == NT_MACRO;
if (node)
check_eol (pfile);
}
push_conditional (pfile, skip, T_IFNDEF, node);
}
static void
do_if (pfile)
cpp_reader *pfile;
{
int skip = 1;
if (! pfile->state.skipping)
skip = _cpp_parse_expr (pfile) == 0;
push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro);
}
static void
do_else (pfile)
cpp_reader *pfile;
{
cpp_buffer *buffer = pfile->buffer;
struct if_stack *ifs = buffer->if_stack;
if (ifs == NULL)
cpp_error (pfile, "#else without #if");
else
{
if (ifs->type == T_ELSE)
{
cpp_error (pfile, "#else after #else");
cpp_error_with_line (pfile, ifs->line, 0,
"the conditional began here");
}
ifs->type = T_ELSE;
pfile->state.skipping = ifs->skip_elses;
ifs->skip_elses = true;
ifs->mi_cmacro = 0;
if (!ifs->was_skipping)
check_eol (pfile);
}
}
static void
do_elif (pfile)
cpp_reader *pfile;
{
cpp_buffer *buffer = pfile->buffer;
struct if_stack *ifs = buffer->if_stack;
if (ifs == NULL)
cpp_error (pfile, "#elif without #if");
else
{
if (ifs->type == T_ELSE)
{
cpp_error (pfile, "#elif after #else");
cpp_error_with_line (pfile, ifs->line, 0,
"the conditional began here");
}
ifs->type = T_ELIF;
if (ifs->skip_elses)
pfile->state.skipping = 1;
else
{
pfile->state.skipping = 0;
pfile->state.skipping = ! _cpp_parse_expr (pfile);
ifs->skip_elses = ! pfile->state.skipping;
}
ifs->mi_cmacro = 0;
}
}
static void
do_endif (pfile)
cpp_reader *pfile;
{
cpp_buffer *buffer = pfile->buffer;
struct if_stack *ifs = buffer->if_stack;
if (ifs == NULL)
cpp_error (pfile, "#endif without #if");
else
{
if (!ifs->was_skipping)
check_eol (pfile);
if (ifs->next == 0 && ifs->mi_cmacro)
{
pfile->mi_valid = true;
pfile->mi_cmacro = ifs->mi_cmacro;
}
buffer->if_stack = ifs->next;
pfile->state.skipping = ifs->was_skipping;
obstack_free (&pfile->buffer_ob, ifs);
}
}
static void
push_conditional (pfile, skip, type, cmacro)
cpp_reader *pfile;
int skip;
int type;
const cpp_hashnode *cmacro;
{
struct if_stack *ifs;
cpp_buffer *buffer = pfile->buffer;
ifs = xobnew (&pfile->buffer_ob, struct if_stack);
ifs->line = pfile->directive_line;
ifs->next = buffer->if_stack;
ifs->skip_elses = pfile->state.skipping || !skip;
ifs->was_skipping = pfile->state.skipping;
ifs->type = type;
if (pfile->mi_valid && pfile->mi_cmacro == 0)
ifs->mi_cmacro = cmacro;
else
ifs->mi_cmacro = 0;
pfile->state.skipping = skip;
buffer->if_stack = ifs;
}
static int
parse_answer (pfile, answerp, type)
cpp_reader *pfile;
struct answer **answerp;
int type;
{
const cpp_token *paren;
struct answer *answer;
unsigned int acount;
paren = cpp_get_token (pfile);
if (paren->type != CPP_OPEN_PAREN)
{
if (type == T_IF)
{
_cpp_backup_tokens (pfile, 1);
return 0;
}
if (type == T_UNASSERT && paren->type == CPP_EOF)
return 0;
cpp_error (pfile, "missing '(' after predicate");
return 1;
}
for (acount = 0;; acount++)
{
size_t room_needed;
const cpp_token *token = cpp_get_token (pfile);
cpp_token *dest;
if (token->type == CPP_CLOSE_PAREN)
break;
if (token->type == CPP_EOF)
{
cpp_error (pfile, "missing ')' to complete answer");
return 1;
}
room_needed = (sizeof (struct answer) + acount * sizeof (cpp_token));
if (BUFF_ROOM (pfile->a_buff) < room_needed)
_cpp_extend_buff (pfile, &pfile->a_buff, sizeof (struct answer));
dest = &((struct answer *) BUFF_FRONT (pfile->a_buff))->first[acount];
*dest = *token;
if (acount == 0)
dest->flags &= ~PREV_WHITE;
}
if (acount == 0)
{
cpp_error (pfile, "predicate's answer is empty");
return 1;
}
answer = (struct answer *) BUFF_FRONT (pfile->a_buff);
answer->count = acount;
answer->next = NULL;
*answerp = answer;
return 0;
}
static cpp_hashnode *
parse_assertion (pfile, answerp, type)
cpp_reader *pfile;
struct answer **answerp;
int type;
{
cpp_hashnode *result = 0;
const cpp_token *predicate;
pfile->state.prevent_expansion++;
*answerp = 0;
predicate = cpp_get_token (pfile);
if (predicate->type == CPP_EOF)
cpp_error (pfile, "assertion without predicate");
else if (predicate->type != CPP_NAME)
cpp_error (pfile, "predicate must be an identifier");
else if (parse_answer (pfile, answerp, type) == 0)
{
unsigned int len = NODE_LEN (predicate->val.node);
unsigned char *sym = alloca (len + 1);
sym[0] = '#';
memcpy (sym + 1, NODE_NAME (predicate->val.node), len);
result = cpp_lookup (pfile, sym, len + 1);
}
pfile->state.prevent_expansion--;
return result;
}
static struct answer **
find_answer (node, candidate)
cpp_hashnode *node;
const struct answer *candidate;
{
unsigned int i;
struct answer **result;
for (result = &node->value.answers; *result; result = &(*result)->next)
{
struct answer *answer = *result;
if (answer->count == candidate->count)
{
for (i = 0; i < answer->count; i++)
if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i]))
break;
if (i == answer->count)
break;
}
}
return result;
}
int
_cpp_test_assertion (pfile, value)
cpp_reader *pfile;
int *value;
{
struct answer *answer;
cpp_hashnode *node;
node = parse_assertion (pfile, &answer, T_IF);
if (node)
*value = (node->type == NT_ASSERTION &&
(answer == 0 || *find_answer (node, answer) != 0));
return node == 0;
}
static void
do_assert (pfile)
cpp_reader *pfile;
{
struct answer *new_answer;
cpp_hashnode *node;
node = parse_assertion (pfile, &new_answer, T_ASSERT);
if (node)
{
new_answer->next = 0;
if (node->type == NT_ASSERTION)
{
if (*find_answer (node, new_answer))
{
cpp_warning (pfile, "\"%s\" re-asserted", NODE_NAME (node) + 1);
return;
}
new_answer->next = node->value.answers;
}
node->type = NT_ASSERTION;
node->value.answers = new_answer;
BUFF_FRONT (pfile->a_buff) += (sizeof (struct answer)
+ (new_answer->count - 1)
* sizeof (cpp_token));
check_eol (pfile);
}
}
static void
do_unassert (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node;
struct answer *answer;
node = parse_assertion (pfile, &answer, T_UNASSERT);
if (node && node->type == NT_ASSERTION)
{
if (answer)
{
struct answer **p = find_answer (node, answer), *temp;
temp = *p;
if (temp)
*p = temp->next;
if (node->value.answers == 0)
node->type = NT_VOID;
check_eol (pfile);
}
else
_cpp_free_definition (node);
}
}
void
cpp_define (pfile, str)
cpp_reader *pfile;
const char *str;
{
char *buf, *p;
size_t count;
count = strlen (str);
buf = (char *) alloca (count + 3);
memcpy (buf, str, count);
p = strchr (str, '=');
if (p)
buf[p - str] = ' ';
else
{
buf[count++] = ' ';
buf[count++] = '1';
}
buf[count] = '\0';
#ifdef PFE
if (pfe_operation == PFE_LOAD
&& pfe_is_cmd_ln_processing()
&& pfe_macro_validation)
{
pfe_macro_status = 0;
pfe_find_macro (buf);
}
#endif
run_directive (pfile, T_DEFINE, buf, count);
}
void
_cpp_define_builtin (pfile, str)
cpp_reader *pfile;
const char *str;
{
run_directive (pfile, T_DEFINE, str, strlen (str));
}
void
cpp_undef (pfile, macro)
cpp_reader *pfile;
const char *macro;
{
run_directive (pfile, T_UNDEF, macro, strlen (macro));
}
void
cpp_assert (pfile, str)
cpp_reader *pfile;
const char *str;
{
handle_assertion (pfile, str, T_ASSERT);
}
void
cpp_unassert (pfile, str)
cpp_reader *pfile;
const char *str;
{
handle_assertion (pfile, str, T_UNASSERT);
}
static void
handle_assertion (pfile, str, type)
cpp_reader *pfile;
const char *str;
int type;
{
size_t count = strlen (str);
const char *p = strchr (str, '=');
if (p)
{
char *buf = (char *) alloca (count + 2);
memcpy (buf, str, count);
buf[p - str] = '(';
buf[count++] = ')';
buf[count] = '\0';
str = buf;
}
run_directive (pfile, type, str, count);
}
unsigned int
cpp_errors (pfile)
cpp_reader *pfile;
{
return pfile->errors;
}
cpp_options *
cpp_get_options (pfile)
cpp_reader *pfile;
{
return &pfile->opts;
}
cpp_callbacks *
cpp_get_callbacks (pfile)
cpp_reader *pfile;
{
return &pfile->cb;
}
const struct line_maps *
cpp_get_line_maps (pfile)
cpp_reader *pfile;
{
return &pfile->line_maps;
}
void
cpp_set_callbacks (pfile, cb)
cpp_reader *pfile;
cpp_callbacks *cb;
{
pfile->cb = *cb;
}
cpp_buffer *
cpp_push_buffer (pfile, buffer, len, from_stage3, return_at_eof)
cpp_reader *pfile;
const U_CHAR *buffer;
size_t len;
int from_stage3;
int return_at_eof;
{
cpp_buffer *new = xobnew (&pfile->buffer_ob, cpp_buffer);
memset (new, 0, sizeof (cpp_buffer));
new->line_base = new->buf = new->cur = buffer;
new->rlimit = buffer + len;
new->from_stage3 = from_stage3;
new->prev = pfile->buffer;
new->return_at_eof = return_at_eof;
new->saved_flags = BOL;
pfile->buffer = new;
return new;
}
void
_cpp_pop_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *buffer = pfile->buffer;
struct if_stack *ifs;
bool pushed = false;
for (ifs = buffer->if_stack; ifs; ifs = ifs->next)
cpp_error_with_line (pfile, ifs->line, 0,
"unterminated #%s", dtable[ifs->type].name);
pfile->state.skipping = 0;
pfile->buffer = buffer->prev;
if (buffer->inc)
pushed = _cpp_pop_file_buffer (pfile, buffer->inc);
if (!pushed)
obstack_free (&pfile->buffer_ob, buffer);
}
void
_cpp_init_directives (pfile)
cpp_reader *pfile;
{
unsigned int i;
cpp_hashnode *node;
for (i = 0; i < (unsigned int) N_DIRECTIVES; i++)
{
node = cpp_lookup (pfile, dtable[i].name, dtable[i].length);
node->directive_index = i + 1;
}
}
#ifdef PFE
void
pfe_freeze_thaw_answer (ap)
struct answer **ap;
{
struct answer *a = PFE_FREEZE_THAW_PTR (ap);
unsigned int i;
struct cpp_token *token;
while (a)
{
for (i = 0; i < a->count; i++)
{
token = &a->first[i];
pfe_freeze_thaw_cpp_token (&token);
}
a = PFE_FREEZE_THAW_PTR (&a->next);
}
}
DEFINE_CHECK_STRUCT_FUNCTION (answer)
#endif