Can a macro access its own name?

No. The macro must be expanded to reveal and execute the code. But the expansion replaces the macro token with the definition text, meaning the original macro is gone and no trace* is left that shows, where the code has come from.

* If \tracingmacros is active, then the .log file would tell the expansion step, but enabling \tracingmacros in the macro itself is too late. Also reading the .log file from within TeX is not as easy because the .log file block might not yet be written (buffered output/OS dependent behavior/...) and in the second run the .log file will be overwritten.


I don't know the origin of this question (two macros are the same from \ifx point of view and behaves differently with respect of their name). But I would to present the way to modification of TeX source to solve this task. I don't expect that somebody use this patch. This is only an illustration how easy or hard such modification is. Let me start by citation:

Certainly, if I were in the publishing business myself, I would have probably had ten different versions of TEX by now for ten different complicated projects that had come in. They would all look almost the same as TEX, but no one else would have this program--they wouldn't need it, they're not doing exactly the book that my publishing house was doing.

Donald E. Knuth, Prague, March 1996

We need to add the new primitive \lastexpanded which expands to the name of the last expanded macro similar as \string does it. This means, that

\TeX \edef\a{\lastexpanded}  \edef\b{\string\TeX}
now: \a is equal to \b

We do this by creating mytex.ch change file. This is a "patch" to the tex.web source file. We start by intensively flipping through second volume of C&T (TeX: The program) and by intensively thinking about it. Then we create the following file:


% This is a modification of TeX inspired by
% http://tex.stackexchange.com/questions/130285/has-a-command-access-to-its-own-name
% This modification adds new primitive \lastexpanded which expands to the
% \string of the last expanded macro name.

\S 297 declaration of global variables
@x
@!cur_tok: halfword; {packed representative of |cur_cmd| and |cur_chr|}
@y
@!cur_tok: halfword; {packed representative of |cur_cmd| and |cur_chr|}
@!lastexpanded_cs: pointer; {variable for \.{\\lastexpanded}}   
@!lastexpanded_chr: halfword; {|cur_chr| for \.{\\lastexpanded}}
@z

\S 389 macro_call saves its name
@x
warning_index:=cur_cs; ref_count:=cur_chr; r:=link(ref_count); n:=0;
@y
warning_index:=cur_cs; ref_count:=cur_chr; r:=link(ref_count); n:=0;  
lastexpanded_cs:=cur_cs; lastexpanded_chr:=cur_chr;
@z

\S 439 default values
@x
cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=normal;
@y
cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=normal;
lastexpanded_cs:=0; lastexpanded_chr:=0;
@z


\S 468 adding new expandable primitive \lastexpanded
@x 
@d job_name_code=pdftex_convert_codes {command code for \.{\\jobname}}
@y
@d job_name_code=pdftex_convert_codes {command code for \.{\\jobname}}
@d lastexpanded_code=pdftex_convert_codes + 1 {command code for
\.{\\lastexpanded}}
@z

@x
primitive("jobname",convert,job_name_code);@/
@!@:job_name_}{\.{\\jobname} primitive@>
@y
primitive("jobname",convert,job_name_code);@/
@!@:job_name_}{\.{\\jobname} primitive@>
primitive("lastexpanded",convert,lastexpanded_code);@/
@!@:lastexpanded_}{\.{\\lastexpanded} primitive@>
@z

\S 469 printing about new primitive
@x
  othercases print_esc("jobname")
@y
  lastexpanded_code:   print_esc("lastexpanded");
  othercases print_esc("jobname")
@z

\S 470 the c declaration
@x
@!c:number_code..job_name_code; {desired type of conversion}
@y
@!c:number_code..lastexpanded_code; {desired type of conversion}
@z

\S 471 Scanning argument, \lastexpanded has no argument
@x
job_name_code: if job_name=0 then open_log_file;
@y
job_name_code: if job_name=0 then open_log_file;
lastexpanded_code:  do_nothing;
@z

\S 472
@x
job_name_code: print(job_name);
@y
job_name_code: print(job_name);
lastexpanded_code: if lastexpanded_cs<>0 then sprint_cs(lastexpanded_cs)
  else print_char(lastexpanded_chr);
@z

The new expandable primitive is added in section 468. Here is a little complication because our patch will be applied to the pdftex: there are many new primitives and this is a reason why there is different value of the last code job_name_code than in the original TeX. The global variables lastexpanded_cs and lastexpanded_chr are set in macro_call procedure (section 389) and they are used in section 472 when \lastexpanded is expanded.

Now, you can add the mytex.ch as the last item to the pdftex_ch_srcs list in the Makefile in the source/build/texk/web2c/ of the pdftex source. Then you can run make pdftex. The new pdftex binary is compiled. You can try:

 ./pdftex -ini
 **\relax
 *\show\lastexpanded
 > \lastexpanded=\lastexpanded.

You can generate the format ./pdftex -ini -jobname pdftex -etex pdfetex.ini and use it in the same directory by ./pdftex test. The test.tex would be:

\edef\redname{\string\red}
\def\red{\edef\myname{\lastexpanded}%
    \ifx\myname\redname \message{I am RED}%
    \else  \message{I am NOT red}%
    \fi
}

\let\foo=\red

\red   % the output:  I am RED
\foo   % the output:  I am NOT red

\ifx\red\foo \message{YES}\fi   % the otput: YES

\end

Also as Heiko has said, it is not possible to do that using a macro by itself, I think it might be possible to do this using something that looks like a macro but is not.

The mean i think of would be do decide of a prefix character that would be applied to every color, and make this to be active. You would then be able to gobble the tokens of the color name from within that active character and do what you described.

For exemple, using "/" as the active character, you would then declare your color using

/red  % Gives "red"
/blue % Gives "not red" 

Tags:

Tex Core