diff options
author | Richard Henderson <rth@gcc.gnu.org> | 2006-01-04 08:33:38 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2006-01-04 08:33:38 -0800 |
commit | bc4071dd66fd4d093dc3fe3592ea879c2996868b (patch) | |
tree | 665a7e61be294c2530782e0d9fbb6a33d6ef62ea /gcc/c-parser.c | |
parent | 59bb84ef39a86a30c2f0280eb2176ee73a9e4cb9 (diff) | |
download | gcc-bc4071dd66fd4d093dc3fe3592ea879c2996868b.zip gcc-bc4071dd66fd4d093dc3fe3592ea879c2996868b.tar.gz gcc-bc4071dd66fd4d093dc3fe3592ea879c2996868b.tar.bz2 |
directives.c (struct pragma_entry): Add is_deferred.
libcpp/
* directives.c (struct pragma_entry): Add is_deferred. Add ident
entry to value union.
(end_directive): Don't eat the line if in_deferred_pragma.
(run_directive): Remove pragma hacks.
(insert_pragma_entry): Remove.
(new_pragma_entry): New.
(register_pragma_1): Split out of register_pragma. Only handle
the lookup tree and return the new entry.
(cpp_register_pragma): Fill in the pragma entry here.
(cpp_register_deferred_pragma): New.
(register_pragma_internal): New.
(_cpp_init_internal_pragmas): Use register_pragma_internal.
(do_pragma): Allow pragma expansion after namespace. For deferred
pragmas, don't slurp the line into a string.
(destringize_and_run): Save tokens for deferred pragmas.
(cpp_handle_deferred_pragma): Remove.
* macro.c (builtin_macro): Remove pragma token hack.
(_cpp_push_token_context): Rename from push_token_context and export.
* internal.h (struct lexer_state): Add pragma_allow_expansion.
(_cpp_push_token_context): Declare.
* lex.c (_cpp_lex_token): Allow _cpp_handle_directive to return
a token. Update the line number correctly if so.
(_cpp_lex_direct): Emit CPP_PRAGMA_EOL tokens.
(cpp_token_val_index): Return CPP_TOKEN_FLD_PRAGMA for pragmas.
* include/cpplib.h (PRAGMA_EOL): New.
(CPP_TOKEN_FLD_PRAGMA): New.
(struct cpp_token): Add val.pragma.
(struct cpp_options): Remove defer_pragmas.
(cpp_handle_deferred_pragma): Remove.
(cpp_register_deferred_pragma): Declare.
gcc/
* c-lex.c (c_lex_with_flags) <CPP_PRAGMA>: Smuggle pragma id
via integer constant.
(pragma_lex): Remove.
* c-pch.c (c_common_pch_pragma): Accept the name as an argument,
rather than parsing it.
* c-pragma.c (handle_pragma_weak, handle_pragma_redefine_extname,
handle_pragma_extern_prefix): Add %< %> quotes.
(registered_pragmas): New.
(c_register_pragma_1): New.
(c_register_pragma): Use it.
(c_register_pragma_with_expansion): Likewise.
(c_invoke_pragma_handler): New.
(init_pragma): Use cpp_register_deferred_pragma directly for
pch_preprocess.
* c-pragma.h (enum pragma_kind): New.
(pragma_handler): New.
(c_invoke_pragma_handler): Declare.
* c-common.c (c_parse_error): Pretty print CPP_PRAGMA and
CPP_PRAGMA_EOL.
* c-common.h (c_common_pch_pragma): Update decl.
* Makefile.in (c-parser.o): Update dependencies.
(GTFILES): Add c-pragma.h.
* c-parser.c (struct c_token): Add pragma_kind.
(struct c_parser): Add in_pragma.
(c_lex_one_token): Always initialize keyword and pragma_kind.
Extract data for CPP_PRAGMA.
(c_parser_peek_2nd_token): Deny CPP_PRAGMA_EOL.
(c_parser_consume_token): Don't allow CPP_PRAGMA unless errors.
Don't allow CPP_PRAGMA_EOL if in_pragma.
(c_parser_consume_pragma): New.
(c_parser_skip_until_found): Stop on CPP_PRAGMA_EOL.
(c_parser_skip_to_end_of_parameter): Likewise.
(c_parser_skip_to_end_of_block_or_statement): Likewise.
(c_parser_skip_to_pragma_eol): New.
(c_parser_external_declaration): Handle CPP_PRAGMA.
(c_parser_compound_statement_nostart): Likewise.
(c_parser_statement_after_labels): Likewise.
(c_parser_pragma): New.
(pragma_lex): Likewise.
(c_parser_pragma_pch_preprocess): New.
(c_parser_new): Merge into ...
(c_parse_file): ... here. Call c_parser_pragma_pch_preprocess.
gcc/cp/
* lex.c (handle_pragma_java_exceptions): Fix whitespace.
* parser.c (struct cp_token): Add pragma_kind.
(eof_token): Update to match.
(struct cp_lexer): Add in_pragma; rearrange next for better packing.
(cp_parser_initial_pragma): New.
(cp_lexer_new_main): Use it. Don't bother clearing
c_lex_return_raw_strings.
(cp_lexer_get_preprocessor_token): Always initialize keyword
and pragma_kind fields. Handle CPP_PRAGMA.
(cp_lexer_consume_token): Don't allow CPP_PRAGMA_EOL when
in_pragma is set.
(cp_lexer_handle_pragma): Remove. Update callers to cp_parser_pragma.
(cp_lexer_print_token) <CPP_PRAGMA>: Don't print as a string.
(cp_parser_skip_to_pragma_eol): New.
(cp_parser_error): Use it.
(cp_parser_skip_to_closing_parenthesis): Stop at CPP_PRAGMA_EOL;
rearrange with switch statement.
(cp_parser_skip_to_end_of_statement): Likewise.
(cp_parser_skip_to_end_of_block_or_statement): Likewise.
(cp_parser_skip_to_closing_brace): Likewise.
(cp_parser_skip_until_found): Likewise.
(cp_parser_statement): Add in_compound argument; update callers.
Use it to decide how to handle pragma parsing.
(cp_parser_labeled_statement): Add in_compound argument; pass
it on to cp_parser_statement.
(cp_parser_statement_seq_opt): Stop at CPP_PRAGMA_EOL.
(cp_parser_declaration_seq_opt): Likewise.
(cp_parser_parameter_declaration): Likewise.
(cp_parser_member_specification_opt): Likewise.
(cp_parser_function_definition_after_decl): Likewise.
(cp_parser_cache_group): Handle CPP_PRAGMA/CPP_PRAGMA_EOL pairs.
(cp_parser_pragma): New.
(pragma_lex): New.
gcc/testsuite/
* g++.dg/parse/pragma2.C: Update expected error lines.
From-SVN: r109336
Diffstat (limited to 'gcc/c-parser.c')
-rw-r--r-- | gcc/c-parser.c | 244 |
1 files changed, 205 insertions, 39 deletions
diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 8469eca..eff5b83 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -42,6 +42,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "coretypes.h" #include "tm.h" #include "tree.h" +#include "rtl.h" #include "langhooks.h" #include "input.h" #include "cpplib.h" @@ -53,6 +54,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "toplev.h" #include "ggc.h" #include "c-common.h" +#include "vec.h" +#include "target.h" /* Miscellaneous data and functions needed for the parser. */ @@ -266,6 +269,9 @@ typedef struct c_token GTY (()) /* If this token is a keyword, this value indicates which keyword. Otherwise, this value is RID_MAX. */ ENUM_BITFIELD (rid) keyword : 8; + /* If this token is a CPP_PRAGMA, this indicates the pragma that + was seen. Otherwise it is PRAGMA_NONE. */ + ENUM_BITFIELD (pragma_kind) pragma_kind : 7; /* True if this token is from a system header. */ BOOL_BITFIELD in_system_header : 1; /* The value associated with this token, if any. */ @@ -287,21 +293,34 @@ typedef struct c_parser GTY(()) c_parser_error sets this flag. It should clear this flag when enough tokens have been consumed to recover from the error. */ BOOL_BITFIELD error : 1; + /* True if we're processing a pragma, and shouldn't automatically + consume CPP_PRAGMA_EOL. */ + BOOL_BITFIELD in_pragma : 1; } c_parser; + +/* The actual parser and external interface. ??? Does this need to be + garbage-collected? */ + +static GTY (()) c_parser *the_parser; + + /* Read in and lex a single token, storing it in *TOKEN. */ static void c_lex_one_token (c_token *token) { timevar_push (TV_LEX); + token->type = c_lex_with_flags (&token->value, &token->location, NULL); + token->id_kind = C_ID_NONE; + token->keyword = RID_MAX; + token->pragma_kind = PRAGMA_NONE; token->in_system_header = in_system_header; + switch (token->type) { case CPP_NAME: - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; { tree decl; @@ -358,13 +377,12 @@ c_lex_one_token (c_token *token) break; } } + token->id_kind = C_ID_ID; } - token->id_kind = C_ID_ID; break; case CPP_AT_NAME: /* This only happens in Objective-C; it must be a keyword. */ token->type = CPP_KEYWORD; - token->id_kind = C_ID_NONE; token->keyword = C_RID_CODE (token->value); break; case CPP_COLON: @@ -374,12 +392,13 @@ c_lex_one_token (c_token *token) /* These tokens may affect the interpretation of any identifiers following, if doing Objective-C. */ OBJC_NEED_RAW_IDENTIFIER (0); - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; + break; + case CPP_PRAGMA: + /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ + token->pragma_kind = TREE_INT_CST_LOW (token->value); + token->value = NULL; break; default: - token->id_kind = C_ID_NONE; - token->keyword = RID_MAX; break; } timevar_pop (TV_LEX); @@ -582,6 +601,7 @@ c_parser_peek_2nd_token (c_parser *parser) return &parser->tokens[1]; gcc_assert (parser->tokens_avail == 1); gcc_assert (parser->tokens[0].type != CPP_EOF); + gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL); c_lex_one_token (&parser->tokens[1]); parser->tokens_avail = 2; return &parser->tokens[1]; @@ -592,16 +612,30 @@ c_parser_peek_2nd_token (c_parser *parser) static void c_parser_consume_token (c_parser *parser) { + gcc_assert (parser->tokens_avail >= 1); + gcc_assert (parser->tokens[0].type != CPP_EOF); + gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); + gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); if (parser->tokens_avail == 2) parser->tokens[0] = parser->tokens[1]; - else - { - gcc_assert (parser->tokens_avail == 1); - gcc_assert (parser->tokens[0].type != CPP_EOF); - } parser->tokens_avail--; } +/* Expect the current token to be a #pragma. Consume it and remember + that we've begun parsing a pragma. */ + +static void +c_parser_consume_pragma (c_parser *parser) +{ + gcc_assert (!parser->in_pragma); + gcc_assert (parser->tokens_avail >= 1); + gcc_assert (parser->tokens[0].type == CPP_PRAGMA); + if (parser->tokens_avail == 2) + parser->tokens[0] = parser->tokens[1]; + parser->tokens_avail--; + parser->in_pragma = true; +} + /* Update the globals input_location and in_system_header from TOKEN. */ static inline void @@ -614,23 +648,6 @@ c_parser_set_source_position_from_token (c_token *token) } } -/* Allocate a new parser. */ - -static c_parser * -c_parser_new (void) -{ - /* Use local storage to lex the first token because loading a PCH - file may cause garbage collection. */ - c_parser tparser; - c_parser *ret; - memset (&tparser, 0, sizeof tparser); - c_lex_one_token (&tparser.tokens[0]); - tparser.tokens_avail = 1; - ret = GGC_NEW (c_parser); - memcpy (ret, &tparser, sizeof tparser); - return ret; -} - /* Issue a diagnostic of the form FILE:LINE: MESSAGE before TOKEN where TOKEN is the next token in the input stream of PARSER. @@ -732,9 +749,12 @@ c_parser_skip_until_found (c_parser *parser, c_parser_consume_token (parser); break; } + /* If we've run out of tokens, stop. */ if (token->type == CPP_EOF) return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; if (token->type == CPP_OPEN_BRACE || token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_SQUARE) @@ -769,6 +789,8 @@ c_parser_skip_to_end_of_parameter (c_parser *parser) /* If we've run out of tokens, stop. */ if (token->type == CPP_EOF) return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; if (token->type == CPP_OPEN_BRACE || token->type == CPP_OPEN_PAREN || token->type == CPP_OPEN_SQUARE) @@ -803,6 +825,8 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser) /* If we've run out of tokens, stop. */ if (token->type == CPP_EOF) return; + if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) + return; /* If the next token is a ';', we have reached the end of the statement. */ if (token->type == CPP_SEMICOLON && !nesting_depth) @@ -828,6 +852,31 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser) parser->error = false; } +/* Expect to be at the end of the pragma directive and consume an + end of line marker. */ + +static void +c_parser_skip_to_pragma_eol (c_parser *parser) +{ + gcc_assert (parser->in_pragma); + parser->in_pragma = false; + + if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line")) + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + break; + if (token->type == CPP_PRAGMA_EOL) + { + c_parser_consume_token (parser); + break; + } + c_parser_consume_token (parser); + } + + parser->error = false; +} /* Save the warning flags which are controlled by __extension__. */ @@ -932,6 +981,9 @@ static struct c_expr c_parser_expression (c_parser *); static struct c_expr c_parser_expression_conv (c_parser *); static tree c_parser_expr_list (c_parser *, bool); +enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +static bool c_parser_pragma (c_parser *, enum pragma_context); + /* These Objective-C parser functions are only ever called when compiling Objective-C. */ static void c_parser_objc_class_definition (c_parser *); @@ -1063,6 +1115,9 @@ c_parser_external_declaration (c_parser *parser) pedwarn ("ISO C does not allow extra %<;%> outside of a function"); c_parser_consume_token (parser); break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_external); + break; case CPP_PLUS: case CPP_MINUS: if (c_dialect_objc ()) @@ -1082,6 +1137,7 @@ c_parser_external_declaration (c_parser *parser) } } + /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1). If FNDEF_OK is true, a function definition is accepted; otherwise (old-style parameter declarations) only other @@ -1142,6 +1198,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok, tree prefix_attrs; tree all_prefix_attrs; bool diagnosed_no_specs = false; + specs = build_null_declspecs (); c_parser_declspecs (parser, specs, true, true, start_attr_ok); if (parser->error) @@ -1808,6 +1865,12 @@ c_parser_struct_or_union_specifier (c_parser *parser) c_parser_consume_token (parser); break; } + /* Accept #pragmas at struct scope. */ + if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_external); + continue; + } /* Parse some comma-separated declarations, but not the trailing semicolon if any. */ decls = c_parser_struct_declaration (parser); @@ -3268,11 +3331,6 @@ c_parser_compound_statement_nostart (c_parser *parser) while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) { location_t loc = c_parser_peek_token (parser)->location; - if (c_parser_next_token_is (parser, CPP_EOF)) - { - c_parser_error (parser, "expected declaration or statement"); - return; - } if (c_parser_next_token_is_keyword (parser, RID_CASE) || c_parser_next_token_is_keyword (parser, RID_DEFAULT) || (c_parser_next_token_is (parser, CPP_NAME) @@ -3325,6 +3383,21 @@ c_parser_compound_statement_nostart (c_parser *parser) else goto statement; } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + /* External pragmas, and some omp pragmas, are not associated + with regular c code, and so are not to be considered statements + syntactically. This ensures that the user doesn't put them + places that would turn into syntax errors if the directive + were ignored. */ + if (c_parser_pragma (parser, pragma_compound)) + last_label = false, last_stmt = true; + } + else if (c_parser_next_token_is (parser, CPP_EOF)) + { + c_parser_error (parser, "expected declaration or statement"); + return; + } else { statement: @@ -3578,6 +3651,9 @@ c_parser_statement_after_labels (c_parser *parser) c_parser_error (parser, "expected statement"); c_parser_consume_token (parser); break; + case CPP_PRAGMA: + c_parser_pragma (parser, pragma_stmt); + break; default: expr_stmt: stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value); @@ -5558,6 +5634,12 @@ c_parser_objc_class_instance_variables (c_parser *parser) objc_set_visibility (1); continue; } + else if (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + c_parser_pragma (parser, pragma_external); + continue; + } + /* Parse some comma-separated declarations. */ decls = c_parser_struct_declaration (parser); { @@ -6262,17 +6344,101 @@ c_parser_objc_keywordexpr (c_parser *parser) } -/* The actual parser and external interface. ??? Does this need to be - garbage-collected? */ +/* Handle pragmas. ALLOW_STMT is true if we're within the context of + a function and such pragmas are to be allowed. Returns true if we + actually parsed such a pragma. */ -static GTY (()) c_parser *the_parser; +static bool +c_parser_pragma (c_parser *parser, enum pragma_context context ATTRIBUTE_UNUSED) +{ + unsigned int id; + + id = c_parser_peek_token (parser)->pragma_kind; + gcc_assert (id != PRAGMA_NONE); + + switch (id) + { + case PRAGMA_GCC_PCH_PREPROCESS: + c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + + default: + gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); + break; + } + + c_parser_consume_pragma (parser); + c_invoke_pragma_handler (id); + /* Skip to EOL, but suppress any error message. Those will have been + generated by the handler routine through calling error, as opposed + to calling c_parser_error. */ + parser->error = true; + c_parser_skip_to_pragma_eol (parser); + + return false; +} + +/* The interface the pragma parsers have to the lexer. */ + +enum cpp_ttype +pragma_lex (tree *value) +{ + c_token *tok = c_parser_peek_token (the_parser); + enum cpp_ttype ret = tok->type; + + *value = tok->value; + if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) + ret = CPP_EOF; + else + { + if (ret == CPP_KEYWORD) + ret = CPP_NAME; + c_parser_consume_token (the_parser); + } + + return ret; +} + +static void +c_parser_pragma_pch_preprocess (c_parser *parser) +{ + tree name = NULL; + + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_STRING)) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else + c_parser_error (parser, "expected string literal"); + c_parser_skip_to_pragma_eol (parser); + + if (name) + c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); +} + /* Parse a single source file. */ void c_parse_file (void) { - the_parser = c_parser_new (); + /* Use local storage to begin. If the first token is a pragma, parse it. + If it is #pragma GCC pch_preprocess, then this will load a PCH file + which will cause garbage collection. */ + c_parser tparser; + + memset (&tparser, 0, sizeof tparser); + the_parser = &tparser; + + if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) + c_parser_pragma_pch_preprocess (&tparser); + + the_parser = GGC_NEW (c_parser); + *the_parser = tparser; + c_parser_translation_unit (the_parser); the_parser = NULL; } |