2

I defined a newenvironment with this code (sample):

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{amsthm}

\newenvironment{myEnv}[1][default]
{
   \pushQED{#1}
   \expandafter\csname x#1 \endcsname
}
{    \expandafter\csname endx\popQED \endcsname    }

\newenvironment{xdefault}{}{}

\begin{document}

\begin{myEnv}
\end{myEnv}

\end{document}

I need this for some stuff later to call a specific environment using the argument. But I get the following error in Overleaf:

Missing \endcsname inserted.

<to be read again> 
               \begingroup 
l.35 \end{myEnv}

The control sequence marked <to be read again> should
not appear between \csname and \endcsname.
-----------
Extra \endcsname.

\endmyEnv ...after \csname endx\popQED \endcsname 

l.35 \end{myEnv}

I'm ignoring this, since I wasn't doing a \csname.

As far as I can tell, the csname/endcsname's should be correct, I don't see an error, so I have no idea what causes this. When I searched the error I only found topics that were unrealated to my example.

Does someone know how to fix this?

  • My guess would be that the \popQED within \csname ... \endcsname is a bit too much for LaTeX. I presume \popQED does not expand to simple text, so LaTeX fails to make sense of it as part of a control sequence name. Maybe you just mean \csname endx#1\endcsname\popQED? I'm also not quite sure if the \expandafters are needed and the trailing space after #1 in \csname x#1 \endcsname might be too much. (But this is all speculation without a full example document where I can verify the definitions involved.) – moewe May 19 at 19:56
  • @moewe Using pushQED was something I found searching for how to pass arguments to the end part. The space after #1 was from searching the error, removing them doesn't change that. moving popQED behind endscname causes the error to go, but then it prints 'default' and doesn't call endxdefault – Thorsten Schmitz May 19 at 20:01
  • Ah, I see. I don't think \popQED and \pushQED can help you here. Try \def\tssavedarg{#1} and \csname endx\tssavedarg\endcsname instead. – moewe May 19 at 20:05
  • \expandafter\csname x expands x which is not expandable, so the \expandafter is doing nothing. – David Carlisle May 19 at 20:30
4

Try something like

\documentclass{article}
\usepackage[utf8]{inputenc}

% make sure \tssavedarg is not taken already
\newcommand*{\tssavedarg}{}
\newenvironment{myEnv}[1][default]
  {\def\tssavedarg{#1}%
   \csname x#1\endcsname}
  {\csname endx\tssavedarg\endcsname}

\newenvironment{xdefault}{XX}{YY}

\begin{document}

\begin{myEnv}
A
\end{myEnv}

\end{document}

\pushQED and \popQED are specifically for QED handling in amsmath and they seem to implement a full QED stack, which you do not need. In particular \popQED does not simply expand to the contents saved with \pushQED, so it does not work within \csname ... \endcsname as expected.

In your case it is enough to just save the #1 in a normal macro with \def and then retrieve the macro value by calling it.

Related Why can't the end code of an environment contain an argument?.

The xparse/LaTeX3 solution would be

\usepackage{xparse}
\NewDocumentEnvironment{myEnv}{O{default}}
  {\csname x#1\endcsname}
  {\csname endx#1\endcsname}

or maybe even more expl3-y

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{myEnv}{O{default}}
  {\use:c{x#1}}
  {\use:c{endx#1}}
\ExplSyntaxOff

because xparse's environments can access the arguments even in the end code.

  • Thanks for your answer, I will lok into this. Btw could you tell me where you found the doc for pushQED/popQED? I couldn't find one, so I didn't really know, how they worked. Just did what was recommended in a thread I found. – Thorsten Schmitz May 19 at 20:29
  • @ThorstenSchmitz I didn't find a lot about the two. The amsthm documentation mentions the two only in a code example. But the source code shows that \popQED does not simply expand to the saved test and suggests that the two implement a sort of stack. Where were those commands recommended for the job you had in mind, if I might ask? – moewe May 19 at 20:32
  • mirrors.ctan.org/macros/latex/required/amscls/doc/amsclass.pdf also has a little bit on the commands and their implementation – moewe May 19 at 20:37
  • It was in a thread, but I don't remember where exactly. Didn't think I would need to since there was just a recommendation without further information. – Thorsten Schmitz May 20 at 9:40
4

Let's see how \pushQED and \popQED are defined in amsthm.sty:

    274 \DeclareRobustCommand{\qed}{%
    275   \ifmmode \mathqed
    276   \else
    277     \leavevmode\unskip\penalty9999 \hbox{}\nobreak\hfill
    278     \quad\hbox{\qedsymbol}%
    279   \fi
    280 }
    281 \let\QED@stack\@empty
    282 \let\qed@elt\relax
    283 \newcommand{\pushQED}[1]{%
    284   \toks@{\qed@elt{#1}}\@temptokena\expandafter{\QED@stack}%
    285   \xdef\QED@stack{\the\toks@\the\@temptokena}%
    286 }
    287 \newcommand{\popQED}{%
    288   \begingroup\let\qed@elt\popQED@elt \QED@stack\relax\relax\endgroup
    289 }
    290 \def\popQED@elt#1#2\relax{#1\gdef\QED@stack{#2}}
    291 \newcommand{\qedhere}{%
    292   \begingroup \let\mathqed\math@qedhere
    293     \let\qed@elt\setQED@elt \QED@stack\relax\relax \endgroup
    294 }

The name clearly shows that this has to do with the typesetting of the QED marker in proofs, so I included the definition of \qed.

There is a “stack”, actually a macro, called \QED@stack, that's initialized to empty.

Suppose we call \pushQED{foo} when the stack is empty. Two scratch token registers are set: first \toks@ is set to \qed@elt{foo}, then \@temptokena is set to contain the current first level expansion of \QED@stack (in this case, nothing). Next, \QED@stack is redefined to contain the token lists in the two registers; with e-TeX extensions, this could be achieved with the single instruction

\xdef\QED@stack{\unexpanded{\qed@elt{#1}}\unexpanded\expandafter{\QED@stack}}

So now \QED@stack will expand to \qed@elt{foo}. If another \pushQED{bar} follows, the expansion would become \qed@elt{bar}\qed@elt{foo}. But let's stay with the simple case.

What happens when \popQED is called? The instructions at line 288 are executed, namely

\begingroup\let\qed@elt\popQED@elt \QED@stack\relax\relax\endgroup

The macro \qed@elt (that normally is \relax, see line 282) is set to mean \popQED@elt inside a group and then \QED@stack\relax\relax is examined. In your case it is

\qed@elt{foo}\relax\relax

Since the macro \qed@elt has been redefined, this is the same as \popQED@elt{foo}\relax\relax and, according to the definition of \popQED@elt,

#1 <- {foo}
#2 <- 

and therefore

foo\gdef\QED@stack{}\relax

would remain in the main token list (the braces are stripped off by rule of TeX). In case \QED@stack had been \qed@elt{bar}\qed@elt{foo}, we'd have

#1 <- {bar}
#2 <- \qed@elt{foo}

and bar\gdef\QED@stack{\qed@elt{foo}}\relax would be pushed into the main input stream.

Just the fact that the expansion of \popQED begins with \begingroup disqualifies it from being legal inside \csname...\endcsname; moreover assignments cannot be performed in that context, so it's a lost battle to begin with.

The double \relax is in case the stack is empty at the time \popQED is called, that is without a matching \pushQED command.

What's the main usage of the system? The standard proof environment in amsthm.sty is defined as

    432 \newenvironment{proof}[1][\proofname]{\par
    433   \pushQED{\qed}%
    434   \normalfont \topsep6\p@\@plus6\p@\relax
    435   \trivlist
    436   \item[\hskip\labelsep
    437         \itshape
    438     #1\@addpunct{.}]\ignorespaces
    439 }{%
    440   \popQED\endtrivlist\@endpefalse
    441 }

The idea is that a subordinate proof environment might define its own tombstone symbol and push it in the stack, so at end environment the right symbol would be used.


Can you use stacks for this purpose? Yes.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newstack}{m}
 {
  \seq_new:c { g_thorsten_#1_stack_seq }
 }

\NewDocumentCommand{\push}{mm}
 {% #1 is the stack's name, #2 the item to push
  \seq_gpush:cn { g_thorsten_#1_stack_seq } { #2 }
 }

\NewDocumentCommand{\pop}{mo}
 {% #1 is the stack's name, #2 what you should do with the top item
  % reinitialize, in case it has been modified
  \cs_set_eq:NN \__thorsten_stack_exec:n \__thorsten_stack_exec_default:n
  \IfValueT{ #2 }
   {
    \cs_set:Nn \__thorsten_stack_exec:n { #2 }
   }
  \seq_gpop:cNTF { g_thorsten_#1_stack_seq } \l__thorsten_stack_item_tl
   {% if the stack is not empty
    \__thorsten_stack_exec:V \l__thorsten_stack_item_tl
   }
   {% if the stack is empty, issue an error
    \__thorsten_stack_exec:n { \STACKEMPTYERROR }
   }
 }

\tl_new:N \l__thorsten_stack_item_tl
\cs_new_protected:Nn \__thorsten_stack_exec_default:n { #1 }
\cs_set_eq:NN \__thorsten_stack_exec:n \__thorsten_stack_exec_default:n
\cs_generate_variant:Nn \__thorsten_stack_exec:n { V }

\ExplSyntaxOff

\newstack{env}

\newenvironment{myEnv}[1][default]
 {%
  \push{env}{#1}%
  \csname x#1\endcsname
 }
 {%
  \pop{env}[\csname endx##1\endcsname]%
 }

\newenvironment{xdefault}{\par start}{finish\par}
\newenvironment{xinner}{\par startinner}{finishinner\par}

\begin{document}

\begin{myEnv}
\begin{myEnv}[inner]
\end{myEnv}
\end{myEnv}

\newstack{foo}

\push{foo}{A}
\push{foo}{B}
\push{foo}{C}

\pop{foo}[@@#1@@]
\pop{foo}[??#1??]
\pop{foo}[!!#1!!]
\pop{foo}[---#1---]

\end{document}

The \push command takes as arguments the stack's name and the item to push. \pop takes as mandatory argument the stack's name and the optional argument is a template for what to do with the popped item (default is to just deliver it) after removing the item from the top of the stack.

Be careful with spaces in your input: \csname x#1 \endcsname is not the same as \csname x#1\endcsname.

enter image description here

Since in the last example the \pop operation is called on an empty stack, an error is produced

! Undefined control sequence.
<argument> \STACKEMPTYERROR 

l.69 \pop{foo}[---#1---]
  • Thanks for that very detailed explanation. For now I will stick to the xparse package, but I'm sure this will be usefull in the future. At the very least it's a great explanation for pushQED/popQED. – Thorsten Schmitz May 20 at 9:39

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.