1

My \Render that attempts to iterate a list and invoke macros dynamically produces errors. The given MWE with detailed comments tells what my objective is. How to fix it? I have no more idea how to fix the following errors:

enter image description here

MWE

\documentclass{book}

\usepackage{filecontents}
% There is a huge number of Japanese words as follows.
% Format: \NewWord{<word macro name>}{<word in Kanji>}{<meaning in English>}
\begin{filecontents*}{vocabularies.tex}
\NewWord{watashi}{私}{I}
\NewWord{ki@spirit}{気}{spirit}
\NewWord{ki@tree}{木}{tree}
\NewWord{aikidou}{合気道}{aikidou}
\end{filecontents*}


\usepackage{xeCJK}
\usepackage{etoolbox}
\setmainfont{Cambria}
\setCJKmainfont{ipaexm.ttf}
\usepackage{pgffor}

% \FlashCard is used to create a flash card.
% Format: \FlashCard{<word in Kanji>}{<meaning in English>}
\newcommand\FlashCard[2]{\fbox{#1: #2} }

\gdef\Pushed{}
% \Push is used to push "macro name" into \Pushed.
% \Pushed is a comma separated list of "macro name".
\newcommand\Push[1]{\xdef\Pushed{#1,\Pushed}}


% #1: macro name, 
% #2: word in Kanji, 
% #3: meaning in English
% ----------------------
\newcommand\NewWord[3]{%
    %
    % create conditional macro
    \expandafter\newif\csname if#1IsInserted\endcsname
    % set the conditional macro to false
    \csname #1IsInsertedfalse\endcsname
    %
    % create flash card macro   
    \expandafter\newrobustcmd\csname#1FlashCard\endcsname{\FlashCard{#2}{#3}}%
    %
    % create "word macro",
    \expandafter\newrobustcmd\csname#1\endcsname[1][#2]{%
        % output
        ##1%
        % uniqueness routine
        \csname if#1IsInserted\endcsname
        % do nothing
        \else
            \Push{#1} 
            \csname #1IsInsertedtrue\endcsname
        \fi
    }%
}


\newcommand\Render{%
    \par Flash Cards:\\[12pt]%
    % For each <element> in \Pushed, invoke its <element>FlashCard and
    % set <element>IsInserted to false.
    \foreach \x in \Pushed {\csname\x FlashCard\endcsname\global\csname\x IsInsertedfalse\endcsname}%
    %
    % Make \Pushed empty
    \gdef\Pushed{}%
}

\makeatletter
\input{vocabularies.tex}

\begin{document}

\begin{enumerate}
\item 
\watashi は合\ki@spirit 道が好きです。 いい天\ki@spirit ですので、木の下に座っています。
\Render

\item 
\ki@tree の下に誰もいないです。
\Render
\end{enumerate}
\end{document}
2
  • 4
    the posted code runs without error in texlive 2015 xelatex. please don't just have a title "please fix this error" make title (and words in the question) describe the error so it is useful for future searching in the archive – David Carlisle Dec 7 '15 at 16:39
  • @DavidCarlisle: See my last update. I think the code you tested is my first code where \Render was commented (disabled). Please kindly try the last one. – Money Sets You Free Dec 7 '15 at 21:29
3

You had a trailing , in your list and that meant in the last step \x was empty and generated errors:

\documentclass{book}

\usepackage{filecontents}
% There is a huge number of Japanese words as follows.
% Format: \NewWord{<word macro name>}{<word in Kanji>}{<meaning in English>}
\begin{filecontents*}{vocabularies.tex}
\NewWord{watashi}{私}{I}
\NewWord{ki@spirit}{気}{spirit}
\NewWord{ki@tree}{木}{tree}
\NewWord{aikidou}{合気道}{aikidou}
\end{filecontents*}


\usepackage{xeCJK}
\usepackage{etoolbox}
\setmainfont{Cambria}
\setCJKmainfont{ipaexm.ttf}
\usepackage{pgffor}

% \FlashCard is used to create a flash card.
% Format: \FlashCard{<word in Kanji>}{<meaning in English>}
\newcommand\FlashCard[2]{\fbox{#1: #2} }

\gdef\Pushed{}
% \Push is used to push "macro name" into \Pushed.
% \Pushed is a comma separated list of "macro name".
\newcommand\Push[1]{\xdef\Pushed{#1\ifx\Pushed\empty\else,\Pushed\fi}}


% #1: macro name, 
% #2: word in Kanji, 
% #3: meaning in English
% ----------------------
\newcommand\NewWord[3]{%
    %
    % create conditional macro
    \expandafter\newif\csname if#1IsInserted\endcsname
    % set the conditional macro to false
    \csname #1IsInsertedfalse\endcsname
    %
    % create flash card macro   
    \expandafter\newrobustcmd\csname#1FlashCard\endcsname{\FlashCard{#2}{#3}}%
    %
    % create "word macro",
    \expandafter\newrobustcmd\csname#1\endcsname[1][#2]{%
        % output
        ##1%
        % uniqueness routine
        \csname if#1IsInserted\endcsname
        % do nothing
        \else
            \Push{#1} 
            \csname #1IsInsertedtrue\endcsname
        \fi
    }%
}


\newcommand\Render{%
    \par Flash Cards:\\[12pt]%
    % For each <element> in \Pushed, invoke its <element>FlashCard and
    % set <element>IsInserted to false.
%\show\Pushed
    \foreach \x in \Pushed {%
%\show\x
\csname\x FlashCard\endcsname\global\csname\x IsInsertedfalse\endcsname}%
    %
    % Make \Pushed empty
    \gdef\Pushed{}%
}

\makeatletter
\input{vocabularies.tex}

\begin{document}

\begin{enumerate}
\item 
\watashi は合\ki@spirit 道が好きです。 いい天\ki@spirit ですので、木の下に座っています。
\Render

\item 
\ki@tree の下に誰もいないです。
\Render
\end{enumerate}
\end{document}

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.