5

First of all, this question is not part of a real-world problem, it's just to see whether the following is possible with TeX or not.

Consider this short code:

\begingroup
\toks0={\def\foo<}
\toks1={>}
\edef\bar{\the\toks0 foo\the\toks1}
\show\bar
\endgroup

Is it possible to replace < and > in the above code by explicit braces { and }, respectively, such that \bar will expand to \def\foo{foo}?

I found a way to get the desired result by using two \edefs:

\begingroup
\toks0={\noexpand\def\noexpand\foo{\iffalse}\fi}
\toks1={\iffalse{\fi}}
\edef\bar{\the\toks0 foo\the\toks1}
\expandafter\edef\expandafter\bar\expandafter{\bar}
\show\bar
\endgroup

But this requires all tokens in the two registers to be prepared for the second \edef. I'm interested in a solution (if any) that uses the contents of both registers literally.

3
  • 6
    A token register can only be assigned text with balanced braces.
    – egreg
    Commented Oct 5, 2018 at 22:35
  • 3
    Nothing can be assigned with unbalanced braces (the \iffalse trick doesn't actually store an unbalanced brace in anything) ...
    – Joseph Wright
    Commented Oct 5, 2018 at 23:55
  • 4
    possibly the nearest you can get to being able to have the start and end in separate lists is to use <> as you have but use \toks0={\zz\def\foo<} where the \zz helper is defined as \def\zz#1<#2>{#1{#2}} Commented Oct 6, 2018 at 0:38

2 Answers 2

1

Given that you cannot store unbalanced braces in the token register, perhaps this is an alternative...store an active character < in the register that behaves with the syntax you desire, namely: \toks0={\gdef\foo<} and \toks1={>}.

When active, < behaves as \gdef<#1>{{#1}}.

\documentclass{article}
\def\tmpA#1#2{\expandafter#1\expandafter#2}
\def\tmpB#1{\expandafter\tmpA\the\toks0 #1}
\def\usethetoks#1{\def\tmpC{\tmpB #1}%
  \expandafter\tmpC\the\toks1}
\begingroup
\catcode`<=\active
\gdef<#1>{{#1}}
\endgroup
\begin{document}
\begingroup
\catcode`<=\active

\toks0={\gdef\foo<}
\toks1={>}
\usethetoks{bar}

\toks0={\gdef\foobar<Pre-}
\toks1={-post>}
\usethetoks{baz}

\endgroup

\foo{} and \foobar

Is $<$ restored? \ifnum1<2\relax True\else False\fi
\end{document}

enter image description here

1

You can't store unbalanced token lists in the text of a definition nor in a token list register.

You can fake it by using special tokens, here \BGROUP and \EGROUP to be replaced at the end.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\splitdefbegin}{mO{0}}
 {
  \siracusa_splitdef_begin:nn { #1 } { #2 }
 }
\NewDocumentCommand{\splitdefadd}{m}
 {
  \siracusa_splitdef_add:n { #1 }
 }
\NewDocumentCommand{\splitdefend}{ }
 {
  \siracusa_splitdef_end:
 }

\tl_new:N \l__siracusa_splitdef_name_tl
\int_new:N \l__siracusa_splitdef_args_int
\prg_generate_conditional_variant:Nnn \regex_match:nn { nV } { T,F,TF }
\cs_generate_variant:Nn \cs_set:Nn { cV }

\cs_new_protected:Nn \siracusa_splitdef_begin:nn
 {
  \tl_set:Nn \l__siracusa_splitdef_name_tl { #1 }
  \int_set:Nn \l__siracusa_splitdef_args_int { #2 }
  \tl_build_begin:N \l__siracusa_splitdef_body_tl
 }
\cs_new_protected:Nn \siracusa_splitdef_add:n
 {
  \tl_build_put_right:Nn \l__siracusa_splitdef_body_tl { #1 }
 }
\cs_new_protected:Nn \siracusa_splitdef_end:
 {
  \tl_build_end:N \l__siracusa_splitdef_body_tl
  \__siracusa_splitdef_normalize:
  \cs_set:cV
   { __siracusa_splitdef_temp:\prg_replicate:nn { \l__siracusa_splitdef_args_int } { n } }
   \l__siracusa_splitdef_body_tl
  \cs_set_eq:cc
   { \l__siracusa_splitdef_name_tl }
   { __siracusa_splitdef_temp:\prg_replicate:nn { \l__siracusa_splitdef_args_int } { n } }
 }

\cs_new_protected:Nn \__siracusa_splitdef_normalize:
 {
  % recursively replace \BGROUP...\EGROUP with {...}
  \regex_match:nVT { \c{BGROUP} } \l__siracusa_splitdef_body_tl
   {
    \regex_replace_all:nnN
     { \c{BGROUP}(.*)\c{EGROUP} }  % search
     { \cB\{ \1 \cE\} }            % replace
     \l__siracusa_splitdef_body_tl % in
    \__siracusa_splitdef_normalize:
   }
 }

\ExplSyntaxOff

\splitdefbegin{foo}[2]

\splitdefadd{x\fbox\BGROUP#1}
\splitdefadd{y\fbox\BGROUP{#2}z\EGROUP}
\splitdefadd{!\EGROUP}

\splitdefend

\begin{document}

\texttt{\meaning\foo}

\foo{A}{B}

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .