diff options
Diffstat (limited to 'libcpp/directives.c')
-rw-r--r-- | libcpp/directives.c | 115 |
1 files changed, 96 insertions, 19 deletions
diff --git a/libcpp/directives.c b/libcpp/directives.c index 01bb599e266..aed940e56e1 100644 --- a/libcpp/directives.c +++ b/libcpp/directives.c @@ -126,6 +126,8 @@ static int parse_answer (cpp_reader *, struct answer **, int, source_location); static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int); static struct answer ** find_answer (cpp_hashnode *, const struct answer *); static void handle_assertion (cpp_reader *, const char *, int); +static void do_pragma_push_macro (cpp_reader *); +static void do_pragma_pop_macro (cpp_reader *); /* This is the table of directive handlers. It is ordered by frequency of occurrence; the numbers at the end are directive @@ -1244,6 +1246,8 @@ _cpp_init_internal_pragmas (cpp_reader *pfile) { /* Pragmas in the global namespace. */ register_pragma_internal (pfile, 0, "once", do_pragma_once); + register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro); + register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro); /* New GCC-specific pragmas should be put in the GCC namespace. */ register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison); @@ -1423,6 +1427,96 @@ do_pragma_once (cpp_reader *pfile) _cpp_mark_file_once_only (pfile, pfile->buffer->file); } +/* Handle #pragma push_macro(STRING). */ +static void +do_pragma_push_macro (cpp_reader *pfile) +{ + char *macroname, *dest; + const char *limit, *src; + const cpp_token *txt; + struct def_pragma_macro *c; + + txt = get__Pragma_string (pfile); + if (!txt) + { + source_location src_loc = pfile->cur_token[-1].src_loc; + cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0, + "invalid #pragma push_macro directive"); + check_eol (pfile, false); + skip_rest_of_line (pfile); + return; + } + dest = macroname = (char *) alloca (txt->val.str.len + 2); + src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L')); + limit = (const char *) (txt->val.str.text + txt->val.str.len - 1); + while (src < limit) + { + /* We know there is a character following the backslash. */ + if (*src == '\\' && (src[1] == '\\' || src[1] == '"')) + src++; + *dest++ = *src++; + } + *dest = 0; + check_eol (pfile, false); + skip_rest_of_line (pfile); + c = XNEW (struct def_pragma_macro); + c->name = XNEWVAR (char, strlen (macroname) + 1); + strcpy (c->name, macroname); + c->next = pfile->pushed_macros; + c->value = cpp_push_definition (pfile, c->name); + pfile->pushed_macros = c; +} + +/* Handle #pragma pop_macro(STRING). */ +static void +do_pragma_pop_macro (cpp_reader *pfile) +{ + char *macroname, *dest; + const char *limit, *src; + const cpp_token *txt; + struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros; + txt = get__Pragma_string (pfile); + if (!txt) + { + source_location src_loc = pfile->cur_token[-1].src_loc; + cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0, + "invalid #pragma pop_macro directive"); + check_eol (pfile, false); + skip_rest_of_line (pfile); + return; + } + dest = macroname = (char *) alloca (txt->val.str.len + 2); + src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L')); + limit = (const char *) (txt->val.str.text + txt->val.str.len - 1); + while (src < limit) + { + /* We know there is a character following the backslash. */ + if (*src == '\\' && (src[1] == '\\' || src[1] == '"')) + src++; + *dest++ = *src++; + } + *dest = 0; + check_eol (pfile, false); + skip_rest_of_line (pfile); + + while (c != NULL) + { + if (!strcmp (c->name, macroname)) + { + if (!l) + pfile->pushed_macros = c->next; + else + l->next = c->next; + cpp_pop_definition (pfile, c->name, c->value); + free (c->name); + free (c); + break; + } + l = c; + c = c->next; + } +} + /* Handle #pragma GCC poison, to poison one or more identifiers so that the lexer produces a hard error for each subsequent usage. */ static void @@ -2225,28 +2319,11 @@ cpp_undef (cpp_reader *pfile, const char *macro) run_directive (pfile, T_UNDEF, buf, len); } -/* Like lex_macro_node, but read the input from STR. */ -static cpp_hashnode * -lex_macro_node_from_str (cpp_reader *pfile, const char *str) -{ - size_t len = strlen (str); - uchar *buf = (uchar *) alloca (len + 1); - cpp_hashnode *node; - - memcpy (buf, str, len); - buf[len] = '\n'; - cpp_push_buffer (pfile, buf, len, true); - node = lex_macro_node (pfile, true); - _cpp_pop_buffer (pfile); - - return node; -} - /* If STR is a defined macro, return its definition node, else return NULL. */ cpp_macro * cpp_push_definition (cpp_reader *pfile, const char *str) { - cpp_hashnode *node = lex_macro_node_from_str (pfile, str); + cpp_hashnode *node = _cpp_lex_identifier (pfile, str); if (node && node->type == NT_MACRO) return node->value.macro; else @@ -2258,7 +2335,7 @@ cpp_push_definition (cpp_reader *pfile, const char *str) void cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn) { - cpp_hashnode *node = lex_macro_node_from_str (pfile, str); + cpp_hashnode *node = _cpp_lex_identifier (pfile, str); if (node == NULL) return; |