From: Thomas Walker Lynch Date: Sun, 11 May 2025 10:00:24 +0000 (-0700) Subject: checkpoing workign on _cpp_create_assign X-Git-Url: https://git.reasoningtechnology.com/fossil/timeline?a=commitdiff_plain;h=4f42e7598e538286f4b30a25ca81c224eef85a3c;p=RT-gcc checkpoing workign on _cpp_create_assign --- diff --git "a/script_gcc_min-12\360\237\226\211/directives.cc" "b/script_gcc_min-12\360\237\226\211/directives.cc" index db37dd5..5ac29d1 100644 --- "a/script_gcc_min-12\360\237\226\211/directives.cc" +++ "b/script_gcc_min-12\360\237\226\211/directives.cc" @@ -2805,49 +2805,64 @@ _cpp_bracket_include(cpp_reader *pfile) // RT extensions //-------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------- -// directive `#macro` -// #macro name (parameter [,parameter] ...) (body_expr) -// #macro name () (body_expr) -// -// The body expr can be empty, but the parents remain -// Whitespace between name and parents, and between parens, is ignored - -extern bool _cpp_create_macro (cpp_reader *pfile, cpp_hashnode *node); - -static void -do_macro (cpp_reader *pfile) +const char * +cpp_token_as_text(const cpp_token *token) { - cpp_hashnode *node = lex_macro_node(pfile, true); + static char buffer[128]; - if(node) + switch (token->type) { - /* If we have been requested to expand comments into macros, - then re-enable saving of comments. */ - pfile->state.save_comments = - ! CPP_OPTION (pfile, discard_comments_in_macro_exp); + case CPP_NAME: + snprintf(buffer, sizeof(buffer), "identifier '%s'", + NODE_NAME(token->val.node.node)); + break; - if(pfile->cb.before_define) - pfile->cb.before_define (pfile); + case CPP_NUMBER: + case CPP_STRING: + case CPP_CHAR: + case CPP_HEADER_NAME: + snprintf(buffer, sizeof(buffer), "'%.*s'", + token->val.str.len, + token->val.str.text); + break; - if( _cpp_create_macro(pfile, node) ) - if (pfile->cb.define) - pfile->cb.define (pfile, pfile->directive_line, node); + case CPP_EOF: + return ""; + case CPP_OTHER: + return ""; + case CPP_OPEN_PAREN: + return "'('"; + case CPP_CLOSE_PAREN: + return "')'"; + case CPP_COMMA: + return "','"; + case CPP_SEMICOLON: + return "';'"; + case CPP_PLUS: + return "'+'"; + case CPP_MINUS: + return "'-'"; + case CPP_MULT: + return "'*'"; + case CPP_DIV: + return "'/'"; + case CPP_MOD: + return "'%'"; + // ... handle other symbolic types as needed ... - node->flags &= ~NODE_USED; + default: + snprintf(buffer, sizeof(buffer), "", token->type); + break; } -} + return buffer; +} -//-------------------------------------------------------------------------------- -// RT extention, directive `#assign` - -extern bool _cpp_create_assign(cpp_reader *pfile, cpp_hashnode *node); - +#if 0 const char * -cpp_token_as_text(const cpp_token *token) +cpp_token_as_text (const cpp_token *token) { - static char buffer[128]; + static char buffer[256]; switch (token->type) { @@ -2887,81 +2902,136 @@ cpp_token_as_text(const cpp_token *token) return "'/'"; case CPP_MOD: return "'%'"; - // ... handle other symbolic types as needed ... + // Add more token types as needed... default: snprintf(buffer, sizeof(buffer), "", token->type); break; } + // Append token flags if any are set + if (token->flags & (PREV_WHITE | DIGRAPH | STRINGIFY_ARG | + PASTE_LEFT | NAMED_OP | BOL | PURE_ZERO | + SP_DIGRAPH | SP_PREV_WHITE | NO_EXPAND | PRAGMA_OP)) + { + size_t len = strlen(buffer); + snprintf(buffer + len, sizeof(buffer) - len, " [flags:"); + + if (token->flags & PREV_WHITE) + strncat(buffer, " PREV_WHITE", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & DIGRAPH) + strncat(buffer, " DIGRAPH", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & STRINGIFY_ARG) + strncat(buffer, " STRINGIFY", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & PASTE_LEFT) + strncat(buffer, " ##L", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & NAMED_OP) + strncat(buffer, " NAMED_OP", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & BOL) + strncat(buffer, " BOL", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & PURE_ZERO) + strncat(buffer, " ZERO", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & SP_DIGRAPH) + strncat(buffer, " ##DIGRAPH", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & SP_PREV_WHITE) + strncat(buffer, " SP_WHITE", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & NO_EXPAND) + strncat(buffer, " NO_EXPAND", sizeof(buffer) - strlen(buffer) - 1); + if (token->flags & PRAGMA_OP) + strncat(buffer, " _Pragma", sizeof(buffer) - strlen(buffer) - 1); + + strncat(buffer, " ]", sizeof(buffer) - strlen(buffer) - 1); + } + return buffer; } +#endif -cpp_hashnode * -_cpp_lex_paren_delim_token(cpp_reader *pfile){ - const cpp_token *tok = _cpp_lex_token(pfile); +void print_token_list(const cpp_token *tokens ,size_t count){ + for (size_t i = 0; i < count; ++i) + fprintf( stderr ,"[%zu] %s\n" ,i , cpp_token_as_text(&tokens[i]) ); +} - if(tok->type != CPP_OPEN_PAREN){ - cpp_error_with_line( - pfile - ,CPP_DL_ERROR - ,tok->src_loc - ,0 - ,"expected '(' before name ,but found: %s" - ,cpp_token_as_text(tok) - ); - return NULL; - } - tok = _cpp_lex_token(pfile); - if(tok->type != CPP_NAME){ - cpp_error_with_line( - pfile - ,CPP_DL_ERROR - ,tok->src_loc - ,0 - ,"expected macro name identifier ,but found: %s" - ,cpp_token_as_text(tok) - ); - return NULL; - } +//-------------------------------------------------------------------------------- +// directive `#macro` +// #macro name (parameter [,parameter] ...) (body_expr) +// #macro name () (body_expr) +// +// The body expr can be empty, but the parents remain +// Whitespace has no semantic meaning beyond its usual duty as a separator. - cpp_hashnode *node = tok->val.node.node; - - tok = _cpp_lex_token(pfile); - if(tok->type != CPP_CLOSE_PAREN){ - cpp_error_with_line( - pfile - ,CPP_DL_ERROR - ,tok->src_loc - ,0 - ,"expected ')' after macro name ,but found: %s" - ,cpp_token_as_text(tok) - ); - return NULL; - } +extern bool _cpp_create_macro (cpp_reader *pfile, cpp_hashnode *node); + +static void +do_macro (cpp_reader *pfile) +{ + cpp_hashnode *node = lex_macro_node(pfile, true); - return node; + if(node) + { + /* If we have been requested to expand comments into macros, + then re-enable saving of comments. */ + pfile->state.save_comments = + ! CPP_OPTION (pfile, discard_comments_in_macro_exp); + + if(pfile->cb.before_define) + pfile->cb.before_define (pfile); + + if( _cpp_create_macro(pfile, node) ) + if (pfile->cb.define) + pfile->cb.define (pfile, pfile->directive_line, node); + + node->flags &= ~NODE_USED; + } } + +//-------------------------------------------------------------------------------- +// RT extention, directive `#assign` +// +// #assign (name_expr) (body_expr) +// +// The body expr can be empty, but name_expr can not be. +// Whitespace has no semantic meaning beyond its usual duty as a separator. +// +// This differs from `#define`: +// -Assign takes no arguments. +// -Name_expr and body_expr are expanded as though macros +// -The name expr must expand to become a valid macro name. +// -The name is entered into the symbol table with the value of +// the expanded body after the expansion. + + +extern bool _cpp_create_assign(cpp_reader *pfile); + + static void do_assign(cpp_reader *pfile){ - cpp_hashnode *node = _cpp_lex_paren_delim_token(pfile); - if(!node) return; + _cpp_create_assign(pfile); - /* If we have been requested to expand comments into macros, - then re-enable saving of comments. */ - pfile->state.save_comments = - ! CPP_OPTION (pfile ,discard_comments_in_macro_exp); +#if 0 - if (pfile->cb.before_define) - pfile->cb.before_define (pfile); - if (_cpp_create_assign (pfile ,node)) - if (pfile->cb.define) - pfile->cb.define (pfile ,pfile->directive_line ,node); + cpp_hashnode *node = lex_macro_node(pfile, true); + + if(node) + { + /* If we have been requested to expand comments into macros, + then re-enable saving of comments. */ + pfile->state.save_comments = + ! CPP_OPTION (pfile, discard_comments_in_macro_exp); - node->flags &= ~NODE_USED; + if(pfile->cb.before_define) + pfile->cb.before_define (pfile); + + if( _cpp_create_assign(pfile, node) ) + if (pfile->cb.define) + pfile->cb.define (pfile, pfile->directive_line, node); + + node->flags &= ~NODE_USED; + } +#endif } diff --git "a/script_gcc_min-12\360\237\226\211/expand_assign_arg_try_0.cc" "b/script_gcc_min-12\360\237\226\211/expand_assign_arg_try_0.cc" new file mode 100644 index 0000000..1c371d4 --- /dev/null +++ "b/script_gcc_min-12\360\237\226\211/expand_assign_arg_try_0.cc" @@ -0,0 +1,61 @@ +/* + Given the cpp_reader and an assignment argument in the form of a macro. + Returns ... through the `result` argument. + Returns ... + + Assign name_expr and body_expr arguments are each placed into a + macro instance, then are sent here to be expanded. + + Push the context of a macro onto the context stack. If we can + successfully expand the macro, we push a context containing its + yet-to-be-rescanned replacement list and return one. LOCATION is + the location of the expansion point of the macro. + + derived from enter_macro_context() +*/ +static int +expand_assign_arg (cpp_reader *pfile, cpp_macro *macro, + const cpp_token *result, location_t location) +{ + /* The presence of a macro invalidates a file's controlling macro. */ + pfile->mi_valid = false; + pfile->state.angled_headers = false; + pfile->about_to_expand_macro_p = true; + + // not expanding a pragma + + /* Disable the macro within its expansion. */ + node->flags |= NODE_DISABLED; + + // not lazy, doing it now + // no need to notify of macro use + // macro->paramc is indeed zero when we get here (assign has no parameters) + + unsigned tokens_count = macro_real_token_count (macro); + + // no need to check for the track_macro_expansion option + + _cpp_push_token_context (pfile, node, macro->exp.tokens, tokens_count); + + num_macro_tokens_counter += tokens_count; + + // not inside of a pragma (inside of a #assign) + + pfile->about_to_expand_macro_p = false; + return 1; + + pfile->about_to_expand_macro_p = false; + /* Handle built-in macros and the _Pragma operator. */ + { + location_t expand_loc; + + // not function like + + /* Otherwise, the location of the end of the macro invocation is + the location of the expansion point of that top-level macro + invocation. */ + expand_loc = pfile->invocation_location; + + return builtin_macro (pfile, node, location, expand_loc); + } +} diff --git "a/script_gcc_min-12\360\237\226\211/macro.cc" "b/script_gcc_min-12\360\237\226\211/macro.cc" index e24204f..b43ad75 100644 --- "a/script_gcc_min-12\360\237\226\211/macro.cc" +++ "b/script_gcc_min-12\360\237\226\211/macro.cc" @@ -2663,12 +2663,14 @@ ensure_expanded_arg_room (cpp_reader *pfile, macro_arg *arg, } } -/* Expand an argument ARG before replacing parameters in a - function-like macro. This works by pushing a context with the - argument's tokens, and then expanding that into a temporary buffer - as if it were a normal part of the token stream. collect_args() - has terminated the argument's tokens with a CPP_EOF so that we know - when we have fully expanded the argument. */ +/* + Expand an argument ARG before replacing parameters in a + function-like macro. This works by pushing a context with the + argument's tokens, and then expanding that into a temporary buffer + as if it were a normal part of the token stream. collect_args() + has terminated the argument's tokens with a CPP_EOF so that we know + when we have fully expanded the argument. + */ static void expand_arg (cpp_reader *pfile, macro_arg *arg) { @@ -4137,6 +4139,7 @@ cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node, // see directives.cc extern const char *cpp_token_as_text(const cpp_token *token); +extern void print_token_list (const cpp_token *tokens, size_t count); // a helper function for probing where the parser thinks it is in the source void @@ -4156,6 +4159,11 @@ debug_peek_token (cpp_reader *pfile) _cpp_backup_tokens(pfile, 1); } + +/*-------------------------------------------------------------------------------- + Collect body tokens. +*/ + // collects the body of a #define or related directive typedef enum collect_body_tokens_return { CBT_OK = 0, // Normal successful collection @@ -4206,7 +4214,6 @@ debug_collect_body_tokens_status(enum collect_body_tokens_return status) #endif } - static enum collect_body_tokens_return collect_body_tokens_1( cpp_reader *pfile @@ -4274,7 +4281,7 @@ collect_body_tokens_1( } } - // exit loop at the end of the macro body + // Determine if routine has lexed the final macro body token and should exit. if( paren_matching && paren_depth == 0 || !paren_matching && token->type == CPP_EOF @@ -4326,6 +4333,12 @@ collect_body_tokens_1( } +/* + Given a cpp_macro and cpp_reader reference. + Returns the body tokens in `macro->exp.tokens`. + + The macro need not have been committed. +*/ static bool collect_body_tokens( cpp_reader *pfile, @@ -4381,22 +4394,18 @@ collect_body_tokens( return status == CBT_OK; } +/*-------------------------------------------------------------------------------- + This code was derived from create_iso_defined(). + Given pfile returns a macro definition. + #macro name (parameter [,parameter] ...) (body_expr) + #macro name () (body_expr) + like _cpp_create_definition though uses paren blancing instead or requiring a single line definition. -//-------------------------------------------------------------------------------- -// for `#macro` directive -/* - #macro NAME ( [optional parameters] ) (body) - like _cpp_create_definition though uses paren blancing instead or requiring a single line definition. -*/ - -/* the cpp_macro struct is defined in cpplib.h: `struct GTY(()) cpp_macro {` it has a flexible array field in a union as a last member: cpp_token tokens[1]; */ - -// derived from create_iso_defined static cpp_macro * create_iso_macro (cpp_reader *pfile) { @@ -4410,144 +4419,128 @@ create_iso_macro (cpp_reader *pfile) bool ok = false; cpp_macro *macro = NULL; -int saved_in_directive = pfile->state.in_directive; -int saved = pfile->keep_tokens; - - /* - -Saves token allocation address held in pfile->cur_token. - -Gives a new token allocation address to pfile->cur_token, that of cpp_token first. - - Neither `first` nor `saved_cur_token` are referred to again, but as I don't have a - full test bench, I will leave this as I found it. Perhaps in the future if someone - understands what this is for, they can replace this comment. -Thomas - - -Parses out a token called 'token'. 'token' does get used. - */ - cpp_token first; - cpp_token *saved_cur_token = pfile->cur_token; - pfile->cur_token = &first; - cpp_token *token = _cpp_lex_direct (pfile); - pfile->cur_token = saved_cur_token; - - /* - -For #define if the next token is a space, then it is not a function macro. - -For #macro it is always a function macro, perhaps with an empty param list. - */ - if(token->type != CPP_OPEN_PAREN){ - cpp_error_with_line( - pfile - ,CPP_DL_ERROR - ,token->src_loc - ,0 - ,"expected '(' to open arguments list, but found: %s" - ,cpp_token_as_text(token) - ); - goto out; - } - /* - - returns parameter list for a function macro, or NULL - - returns via &arg count of parameters - - returns via &arg the varadic flag + At this point the name has already been parsed. The next token will be the opening paren of the parameter list. - after parse_parms runs, the next token returned by pfile will be subsequent to the parameter list, e.g.: - 7 | #macro Q(f ,...) printf(f ,__VA_ARGS__) - | ^~~~~~ + The `#dmacro` directive always has a parameter list. (If this were a `#define` the parser + would be looking for a space or a paren to determin if this was a function macro.) - */ - if( !parse_params(pfile, &nparms, &varadic) ) goto out; - - // finalizes the reserved room, otherwise it will be reused on the next reserve room call. - params = (cpp_hashnode **)_cpp_commit_buff( pfile, sizeof (cpp_hashnode *) * nparms ); - token = NULL; + After this six lines ofs code, the next token will be in the variable 'token'. - // This reserves room for a new macro struct. A macro struct is variable size, the actual size will be worked out when the memory is committed. - macro = _cpp_new_macro( - pfile - ,cmk_macro - ,_cpp_reserve_room( pfile, 0, sizeof(cpp_macro) ) - ); - macro->variadic = varadic; - macro->paramc = nparms; - macro->parm.params = params; - macro->fun_like = true; - - /* - Collect the macro body tokens. - A #macro () body is delineated by parentheses + Neither `first` nor `saved_cur_token` are referred to again, and I don't really understand the dance here. Apparently we must give pfile->cur_token an allocation to point at. */ + cpp_token first; + cpp_token *saved_cur_token = pfile->cur_token; + pfile->cur_token = &first; + cpp_token *token = _cpp_lex_direct (pfile); + pfile->cur_token = saved_cur_token; + + // parameter list parsing + // + if(token->type != CPP_OPEN_PAREN){ + cpp_error_with_line( + pfile + ,CPP_DL_ERROR + ,token->src_loc + ,0 + ,"expected '(' to open arguments list, but found: %s" + ,cpp_token_as_text(token) + ); + goto out; + } + /* + - returns parameter list for a function macro, or NULL + - returns via &arg count of parameters + - returns via &arg the varadic flag -pfile->state.in_directive = 0; // allow fresh lines -pfile->keep_tokens = 1; - - // collects the remaining body tokens - if( - !collect_body_tokens( - pfile - ,macro - ,&num_extra_tokens - ,paste_op_error_msg - ,true - ) - ) goto out; - -pfile->keep_tokens = saved; -pfile->state.in_directive = saved_in_directive; // restore - - + after parse_parms runs, the next token returned by pfile will be subsequent to the parameter list, e.g.: + 7 | #macro Q(f ,...) printf(f ,__VA_ARGS__) + | ^~~~~~ + */ + if( !parse_params(pfile, &nparms, &varadic) ) goto out; - // At this point, even if the body parse fails, we will say we made a macro. I'm not sure why as we haven't commited it yet, but this is what is in the code. Apparently we throw away the macro if the body does not parse. - ok = true; - - // commit the cpp struct to memory - // the struct reserves space for one token, the others run off the end - macro = (cpp_macro *)_cpp_commit_buff( - pfile - ,sizeof (cpp_macro) - sizeof (cpp_token) + sizeof (cpp_token) * macro->count - ); + // finalizes the reserved room, otherwise it will be reused on the next reserve room call. + params = (cpp_hashnode **)_cpp_commit_buff( pfile, sizeof (cpp_hashnode *) * nparms ); + token = NULL; + // macro declaration + // A macro struct is variable size, due to a trailing token list, so the memory + // reservations size will be adjusted when this is committed. + // + macro = _cpp_new_macro( + pfile + ,cmk_macro + ,_cpp_reserve_room( pfile, 0, sizeof(cpp_macro) ) + ); + macro->variadic = varadic; + macro->paramc = nparms; + macro->parm.params = params; + macro->fun_like = true; + + // parse macro body + // A `#macro` body is delineated by parentheses + // + if( + !collect_body_tokens( + pfile + ,macro + ,&num_extra_tokens + ,paste_op_error_msg + ,true // parenthesis delineated + ) + ) goto out; + + // ok time to commit the macro + // + ok = true; + macro = (cpp_macro *)_cpp_commit_buff( + pfile + ,sizeof (cpp_macro) - sizeof (cpp_token) + sizeof (cpp_token) * macro->count + ); - /* - It might be that the first token of the macro body was preceded by white space,so - the white space flag is set. However, upon expansion, there might not be a white - space before said token, so the following code clears the flag. - */ - if (macro->count) - macro->exp.tokens[0].flags &= ~PREV_WHITE; + // some end cases we must clean up + // + /* + It might be that the first token of the macro body was preceded by white space,so + the white space flag is set. However, upon expansion, there might not be a white + space before said token, so the following code clears the flag. + */ + if (macro->count) + macro->exp.tokens[0].flags &= ~PREV_WHITE; - /* - Identifies consecutive ## tokens (a.k.a. CPP_PASTE) that were invalid or ambiguous, + /* + Identifies consecutive ## tokens (a.k.a. CPP_PASTE) that were invalid or ambiguous, - Removes them from the main macro body, + Removes them from the main macro body, - Stashes them at the end of the tokens[] array in the same memory, + Stashes them at the end of the tokens[] array in the same memory, - Sets macro->extra_tokens = 1 to signal their presence. - */ - if (num_extra_tokens) - { - /* Place second and subsequent ## or %:%: tokens in sequences of - consecutive such tokens at the end of the list to preserve - information about where they appear, how they are spelt and - whether they are preceded by whitespace without otherwise - interfering with macro expansion. Remember, this is - extremely rare, so efficiency is not a priority. */ - cpp_token *temp = (cpp_token *)_cpp_reserve_room - (pfile, 0, num_extra_tokens * sizeof (cpp_token)); - unsigned extra_ix = 0, norm_ix = 0; - cpp_token *exp = macro->exp.tokens; - for (unsigned ix = 0; ix != macro->count; ix++) - if (exp[ix].type == CPP_PASTE) - temp[extra_ix++] = exp[ix]; - else - exp[norm_ix++] = exp[ix]; - memcpy (&exp[norm_ix], temp, num_extra_tokens * sizeof (cpp_token)); + Sets macro->extra_tokens = 1 to signal their presence. + */ + if (num_extra_tokens) + { + /* Place second and subsequent ## or %:%: tokens in sequences of + consecutive such tokens at the end of the list to preserve + information about where they appear, how they are spelt and + whether they are preceded by whitespace without otherwise + interfering with macro expansion. Remember, this is + extremely rare, so efficiency is not a priority. */ + cpp_token *temp = (cpp_token *)_cpp_reserve_room + (pfile, 0, num_extra_tokens * sizeof (cpp_token)); + unsigned extra_ix = 0, norm_ix = 0; + cpp_token *exp = macro->exp.tokens; + for (unsigned ix = 0; ix != macro->count; ix++) + if (exp[ix].type == CPP_PASTE) + temp[extra_ix++] = exp[ix]; + else + exp[norm_ix++] = exp[ix]; + memcpy (&exp[norm_ix], temp, num_extra_tokens * sizeof (cpp_token)); - /* Record there are extra tokens. */ - macro->extra_tokens = 1; - } + /* Record there are extra tokens. */ + macro->extra_tokens = 1; + } out: @@ -4570,8 +4563,6 @@ pfile->state.in_directive = saved_in_directive; // restore return ok ? macro : NULL; } - - bool _cpp_create_macro(cpp_reader *pfile, cpp_hashnode *node){ cpp_macro *macro; @@ -4628,61 +4619,110 @@ _cpp_create_macro(cpp_reader *pfile, cpp_hashnode *node){ //-------------------------------------------------------------------------------- -// similar to _cpp_create_definition, though evaluates the body first and uses -// paren balancing rather than requiring a single line definition. +// `#assign` directive +// called from directives.cc::do_assign() + bool -_cpp_create_assign(cpp_reader *pfile, cpp_hashnode *node){ - cpp_macro *macro; +_cpp_create_assign(cpp_reader *pfile){ - if (CPP_OPTION (pfile, traditional)) - macro = _cpp_create_trad_definition (pfile); - else - macro = create_iso_definition (pfile); + /* parse the name expr + + We first parse the as though a cpp_macro definition to collect the arg list. + We then convert the macro arg list to a cpp_arg arg definition, so it can be + passed to expand_arg. + */ + cpp_macro *macro = _cpp_new_macro( + pfile + ,cmk_macro + ,_cpp_reserve_room( pfile, 0, sizeof(cpp_macro) ) + ); + macro->variadic = false; + macro->paramc = 0; + macro->parm.params = NULL;; + macro->fun_like = false; + + const char *paste_op_error_msg = + N_("'##' cannot appear at either end of a macro expansion"); + unsigned int num_extra_tokens = 0; + !collect_body_tokens( + pfile + ,macro + ,&num_extra_tokens + ,paste_op_error_msg + ,true // parenthesis delineated + ); + fprintf(stderr, "assign directive name_exp:"); + print_token_list(macro->exp.tokens, macro->count); - if (!macro) + + macro_arg arg; + memset(&arg, 0, sizeof(arg)); + const cpp_token *token_ptr = macro->exp.tokens; + arg.first = &token_ptr; + arg.count = macro->count; + + /* + Expand the arg, and check if we can use it as a name, if not, throw + an error. + */ + _cpp_push_macro_context(pfile, NULL); // NULL = no macro node needed + expand_arg(pfile, &arg); + _cpp_pop_context(pfile); + + const cpp_token *expanded_name = *arg.expanded; + size_t name_len = arg.expanded_count; + fprintf(stderr, "cpp_create_assign:: expanded_name: "); + print_token_list(expanded_name, name_len); + +#if 0 + + + + + +if (name_len != 1 || expanded_name[0].type != CPP_NAME) + { + cpp_error(pfile, CPP_DL_ERROR, + "first expression of #assign must expand to a single macro name"); + // cleanup + free(arg.expanded); return false; + } - if (cpp_macro_p (node)) - { - if (CPP_OPTION (pfile, warn_unused_macros)) - _cpp_warn_if_unused_macro (pfile, node, NULL); +cpp_hashnode *name_node = expanded_name[0].val.node; - if (warn_of_redefinition (pfile, node, macro)) - { - const enum cpp_warning_reason reason - = (cpp_builtin_macro_p (node) && !(node->flags & NODE_WARN)) - ? CPP_W_BUILTIN_MACRO_REDEFINED : CPP_W_NONE; - bool warned = - cpp_pedwarning_with_line (pfile, reason, - pfile->directive_line, 0, - "\"%s\" redefined", NODE_NAME (node)); - if (warned && cpp_user_macro_p (node)) - cpp_error_with_line (pfile, CPP_DL_NOTE, - node->value.macro->line, 0, - "this is the location of the previous definition"); - } - _cpp_free_definition (node); - } + // expand the name expr + // puts the result in expanded_name and name_len + // + size_t name_len; + cpp_token *expanded_name = expand_assign_arg( + pfile + ,macro->exp.tokens + ,macro->count + ,&name_len + ); + + fprintf(stderr, "cpp_create_assign:: expanded_name: "); + print_token_list(expanded_name, name_len); + + + // name must expand to a single identifier + // + if (name_len != 1 || expanded_name[0].type != CPP_NAME) + { + cpp_error(pfile, CPP_DL_ERROR, + "first expression of #assign must expand to a single macro name"); + return false; + } + + // cpp_hashnode *name_node = expanded_name[0].val.node; + +#endif - /* Enter definition in hash table. */ - node->type = NT_USER_MACRO; - node->value.macro = macro; - if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_")) - && ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_FORMAT_MACROS") - /* __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS are mentioned - in the C standard, as something that one must use in C++. - However DR#593 and C++11 indicate that they play no role in C++. - We special-case them anyway. */ - && ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_LIMIT_MACROS") - && ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_CONSTANT_MACROS")) - node->flags |= NODE_WARN; - /* If user defines one of the conditional macros, remove the - conditional flag */ - node->flags &= ~NODE_CONDITIONAL; return true; }