由于 xparse 和 \newenvironment 导致的奇怪错误消息

由于 xparse 和 \newenvironment 导致的奇怪错误消息

当我编译我的文档时出现以下奇怪的错误:

! Incomplete \ifcase; all text was ignored after line 256.
<inserted text> 
                \fi 
l.256       \foo[
             0]{|>I>-:a:c.-:a:c:c b|}\\
? 

这远非一个最小的工作示例,但这里有其中的相关部分:

\documentclass{article}

\usepackage{xparse}

\usepackage{tikz}
\usetikzlibrary{calc,arrows,patterns,decorations.pathmorphing,backgrounds,fadings,external}
\tikzset{external/system call={pdflatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"}} 
\tikzexternalize[prefix=figures/cache/] %,up to date check=md5]

% Colors
\definecolor{tape}{rgb}{.9,.9,.9}
\definecolor{transition}{rgb}{.1,.4,.9}
\definecolor{quantum}{rgb}{1,.8,.1}
\newcommand{\ta}{.8}
\newcommand{\dx}{.175}
\tikzfading[name=fade down, top color=transparent!0, bottom color=transparent!100]
\tikzfading[name=fade up, top color=transparent!100, bottom color=transparent!0]

\pgfdeclarelayer{blurb}
\pgfdeclarelayer{pipe}
\pgfdeclarelayer{tape}
\pgfdeclarelayer{quantum}
\pgfsetlayers{background,blurb,pipe,tape,quantum,main}

% Graph environments
% need to use environ package to work with externalizing tikz for caching
\usepackage{environ}
\NewEnviron{tape}[1][1]{%
%\newenvironment{tape}[1][1]{%
%expand body command exactly once, then take md5 sum from it
\tikzsetnextfilename{\pdfmdfivesum{\expandafter\detokenize\expandafter\expandafter\expandafter{\csname BODY\endcsname}}}%
\begin{tikzpicture}[
  tape/.style = {fill = tape, draw = tape, line width=\dx\ts, align = center, rounded corners=.1\ts},
  debug/.style = {fill = none, draw = none},
  quantum/.style = {fill = quantum, draw = quantum, line width=\dx\ts, align = center, rounded corners=.1\ts},
  transition/.style = {fill = transition, draw=none, line width=\dx\ts},
  draw=black,
  line width=.08\ts,
  baseline = #1,
  x=\ta\ts,y=\ts
  ]
%}{
\BODY
  \begin{pgfonlayer}{tape}
      \draw[tape] (0,0) rectangle (\thetx+\thetx*\dx-\dx,1);
  \end{pgfonlayer}
      \draw[debug] (current bounding box.north east) rectangle (current bounding  box.south west);
\end{tikzpicture}%
}

% Tape symbol macro
\makeatletter
\newcommand\tapesymbols[1]{%
  \@tapesymbols#1\@nnil
}
\def\@tapesymbols#1{%
  \ifx\@nnil#1\relax\else%
  \@nameuse{tapesymbols@char@#1\expandafter}%
  \fi
}
\DeclareDocumentCommand \defcharcode { m O{} O{} m }{
  \@namedef{tapesymbols@char@#1}#2#3{
    \begin{scope}[shift={(\thetx + \thetx*\dx,0)}]
      \draw[debug] (0,0) rectangle (\ta\ts,\ts);
      \begin{pgfinterruptboundingbox}
        #4
      \end{pgfinterruptboundingbox}
    \end{scope}
    \stepcounter{tx}
    \@tapesymbols
  }%
}
\makeatother
\DeclareDocumentCommand \inputinkscape{ m O{.01} }{
  \begin{scope}[x=#2\ts,y=#2\ts,yscale=-1,shift={(0,-\ts)}]%have to give explicit units here
    \InputIfFileExists{./figures/#1}{}{\input{#1}}
  \end{scope}
}

% transition and penalty markers
\defcharcode{>}{
  \draw[transition, path fading=fade up] (-\dx,-.2) rectangle (1+\dx,.3);
  \addtocounter{tx}{-1}
}
\defcharcode{<}{
  \draw[transition, path fading=fade down] (-\dx,.7) rectangle (1+\dx,1.2);
  \addtocounter{tx}{-1}
}
\defcharcode{-}{
  \begin{pgfonlayer}{quantum}
    \draw[quantum] (0,0) rectangle (\ta\ts,\ts);
  \end{pgfonlayer}
  \addtocounter{tx}{-1}
}
\defcharcode{,}{
  \begin{pgfonlayer}{quantum}
    \draw[quantum] (0,0) rectangle (2*\ta\ts+6*\dx,\ts);
  \end{pgfonlayer}
  \addtocounter{tx}{-1}
}
% rhombus
\newcommand{\rhombus}[1]{
  \draw[#1] (.1,.5) -- (.5,.8) -- (.9,.5) -- (.5,.2) -- cycle;
}

% symbols
\defcharcode{|}{
  \draw[double=tape] (.5,0) -- (.5,1);
}
\defcharcode{!}{
  \draw[decorate, decoration={coil, aspect=0, amplitude=.04cm, segment length=0.07cm}] (.5,0) -- (.5,1);
}
\defcharcode{?}{
  \draw[line width=1.5*\dx\ts,black] (.5,0) -- (.5,1);
}
\defcharcode{o}{
  \draw[rounded corners=.2] (.1,.1) rectangle (.9,.9);
}
\defcharcode{O}[#1]{
  \draw[rounded corners=.2,fill=black] (.05,.05) rectangle (.95,.95);
  \ifx#1T
    \node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{T}}};
  \else\ifx#1U
    \node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{U}}};
  \else\ifx#1A
    \node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{A}}};
  \else\ifx#1H
    \node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{H}}};
  \else\ifx#1S
    \node[text centered,text height=5,scale=.7,white] at (.5,.4) {\textbf{\textup{S}}};
  \else    
    \node[text centered,text depth=1,white] at (.5,.4) {$#1$};
  \fi\fi\fi\fi\fi
}
\defcharcode{.}{
  \fill (.33,.5) circle [radius=.1];
  \fill (1,.5) circle [radius=.1];
  \fill (1.66,.5) circle [radius=.1];
  \stepcounter{tx}
}
\defcharcode{G}{
  \inputinkscape{ghost}
}
\defcharcode{B}{
  \inputinkscape{ghostb}
}
\defcharcode{g}{
  \inputinkscape{ighost}
}
\defcharcode{b}{
  \inputinkscape{ighostb}
}
\defcharcode{I}{
  \inputinkscape{initializer}
}
\defcharcode{+}{
  \draw[fill,rounded corners=.2] (.1,0) -- (.1,1) -- (1,.5) -- cycle;
  \begin{scope}[line width=1,white,line cap=round]
    \draw (0.2,.5) -- (0.7,.5);
    \draw (0.45,.25) -- (.45,.75);
  \end{scope}
}
\defcharcode{D}{
  \draw[fill,rounded corners=.2] (.1,0) -- (.1,1) -- (1,.5) -- cycle;
}
\defcharcode{X}{
  \draw[rounded corners=.2] (.1,0) -- (.1,1) -- (1,.5) -- cycle;
}
\defcharcode{Y}{
  \draw[rounded corners=.2] (.1,0) -- (.1,1) -- (1,.5) -- cycle;
  \draw[rounded corners=.2] (.3,.3) -- (.3,.7) -- (.65,.5) -- cycle;
}
\defcharcode{Z}{
    \draw[rounded corners=.2] (.9,0) -- (0,.5) -- (.9,1) -- cycle;    
}
\defcharcode{C}{
    \draw[fill, rounded corners=.2] (.9,0) -- (0,.5) -- (.9,1) -- cycle;    
}
\defcharcode{:}[#1]{
  \ifx#1T
    \node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{T}}};
  \else\ifx#1U
    \node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{U}}};
  \else\ifx#1A
    \node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{A}}};
  \else\ifx#1H
    \node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{H}}};
  \else\ifx#1S
    \node[text centered,text height=5,scale=.7] at (.5,.35) {\textbf{\textup{S}}};
  \else
    \node[text centered,text height=5] at (.5,.4) {$#1$};
  \fi\fi\fi\fi\fi
}
\defcharcode{;}[#1]{
  \node[text centered,text height=5,text depth=-0.2] at (.6,.4) {$\dot{#1}$};
}
\defcharcode{"}[#1]{
    \node[text centered,text height=5,text depth=-0.2] at (.6,.4) {$\ddot{#1}$};
}
\defcharcode{*}[#1]{
    \node[text centered,text height=5,text depth=-0.2] at (.6,.4) {$\vec{#1}$};
}
\defcharcode{@}[#1]{
  \draw[fill = black] (0,0) -- (0,1) -- (.6,1) -- (1,.5) -- (.6,0) -- cycle;
  \ifx#1r
    \rhombus{fill=white,draw=none}
  \else\ifx#1T
    \node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{T}}};
  \else\ifx#1U
    \node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{U}}};
  \else\ifx#1A
    \node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{A}}};
  \else\ifx#1H
    \node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{H}}};
  \else\ifx#1S
    \node[text centered,text height=5,scale=.7,white] at (.4,.4) {\textbf{\textup{S}}};
  \else
    \node[text centered,text height=5,white] at (.4,.4) {$#1$};
  \fi\fi\fi\fi\fi\fi
}
\defcharcode{r}{
  \rhombus{}
}
\defcharcode{R}{
  \rhombus{fill=black}
}
\defcharcode{w}{
  \draw (.1,.6) -- (.5,.9) -- (.9,.6);
  \draw (.1,.4) -- (.5,.1) -- (.9,.4);
}

% tape macro
\newlength{\ts}
\newcounter{tx}
\DeclareDocumentCommand \foo { O{0} m } {%
  \settoheight{\ts}{Z}%
  \setlength{\ts}{1.2\ts}%
  \setcounter{tx}{0}%
  \begin{tape}
    \draw[debug] (-#1-#1*\dx-\dx,0) -- (0,1);
    \tapesymbols{#2}
  \end{tape}%
}

\newenvironment{rules}{%
  \renewcommand{\arraystretch}{0.8}%
  \begin{tabular}[t]{@{}l@{}}
}{
  \end{tabular}%
}

\newcommand{\rvdots}{\multicolumn{1}{c}{\vdots}}

\begin{document}
    \begin{rules}
        \foo[0]{|>I>-:a:c.-:a:c:c b|}\\
        \foo[1]{<-:a<>I>:c}\\
        \foo[2]{<:c<I}\\
        \rvdots\\
        \foo[6]{:c>I>:cb|}\\
        \foo[7]{<:c<>I>b|}\\    
        \foo[0]{|-:a:c.-:a:c:c<o<B|}
    \end{rules}
\end{document}

我认为问题是由\DeclareDocumentCommand(采用可选参数)和rules环境的结合引起的。

关于如何修复此问题同时保持相同功能,有什么建议吗?

笔记:我的文档以前编译得很好,但在我更新解析包裹最近。

答案1

\foo是不可扩展的(由于[...]参数),所以尝试\DeclareExpandableDocumentCommand,但我想,可能有比使用\foo这种方式更好的方法。

\documentclass{article}
\usepackage{xparse}

\newenvironment{rules}{%
  \tabular{l}
}{
  \endtabular%
}

\DeclareExpandableDocumentCommand\foo{ O{0} m } {%
}

\begin{document}
\begin{rules}
  \foo[0]{}
\end{rules}
\end{document}

相关内容