%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%% mrecog.tex %%%%% mrecog.sty %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Mathmode control-sequence recognition for TeX/LaTeX % % Version 0.1 (Beta test version) % Last revised: June 26, 1990 % % Author: Robert H. Wentworth (rhw@hoh-1.att.com) % % (C) Copyright 1990 Robert H. Wentworth % % Description: % When this file is included in a TeX or LaTeX file, % (via \input or as a *.sty file) "command sequence recognition" % is activated for all text appearing in math mode. % What this means is that any consecutive sequence of two or more % letters delimited by nonletters will be checked to see if it is % the name of a currently-defined control sequence, and if it is % then the sequence of letters will be replaced by the corresponding % control sequence. The intent is to render equations more % readable by eliminating the need for explicit escape characters % (usually backslashes). % % Examples: % The following samples expand as if backslashes were inserted % in appropriate spots: % % It is obvious that % $$ f(x) = (a times b) % int_0^{infty} g(x) cos(pi log phi)\,d phi $$ % % Note that ``theta'' is not recognized but $theta$ is. % % \def\cis(#1){cos(#1) + i{}sin(#1)} % $$e^{i theta} = cis(theta) qquad \hbox{for $theta$ real}$$ % % Details: % Command sequences with explicit escapes (backslashes) will % continue to be recognized in the normal way. % % Single letters are not recognized as command sequences; to type % a command sequence whose name is a single letter an explicit % escape (backslash) should be used (e.g., $\j$ yields a j without % a dot, but $j$ does not). % % Whitespace (spaces, tabs, returns) may delimit letter-sequences. % Thus if a sequence of letters which should be interpreted literally % is in danger of being recognized as a control sequence, this can % be avoided by inserting a space (or {}) into the sequence % (e.g., $div$ yields a division sign, but $d i v$ or $di{}v$ does not). % % If the count variable \tracingrecognition is set to a positive number % then information regarding what command sequences have been % recognized will be printed to the terminal and the log file. % This is useful for debugging. % % There should be no effect outside mathmode (unless a symbolic % name is used which conflicts with names used in this file; % an attempt has been made to minimize the likelihood of this.) % Active letters cannot be used without conflicting with the % workings of this file, and whitespace must be defined in the % usual way within mathmode. % % Recognition can be turned off/on by either of two mechanisms: % % \dorecognition=0 \dorecognition=1 % This turns recognition off/on very quickly, % but some processing overhead continues to % be present even when recognition is off; % some complicated mathmode macros which object to % the use of active letters might be interfered % with even when recognition is off. % This mechanisim affects only the current % group unless a \global assignment is used. % % \deactivatemathletters \activatemathletters % These require somewhat more processing to % turn recognition off or on, but when % recognition is off mathmode is more % nearly in its native state, so that even % most complicated mathmode macros should % function properly. This mechanism has % global effects. % % Recognition is initially on. % % Recognition is recursive. Thus text generated by macros inside % mathmode will itself be scanned for recognizable control sequence % names. % % The use of the recognition feature will slow down the processing % of equations somewhat, but the additional computations done are % linear in the amount of mathmode letter-text scanned, and the % memory used is more-or-less constant, so pathological slowdowns % or memory overflows are not expected. % % Known limitations: % % Command sequences whose names are followed by spaces which % precede arguments or syntactically significant tokens will % not work properly unless explicitly escaped. Typically % these macros are not part of the natural flow of the % equation anyway, so the use of explicit escapes (backslashes) % is not particularly objectionable. % (This was a design tradeoff. These could have been made to % work, but with the unpleasant side-effect that the sequence % \def\cat{dog}\def\dogflea{mouse} $cat flea$ would expand % to $mouse$; i.e., the space would only act as a delimiter % during the first evaluation.) % Examples: use $\hbox to 1in{...}$ rather than $hbox to 1in{...}$; % or use $hskip1in etc.$ or $\hskip 1in etc.$ rather than % $hskip 1in etc.$. % % The recursive nature of the recognition can cause problems % unless one is careful to prevent them. For example, % \def\dog{{\it dog}} $dog$ causes an infinite recursion. % Special macros are defined in this file that can be used % to prevent such recursion in simple macros: % % \norecogwithin{\dog} will turn off recognition within future % expansions of \dog; note that \dog expands in a group, and % hence some side-effects will only be local; macro should only % be used for macros without arguments. % % \norecogafter{\it} will turn off recognition prior to any % subsequent expansion of \it; note that recognition will % continue to stay off until local group containing \it % ends or \dorecognition=1 occurs. Recognition is turned % off only when \it occurs in mathmode. % % To prevent infinite recursion in common command sequences like % \sin, \cos, etc., this file declares \norecogafter{\rm}. % This redefines \rm (in a relatively minor way). The original % definition of \rm can be restored using \let\rm=\originalrm. % % In general recursive recognition is awkward to make practical % use of. (Recursive evaluation is a side-effect of the implementation % and isn't a priori desirable.) There are various hazards having to do % with differences between the state of letters and spaces under various % circumstances. In a typical problem, the sequence % \def\dog#1{sin #1} $dog{theta}$ % expands to $sintheta$ rather than $\sin\theta$ because the space in % the definition of \dog is an ordinary space which does not serve as % a recognition-delimiter. Moving the definition inside mathmode % doesn't work either, because the letters of space gets scanned as % an ordinary space. (Spaces are modified only when they are first % scanned as a token following a letter-sequence which is a % candidate for recognition.) The example works for \dog defined by % \def\dog#1{sin{}#1} or \def\dog{\sin#1}. % % Improvements/comments: % The author would appreciate hearing about any positive or negative % experiences people may experience in using this feature, and also % about any improvements others may make. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % allow private names using @ in such a way that prior state can be restored. % this should permit file to be used either as a *.sty file or as a simple % \input file. \newif\ifatsignwasaletter \ifcat @a \atsignwasalettertrue \else \atsignwasaletterfalse \catcode`\@=11 \fi % change mathcodes to activate letters in mathmode \def\activatemathletters{% \begingroup \def\doallletters{\do{a}\do{b}\do{c}\do{d}\do{e}\do{f}\do{g}\do{h}\do{i}\do{j} \do{k}\do{l}\do{m}\do{n}\do{o}\do{p}\do{q}\do{r}\do{s}\do{t}\do{u}\do{v} \do{w}\do{x}\do{y}\do{z}\do{A}\do{B}\do{C}\do{D}\do{E}\do{F}\do{G}\do{H} \do{I}\do{J}\do{K}\do{L}\do{M}\do{N}\do{O}\do{P}\do{Q}\do{R}\do{S}\do{T} \do{U}\do{V}\do{W}\do{X}\do{Y}\do{Z}\relax} \def\do##1{\global\mathcode`##1="8000} \doallletters \endgroup} \activatemathletters % set up command to permit deactivation \def\deactivatemathletters{% \global\mathcode`A="7141\global\mathcode`B="7142\global\mathcode`C="7143 \global\mathcode`D="7144\global\mathcode`E="7145\global\mathcode`F="7146 \global\mathcode`G="7147\global\mathcode`H="7148\global\mathcode`I="7149 \global\mathcode`J="714A\global\mathcode`K="714B\global\mathcode`L="714C \global\mathcode`M="714D\global\mathcode`N="714E\global\mathcode`O="714F \global\mathcode`P="7150\global\mathcode`Q="7151\global\mathcode`R="7152 \global\mathcode`S="7153\global\mathcode`T="7154\global\mathcode`U="7155 \global\mathcode`V="7156\global\mathcode`W="7157\global\mathcode`X="7158 \global\mathcode`Y="7159\global\mathcode`Z="715A\global\mathcode`a="7161 \global\mathcode`b="7162\global\mathcode`c="7163\global\mathcode`d="7164 \global\mathcode`e="7165\global\mathcode`f="7166\global\mathcode`g="7167 \global\mathcode`h="7168\global\mathcode`i="7169\global\mathcode`j="716A \global\mathcode`k="716B\global\mathcode`l="716C\global\mathcode`m="716D \global\mathcode`n="716E\global\mathcode`o="716F\global\mathcode`p="7170 \global\mathcode`q="7171\global\mathcode`r="7172\global\mathcode`s="7173 \global\mathcode`t="7174\global\mathcode`u="7175\global\mathcode`v="7176 \global\mathcode`w="7177\global\mathcode`x="7178\global\mathcode`y="7179 \global\mathcode`z="717A\relax} % set up definitions for active uppercase characters {\def\\{A}\catcode`A=\active\xdefA{\noexpand\dolett@r{\\}{\mathchar"7141}}} {\def\\{B}\catcode`B=\active\xdefB{\noexpand\dolett@r{\\}{\mathchar"7142}}} {\def\\{C}\catcode`C=\active\xdefC{\noexpand\dolett@r{\\}{\mathchar"7143}}} {\def\\{D}\catcode`D=\active\xdefD{\noexpand\dolett@r{\\}{\mathchar"7144}}} {\def\\{E}\catcode`E=\active\xdefE{\noexpand\dolett@r{\\}{\mathchar"7145}}} {\def\\{F}\catcode`F=\active\xdefF{\noexpand\dolett@r{\\}{\mathchar"7146}}} {\def\\{G}\catcode`G=\active\xdefG{\noexpand\dolett@r{\\}{\mathchar"7147}}} {\def\\{H}\catcode`H=\active\xdefH{\noexpand\dolett@r{\\}{\mathchar"7148}}} {\def\\{I}\catcode`I=\active\xdefI{\noexpand\dolett@r{\\}{\mathchar"7149}}} {\def\\{J}\catcode`J=\active\xdefJ{\noexpand\dolett@r{\\}{\mathchar"714A}}} {\def\\{K}\catcode`K=\active\xdefK{\noexpand\dolett@r{\\}{\mathchar"714B}}} {\def\\{L}\catcode`L=\active\xdefL{\noexpand\dolett@r{\\}{\mathchar"714C}}} {\def\\{M}\catcode`M=\active\xdefM{\noexpand\dolett@r{\\}{\mathchar"714D}}} {\def\\{N}\catcode`N=\active\xdefN{\noexpand\dolett@r{\\}{\mathchar"714E}}} {\def\\{O}\catcode`O=\active\xdefO{\noexpand\dolett@r{\\}{\mathchar"714F}}} {\def\\{P}\catcode`P=\active\xdefP{\noexpand\dolett@r{\\}{\mathchar"7150}}} {\def\\{Q}\catcode`Q=\active\xdefQ{\noexpand\dolett@r{\\}{\mathchar"7151}}} {\def\\{R}\catcode`R=\active\xdefR{\noexpand\dolett@r{\\}{\mathchar"7152}}} {\def\\{S}\catcode`S=\active\xdefS{\noexpand\dolett@r{\\}{\mathchar"7153}}} {\def\\{T}\catcode`T=\active\xdefT{\noexpand\dolett@r{\\}{\mathchar"7154}}} {\def\\{U}\catcode`U=\active\xdefU{\noexpand\dolett@r{\\}{\mathchar"7155}}} {\def\\{V}\catcode`V=\active\xdefV{\noexpand\dolett@r{\\}{\mathchar"7156}}} {\def\\{W}\catcode`W=\active\xdefW{\noexpand\dolett@r{\\}{\mathchar"7157}}} {\def\\{X}\catcode`X=\active\xdefX{\noexpand\dolett@r{\\}{\mathchar"7158}}} {\def\\{Y}\catcode`Y=\active\xdefY{\noexpand\dolett@r{\\}{\mathchar"7159}}} {\def\\{Z}\catcode`Z=\active\xdefZ{\noexpand\dolett@r{\\}{\mathchar"715A}}} % set up definitions for active uppercase characters \begingroup \let\CATCODE=\catcode \let\GDEF=\gdef \def\DOLETT@R{\noexpand\dolett@r} \def\MATHCHAR{\mathchar} \let\ACTIVE=\active \let\XDEF=\xdef \let\DEF=\def {\DEF\\{a}\CATCODE`a=\ACTIVE\XDEFa{\DOLETT@R{\\}{\MATHCHAR"7161}}} {\DEF\\{b}\CATCODE`b=\ACTIVE\XDEFb{\DOLETT@R{\\}{\MATHCHAR"7162}}} {\DEF\\{c}\CATCODE`c=\ACTIVE\XDEFc{\DOLETT@R{\\}{\MATHCHAR"7163}}} {\DEF\\{d}\CATCODE`d=\ACTIVE\XDEFd{\DOLETT@R{\\}{\MATHCHAR"7164}}} {\DEF\\{e}\CATCODE`e=\ACTIVE\XDEFe{\DOLETT@R{\\}{\MATHCHAR"7165}}} {\DEF\\{f}\CATCODE`f=\ACTIVE\XDEFf{\DOLETT@R{\\}{\MATHCHAR"7166}}} {\DEF\\{g}\CATCODE`g=\ACTIVE\XDEFg{\DOLETT@R{\\}{\MATHCHAR"7167}}} {\DEF\\{h}\CATCODE`h=\ACTIVE\XDEFh{\DOLETT@R{\\}{\MATHCHAR"7168}}} {\DEF\\{i}\CATCODE`i=\ACTIVE\XDEFi{\DOLETT@R{\\}{\MATHCHAR"7169}}} {\DEF\\{j}\CATCODE`j=\ACTIVE\XDEFj{\DOLETT@R{\\}{\MATHCHAR"716A}}} {\DEF\\{k}\CATCODE`k=\ACTIVE\XDEFk{\DOLETT@R{\\}{\MATHCHAR"716B}}} {\DEF\\{l}\CATCODE`l=\ACTIVE\XDEFl{\DOLETT@R{\\}{\MATHCHAR"716C}}} {\DEF\\{m}\CATCODE`m=\ACTIVE\XDEFm{\DOLETT@R{\\}{\MATHCHAR"716D}}} {\DEF\\{n}\CATCODE`n=\ACTIVE\XDEFn{\DOLETT@R{\\}{\MATHCHAR"716E}}} {\DEF\\{o}\CATCODE`o=\ACTIVE\XDEFo{\DOLETT@R{\\}{\MATHCHAR"716F}}} {\DEF\\{p}\CATCODE`p=\ACTIVE\XDEFp{\DOLETT@R{\\}{\MATHCHAR"7170}}} {\DEF\\{q}\CATCODE`q=\ACTIVE\XDEFq{\DOLETT@R{\\}{\MATHCHAR"7171}}} {\DEF\\{r}\CATCODE`r=\ACTIVE\XDEFr{\DOLETT@R{\\}{\MATHCHAR"7172}}} {\DEF\\{s}\CATCODE`s=\ACTIVE\XDEFs{\DOLETT@R{\\}{\MATHCHAR"7173}}} {\DEF\\{t}\CATCODE`t=\ACTIVE\XDEFt{\DOLETT@R{\\}{\MATHCHAR"7174}}} {\DEF\\{u}\CATCODE`u=\ACTIVE\XDEFu{\DOLETT@R{\\}{\MATHCHAR"7175}}} {\DEF\\{v}\CATCODE`v=\ACTIVE\XDEFv{\DOLETT@R{\\}{\MATHCHAR"7176}}} {\DEF\\{w}\CATCODE`w=\ACTIVE\XDEFw{\DOLETT@R{\\}{\MATHCHAR"7177}}} {\DEF\\{x}\CATCODE`x=\ACTIVE\XDEFx{\DOLETT@R{\\}{\MATHCHAR"7178}}} {\DEF\\{y}\CATCODE`y=\ACTIVE\XDEFy{\DOLETT@R{\\}{\MATHCHAR"7179}}} {\DEF\\{z}\CATCODE`z=\ACTIVE\XDEFz{\DOLETT@R{\\}{\MATHCHAR"717A}}} \endgroup % allocate registers and initialize \newtoks\cod@toks \newtoks\lett@rtoks \newcount\tracingrecognition \newcount\dorecognition \newcount\readyneww@rd \newcount\charsinw@rd \tracingrecognition=0 \dorecognition=1 \readyneww@rd=1 % set up spaces so that if \mak@spacesordin@ry is declared the next whitespace % character (space, tab, return) will be an ordinary nonletter character. % effect is undone by \restor@regularspaces \def\mak@spacesordin@ry{% \catcode`\ =12\catcode`\^^I=12\catcode`\^^M=12\relax} \def\restor@regularspaces{\catcode`\ =10\catcode`\^^I=10\catcode`\^^M=5\relax} % macro to process a letter in mathmode: save forms of letter on % appropriate token lists, and take appropriate action if letter % is the first or last in a word \def\dolett@r#1#2{\ifodd\dorecognition \ifodd\readyneww@rd\beginmathw@rd\fi \edef\worddef##1{##1={\the\cod@toks#2}}\worddef\cod@toks \edef\worddef##1{##1={\the\lett@rtoks\noexpand#1}}\worddef\lett@rtoks \advance\charsinw@rd by 1 \let\enddolett@r=\rec@gnitionenddolett@r \else \def\enddolett@r{#2}\fi \enddolett@r} \def\rec@gnitionenddolett@r{\futurelet\n@xttok@n\ch@ckn@xttok@n} % macro to decide whether or not next token is special case: % if open-brace or close-brace follows, simply terminate word; % otherwise do more extensive processing which involves % slightly more "destructive" processing on the next token (in that it % becomes a macro argument). \def\ch@ckn@xttok@n{\def\trailing@cs{}\ifx\n@xttok@n\bgroup \simpl@endw@rd\else \ifx\n@xttok@n\egroup \simpl@endw@rd\else \def\fin@l@cs{\ch@ckn@xtargum@nt}\fi \fi \fin@l@cs} % macro to terminate word without messing with subsequent tokens \def\simpl@endw@rd{\def\fin@l@cs{\endmathw@rd\trailing@cs}} % macro to see if next token is a letter; if not, terminates word \def\ch@ckn@xtargum@nt#1{\ifcat\noexpand#1a\else \endmathw@rd\fi \trailing@cs#1} % macro to do initialization needed at the beggining of a new word \def\beginmathw@rd{\readyneww@rd=0 \charsinw@rd=0 \cod@toks={}\lett@rtoks={}\mak@spacesordin@ry} % macro to do appropriate processing at the end of a word \def\endmathw@rd{\restor@regularspaces \readyneww@rd=1 % ready to start new word (new word could be generated by control sequence) \ifnum\charsinw@rd=1 \the\cod@toks % don't recognize single letters as control sequences \else \expandafter\ifx\csname\the\lett@rtoks\endcsname\relax \the\cod@toks \else \expandafter\def\expandafter\trailing@cs\expandafter {\csname\the\lett@rtoks\endcsname}\ifnum \tracingrecognition>0 \immediate\write16{{Recognized math sequence: \expandafter \string\csname\the\lett@rtoks\endcsname}}\fi \fi \fi} % macros to block excessive recognition % redefine macro to turn off recognition, then expand \def\norecogafter#1{{\let\t@mp@@@=#1% \xdef#1{\noexpand\ifmmode\dorecognition=0\noexpand\fi\t@mp@@@}}} % redefine argumentless macro to turn off recognition only while it expands % expansion is done within a group (so side-effects are only local unless % explicitly global) \def\norecogwithin#1{{\let\t@mp@@@=#1% \xdef#1{\begingroup\dorecognition=0\t@mp@@@\endgroup}}} % set up \rm so that it disables subsequent recognition \let\originalrm=\rm \norecogafter{\rm} % attempt to restore prior catcode for @ \ifatsignwasaletter \else % hide private names \catcode`@=12 \fi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%