aboutsummaryrefslogtreecommitdiff
path: root/gcc/cppexp.c
diff options
context:
space:
mode:
authorNeil Booth <neilb@earthling.net>2000-10-28 17:59:06 +0000
committerNeil Booth <neil@gcc.gnu.org>2000-10-28 17:59:06 +0000
commit93c80368d9a16c073f2b930bef4232661971765f (patch)
treeb1f50a88de9fbdd6a784d0c03fa8cd31e4ac5916 /gcc/cppexp.c
parentde48b52da8468f94c0bdffc11fa7e8fe49b4ba66 (diff)
downloadgcc-93c80368d9a16c073f2b930bef4232661971765f.zip
gcc-93c80368d9a16c073f2b930bef4232661971765f.tar.gz
gcc-93c80368d9a16c073f2b930bef4232661971765f.tar.bz2
New macro expander.
2000-10-28 Neil Booth <neilb@earthling.net> New macro expander. * cpplib.c (struct answer): New. (struct if_stack): Use cpp_lexer_pos rather than line and col. Rename cmacro mi_cmacro. (struct directive, KANDR, STDC89, EXTENSION, COND, IF_COND, INCL, IN_I): New directive and flags. (skip_rest_of_line, check_eol, run_directive, glue_header_name, parse_answer, parse_assertion, find_answer): New functions. (parse_ifdef, detect_if_not_defined, validate_else): Remove. (lex_macro_node): New function to replace parse_ifdef and get_define_node. (_cpp_handle_directive): New function, combines _cpp_check_directive and _cpp_check_linemarker. (do_define, do_undef, parse_include, do_include, do_import, do_include_next, read_line_number, do_line, do_ident, do_pragma, do_pragma_once, do_pragma_poison, do_pragma_dependency): Update for new token getting interface. (do_ifdef, do_ifndef, do_if, do_else, do_endif, push_conditional) : Update for new multiple-include optimisation technique. (do_elif): Don't forget to invalidate controlling macros. (unwind_if_stack, cpp_defined, cpp_push_buffer, cpp_pop_buffer): Update. (parse_assertion, parse_answer, find_answer, _cpp_test_assertion): Functions to handle assertions with the new token interface. (do_assert, do_unassert): Use them. (cpp_define, _cpp_define_builtin, cpp_undef, cpp_assert, cpp_unassert): Use run_directive. (_cpp_init_stacks): Register directive names. Don't register special nodes. * cpperror.c (print_containing_files, _cpp_begin_message): Update to new position recording regime. (cpp_ice, cpp_fatal, cpp_error, cpp_error_with_line, cpp_warning, cpp_warning_with_line, cpp_pedwarn, cpp_pedwarn_with_line, cpp_pedwarn_with_file_and_line): Update for _cpp_begin_message changes. (cpp_type2name): Move to cpplex.c. * cppexp.c (parse_charconst): spec_nodes is no longer a pointer. (parse_defined): Update to handle new multiple include optimisation method. Remove poisoned identifier warning. (parse_assertion, TYPE_NAME): Delete. (lex): Update for multiple include optimisation, removal of CPP_DEFINED, to use _cpp_test_assertion for assertions and cpp_token_as_text. (_cpp_parse_expr): Update for MI optimisation, and to use op_as_text. (op_as_text): New function, to wrap cpp_token_as_text. * cppfiles.c (stack_include_file, _cpp_pop_file_buffer): Update for MI optimisation. (_cpp_execute_include): Take a token rather than 3 arguments. Fix segfault on diagnostic. (_cpp_compare_file_date): Take a token rather than 3 args. (cpp_read_file): Work correctly for zero-length files. * cpphash.c (_cpp_init_macros, _cpp_cleanup_macros): Rename _cpp_init_hashtable and _cpp_cleanup_hashtable. (cpp_lookup): Place identifiers at front of identifier pool for _cpp_lookup_with_hash. (_cpp_lookup_with_hash): Require identifiers to be at the front of the identifier pool. Commit the memory if not already in the hash table. * cppinit.c (cpp_reader_init): Move cpp_init_completed test to top. Initialise various members of cpp_reader, memory pools, and the special nodes. (cpp_printer_init): Delete. (cpp_cleanup): Update. (struct builtin, builtin_array, initialize_builtins): Update for new hashnode definition and builtin handling. (cpp_start_read, cpp_finish): Don't take or initialise a printer. Update. * cpplib.h (cpp_printer, cpp_toklist, CPP_DEFINED, BOL, PASTED, VAR_ARGS, BEG_OF_FILE, IN_DIRECTIVE, KNOWN_DIRECTIVE, T_VOID, T_SPECLINE, T_DATE, T_FILE, T_BASE_FILE, T_INCLUDE_LEVEL, T_TIME, T_STDC, T_OPERATOR, T_POISON, T_MACRO, T_ASSERTION): Delete. (struct cpp_pool, struct cpp_macro, struct cpp_lexer_pos, struct cpp_lookahead, CPP_DHASH, enum mi_state, enum mi_ind, NO_EXPAND, VARARGS_FIRST, struct cpp_token_with_pos, struct toklist, struct cpp_context, struct specnodes, TOKEN_LOOKAHEAD, TOKEN_BUFFSIZE, NODE_OPERATOR, NODE_POISONED, NODE_BUILTIN, NODE_DIAGNOSTIC, NT_VOID, NT_MACRO, NT_ASSERTION, enum builtin_type, cpp_can_paste): New. (struct cpp_token): Delete line and col members. (struct cpp_buffer): New member output_lineno. (struct lexer_state): Delete indented, in_lex_line, seen_dot. Add va_args_ok, poisoned_ok, prevent_expansion, parsing_args. (struct cpp_reader): New members lexer_pos, macro_pos, directive_pos, ident_pool, temp_string_pool, macro_pool, argument_pool, string_pool, base_context, context, directive, mi_state, mi_if_not_defined, mi_lexed, mi_cmacro, mi_ind_cmacro, la_read, la_write, la_unused, mlstring_pos, macro_buffer, macro_buffer_len. Delete members mls_line, mls_column, token_list, potential_control_macro, temp_tokens, temp_cap, temp_alloced, temp_used, first_directive_token, context_cap, cur_context, no_expand_level, paste_level, contexts, args, save_parameter_spellings, need_newline, . Change type of date, time and spec_nodes members. Change prototypes for include and ident callbacks. (struct cpp_hashnode): Change type of name. Remove union members expansion and code. Add members macro, operator and builtin. (cpp_token_len, cpp_token_as_text, cpp_spell_token, cpp_start_read, cpp_finish, cpp_avoid_paste, cpp_get_token, cpp_get_line, cpp_get_output_line, cpp_macro_definition, cpp_start_lookahead, cpp_stop_lookahead): New prototypes. (cpp_printer_init, cpp_dump_definition): Delete prototypes. (U_CHAR, U, ustrcmp, ustrncmp, ustrlen, uxstrdup, ustrchr, ufputs): Move from cpphash.h. * cpphash.h (U_CHAR, U, ustrcmp, ustrncmp, ustrlen, uxstrdup, ustrchr, ufputs): Move to cpplib.h. (enum spell_type, struct token_spelling, _cpp_token_spellings, TOKEN_SPELL, TOKEN_NAME, struct answer, FREE_ANSWER, KANDR, STDC89, EXTENSION, COND, EXPAND, INCL, COMMENTS, IN_I, struct directive, directive_handler, struct spec_nodes, _cpp_digraph_spellings, _cpp_free_temp_tokens, _cpp_init_input_buffer, _cpp_grow_token_buffer, _cpp_init_toklist, _cpp_clear_toklist, _cpp_expand_token_space, _cpp_expand_name_space, _cpp_equiv_tokens, _cpp_equiv_toklists, _cpp_process_directive, _cpp_run_directive, _cpp_get_line, _cpp_get_raw_token, _cpp_glue_header_name, _cpp_can_paste, _cpp_check_directive, _cpp_check_linemarker, _cpp_parse_assertion, _cpp_find_answer): Delete. (VALID_SIGN, ALIGN, POOL_FRONT, POOL_LIMIT, POOL_BASE, POOL_SIZE, POOL_USED, POOL_COMMIT, struct cpp_chunk, _cpp_lex_token, _cpp_init_pool, _cpp_free_pool, _cpp_pool_reserve, _cpp_pool_alloc, _cpp_next_chunk, _cpp_lock_pool, _cpp_unlock_pool, _cpp_test_assertion, _cpp_handle_directive, DSC): New. (struct include_file): New member defined. (DO_NOT_REREAD, _cpp_begin_message, _cpp_execute_include, _cpp_compare_file_date): Update. (_cpp_pop_context, _cpp_get_token, _cpp_free_lookaheads, _cpp_push_token): New. (_cpp_init_macros, _cpp_cleanup_macros): Rename to _cpp_init_hashtable, _cpp_cleanup_hashtable. * Makefile.in: Remove cppoutput.c. * cppoutput.c: Delete * fixheader.c (read_scan_file): Update for new cpp_get_token prototype. (recognized_function): New argument LINE. * scan-decls.c (skip_to_closing_brace, scan_decls): Update for new cpp_get_token prototype. * scan.h (recognized_function): Update prototype. * po/POTFILES.in: Remove cppoutput.c. From-SVN: r37098
Diffstat (limited to 'gcc/cppexp.c')
-rw-r--r--gcc/cppexp.c181
1 files changed, 111 insertions, 70 deletions
diff --git a/gcc/cppexp.c b/gcc/cppexp.c
index 5403dce..566eb15 100644
--- a/gcc/cppexp.c
+++ b/gcc/cppexp.c
@@ -63,10 +63,10 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
static struct op parse_charconst PARAMS ((cpp_reader *, const cpp_token *));
static struct op parse_defined PARAMS ((cpp_reader *));
-static struct op parse_assertion PARAMS ((cpp_reader *));
static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, const U_CHAR **,
const U_CHAR *, HOST_WIDEST_INT));
-static struct op lex PARAMS ((cpp_reader *, int));
+static struct op lex PARAMS ((cpp_reader *, int, cpp_token *));
+static const unsigned char *op_as_text PARAMS ((cpp_reader *, enum cpp_ttype));
struct op
{
@@ -291,7 +291,7 @@ parse_charconst (pfile, tok)
/* If char type is signed, sign-extend the constant. */
num_bits = num_chars * width;
- if (pfile->spec_nodes->n__CHAR_UNSIGNED__->type != T_VOID
+ if (pfile->spec_nodes.n__CHAR_UNSIGNED__->type == NT_MACRO
|| ((result >> (num_bits - 1)) & 1) == 0)
op.value = result & ((unsigned HOST_WIDEST_INT) ~0
>> (HOST_BITS_PER_WIDEST_INT - num_bits));
@@ -313,85 +313,85 @@ static struct op
parse_defined (pfile)
cpp_reader *pfile;
{
- int paren;
- const cpp_token *tok;
+ int paren = 0;
+ cpp_hashnode *node = 0;
+ cpp_token token;
struct op op;
- paren = 0;
- tok = _cpp_get_raw_token (pfile);
- if (tok->type == CPP_OPEN_PAREN)
+ /* Don't expand macros. */
+ pfile->state.prevent_expansion++;
+
+ _cpp_get_token (pfile, &token);
+ if (token.type == CPP_OPEN_PAREN)
{
paren = 1;
- tok = _cpp_get_raw_token (pfile);
+ _cpp_get_token (pfile, &token);
}
- if (tok->type != CPP_NAME)
- SYNTAX_ERROR ("\"defined\" without an identifier");
-
- if (paren && _cpp_get_raw_token (pfile)->type != CPP_CLOSE_PAREN)
- SYNTAX_ERROR ("missing close paren after \"defined\"");
-
- if (tok->val.node->type == T_POISON)
- SYNTAX_ERROR2 ("attempt to use poisoned \"%s\"", tok->val.node->name);
-
- op.value = tok->val.node->type != T_VOID;
- op.unsignedp = 0;
- op.op = CPP_INT;
- return op;
-
- syntax_error:
- op.op = CPP_ERROR;
- return op;
-}
-
-static struct op
-parse_assertion (pfile)
- cpp_reader *pfile;
-{
- struct op op;
- struct answer *answer;
- cpp_hashnode *hp;
+ if (token.type == CPP_NAME)
+ {
+ node = token.val.node;
+ if (paren)
+ {
+ _cpp_get_token (pfile, &token);
+ if (token.type != CPP_CLOSE_PAREN)
+ {
+ cpp_error (pfile, "missing ')' after \"defined\"");
+ node = 0;
+ }
+ }
+ }
+ else
+ cpp_error (pfile, "\"defined\" without an identifier");
- op.op = CPP_ERROR;
- hp = _cpp_parse_assertion (pfile, &answer);
- if (hp)
+ if (!node)
+ op.op = CPP_ERROR;
+ else
{
- /* If we get here, the syntax is valid. */
- op.op = CPP_INT;
+ op.value = node->type == NT_MACRO;
op.unsignedp = 0;
- op.value = (hp->type == T_ASSERTION &&
- (answer == 0 || *_cpp_find_answer (hp, &answer->list) != 0));
+ op.op = CPP_INT;
- if (answer)
- FREE_ANSWER (answer);
+ /* No macros? At top of file? */
+ if (pfile->mi_state == MI_OUTSIDE && pfile->mi_cmacro == 0
+ && pfile->mi_if_not_defined == MI_IND_NOT && pfile->mi_lexed == 1)
+ {
+ cpp_start_lookahead (pfile);
+ cpp_get_token (pfile, &token);
+ if (token.type == CPP_EOF)
+ pfile->mi_ind_cmacro = node;
+ cpp_stop_lookahead (pfile, 0);
+ }
}
+
+ pfile->state.prevent_expansion--;
return op;
}
/* Read one token. */
static struct op
-lex (pfile, skip_evaluation)
+lex (pfile, skip_evaluation, token)
cpp_reader *pfile;
int skip_evaluation;
+ cpp_token *token;
{
struct op op;
- const cpp_token *tok;
retry:
- tok = _cpp_get_token (pfile);
+ _cpp_get_token (pfile, token);
- switch (tok->type)
+ switch (token->type)
{
case CPP_PLACEMARKER:
goto retry;
case CPP_INT:
case CPP_NUMBER:
- return parse_number (pfile, tok);
+ return parse_number (pfile, token);
case CPP_CHAR:
case CPP_WCHAR:
- return parse_charconst (pfile, tok);
+ return parse_charconst (pfile, token);
case CPP_STRING:
case CPP_WSTRING:
@@ -401,36 +401,60 @@ lex (pfile, skip_evaluation)
SYNTAX_ERROR ("floating point numbers are not valid in #if");
case CPP_OTHER:
- if (ISGRAPH (tok->val.aux))
- SYNTAX_ERROR2 ("invalid character '%c' in #if", tok->val.aux);
+ if (ISGRAPH (token->val.aux))
+ SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.aux);
else
- SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", tok->val.aux);
-
- case CPP_DEFINED:
- return parse_defined (pfile);
+ SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.aux);
case CPP_NAME:
+ if (token->val.node == pfile->spec_nodes.n_defined)
+ {
+ if (pfile->context->prev && CPP_PEDANTIC (pfile))
+ cpp_pedwarn (pfile, "\"defined\" operator appears during macro expansion");
+
+ return parse_defined (pfile);
+ }
+ /* Controlling #if expressions cannot contain identifiers (they
+ could become macros in the future). */
+ pfile->mi_state = MI_FAILED;
+
op.op = CPP_INT;
op.unsignedp = 0;
op.value = 0;
if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
- cpp_warning (pfile, "\"%s\" is not defined", tok->val.node->name);
+ cpp_warning (pfile, "\"%s\" is not defined", token->val.node->name);
+
return op;
case CPP_HASH:
- return parse_assertion (pfile);
+ {
+ int temp;
+
+ op.op = CPP_INT;
+ if (_cpp_test_assertion (pfile, &temp))
+ op.op = CPP_ERROR;
+ op.unsignedp = 0;
+ op.value = temp;
+ return op;
+ }
+
+ case CPP_NOT:
+ /* We don't worry about its position here. */
+ pfile->mi_if_not_defined = MI_IND_NOT;
+ /* Fall through. */
default:
- if ((tok->type > CPP_EQ && tok->type < CPP_PLUS_EQ)
- || tok->type == CPP_EOF)
+ if ((token->type > CPP_EQ && token->type < CPP_PLUS_EQ)
+ || token->type == CPP_EOF)
{
- op.op = tok->type;
+ op.op = token->type;
return op;
}
- SYNTAX_ERROR2("'%s' is not valid in #if expressions", TOKEN_NAME (tok));
- }
+ SYNTAX_ERROR2 ("\"%s\" is not valid in #if expressions",
+ cpp_token_as_text (pfile, token));
+ }
syntax_error:
op.op = CPP_ERROR;
@@ -709,8 +733,6 @@ op_to_prio[] =
/* Parse and evaluate a C expression, reading from PFILE.
Returns the truth value of the expression. */
-#define TYPE_NAME(t) _cpp_token_spellings[t].name
-
int
_cpp_parse_expr (pfile)
cpp_reader *pfile;
@@ -729,6 +751,7 @@ _cpp_parse_expr (pfile)
struct op init_stack[INIT_STACK_SIZE];
struct op *stack = init_stack;
struct op *limit = stack + INIT_STACK_SIZE;
+ cpp_token token;
register struct op *top = stack + 1;
int skip_evaluation = 0;
int result;
@@ -737,6 +760,10 @@ _cpp_parse_expr (pfile)
int save_skipping = pfile->skipping;
pfile->skipping = 0;
+ /* Set up detection of #if ! defined(). */
+ pfile->mi_lexed = 0;
+ pfile->mi_if_not_defined = MI_IND_NONE;
+
/* We've finished when we try to reduce this. */
top->op = CPP_EOF;
/* Nifty way to catch missing '('. */
@@ -751,7 +778,8 @@ _cpp_parse_expr (pfile)
struct op op;
/* Read a token */
- op = lex (pfile, skip_evaluation);
+ op = lex (pfile, skip_evaluation, &token);
+ pfile->mi_lexed++;
/* If the token is an operand, push its value and get next
token. If it is an operator, get its priority and flags, and
@@ -797,7 +825,7 @@ _cpp_parse_expr (pfile)
SYNTAX_ERROR ("void expression between '(' and ')'");
else
SYNTAX_ERROR2 ("operator '%s' has no right operand",
- TYPE_NAME (top->op));
+ op_as_text (pfile, top->op));
}
unsigned2 = top->unsignedp, v2 = top->value;
@@ -808,7 +836,8 @@ _cpp_parse_expr (pfile)
switch (top[1].op)
{
default:
- cpp_ice (pfile, "impossible operator type %s", TYPE_NAME (op.op));
+ cpp_ice (pfile, "impossible operator '%s'",
+ op_as_text (pfile, top[1].op));
goto syntax_error;
case CPP_NOT: UNARY(!); break;
@@ -967,13 +996,13 @@ _cpp_parse_expr (pfile)
{
if (top->flags & HAVE_VALUE)
SYNTAX_ERROR2 ("missing binary operator before '%s'",
- TYPE_NAME (op.op));
+ op_as_text (pfile, top->op));
}
else
{
if (!(top->flags & HAVE_VALUE))
SYNTAX_ERROR2 ("operator '%s' has no left operand",
- TYPE_NAME (op.op));
+ op_as_text (pfile, top->op));
}
/* Check for and handle stack overflow. */
@@ -1017,3 +1046,15 @@ _cpp_parse_expr (pfile)
pfile->skipping = save_skipping;
return result;
}
+
+static const unsigned char *
+op_as_text (pfile, op)
+ cpp_reader *pfile;
+ enum cpp_ttype op;
+{
+ cpp_token token;
+
+ token.type = op;
+ token.flags = 0;
+ return cpp_token_as_text (pfile, &token);
+}