The problem with the verbatim
-environment is:
The verbatim
-environment expects its "body" and the phrase \end{verbatim}
to be tokenized under some non-standard-catcode-régime, yielding a set of tokens differing from the set of tokens one would obtain by tokenizing under standard-catcode-régime.
If coming from the argument of a macro which is tokenized under standard-catcode-régime, then the phrase \end{verbatim}
won't be recognized as the end of the environment verbatim
.
As a workaround I can offer a routine
\DefineVerbatimToScantokens{⟨control-word-token⟩}{⟨xparse-argument-specifiers⟩}{%
⟨verbatim-material to be passed to \scantokens⟩
}%
⟨verbatim-material to be passed to \scantokens⟩ is read and tokenized under verbatim-catcode-régime.
Then within ⟨verbatim-material to be passed to \scantokens⟩ every #
is replaced by a character-token of catcode 6(parameter).
Then ⟨control-word-token⟩ is defined to process arguments according to ⟨xparse-argument-specifiers⟩ and to pass ⟨verbatim-material to be passed to \scantokens⟩ to \scantokens
.
Caveats:
The routine does not take from you the task of ensuring that things are referenced/called in circumstances where they can be processed/typeset properly.
E.g., if you define a ⟨control-word-token⟩ denoting only tokens that require math-mode, then you need to ensure math-mode when executing the ⟨control-word-token⟩.
E.g., if you have a ⟨control-word-token⟩ expanding to a verbatim-environment, which is based on \trivlist
, then you need to ensure that the ⟨control-word-token⟩ is carried out only in situations where \trivlist
can be typeset, which is not the case, e.g., with restricted horizontal mode.
⟨control-word-token⟩ can be used within macro-arguments but you need to take care of its usage within moving arguments: ⟨control-word-token⟩ must already be defined when the moving argument is used. This might be a problem. That's why I added another answer where macros \verblabel
/\verbref
are defined.
\documentclass{article}
%=== Code of \DefineVerbatimToScantokens ========================
% With older LaTeX-releases uncomment the following line:
%\usepackage{xparse}
\NewDocumentCommand\DefineVerbatimToScantokens{mm}{%
\begingroup
\catcode`\^^I=12\relax
\InnerDefineVerbatimToScantokens{#1}{#2}%
}%
\begingroup
\makeatletter
\def\InnerDefineVerbatimToScantokens#1#2{%
\endgroup
\NewDocumentCommand\InnerDefineVerbatimToScantokens{mm+v}{%
\endgroup\ReplaceHashloop{##3}{##1}{##2}%
}%
\newcommand\ReplaceHashloop[3]{%
\ifcat$\detokenize\expandafter{\Hashcheck##1#1}$%
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{%
\NewDocumentCommand{##2}{##3}{%
\begingroup\newlinechar=\endlinechar
\scantokens{\endgroup##1#2}%
}%
}{%
\expandafter\ReplaceHashloop\expandafter{\Hashreplace##1}{##2}{##3}%
}%
}%
\@ifdefinable\Hashcheck{\long\def\Hashcheck##1#1{}}%
\@ifdefinable\Hashreplace{\long\def\Hashreplace##1#1{##1####}}%
}%
\catcode`\%=12\relax
\catcode`\#=12\relax
\InnerDefineVerbatimToScantokens{#}{%}%
%=== End of code of \DefineVerbatimToScantokens =================
% Be aware that indenting does matter within \DefineVerbatimToScantokens's
% <verbatim-material to be passed to \scantokens>-argument:
% We don't want arguments, thus the <xparse-argument-specifiers>-argument
% is left empty. As \DefineVerbatimToScantokens is a command for defining
% macros, the rules for hash-doubling apply:
\DefineVerbatimToScantokens\mymacro{}{%
before
\begin{verbatim}
12##345 6_789$^%
12##345 6_789$^%
\end{verbatim}
after%
}%
\begin{document}
\medskip\hrule\medskip
before
\begin{verbatim}
12#345 6_789$^%
12#345 6_789$^%
\end{verbatim}
after%
\medskip\hrule\medskip
\mymacro
\medskip\hrule\medskip
\end{document}

_
and^
and$
are not printable symbols but directives for how to typeset subsequent typesettable material.