summaryrefslogtreecommitdiff
path: root/macros/plain/contrib/misc/mrecog.tex
blob: 15fca10eb2db63730343864155a22a368f4452d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% 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
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%