4

Given this example code:

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn

\group_begin:
\char_set_catcode_active:n { `\* }
\cs_new_protected:Npn \foo #1
  {
    \group_begin:
    \char_set_catcode_active:N \ 
    \char_set_lccode:nn { `\* } { `\  }
    \tex_lowercase:D { \cs_set:Npn * } { Y }
%    \tl_lower_case:n { \cs_set:Npn * } { Y }
    #1
    \group_end:
  }
\group_end:

\ExplSyntaxOff

\begin{document}
\begingroup
\catcode`\ \active
\gdef {X}
\gdef\fooarg{   }
\endgroup

\fooarg

\expandafter\foo\expandafter{\fooarg}
\end{document}

Within the argument of \foo active space characters are re-mapped to a new meaning. To not bring an active space into scope for the whole definition of \foo, the \lowercase trick was used.

There are two issues with this code:

  1. The relevant line of the trick uses a "do not use" function, namely \tex_lowercase:D. Is there a more idiomatic way for replacing that whole pattern using expl3-only functions?
  2. According to the documentation of \char_set_lccode:nn, \tl_lower_case:n seem to be the "official" \tex_lowercase:D replacement function. But when used in the above code it produces an error

    ! Undefined control sequence.
    <argument> *
    

    not only for * but also for several other characters. Why does this happen?

  • 1
    The \char_set_catcode_active:N \ line seems quite suspicious – egreg Jun 24 '19 at 8:52
  • 2
    Note that \tl_lower_case:n is explicitly documented as being about converting 'text' case: it's not intended for any weird catcode stuff. – Joseph Wright Jun 24 '19 at 9:40
4

There's no need to use the \lowercase trick (at the expense of defining an additional function) for locally setting the meaning of an active character, thanks to \char_set_active_eq:nN.

However, you should not define \foo with an argument, or the argument would be collected and tokenized before the space becomes active.

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn

\cs_new_protected:Npn \foo
  {
    \group_begin:
    \cs_set:Npn \siracusa_test: { Y }
    \char_set_active_eq:nN { `\  } \siracusa_test:
    \char_set_catcode_active:n { `\  }
    \__siracusa_foo:n
  }
\cs_new_protected:Npn \__siracusa_foo:n #1
  {
    #1
    \group_end:
  }

\ExplSyntaxOff

\begin{document}
\begingroup
\catcode`\ \active
\gdef {X}
\gdef\fooarg{   }
\endgroup

\fooarg

\expandafter\foo\expandafter{\fooarg}
\end{document}

enter image description here

| improve this answer | |
  • 2
    Perhaps worth adding that the reason we have \char_set_active_eq:nN using a second function is that the latter should be a well-defined and documented code-level construct. – Joseph Wright Jun 24 '19 at 9:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.