% \iffalse meta-comment % % Copyright (C) 2012 by Shengjun Pan % ------------------------------------------------------- % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.2 % of this license or (at your option) any later version. % The latest version of this license is in: % % http://www.latex-project.org/lppl.txt % % and version 1.2 or later is part of all distributions of LaTeX % version 1999/12/01 or later. % % \fi % % \iffalse %<*driver> \ProvidesFile{lmake.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{lmake} %<*package> [2012/02/29 v1.0 .dtx lmake file] % % %<*driver> \documentclass{ltxdoc} \usepackage{amsmath,amssymb} \usepackage[width=5.5in,height=8.6in]{geometry} \usepackage{multirow} \usepackage{graphicx} \usepackage{makeidx} \usepackage[usenames]{color} \usepackage{lmake}[2012/02/29] \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{lmake.dtx} \PrintChanges \PrintIndex \end{document} % % \fi % % \CheckSum{412} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v1.0}{\filedate}{Initial version} % % \GetFileInfo{lmake.dtx} % % \DoNotIndex{\newcommand,\newenvironment} % \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ } % \DoNotIndex{\def,\edef,\if,\else,\fi,\begingroup,\endgroup} % \DoNotIndex{\@ifpackageloaded,\advance,\cdots,\csname,\endcsname} % \DoNotIndex{\dotsb,\dotsc,\empty,\end,\expandafter,\global} % \DoNotIndex{\i,\ifcase,\ifnum,\ifx,\or,\relax,\string,\the,\let} % \DoNotIndex{\ldots,\newcount,\newif,\noexpand,\protected@edef} % % % \title{The \texttt{lmake} package\thanks{This document % corresponds to \texttt{lmake}~\fileversion, dated \filedate.}} % \author{Shengjun Pan \\ \texttt{panshengjun@gmail.com}} % \date{} % \maketitle % \newcommand{\bs}{\char`\\} % \newcommand{\us}{\char`\_} % \newcommand{\ur}{\char`\^} % \renewcommand{\arraystretch}{1.2} % \setlength{\fboxsep}{1ex} % \definecolor{lightGray}{rgb}{0.85,0.85,0.85} % \definecolor{lightBlue}{rgb}{0.75,0.75,1} % \noindent\hspace*{-0.075\textwidth}\colorbox{lightGray}{\begin{minipage}{1.15\textwidth} % \[ % \lcmd{\hat}{h}{X,A,B,F,\mu,\phi,\sigma} % \lmake[\int_{\hX_\i=\hA_\i}^{\hB_\i},\empty] % \binom{N}{\lmake[\i\hphi_\i,,m]} % \lmake[e^{-\frac{(\hX_\i-\hmu_\i)^2}{2\hsigma_\i^2}},c=] % \lmake[d\hX_\i,\,] % \] % \tt % \bs lcmd\{\bs hat\}\{h\}\{X,A,B,F,\bs mu,\bs phi,\bs sigma\}\\ % \bs lmake[\bs in\us\{\bs hX\us\bs i=\bs hA\us\bs i\}\ur\{\bs hB\us\bs i\},\bs empty]\\ % \bs binom\{N\}\{\bs lmake[\bs i\bs hphi\us\bs i,,m]\}\\ % \bs lmake[e\ur\{-\bs frac\{(\bs hX\us\bs i-\bs hmu\us\bs i)\ur2\}\{2\bs hsigma\us\bs i\ur2\}\},c=]\\ % \bs lmake[d\bs hX\us\bs i,\bs,] % \end{minipage}} % \section{Introduction} % This package provides macros for \LaTeX2e to simplify typesetting a % list of phrases that fit a pattern.\\ % \begin{tabular}{ll} % \tt \char`\\lcmd % & makes a list of new commands by adding a prefix to existing % commands.\\ % \tt\char`\\lmake % & makes a list of the form $p(i_1),p(i_2),\dotsc,p(i_n)$, where % $p(.)$ stands for \emph{pattern}. % \end{tabular} % \section{Usage and examples} % \label{sec:usage} % \DescribeMacro{\lcmd} % \fcolorbox{black}{lightBlue}{\tt \char`\\lcmd\{command\}\{prefix\}\{list\}}\\[2ex] % makes a list of new commands from \texttt{command} by adding \texttt{prefix} % to each item in the comma-separated \texttt{list}. If an item in the % list is a macro, only its name is prefixed; the backslash is stripped away.\\[3ex] % \textbf{Examples}: % \footnote{The examples used in this document require packages {\tt amsmath, % amssymb} and {\tt graphicx}.}\\[1ex] % \lcmd{\mathcal}{c}{A,X,P} % \lcmd{\mathbb}{bb}{Z,R,E} % \lcmd{\overline}{vct}{x,\phi,psi} % \begin{tabular}{l@{ defines: }lll} % \hline % \verb|\lcmd{\mathcal}{c}{A,X,P}| % &\texttt{\char`\\ cA} $\to \cA$ % &\texttt{\char`\\ cX} $\to \cX$ % &\texttt{\char`\\ cP} $\to \cP$ % \\ % \verb|\lcmd{\mathbb}{c}{A,X,P}| % &\texttt{\char`\\ bbZ} $\to \bbZ$ % &\texttt{\char`\\ bbR} $\to \bbR$ % &\texttt{\char`\\ bbE} $\to \bbE$\\ % \verb|\lcmd{\overline}{vct}{x,psi,\phi}| % &\texttt{\char`\\ vctx} $\to \vctx$ % &\texttt{\char`\\ vctpsi} $\to \vctpsi$ % &\texttt{\char`\\ vctphi} $\to \vctphi$\\ % \hline % \end{tabular}\\[2ex] % In the last example the new command for \verb|\phi| is % \verb|\vctphi|, not \verb|\vct\phi|. Notice the difference between % \verb|\vctphi| and \verb|\vctpsi|.\\[4ex] % \DescribeMacro{\lmake} % \fcolorbox{black}{lightBlue}{\tt\bs lmake[[key1=]value1,[key2=]value2,...]}\\[2ex] % makes a list of symbols by key-value pairs. Valid keys are % described in the following table.\\[3ex] % \begin{tabular}{@{\tt }rll} % \hline % keys & default & description\\ % \hline % p & \verb|\i| & Pattern. All occurrences of \verb|\i| will be replaced % by the corresponding index.\\ % c & \verb|,| & Separator.\\ % n &\verb|n| & Last index.\\ % 1 & \verb|1| & First index.\\ % 2 & \verb|2| & Second index.\\ % d & \verb|\ldots|, \verb|\cdots| & Dots. If the separator is comma, % \verb|\ldots| is used; otherwise \verb|\cdots| is used.\\ % & \verb|\dotsc|, \verb|\dotsb| & If \verb|amsmath| is loaded, % \verb|\dotsc| and \verb|\dotsb| are used respectively.\\ % $\ell$ & \verb|{}| & List of comma-separated symbols.\\ % \hline % \end{tabular}\\[3ex] % \textbf{Examples}:\\[1ex] % \begin{tabular}{ll} % \hline % what you type & what you see\\ % \hline % \verb|\lmake[]| & $\lmake[]$\\ % \verb|\lmake[2=]| & $\lmake[2=]$\\ % \verb|\lmake[x_\i,c=]| & $\lmake[x_\i,c=]$\\ % \verb|\lmake[x_\i,,N]| & $\lmake[x_\i,,N]$\\ % \verb|\lmake[x_\i,\ge,k]| & $\lmake[x_\i,\ge,k]$\\ % \verb|\lmake[\bar x_{\i},\circ,1=i,i+1]| & $\lmake[\bar x_{\i},\circ,1=i,i+1]$\\ % \verb|\lmake[p_\i^{\mu_\i},c=,m]| & $\lmake[p_\i^{\mu_\i},c=,m]$\\ % \verb|\lmake[N_\i!,\,,\Gamma,\alpha,\beta]| & $\lmake[N_\i!,\,,\Gamma,\alpha,\beta]$\\ % \verb|\lmake[\left(\frac{\i}{\i+1}\right),\!]| % & $\lmake[\left(\frac{\i}{\i+1}\right),\!]$\\ % \verb|\lmake[(e_\i+1),c=,k,1,2]| & $\lmake[(e_\i+1),c=,k,1,2]$\\[1ex] % \verb|\lmake[x_{\i},l={1,3,5,11}]| % & $\lmake[x_{\i},l={1,3,5,11}]$\\ % \verb|\lmake[\rotatebox{-30}{\i},\to,l={A,B,C,D}]| % & $\lmake[\rotatebox{-30}{\i},\to,l={A,B,C,D}]$\\ % \hline % \end{tabular}\\[2ex] % \emph{Remarks:} % \begin{itemize} % \item If $\tt \ell$ is empty, the resulting list has the following form:\\ % \verb|p(1) c p(2) c d c p(n)| % % If $\tt \ell$ is not empty, the resulting list has the % following form, for the example $\tt \ell=\{x,y,z,u\}$:\\ % \verb|p(x) c p(y) c p(z) c p(u)| % \item A \underline{non-empty item without \texttt{=}} in the argument % list is treated as a value. Normally the key-value pairs can appear % out of order in the argument list to \verb|\lmake|. For fast typing % the key can be omitted. The missing key is searched, starting from % the key that would follow the previous key in the table-order. Only % keys without values are searched. % % For example, in \verb|\lmake[\bar x_{\i},\circ,1=i,i+1]|, the % missing key for \verb|\bar x_{\i}| is \verb|p|, the missing key for % \verb|\circ| is \verb|c| since it follows \verb|p| in the % table. Similarly, the missing key for \verb|i+1| is \verb|2| since % it follows the previous key \verb|1| in the able. % \item A key not appearing or skipped in the argument list takes its % default value, unless it's been searched as a missing key and given % a value. % % For example, in \verb|\lamke[x_\i,,N]|, all keys except for \verb|p| % and \verb|n| take default values. Particularly, the key \verb|c| is % skipped and it is treated as missing. % % Note that a skipped key does not take value \emph{empty}. To force a % value to be empty, use one of the following workarounds: % {\tt \char`\\empty}, {\tt key=}, {\tt key=\char`\\empty}, or {\tt % key=\{\}}. % \end{itemize} % % \StopEventually{} % % \section{Implementation} % This section explains in details how verb|\lmake|, \verb|\lcmd| and % necessary internal macros are implemented. % \begin{macro}{\L@Compare} % \verb|\L@Compare{string1}{string2}|\\ % compares two strings. The two arguments are fully expanded before compassion. % \verb|\ifL@Equal| is a Boolean variable for storing the result. % \begin{macrocode} \newif\ifL@Equal \def\L@Compare#1#2{% \protected@edef\L@a{#1}\protected@edef\L@b{#2}% \ifx\L@a\L@b\L@Equaltrue\else\L@Equalfalse\fi} % \end{macrocode} % \end{macro} % \begin{macro}{\L@FuzzyCompare} % \verb|\L@FuzzyCompare{string1}{string2}|\\ % tests if two strings are the same, where white spaces preceding the % second argument are ignores. This allows flexible writing of % the comma-separated argument to \verb|\lmake| so that spaces may be inserted % between an item and the previous comma. % \begin{macrocode} \def\L@FuzzyCompare#1#2{% \L@Compare{#1}{#2}\ifL@Equal\else\L@Compare{#1}{ #2}\fi} % \end{macrocode} % \end{macro} % \begin{macro}{\L@SoftCompare} % \verb|\L@SoftCompare{string1}{string2}|\\ % similar to \verb|\L@Compare|, but does not expand the two % strings. This is usefully if either argument contains undefined % macros, for example, the value to the key \verb|p| in the argument to \verb|\lmake|. % \begin{macrocode} \def\L@SoftCompare#1#2{% \def\L@a{#1}\def\L@b{#2}% \ifx\L@a\L@b\L@Equaltrue\else\L@Equalfalse\fi} % \end{macrocode} % \end{macro} % \begin{macro}{\L@FuzzySoftCompare} % \verb|\L@FuzzySoftCompare{string1}{string2}|\\ % similar to \verb|L@FuzzyCompare|, but uses \verb|\L@SoftCompare| % instead of \verb|\L@Compare|. % \begin{macrocode} \def\L@FuzzySoftCompare#1#2{% \L@SoftCompare{#1}{#2}\ifL@Equal\else\L@SoftCompare{#1}{ #2}\fi} % \end{macrocode} % \end{macro} % \begin{macro}{\L@HasEqualSign} % \verb|\L@HasEqualSign{string}|\\ % tests if a string has an equal sign \verb|=|. This is used to test % if an argument to \verb|\lmake| is a key-value pair or just a % value. It is defined indirectly via \verb|\L@HES|, which is a tail % recursion for scanning the tokens in its argument.\\[1ex] % \verb|\L@Ignore| is an auxiliary macro that simply ignores its % argument. The test result is stored in \verb|\ifL@HasEqualSign|. % \begin{macrocode} \def\L@Ignore#1\end{} \newif\ifL@HasEqualSign \def\L@HasEqualSign#1{% \L@HasEqualSignfalse\L@HES#1\end} \def\L@HES#1{% \ifx#1=\L@HasEqualSigntrue\let\L@Next=\L@Ignore% \else\ifx#1\end\let\L@Next=\relax\else\let\L@Next=\L@HES\fi% \fi\L@Next} % \end{macrocode} % \end{macro} % \begin{macro}{\L@ArName} % \verb|\L@ArName[index]|\\ % returns the name of a macro via a numeric index. % \begin{macrocode} \def\L@ArName[#1]{\ifcase#1 L@Pattern\or L@Comma\or L@Last\or% L@First\or L@Second\or L@Dots\or L@List\else L@Other\fi} % \end{macrocode} % \end{macro} % \begin{macro}{\L@Set,\L@Get} % \verb|\L@Set[index]=value;|\\ % \verb|\L@Get[Index]|\\ % set and get the value of a macro by a numeric index. Numeric indices are % used to locate missing keys in the argument to \verb|\lmake|. % \begin{macrocode} \def\L@Set[#1]=#2;{\global\expandafter\let\csname\L@ArName[#1]\endcsname=#2} \def\L@Get[#1]{\csname\L@ArName[#1]\endcsname} % \end{macrocode} % \end{macro} % \begin{macro}{\L@LDots,\L@Cdots} % denotes the default macro for low dots. If \verb|amsmath| is loaded before % \verb|\lmake|, \verb|\L@LDots| is set to \verb|\dotsc| and % \verb|\L@Cdots| is set to \verb|\dotsb|. Otherwise \verb|\L@LDots| % is set to \verb|\ldots| and \verb|\L@Cdots| is set to \verb|\cdots|. % \begin{macrocode} \@ifpackageloaded{amsmath} {\def\L@Ldots{\dotsc}\def\L@Cdots{\dotsb}} {\def\L@Ldots{\ldots}\def\L@Cdots{\cdots}} % \end{macrocode} % \end{macro} % \begin{macro}{\L@Map} % \verb|\L@Map{function}{list}{new separator}|\\ % maps a list of comma-separated items to a new list, so that each % item is transformed using the given function, and the commas are % replaced with the new separator. It is defined indirectly % indirectly via \verb|\L@Iterate|, which is a tail recursion for % scanning the comma-separated list.\\[1ex] % \verb|\ifL@Start| is used to indicate if the current item is the % first item, which is not preceded by a comma, unlike the remaining % items.\\[1ex] % \verb|\L@Map| % \begin{macrocode} \newif\ifL@Start \def\L@Map#1#2#3{% \def\L@Sym{\empty}\def\LM@Func{#1}\def\L@Sep{#3}% \L@Starttrue\expandafter\L@Iterate#2,\end} \def\L@Iterate#1,#2{% \LM@Func{#1}% \ifx#2\end\let\L@Next=\relax\def\L@Nextarg{\empty}% \else\L@Sep\let\L@Next=\L@Iterate\def\L@Nextarg{#2}\fi% \expandafter\L@Next\L@Nextarg} % \end{macrocode} % \end{macro} % \begin{macro}{\L@GetKeyValue} % \verb|\L@GetKeyValue{key-value pair}|\\ % extracts the key and value from a string, and store them in % \verb|\L@Key| and \verb|\L@Value| respectively. If the argument has no % equal sign, it is used as a value and the key is set to empty. Otherwise, % \verb|\L@GetKV| is called to extract the key and value. % \begin{macrocode} \def\L@GetKeyValue#1{% \def\L@Key{}\def\L@Value{}\L@HasEqualSign{#1}% \ifL@HasEqualSign\L@GetKV#1\end% \else\def\L@Key{}\def\L@Value{#1}% \fi} \def\L@GetKV#1=#2\end{% \def\L@Key{#1}\def\L@Value{#2}} % \end{macrocode} % \end{macro} % \begin{macro}{\L@Parse} % \verb|\L@Parse{list}|\\ % parses a list of comma-separated items, extracts each item, % extract its key and value, looks for keys \verb|p|, \verb|c|, % \verb|n|, \verb|1|, \verb|2|, \verb|d| and \verb|l|, and finally assigns the % corresponding values to \verb|\L@Pattern|, \verb|\L@Comma|, % \verb|\L@Last|, \verb|\L@First|, \verb|\l@Second|, \verb|\L@Dots| % and \verb|\L@List| respectively.\\[1ex] % The counter \verb|\L@idx| is the index of the next key yet to be assigned % with an value. % \begin{macrocode} \newcount\L@idx % \end{macrocode} % If the list is not empty, then it calls a tail recursion \verb|\l@PRS|. % \begin{macrocode} \def\L@Parse#1{\L@idx=0% \L@FuzzySoftCompare{#1}{}% \ifL@Equal\else\def\L@Extra{}\L@PRS#1,\end,\fi} % \end{macrocode} % An artificial item \verb|,\end,| % is added to the end of the actual list, which terminates the % recursion when encountered. % \begin{macrocode} \def\L@PRS#1,{% \L@SoftCompare{#1}{\end}\ifL@Equal% \let\L@Next=\relax% \else% % \end{macrocode} % If an item is empty, the missing key is searched and % the corresponding default value is used. % \begin{macrocode} \L@FuzzySoftCompare{#1}{}\ifL@Equal% \ifnum\L@idx<7% \ifcase\the\L@idx% \def\L@Default{\i}% \or\def\L@Default{,}% \or\def\L@Default{n}% \or\def\L@Default{1}% \or\def\L@Default{2}% \or\def\L@Default{}% \or\def\L@Default{}% \fi% \L@Set[\the\L@idx]=\L@Default;% \advance \L@idx by 1% \fi% % \end{macrocode} % If the item is not empty, the key and value are extracted. Depending % on what the key is, the value is assigned to the approximate macro. % \begin{macrocode} \else% \L@GetKeyValue{#1}\let\L@CV=\L@Value% \L@FuzzyCompare{\L@Key}{p}\ifL@Equal\L@idx=1\L@Set[0]=\L@CV;% \else\L@FuzzyCompare{\L@Key}{c}\ifL@Equal\L@idx=2\L@Set[1]=\L@CV;% \else\L@FuzzyCompare{\L@Key}{n}\ifL@Equal\L@idx=3\L@Set[2]=\L@CV;% \else\L@FuzzyCompare{\L@Key}{1}\ifL@Equal\L@idx=4\L@Set[3]=\L@CV;% \else\L@FuzzyCompare{\L@Key}{2}\ifL@Equal\L@idx=5\L@Set[4]=\L@CV;% \else\L@FuzzyCompare{\L@Key}{d}\ifL@Equal\L@idx=6\L@Set[5]=\L@CV;% \else\L@FuzzyCompare{\L@Key}{l}\ifL@Equal\L@idx=7\L@Set[6]=\L@CV;% % \end{macrocode} % If an item is a value without a key, the missing key is searched and % given the current value. % \begin{macrocode} \else\L@FuzzyCompare{\L@Key}{}\ifL@Equal% \ifnum\L@idx<7% \L@Set[\the\L@idx]=\L@CV;% \fi% \advance \L@idx by 1% \fi\fi\fi\fi\fi\fi\fi\fi\fi% \let\L@Next=\L@PRS% \fi% \L@Next} % \end{macrocode} % \end{macro} % \begin{macro}{\lmake} % \verb|\lmake[key-value list]|\\ % makes a list of symbols using the given key-value % pairs. \verb|\ifL@FoundFirst| is used to indicate if the first % non-empty symbol is encountered; the first symbol is not preceded % by a separator. % \begin{macrocode} \newif\ifL@FoundFirst % \end{macrocode} % \verb|\L@Parse| is used twice. The first time it is used to set the % default values. The second time it is used to set the values % supplied by the argument list. % \begin{macrocode} \newcommand{\lmake}[1][]{% \begingroup% \L@Parse{p=\i,c={,},d=,1=1,2=2,n=n,l=}% \L@Parse{#1}% % \end{macrocode} % The pattern is used to define the transforming function % \verb|\L@Func| by replacing all occurrences of \verb|\i| by the % actual argument. % \begin{macrocode} \def\L@Func##1{\def\i{##1}\L@Get[0]}% % \end{macrocode} % If the key \verb|d| is not given a value, its value is automatically determined by % the value of the separator. % \begin{macrocode} \L@Compare{\L@Dots}{\empty}\ifL@Equal% \L@Compare{\L@Comma}{,}\ifL@Equal% \def\L@Dots{\L@Ldots}\else\def\L@Dots{\L@Cdots}% \fi \fi % \end{macrocode} % The last step is to typeset the list of symbols. If the value to the key $\ell$ is % missing, the typeset list starts with two symbols followed by the dots and % ends with the last symbol. The symbols and dots are separated by the % separator. % \begin{macrocode} \L@Compare{\L@List}{\empty}\ifL@Equal% \L@FoundFirstfalse% \L@Compare{\L@First}{\empty}\ifL@Equal\else% \L@Func{\L@First}\L@FoundFirsttrue% \fi% \L@Compare{\L@Second}{\empty}\ifL@Equal\else% \ifL@FoundFirst\L@Comma\fi% \L@Func{\L@Second}\L@FoundFirsttrue% \fi% \L@Compare{\L@Dots}{\empty}\ifL@Equal\else% \ifL@FoundFirst\L@Comma\fi\L@Dots% \fi% \L@Compare{\L@Last}{\empty}\ifL@Equal\else% \L@Comma\L@Func{\L@Last}% \fi% % \end{macrocode} % If a non-empty value to the key $\ell$ is given, the typeset list % consists of symbols from the items in the value of $\ell$, % transformed by the pattern function. % \begin{macrocode} \else% \L@Map{\L@Func}{\L@List}{\L@Comma}% \fi% \endgroup} % \end{macrocode} % \end{macro} % \begin{macro}{\L@CmdName} % \verb|\L@CmdName{string}|\\ % returns the string itself if it is not a macro, otherwise returns % the macro name with the backslash stripped away. This is an % auxiliary function to \verb|\lcmd|. % \begin{macrocode} \def\L@CmdName#1{% \if\noexpand#1\noexpand\L@anycmd\expandafter\L@StripFirst\string#1\else#1\fi} \def\L@StripFirst#1#2{#2} % \end{macrocode} % \end{macro} % \begin{macro}{\lcmd} % \verb|\lcmd{command}{prefix}{list}|\\ % makes a list of new commands. See Section~\ref{sec:usage} for more details. % \begin{macrocode} \def\lcmd#1#2#3{% \def\L@MakeCmd##1{% \expandafter\def\csname #2\L@CmdName##1\endcsname{#1{##1}}}% \L@Map{\L@MakeCmd}{#3}{}} % \end{macrocode} % \end{macro} % \Finale \endinput