make the lua frontend reentrant as well
[mplib] / src / texk / web2c / mpdir / lib / mp.w
1 % $Id: mp.web,v 1.8 2005/08/24 10:54:02 taco Exp $
2 % MetaPost, by John Hobby.  Public domain.
3
4 % Much of this program was copied with permission from MF.web Version 1.9
5 % It interprets a language very similar to D.E. Knuth's METAFONT, but with
6 % changes designed to make it more suitable for PostScript output.
7
8 % TeX is a trademark of the American Mathematical Society.
9 % METAFONT is a trademark of Addison-Wesley Publishing Company.
10 % PostScript is a trademark of Adobe Systems Incorporated.
11
12 % Here is TeX material that gets inserted after \input webmac
13 \def\hang{\hangindent 3em\noindent\ignorespaces}
14 \def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
15 \def\ps{PostScript}
16 \def\psqrt#1{\sqrt{\mathstrut#1}}
17 \def\k{_{k+1}}
18 \def\pct!{{\char`\%}} % percent sign in ordinary text
19 \font\tenlogo=logo10 % font used for the METAFONT logo
20 \font\logos=logosl10
21 \def\MF{{\tenlogo META}\-{\tenlogo FONT}}
22 \def\MP{{\tenlogo META}\-{\tenlogo POST}}
23 \def\[#1]{\ignorespaces} % left over from pascal web
24 \def\<#1>{$\langle#1\rangle$}
25 \def\section{\mathhexbox278}
26 \let\swap=\leftrightarrow
27 \def\round{\mathop{\rm round}\nolimits}
28 \mathchardef\vb="026A % synonym for `\|'
29
30 \def\(#1){} % this is used to make section names sort themselves better
31 \def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
32 \def\title{MetaPost}
33 \pdfoutput=1
34 \pageno=3
35
36 @* \[1] Introduction.
37
38 This is \MP, a graphics-language processor based on D. E. Knuth's \MF.
39
40 The main purpose of the following program is to explain the algorithms of \MP\
41 as clearly as possible. However, the program has been written so that it
42 can be tuned to run efficiently in a wide variety of operating environments
43 by making comparatively few changes. Such flexibility is possible because
44 the documentation that follows is written in the \.{WEB} language, which is
45 at a higher level than C.
46
47 A large piece of software like \MP\ has inherent complexity that cannot
48 be reduced below a certain level of difficulty, although each individual
49 part is fairly simple by itself. The \.{WEB} language is intended to make
50 the algorithms as readable as possible, by reflecting the way the
51 individual program pieces fit together and by providing the
52 cross-references that connect different parts. Detailed comments about
53 what is going on, and about why things were done in certain ways, have
54 been liberally sprinkled throughout the program.  These comments explain
55 features of the implementation, but they rarely attempt to explain the
56 \MP\ language itself, since the reader is supposed to be familiar with
57 {\sl The {\logos METAFONT\/}book} as well as the manual
58 @.WEB@>
59 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
60 {\sl A User's Manual for MetaPost}, Computing Science Technical Report 162,
61 AT\AM T Bell Laboratories.
62
63 @ The present implementation is a preliminary version, but the possibilities
64 for new features are limited by the desire to remain as nearly compatible
65 with \MF\ as possible.
66
67 On the other hand, the \.{WEB} description can be extended without changing
68 the core of the program, and it has been designed so that such
69 extensions are not extremely difficult to make.
70 The |banner| string defined here should be changed whenever \MP\
71 undergoes any modifications, so that it will be clear which version of
72 \MP\ might be the guilty party when a problem arises.
73 @^extensions to \MP@>
74 @^system dependencies@>
75
76 @d banner "This is MetaPost, Version 1.002" /* printed when \MP\ starts */
77 @d metapost_version "1.002"
78 @d mplib_version "0.20"
79 @d version_string " (Cweb version 0.20)"
80
81 @d true 1
82 @d false 0
83
84 @ The external library header for \MP\ is |mplib.h|. It contains a
85 few typedefs and the header defintions for the externally used
86 fuctions.
87
88 The most important of the typedefs is the definition of the structure 
89 |MP_options|, that acts as a small, configurable front-end to the fairly 
90 large |MP_instance| structure.
91  
92 @(mplib.h@>=
93 typedef struct MP_instance * MP;
94 @<Exported types@>
95 typedef struct MP_options {
96   @<Option variables@>
97 } MP_options;
98 @<Exported function headers@>
99
100 @ The internal header file is much longer: it not only lists the complete
101 |MP_instance|, but also a lot of functions that have to be available to
102 the \ps\ backend, that is defined in a separate \.{WEB} file. 
103
104 The variables from |MP_options| are included inside the |MP_instance| 
105 wholesale.
106
107 @(mpmp.h@>=
108 #include <setjmp.h>
109 typedef struct psout_data_struct * psout_data;
110 typedef int boolean;
111 typedef signed int integer;
112 @<Declare helpers@>;
113 @<Types in the outer block@>;
114 @<Constants in the outer block@>
115 #  ifndef LIBAVL_ALLOCATOR
116 #    define LIBAVL_ALLOCATOR
117     struct libavl_allocator {
118         void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size);
119         void (*libavl_free) (struct libavl_allocator *, void *libavl_block);
120     };
121 #  endif
122 typedef struct MP_instance {
123   @<Option variables@>
124   @<Global variables@>
125 } MP_instance;
126 @<Internal library declarations@>
127
128 @ @c 
129 #include <stdio.h>
130 #include <stdlib.h>
131 #include <string.h>
132 #include <stdarg.h>
133 #include <assert.h>
134 #include <unistd.h> /* for access() */
135 #include <time.h> /* for struct tm \& co */
136 #include "mplib.h"
137 #include "mpmp.h" /* internal header */
138 #include "mppsout.h" /* internal header */
139 @h
140 @<Declarations@>
141 @<Basic printing procedures@>
142 @<Error handling procedures@>
143
144 @ Here are the functions that set up the \MP\ instance.
145
146 @<Declarations@> =
147 @<Declare |mp_reallocate| functions@>;
148 struct MP_options *mp_options (void);
149 MP mp_new (struct MP_options *opt);
150
151 @ @c
152 struct MP_options *mp_options (void) {
153   struct MP_options *opt;
154   opt = malloc(sizeof(MP_options));
155   if (opt!=NULL) {
156     memset (opt,0,sizeof(MP_options));
157   }
158   return opt;
159
160
161 @ The |__attribute__| pragma is gcc-only.
162
163 @<Internal library ... @>=
164 #if !defined(__GNUC__) || (__GNUC__ < 2)
165 # define __attribute__(x)
166 #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
167
168 @ @c
169 MP __attribute__ ((noinline))
170 mp_new (struct MP_options *opt) {
171   MP mp;
172   mp = xmalloc(1,sizeof(MP_instance));
173   @<Set |ini_version|@>;
174   @<Setup the non-local jump buffer in |mp_new|@>;
175   @<Allocate or initialize variables@>
176   if (opt->main_memory>mp->mem_max)
177     mp_reallocate_memory(mp,opt->main_memory);
178   mp_reallocate_paths(mp,1000);
179   mp_reallocate_fonts(mp,8);
180   return mp;
181 }
182
183 @ @c
184 void mp_free (MP mp) {
185   int k; /* loop variable */
186   @<Dealloc variables@>
187   xfree(mp);
188 }
189
190 @ @c
191 void  __attribute__((noinline))
192 mp_do_initialize ( MP mp) {
193   @<Local variables for initialization@>
194   @<Set initial values of key variables@>
195 }
196 int mp_initialize (MP mp) { /* this procedure gets things started properly */
197   mp->history=mp_fatal_error_stop; /* in case we quit during initialization */
198   @<Install and test the non-local jump buffer@>;
199   t_open_out; /* open the terminal for output */
200   @<Check the ``constant'' values...@>;
201   if ( mp->bad>0 ) {
202         char ss[256];
203     snprintf(ss,256,"Ouch---my internal constants have been clobbered!\n"
204                    "---case %i",(int)mp->bad);
205     do_fprintf(mp->err_out,(char *)ss);
206 @.Ouch...clobbered@>
207     return mp->history;
208   }
209   mp_do_initialize(mp); /* erase preloaded mem */
210   if (mp->ini_version) {
211     @<Run inimpost commands@>;
212   }
213   @<Initialize the output routines@>;
214   @<Get the first line of input and prepare to start@>;
215   mp_set_job_id(mp);
216   mp_init_map_file(mp, mp->troff_mode);
217   mp->history=mp_spotless; /* ready to go! */
218   if (mp->troff_mode) {
219     mp->internal[mp_gtroffmode]=unity; 
220     mp->internal[mp_prologues]=unity; 
221   }
222   if ( mp->start_sym>0 ) { /* insert the `\&{everyjob}' symbol */
223     mp->cur_sym=mp->start_sym; mp_back_input(mp);
224   }
225   return mp->history;
226 }
227
228
229 @<Exported function headers@>=
230 extern struct MP_options *mp_options (void);
231 extern MP mp_new (struct MP_options *opt) ;
232 extern void mp_free (MP mp);
233 extern int mp_initialize (MP mp);
234
235 @ The overall \MP\ program begins with the heading just shown, after which
236 comes a bunch of procedure declarations and function declarations.
237 Finally we will get to the main program, which begins with the
238 comment `|start_here|'. If you want to skip down to the
239 main program now, you can look up `|start_here|' in the index.
240 But the author suggests that the best way to understand this program
241 is to follow pretty much the order of \MP's components as they appear in the
242 \.{WEB} description you are now reading, since the present ordering is
243 intended to combine the advantages of the ``bottom up'' and ``top down''
244 approaches to the problem of understanding a somewhat complicated system.
245
246 @ Some of the code below is intended to be used only when diagnosing the
247 strange behavior that sometimes occurs when \MP\ is being installed or
248 when system wizards are fooling around with \MP\ without quite knowing
249 what they are doing. Such code will not normally be compiled; it is
250 delimited by the preprocessor test `|#ifdef DEBUG .. #endif|'.
251
252 @ This program has two important variations: (1) There is a long and slow
253 version called \.{INIMP}, which does the extra calculations needed to
254 @.INIMP@>
255 initialize \MP's internal tables; and (2)~there is a shorter and faster
256 production version, which cuts the initialization to a bare minimum.
257
258 Which is which is decided at runtime.
259
260 @ The following parameters can be changed at compile time to extend or
261 reduce \MP's capacity. They may have different values in \.{INIMP} and
262 in production versions of \MP.
263 @.INIMP@>
264 @^system dependencies@>
265
266 @<Constants...@>=
267 #define file_name_size 255 /* file names shouldn't be longer than this */
268 #define bistack_size 1500 /* size of stack for bisection algorithms;
269   should probably be left at this value */
270
271 @ Like the preceding parameters, the following quantities can be changed
272 at compile time to extend or reduce \MP's capacity. But if they are changed,
273 it is necessary to rerun the initialization program \.{INIMP}
274 @.INIMP@>
275 to generate new tables for the production \MP\ program.
276 One can't simply make helter-skelter changes to the following constants,
277 since certain rather complex initialization
278 numbers are computed from them. 
279
280 @ @<Glob...@>=
281 int max_strings; /* maximum number of strings; must not exceed |max_halfword| */
282 int pool_size; /* maximum number of characters in strings, including all
283   error messages and help texts, and the names of all identifiers */
284 int mem_max; /* greatest index in \MP's internal |mem| array;
285   must be strictly less than |max_halfword|;
286   must be equal to |mem_top| in \.{INIMP}, otherwise |>=mem_top| */
287 int mem_top; /* largest index in the |mem| array dumped by \.{INIMP};
288   must not be greater than |mem_max| */
289
290 @ @<Option variables@>=
291 int error_line; /* width of context lines on terminal error messages */
292 int half_error_line; /* width of first lines of contexts in terminal
293   error messages; should be between 30 and |error_line-15| */
294 int max_print_line; /* width of longest text lines output; should be at least 60 */
295 int hash_size; /* maximum number of symbolic tokens,
296   must be less than |max_halfword-3*param_size| */
297 int hash_prime; /* a prime number equal to about 85\pct! of |hash_size| */
298 int param_size; /* maximum number of simultaneous macro parameters */
299 int max_in_open; /* maximum number of input files and error insertions that
300   can be going on simultaneously */
301 int main_memory; /* only for options, to set up |mem_max| and |mem_top| */
302 void *userdata; /* this allows the calling application to setup local */
303
304
305 @d set_value(a,b,c) do { a=c; if (b>c) a=b; } while (0)
306
307 @<Allocate or ...@>=
308 mp->max_strings=500;
309 mp->pool_size=10000;
310 set_value(mp->error_line,opt->error_line,79);
311 set_value(mp->half_error_line,opt->half_error_line,50);
312 set_value(mp->max_print_line,opt->max_print_line,100);
313 mp->main_memory=5000;
314 mp->mem_max=5000;
315 mp->mem_top=5000;
316 set_value(mp->hash_size,opt->hash_size,9500);
317 set_value(mp->hash_prime,opt->hash_prime,7919);
318 set_value(mp->param_size,opt->param_size,150);
319 set_value(mp->max_in_open,opt->max_in_open,10);
320 mp->userdata=opt->userdata;
321
322 @ In case somebody has inadvertently made bad settings of the ``constants,''
323 \MP\ checks them using a global variable called |bad|.
324
325 This is the first of many sections of \MP\ where global variables are
326 defined.
327
328 @<Glob...@>=
329 integer bad; /* is some ``constant'' wrong? */
330
331 @ Later on we will say `\ignorespaces|if (mem_max>=max_halfword) bad=10;|',
332 or something similar. (We can't do that until |max_halfword| has been defined.)
333
334 @<Check the ``constant'' values for consistency@>=
335 mp->bad=0;
336 if ( (mp->half_error_line<30)||(mp->half_error_line>mp->error_line-15) ) mp->bad=1;
337 if ( mp->max_print_line<60 ) mp->bad=2;
338 if ( mp->mem_top<=1100 ) mp->bad=4;
339 if (mp->hash_prime>mp->hash_size ) mp->bad=5;
340
341 @ Some |goto| labels are used by the following definitions. The label
342 `|restart|' is occasionally used at the very beginning of a procedure; and
343 the label `|reswitch|' is occasionally used just prior to a |case|
344 statement in which some cases change the conditions and we wish to branch
345 to the newly applicable case.  Loops that are set up with the |loop|
346 construction defined below are commonly exited by going to `|done|' or to
347 `|found|' or to `|not_found|', and they are sometimes repeated by going to
348 `|continue|'.  If two or more parts of a subroutine start differently but
349 end up the same, the shared code may be gathered together at
350 `|common_ending|'.
351
352 @ Here are some macros for common programming idioms.
353
354 @d incr(A)   (A)=(A)+1 /* increase a variable by unity */
355 @d decr(A)   (A)=(A)-1 /* decrease a variable by unity */
356 @d negate(A) (A)=-(A) /* change the sign of a variable */
357 @d double(A) (A)=(A)+(A)
358 @d odd(A)   ((A)%2==1)
359 @d chr(A)   (A)
360 @d do_nothing   /* empty statement */
361 @d Return   goto exit /* terminate a procedure call */
362 @f return   nil /* \.{WEB} will henceforth say |return| instead of \\{return} */
363
364 @* \[2] The character set.
365 In order to make \MP\ readily portable to a wide variety of
366 computers, all of its input text is converted to an internal eight-bit
367 code that includes standard ASCII, the ``American Standard Code for
368 Information Interchange.''  This conversion is done immediately when each
369 character is read in. Conversely, characters are converted from ASCII to
370 the user's external representation just before they are output to a
371 text file.
372 @^ASCII code@>
373
374 Such an internal code is relevant to users of \MP\ only with respect to
375 the \&{char} and \&{ASCII} operations, and the comparison of strings.
376
377 @ Characters of text that have been converted to \MP's internal form
378 are said to be of type |ASCII_code|, which is a subrange of the integers.
379
380 @<Types...@>=
381 typedef unsigned char ASCII_code; /* eight-bit numbers */
382
383 @ The present specification of \MP\ has been written under the assumption
384 that the character set contains at least the letters and symbols associated
385 with ASCII codes 040 through 0176; all of these characters are now
386 available on most computer terminals.
387
388 We shall use the name |text_char| to stand for the data type of the characters 
389 that are converted to and from |ASCII_code| when they are input and output. 
390 We shall also assume that |text_char| consists of the elements 
391 |chr(first_text_char)| through |chr(last_text_char)|, inclusive. 
392 The following definitions should be adjusted if necessary.
393 @^system dependencies@>
394
395 @d first_text_char 0 /* ordinal number of the smallest element of |text_char| */
396 @d last_text_char 255 /* ordinal number of the largest element of |text_char| */
397
398 @<Types...@>=
399 typedef unsigned char text_char; /* the data type of characters in text files */
400
401 @ @<Local variables for init...@>=
402 integer i;
403
404 @ The \MP\ processor converts between ASCII code and
405 the user's external character set by means of arrays |xord| and |xchr|
406 that are analogous to Pascal's |ord| and |chr| functions.
407
408 @d xchr(A) mp->xchr[(A)]
409 @d xord(A) mp->xord[(A)]
410
411 @<Glob...@>=
412 ASCII_code xord[256];  /* specifies conversion of input characters */
413 text_char xchr[256];  /* specifies conversion of output characters */
414
415 @ The core system assumes all 8-bit is acceptable.  If it is not,
416 a change file has to alter the below section.
417 @^system dependencies@>
418
419 Additionally, people with extended character sets can
420 assign codes arbitrarily, giving an |xchr| equivalent to whatever
421 characters the users of \MP\ are allowed to have in their input files.
422 Appropriate changes to \MP's |char_class| table should then be made.
423 (Unlike \TeX, each installation of \MP\ has a fixed assignment of category
424 codes, called the |char_class|.) Such changes make portability of programs
425 more difficult, so they should be introduced cautiously if at all.
426 @^character set dependencies@>
427 @^system dependencies@>
428
429 @<Set initial ...@>=
430 for (i=0;i<=0377;i++) { xchr(i)=i; }
431
432 @ The following system-independent code makes the |xord| array contain a
433 suitable inverse to the information in |xchr|. Note that if |xchr[i]=xchr[j]|
434 where |i<j<0177|, the value of |xord[xchr[i]]| will turn out to be
435 |j| or more; hence, standard ASCII code numbers will be used instead of
436 codes below 040 in case there is a coincidence.
437
438 @<Set initial ...@>=
439 for (i=first_text_char;i<=last_text_char;i++) { 
440    xord(chr(i))=0177;
441 }
442 for (i=0200;i<=0377;i++) { xord(xchr(i))=i;}
443 for (i=0;i<=0176;i++) { xord(xchr(i))=i;}
444
445 @* \[3] Input and output.
446 The bane of portability is the fact that different operating systems treat
447 input and output quite differently, perhaps because computer scientists
448 have not given sufficient attention to this problem. People have felt somehow
449 that input and output are not part of ``real'' programming. Well, it is true
450 that some kinds of programming are more fun than others. With existing
451 input/output conventions being so diverse and so messy, the only sources of
452 joy in such parts of the code are the rare occasions when one can find a
453 way to make the program a little less bad than it might have been. We have
454 two choices, either to attack I/O now and get it over with, or to postpone
455 I/O until near the end. Neither prospect is very attractive, so let's
456 get it over with.
457
458 The basic operations we need to do are (1)~inputting and outputting of
459 text, to or from a file or the user's terminal; (2)~inputting and
460 outputting of eight-bit bytes, to or from a file; (3)~instructing the
461 operating system to initiate (``open'') or to terminate (``close'') input or
462 output from a specified file; (4)~testing whether the end of an input
463 file has been reached; (5)~display of bits on the user's screen.
464 The bit-display operation will be discussed in a later section; we shall
465 deal here only with more traditional kinds of I/O.
466
467 @ Finding files happens in a slightly roundabout fashion: the \MP\
468 instance object contains a field that holds a function pointer that finds a
469 file, and returns its name, or NULL. For this, it receives three
470 parameters: the non-qualified name |fname|, the intended |fopen|
471 operation type |fmode|, and the type of the file |ftype|.
472
473 The file types that are passed on in |ftype| can be  used to 
474 differentiate file searches if a library like kpathsea is used,
475 the fopen mode is passed along for the same reason.
476
477 @<Types...@>=
478 typedef unsigned char eight_bits ; /* unsigned one-byte quantity */
479
480 @ @<Exported types@>=
481 enum mp_filetype {
482   mp_filetype_terminal = 0, /* the terminal */
483   mp_filetype_error, /* the terminal */
484   mp_filetype_program , /* \MP\ language input */
485   mp_filetype_log,  /* the log file */
486   mp_filetype_postscript, /* the postscript output */
487   mp_filetype_memfile, /* memory dumps */
488   mp_filetype_metrics, /* TeX font metric files */
489   mp_filetype_fontmap, /* PostScript font mapping files */
490   mp_filetype_font, /*  PostScript type1 font programs */
491   mp_filetype_encoding, /*  PostScript font encoding files */
492   mp_filetype_text,  /* first text file for readfrom and writeto primitives */
493 };
494 typedef char *(*mp_file_finder)(MP, char *, char *, int);
495 typedef void *(*mp_file_opener)(MP, char *, char *, int);
496 typedef char *(*mp_file_reader)(MP, void *, size_t *);
497 typedef void (*mp_binfile_reader)(MP, void *, void **, size_t *);
498 typedef void (*mp_file_closer)(MP, void *);
499 typedef int (*mp_file_eoftest)(MP, void *);
500 typedef void (*mp_file_flush)(MP, void *);
501 typedef void (*mp_file_writer)(MP, void *, char *);
502 typedef void (*mp_binfile_writer)(MP, void *, void *, size_t);
503 #define NOTTESTING 1
504
505 @ @<Option variables@>=
506 mp_file_finder find_file;
507 mp_file_opener open_file;
508 mp_file_reader read_ascii_file;
509 mp_binfile_reader read_binary_file;
510 mp_file_closer close_file;
511 mp_file_eoftest eof_file;
512 mp_file_flush flush_file;
513 mp_file_writer write_ascii_file;
514 mp_binfile_writer write_binary_file;
515
516 @ The default function for finding files is |mp_find_file|. It is 
517 pretty stupid: it will only find files in the current directory.
518
519 This function may disappear altogether, it is currently only
520 used for the default font map file.
521
522 @c
523 char *mp_find_file (MP mp, char *fname, char *fmode, int ftype)  {
524   if (fmode[0] != 'r' || (! access (fname,R_OK)) || ftype) {  
525      return strdup(fname);
526   }
527   return NULL;
528 }
529
530 @ This has to be done very early on, so it is best to put it in with
531 the |mp_new| allocations
532
533 @d set_callback_option(A) do { mp->A = mp_##A;
534   if (opt->A!=NULL) mp->A = opt->A;
535 } while (0)
536
537 @<Allocate or initialize ...@>=
538 set_callback_option(find_file);
539 set_callback_option(open_file);
540 set_callback_option(read_ascii_file);
541 set_callback_option(read_binary_file);
542 set_callback_option(close_file);
543 set_callback_option(eof_file);
544 set_callback_option(flush_file);
545 set_callback_option(write_ascii_file);
546 set_callback_option(write_binary_file);
547
548 @ Because |mp_find_file| is used so early, it has to be in the helpers
549 section.
550
551 @<Internal ...@>=
552 char *mp_find_file (MP mp, char *fname, char *fmode, int ftype) ;
553 void *mp_open_file (MP mp ,char *fname, char *fmode, int ftype) ;
554 char *mp_read_ascii_file (MP mp, void *f, size_t *size) ;
555 void mp_read_binary_file (MP mp, void *f, void **d, size_t *size) ;
556 void mp_close_file (MP mp, void *f) ;
557 int mp_eof_file (MP mp, void *f) ;
558 void mp_flush_file (MP mp, void *f) ;
559 void mp_write_ascii_file (MP mp, void *f, char *s) ;
560 void mp_write_binary_file (MP mp, void *f, void *s, size_t t) ;
561
562 @ The function to open files can now be very short.
563
564 @c
565 void *mp_open_file(MP mp, char *fname, char *fmode, int ftype)  {
566 #if NOTTESTING
567   if (ftype==mp_filetype_terminal) {
568     return (fmode[0] == 'r' ? stdin : stdout);
569   } else if (ftype==mp_filetype_error) {
570     return stderr;
571   } else if (fname != NULL && (fmode[0] != 'r' || (! access (fname,R_OK)))) {
572     return (void *)fopen(fname, fmode);
573   }
574 #endif
575   return NULL;
576 }
577
578 @ This is a legacy interface: (almost) all file names pass through |name_of_file|.
579
580 @<Glob...@>=
581 char name_of_file[file_name_size+1]; /* the name of a system file */
582 int name_length;/* this many characters are actually
583   relevant in |name_of_file| (the rest are blank) */
584
585 @ @<Option variables@>=
586 int print_found_names; /* configuration parameter */
587
588 @ If this parameter is true, the terminal and log will report the found
589 file names for input files instead of the requested ones. 
590 It is off by default because it creates an extra filename lookup.
591
592 @<Allocate or initialize ...@>=
593 mp->print_found_names = (opt->print_found_names>0 ? true : false);
594
595 @ \MP's file-opening procedures return |false| if no file identified by
596 |name_of_file| could be opened.
597
598 The |OPEN_FILE| macro takes care of the |print_found_names| parameter.
599 It is not used for opening a mem file for read, because that file name 
600 is never printed.
601
602 @d OPEN_FILE(A) do {
603   if (mp->print_found_names) {
604     char *s = (mp->find_file)(mp,mp->name_of_file,A,ftype);
605     if (s!=NULL) {
606       *f = (mp->open_file)(mp,mp->name_of_file,A, ftype); 
607       strncpy(mp->name_of_file,s,file_name_size);
608       xfree(s);
609     } else {
610       *f = NULL;
611     }
612   } else {
613     *f = (mp->open_file)(mp,mp->name_of_file,A, ftype); 
614   }
615 } while (0);
616 return (*f ? true : false)
617
618 @c 
619 boolean mp_a_open_in (MP mp, void **f, int ftype) {
620   /* open a text file for input */
621   OPEN_FILE("r");
622 }
623 @#
624 boolean mp_w_open_in (MP mp, void **f) {
625   /* open a word file for input */
626   *f = (mp->open_file)(mp,mp->name_of_file,"rb",mp_filetype_memfile); 
627   return (*f ? true : false);
628 }
629 @#
630 boolean mp_a_open_out (MP mp, void **f, int ftype) {
631   /* open a text file for output */
632   OPEN_FILE("w");
633 }
634 @#
635 boolean mp_b_open_out (MP mp, void **f, int ftype) {
636   /* open a binary file for output */
637   OPEN_FILE("wb");
638 }
639 @#
640 boolean mp_w_open_out (MP mp, void **f) {
641   /* open a word file for output */
642   int ftype = mp_filetype_memfile;
643   OPEN_FILE("wb");
644 }
645
646 @ @c
647 char *mp_read_ascii_file (MP mp, void *ff, size_t *size) {
648   int c;
649   size_t len = 0, lim = 128;
650   char *s = NULL;
651   FILE *f = (FILE *)ff;
652   *size = 0;
653 #if NOTTESTING
654   c = fgetc(f);
655   if (c==EOF)
656     return NULL;
657   s = malloc(lim); 
658   if (s==NULL) return NULL;
659   while (c!=EOF && c!='\n' && c!='\r') { 
660     if (len==lim) {
661       s =realloc(s, (lim+(lim>>2)));
662       if (s==NULL) return NULL;
663       lim+=(lim>>2);
664     }
665         s[len++] = c;
666     c =fgetc(f);
667   }
668   if (c=='\r') {
669     c = fgetc(f);
670     if (c!=EOF && c!='\n')
671        ungetc(c,f);
672   }
673   s[len] = 0;
674   *size = len;
675 #endif
676   return s;
677 }
678
679 @ @c
680 void mp_write_ascii_file (MP mp, void *f, char *s) {
681 #if NOTTESTING
682   if (f!=NULL) {
683     fputs(s,(FILE *)f);
684   }
685 #endif
686 }
687
688 @ @c
689 void mp_read_binary_file (MP mp, void *f, void **data, size_t *size) {
690   size_t len = 0;
691 #if NOTTESTING
692   len = fread(*data,1,*size,(FILE *)f);
693 #endif
694   *size = len;
695 }
696
697 @ @c
698 void mp_write_binary_file (MP mp, void *f, void *s, size_t size) {
699 #if NOTTESTING
700   if (f!=NULL)
701     fwrite(s,size,1,(FILE *)f);
702 #endif
703 }
704
705
706 @ @c
707 void mp_close_file (MP mp, void *f) {
708 #if NOTTESTING
709   fclose((FILE *)f);
710 #endif
711 }
712
713 @ @c
714 int mp_eof_file (MP mp, void *f) {
715 #if NOTTESTING
716   return feof((FILE *)f);
717 #else
718   return 0;
719 #endif
720 }
721
722 @ @c
723 void mp_flush_file (MP mp, void *f) {
724 #if NOTTESTING
725   fflush((FILE *)f);
726 #endif
727 }
728
729 @ Input from text files is read one line at a time, using a routine called
730 |input_ln|. This function is defined in terms of global variables called
731 |buffer|, |first|, and |last| that will be described in detail later; for
732 now, it suffices for us to know that |buffer| is an array of |ASCII_code|
733 values, and that |first| and |last| are indices into this array
734 representing the beginning and ending of a line of text.
735
736 @<Glob...@>=
737 size_t buf_size; /* maximum number of characters simultaneously present in
738                     current lines of open files */
739 ASCII_code *buffer; /* lines of characters being read */
740 size_t first; /* the first unused position in |buffer| */
741 size_t last; /* end of the line just input to |buffer| */
742 size_t max_buf_stack; /* largest index used in |buffer| */
743
744 @ @<Allocate or initialize ...@>=
745 mp->buf_size = 200;
746 mp->buffer = xmalloc((mp->buf_size+1),sizeof(ASCII_code));
747
748 @ @<Dealloc variables@>=
749 xfree(mp->buffer);
750
751 @ @c
752 void mp_reallocate_buffer(MP mp, size_t l) {
753   ASCII_code *buffer;
754   if (l>max_halfword) {
755     mp_confusion(mp,"buffer size"); /* can't happen (I hope) */
756   }
757   buffer = xmalloc((l+1),sizeof(ASCII_code));
758   memcpy(buffer,mp->buffer,(mp->buf_size+1));
759   xfree(mp->buffer);
760   mp->buffer = buffer ;
761   mp->buf_size = l;
762 }
763
764 @ The |input_ln| function brings the next line of input from the specified
765 field into available positions of the buffer array and returns the value
766 |true|, unless the file has already been entirely read, in which case it
767 returns |false| and sets |last:=first|.  In general, the |ASCII_code|
768 numbers that represent the next line of the file are input into
769 |buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
770 global variable |last| is set equal to |first| plus the length of the
771 line. Trailing blanks are removed from the line; thus, either |last=first|
772 (in which case the line was entirely blank) or |buffer[last-1]<>" "|.
773 @^inner loop@>
774
775 The variable |max_buf_stack|, which is used to keep track of how large
776 the |buf_size| parameter must be to accommodate the present job, is
777 also kept up to date by |input_ln|.
778
779 @c 
780 boolean mp_input_ln (MP mp, void *f ) {
781   /* inputs the next line or returns |false| */
782   char *s;
783   size_t size = 0; 
784   mp->last=mp->first; /* cf.\ Matthew 19\thinspace:\thinspace30 */
785   s = (mp->read_ascii_file)(mp,f, &size);
786   if (s==NULL)
787         return false;
788   if (size>0) {
789     mp->last = mp->first+size;
790     if ( mp->last>=mp->max_buf_stack ) { 
791       mp->max_buf_stack=mp->last+1;
792       while ( mp->max_buf_stack>=mp->buf_size ) {
793         mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
794       }
795     }
796     memcpy((mp->buffer+mp->first),s,size);
797     /* while ( mp->buffer[mp->last]==' ' ) mp->last--; */
798   } 
799   free(s);
800   return true;
801 }
802
803 @ The user's terminal acts essentially like other files of text, except
804 that it is used both for input and for output. When the terminal is
805 considered an input file, the file variable is called |term_in|, and when it
806 is considered an output file the file variable is |term_out|.
807 @^system dependencies@>
808
809 @<Glob...@>=
810 void * term_in; /* the terminal as an input file */
811 void * term_out; /* the terminal as an output file */
812 void * err_out; /* the terminal as an output file */
813
814 @ Here is how to open the terminal files. In the default configuration,
815 nothing happens except that the command line (if there is one) is copied
816 to the input buffer.  The variable |command_line| will be filled by the 
817 |main| procedure. The copying can not be done earlier in the program 
818 logic because in the |INI| version, the |buffer| is also used for primitive 
819 initialization.
820
821 @^system dependencies@>
822
823 @d t_open_out  do {/* open the terminal for text output */
824     mp->term_out = (mp->open_file)(mp,"terminal", "w", mp_filetype_terminal);
825     mp->err_out = (mp->open_file)(mp,"error", "w", mp_filetype_error);
826 } while (0)
827 @d t_open_in  do { /* open the terminal for text input */
828     mp->term_in = (mp->open_file)(mp,"terminal", "r", mp_filetype_terminal);
829     if (mp->command_line!=NULL) {
830       mp->last = strlen(mp->command_line);
831       strncpy((char *)mp->buffer,mp->command_line,mp->last);
832       xfree(mp->command_line);
833     } else {
834           mp->last = 0;
835     }
836 } while (0)
837
838 @d t_close_out do { /* close the terminal */
839   (mp->close_file)(mp,mp->term_out);
840   (mp->close_file)(mp,mp->err_out);
841 } while (0)
842
843 @d t_close_in do { /* close the terminal */
844   (mp->close_file)(mp,mp->term_in);
845 } while (0)
846
847 @<Option variables@>=
848 char *command_line;
849
850 @ @<Allocate or initialize ...@>=
851 mp->command_line = xstrdup(opt->command_line);
852
853 @ Sometimes it is necessary to synchronize the input/output mixture that
854 happens on the user's terminal, and three system-dependent
855 procedures are used for this
856 purpose. The first of these, |update_terminal|, is called when we want
857 to make sure that everything we have output to the terminal so far has
858 actually left the computer's internal buffers and been sent.
859 The second, |clear_terminal|, is called when we wish to cancel any
860 input that the user may have typed ahead (since we are about to
861 issue an unexpected error message). The third, |wake_up_terminal|,
862 is supposed to revive the terminal if the user has disabled it by
863 some instruction to the operating system.  The following macros show how
864 these operations can be specified:
865 @^system dependencies@>
866
867 @d update_terminal  (mp->flush_file)(mp,mp->term_out) /* empty the terminal output buffer */
868 @d clear_terminal   do_nothing /* clear the terminal input buffer */
869 @d wake_up_terminal (mp->flush_file)(mp,mp->term_out) 
870                     /* cancel the user's cancellation of output */
871
872 @ We need a special routine to read the first line of \MP\ input from
873 the user's terminal. This line is different because it is read before we
874 have opened the transcript file; there is sort of a ``chicken and
875 egg'' problem here. If the user types `\.{input cmr10}' on the first
876 line, or if some macro invoked by that line does such an \.{input},
877 the transcript file will be named `\.{cmr10.log}'; but if no \.{input}
878 commands are performed during the first line of terminal input, the transcript
879 file will acquire its default name `\.{mpout.log}'. (The transcript file
880 will not contain error messages generated by the first line before the
881 first \.{input} command.)
882
883 The first line is even more special. It's nice to let the user start
884 running a \MP\ job by typing a command line like `\.{MP cmr10}'; in
885 such a case, \MP\ will operate as if the first line of input were
886 `\.{cmr10}', i.e., the first line will consist of the remainder of the
887 command line, after the part that invoked \MP.
888
889 @ Different systems have different ways to get started. But regardless of
890 what conventions are adopted, the routine that initializes the terminal
891 should satisfy the following specifications:
892
893 \yskip\textindent{1)}It should open file |term_in| for input from the
894   terminal. (The file |term_out| will already be open for output to the
895   terminal.)
896
897 \textindent{2)}If the user has given a command line, this line should be
898   considered the first line of terminal input. Otherwise the
899   user should be prompted with `\.{**}', and the first line of input
900   should be whatever is typed in response.
901
902 \textindent{3)}The first line of input, which might or might not be a
903   command line, should appear in locations |first| to |last-1| of the
904   |buffer| array.
905
906 \textindent{4)}The global variable |loc| should be set so that the
907   character to be read next by \MP\ is in |buffer[loc]|. This
908   character should not be blank, and we should have |loc<last|.
909
910 \yskip\noindent(It may be necessary to prompt the user several times
911 before a non-blank line comes in. The prompt is `\.{**}' instead of the
912 later `\.*' because the meaning is slightly different: `\.{input}' need
913 not be typed immediately after~`\.{**}'.)
914
915 @d loc mp->cur_input.loc_field /* location of first unread character in |buffer| */
916
917 @ The following program does the required initialization
918 without retrieving a possible command line.
919 It should be clear how to modify this routine to deal with command lines,
920 if the system permits them.
921 @^system dependencies@>
922
923 @c 
924 boolean mp_init_terminal (MP mp) { /* gets the terminal input started */
925   t_open_in; 
926   if (mp->last!=0) {
927     loc = mp->first = 0;
928         return true;
929   }
930   while (1) { 
931     if (!mp->noninteractive) {
932           wake_up_terminal; do_fprintf(mp->term_out,"**"); update_terminal;
933 @.**@>
934     }
935     if ( ! mp_input_ln(mp, mp->term_in ) ) { /* this shouldn't happen */
936       do_fprintf(mp->term_out,"\n! End of file on the terminal... why?");
937 @.End of file on the terminal@>
938       return false;
939     }
940     loc=mp->first;
941     while ( (loc<(int)mp->last)&&(mp->buffer[loc]==' ') ) 
942       incr(loc);
943     if ( loc<(int)mp->last ) { 
944       return true; /* return unless the line was all blank */
945     }
946     if (!mp->noninteractive) {
947           do_fprintf(mp->term_out,"Please type the name of your input file.\n");
948     }
949   }
950 }
951
952 @ @<Declarations@>=
953 boolean mp_init_terminal (MP mp) ;
954
955
956 @* \[4] String handling.
957 Symbolic token names and diagnostic messages are variable-length strings
958 of eight-bit characters. Many strings \MP\ uses are simply literals
959 in the compiled source, like the error messages and the names of the
960 internal parameters. Other strings are used or defined from the \MP\ input 
961 language, and these have to be interned.
962
963 \MP\ uses strings more extensively than \MF\ does, but the necessary
964 operations can still be handled with a fairly simple data structure.
965 The array |str_pool| contains all of the (eight-bit) ASCII codes in all
966 of the strings, and the array |str_start| contains indices of the starting
967 points of each string. Strings are referred to by integer numbers, so that
968 string number |s| comprises the characters |str_pool[j]| for
969 |str_start[s]<=j<str_start[ss]| where |ss=next_str[s]|.  The string pool
970 is allocated sequentially and |str_pool[pool_ptr]| is the next unused
971 location.  The first string number not currently in use is |str_ptr|
972 and |next_str[str_ptr]| begins a list of free string numbers.  String
973 pool entries |str_start[str_ptr]| up to |pool_ptr| are reserved for a
974 string currently being constructed.
975
976 String numbers 0 to 255 are reserved for strings that correspond to single
977 ASCII characters. This is in accordance with the conventions of \.{WEB},
978 @.WEB@>
979 which converts single-character strings into the ASCII code number of the
980 single character involved, while it converts other strings into integers
981 and builds a string pool file. Thus, when the string constant \.{"."} appears
982 in the program below, \.{WEB} converts it into the integer 46, which is the
983 ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
984 into some integer greater than~255. String number 46 will presumably be the
985 single character `\..'\thinspace; but some ASCII codes have no standard visible
986 representation, and \MP\ may need to be able to print an arbitrary
987 ASCII character, so the first 256 strings are used to specify exactly what
988 should be printed for each of the 256 possibilities.
989
990 @<Types...@>=
991 typedef int pool_pointer; /* for variables that point into |str_pool| */
992 typedef int str_number; /* for variables that point into |str_start| */
993
994 @ @<Glob...@>=
995 ASCII_code *str_pool; /* the characters */
996 pool_pointer *str_start; /* the starting pointers */
997 str_number *next_str; /* for linking strings in order */
998 pool_pointer pool_ptr; /* first unused position in |str_pool| */
999 str_number str_ptr; /* number of the current string being created */
1000 pool_pointer init_pool_ptr; /* the starting value of |pool_ptr| */
1001 str_number init_str_use; /* the initial number of strings in use */
1002 pool_pointer max_pool_ptr; /* the maximum so far of |pool_ptr| */
1003 str_number max_str_ptr; /* the maximum so far of |str_ptr| */
1004
1005 @ @<Allocate or initialize ...@>=
1006 mp->str_pool  = xmalloc ((mp->pool_size +1),sizeof(ASCII_code));
1007 mp->str_start = xmalloc ((mp->max_strings+1),sizeof(pool_pointer));
1008 mp->next_str  = xmalloc ((mp->max_strings+1),sizeof(str_number));
1009
1010 @ @<Dealloc variables@>=
1011 xfree(mp->str_pool);
1012 xfree(mp->str_start);
1013 xfree(mp->next_str);
1014
1015 @ Most printing is done from |char *|s, but sometimes not. Here are
1016 functions that convert an internal string into a |char *| for use
1017 by the printing routines, and vice versa.
1018
1019 @d str(A) mp_str(mp,A)
1020 @d rts(A) mp_rts(mp,A)
1021
1022 @<Internal ...@>=
1023 int mp_xstrcmp (const char *a, const char *b);
1024 char * mp_str (MP mp, str_number s);
1025
1026 @ @<Declarations@>=
1027 str_number mp_rts (MP mp, char *s);
1028 str_number mp_make_string (MP mp);
1029
1030 @ The attempt to catch interrupted strings that is in |mp_rts|, is not 
1031 very good: it does not handle nesting over more than one level.
1032
1033 @c 
1034 int mp_xstrcmp (const char *a, const char *b) {
1035         if (a==NULL && b==NULL) 
1036           return 0;
1037     if (a==NULL)
1038       return -1;
1039     if (b==NULL)
1040       return 1;
1041     return strcmp(a,b);
1042 }
1043
1044 @ @c
1045 char * mp_str (MP mp, str_number ss) {
1046   char *s;
1047   int len;
1048   if (ss==mp->str_ptr) {
1049     return NULL;
1050   } else {
1051     len = length(ss);
1052     s = xmalloc(len+1,sizeof(char));
1053     strncpy(s,(char *)(mp->str_pool+(mp->str_start[ss])),len);
1054     s[len] = 0;
1055     return (char *)s;
1056   }
1057 }
1058 str_number mp_rts (MP mp, char *s) {
1059   int r; /* the new string */ 
1060   int old; /* a possible string in progress */
1061   int i=0;
1062   if (strlen(s)==0) {
1063     return 256;
1064   } else if (strlen(s)==1) {
1065     return s[0];
1066   } else {
1067    old=0;
1068    str_room((integer)strlen(s));
1069    if (mp->str_start[mp->str_ptr]<mp->pool_ptr)
1070      old = mp_make_string(mp);
1071    while (*s) {
1072      append_char(*s);
1073      s++;
1074    }
1075    r = mp_make_string(mp);
1076    if (old!=0) {
1077       str_room(length(old));
1078       while (i<length(old)) {
1079         append_char((mp->str_start[old]+i));
1080       } 
1081       mp_flush_string(mp,old);
1082     }
1083     return r;
1084   }
1085 }
1086
1087 @ Except for |strs_used_up|, the following string statistics are only
1088 maintained when code between |stat| $\ldots$ |tats| delimiters is not
1089 commented out:
1090
1091 @<Glob...@>=
1092 integer strs_used_up; /* strings in use or unused but not reclaimed */
1093 integer pool_in_use; /* total number of cells of |str_pool| actually in use */
1094 integer strs_in_use; /* total number of strings actually in use */
1095 integer max_pl_used; /* maximum |pool_in_use| so far */
1096 integer max_strs_used; /* maximum |strs_in_use| so far */
1097
1098 @ Several of the elementary string operations are performed using \.{WEB}
1099 macros instead of functions, because many of the
1100 operations are done quite frequently and we want to avoid the
1101 overhead of procedure calls. For example, here is
1102 a simple macro that computes the length of a string.
1103 @.WEB@>
1104
1105 @d str_stop(A) mp->str_start[mp->next_str[(A)]] /* one cell past the end of string
1106   number \# */
1107 @d length(A) (str_stop((A))-mp->str_start[(A)]) /* the number of characters in string \# */
1108
1109 @ The length of the current string is called |cur_length|.  If we decide that
1110 the current string is not needed, |flush_cur_string| resets |pool_ptr| so that
1111 |cur_length| becomes zero.
1112
1113 @d cur_length   (mp->pool_ptr - mp->str_start[mp->str_ptr])
1114 @d flush_cur_string   mp->pool_ptr=mp->str_start[mp->str_ptr]
1115
1116 @ Strings are created by appending character codes to |str_pool|.
1117 The |append_char| macro, defined here, does not check to see if the
1118 value of |pool_ptr| has gotten too high; this test is supposed to be
1119 made before |append_char| is used.
1120
1121 To test if there is room to append |l| more characters to |str_pool|,
1122 we shall write |str_room(l)|, which tries to make sure there is enough room
1123 by compacting the string pool if necessary.  If this does not work,
1124 |do_compaction| aborts \MP\ and gives an apologetic error message.
1125
1126 @d append_char(A)   /* put |ASCII_code| \# at the end of |str_pool| */
1127 { mp->str_pool[mp->pool_ptr]=(A); incr(mp->pool_ptr);
1128 }
1129 @d str_room(A)   /* make sure that the pool hasn't overflowed */
1130   { if ( mp->pool_ptr+(A) > mp->max_pool_ptr ) {
1131     if ( mp->pool_ptr+(A) > mp->pool_size ) mp_do_compaction(mp, (A));
1132     else mp->max_pool_ptr=mp->pool_ptr+(A); }
1133   }
1134
1135 @ The following routine is similar to |str_room(1)| but it uses the
1136 argument |mp->pool_size| to prevent |do_compaction| from aborting when
1137 string space is exhausted.
1138
1139 @<Declare the procedure called |unit_str_room|@>=
1140 void mp_unit_str_room (MP mp);
1141
1142 @ @c
1143 void mp_unit_str_room (MP mp) { 
1144   if ( mp->pool_ptr>=mp->pool_size ) mp_do_compaction(mp, mp->pool_size);
1145   if ( mp->pool_ptr>=mp->max_pool_ptr ) mp->max_pool_ptr=mp->pool_ptr+1;
1146 }
1147
1148 @ \MP's string expressions are implemented in a brute-force way: Every
1149 new string or substring that is needed is simply copied into the string pool.
1150 Space is eventually reclaimed by a procedure called |do_compaction| with
1151 the aid of a simple system system of reference counts.
1152 @^reference counts@>
1153
1154 The number of references to string number |s| will be |str_ref[s]|. The
1155 special value |str_ref[s]=max_str_ref=127| is used to denote an unknown
1156 positive number of references; such strings will never be recycled. If
1157 a string is ever referred to more than 126 times, simultaneously, we
1158 put it in this category. Hence a single byte suffices to store each |str_ref|.
1159
1160 @d max_str_ref 127 /* ``infinite'' number of references */
1161 @d add_str_ref(A) { if ( mp->str_ref[(A)]<max_str_ref ) incr(mp->str_ref[(A)]);
1162   }
1163
1164 @<Glob...@>=
1165 int *str_ref;
1166
1167 @ @<Allocate or initialize ...@>=
1168 mp->str_ref = xmalloc ((mp->max_strings+1),sizeof(int));
1169
1170 @ @<Dealloc variables@>=
1171 xfree(mp->str_ref);
1172
1173 @ Here's what we do when a string reference disappears:
1174
1175 @d delete_str_ref(A)  { 
1176     if ( mp->str_ref[(A)]<max_str_ref ) {
1177        if ( mp->str_ref[(A)]>1 ) decr(mp->str_ref[(A)]); 
1178        else mp_flush_string(mp, (A));
1179     }
1180   }
1181
1182 @<Declare the procedure called |flush_string|@>=
1183 void mp_flush_string (MP mp,str_number s) ;
1184
1185
1186 @ We can't flush the first set of static strings at all, so there 
1187 is no point in trying
1188
1189 @c
1190 void mp_flush_string (MP mp,str_number s) { 
1191   if (length(s)>1) {
1192     mp->pool_in_use=mp->pool_in_use-length(s);
1193     decr(mp->strs_in_use);
1194     if ( mp->next_str[s]!=mp->str_ptr ) {
1195       mp->str_ref[s]=0;
1196     } else { 
1197       mp->str_ptr=s;
1198       decr(mp->strs_used_up);
1199     }
1200     mp->pool_ptr=mp->str_start[mp->str_ptr];
1201   }
1202 }
1203
1204 @ C literals cannot be simply added, they need to be set so they can't
1205 be flushed.
1206
1207 @d intern(A) mp_intern(mp,(A))
1208
1209 @c
1210 str_number mp_intern (MP mp, char *s) {
1211   str_number r ;
1212   r = rts(s);
1213   mp->str_ref[r] = max_str_ref;
1214   return r;
1215 }
1216
1217 @ @<Declarations@>=
1218 str_number mp_intern (MP mp, char *s);
1219
1220
1221 @ Once a sequence of characters has been appended to |str_pool|, it
1222 officially becomes a string when the function |make_string| is called.
1223 This function returns the identification number of the new string as its
1224 value.
1225
1226 When getting the next unused string number from the linked list, we pretend
1227 that
1228 $$ \hbox{|max_str_ptr+1|, |max_str_ptr+2|, $\ldots$, |mp->max_strings|} $$
1229 are linked sequentially even though the |next_str| entries have not been
1230 initialized yet.  We never allow |str_ptr| to reach |mp->max_strings|;
1231 |do_compaction| is responsible for making sure of this.
1232
1233 @<Declarations@>=
1234 @<Declare the procedure called |do_compaction|@>;
1235 @<Declare the procedure called |unit_str_room|@>;
1236 str_number mp_make_string (MP mp);
1237
1238 @ @c 
1239 str_number mp_make_string (MP mp) { /* current string enters the pool */
1240   str_number s; /* the new string */
1241 RESTART: 
1242   s=mp->str_ptr;
1243   mp->str_ptr=mp->next_str[s];
1244   if ( mp->str_ptr>mp->max_str_ptr ) {
1245     if ( mp->str_ptr==mp->max_strings ) { 
1246       mp->str_ptr=s;
1247       mp_do_compaction(mp, 0);
1248       goto RESTART;
1249     } else {
1250 #ifdef DEBUG 
1251       if ( mp->strs_used_up!=mp->max_str_ptr ) mp_confusion(mp, "s");
1252 @:this can't happen s}{\quad \.s@>
1253 #endif
1254       mp->max_str_ptr=mp->str_ptr;
1255       mp->next_str[mp->str_ptr]=mp->max_str_ptr+1;
1256     }
1257   }
1258   mp->str_ref[s]=1;
1259   mp->str_start[mp->str_ptr]=mp->pool_ptr;
1260   incr(mp->strs_used_up);
1261   incr(mp->strs_in_use);
1262   mp->pool_in_use=mp->pool_in_use+length(s);
1263   if ( mp->pool_in_use>mp->max_pl_used ) 
1264     mp->max_pl_used=mp->pool_in_use;
1265   if ( mp->strs_in_use>mp->max_strs_used ) 
1266     mp->max_strs_used=mp->strs_in_use;
1267   return s;
1268 }
1269
1270 @ The most interesting string operation is string pool compaction.  The idea
1271 is to recover unused space in the |str_pool| array by recopying the strings
1272 to close the gaps created when some strings become unused.  All string
1273 numbers~$k$ where |str_ref[k]=0| are to be linked into the list of free string
1274 numbers after |str_ptr|.  If this fails to free enough pool space we issue an
1275 |overflow| error unless |needed=mp->pool_size|.  Calling |do_compaction|
1276 with |needed=mp->pool_size| supresses all overflow tests.
1277
1278 The compaction process starts with |last_fixed_str| because all lower numbered
1279 strings are permanently allocated with |max_str_ref| in their |str_ref| entries.
1280
1281 @<Glob...@>=
1282 str_number last_fixed_str; /* last permanently allocated string */
1283 str_number fixed_str_use; /* number of permanently allocated strings */
1284
1285 @ @<Declare the procedure called |do_compaction|@>=
1286 void mp_do_compaction (MP mp, pool_pointer needed) ;
1287
1288 @ @c
1289 void mp_do_compaction (MP mp, pool_pointer needed) {
1290   str_number str_use; /* a count of strings in use */
1291   str_number r,s,t; /* strings being manipulated */
1292   pool_pointer p,q; /* destination and source for copying string characters */
1293   @<Advance |last_fixed_str| as far as possible and set |str_use|@>;
1294   r=mp->last_fixed_str;
1295   s=mp->next_str[r];
1296   p=mp->str_start[s];
1297   while ( s!=mp->str_ptr ) { 
1298     while ( mp->str_ref[s]==0 ) {
1299       @<Advance |s| and add the old |s| to the list of free string numbers;
1300         then |break| if |s=str_ptr|@>;
1301     }
1302     r=s; s=mp->next_str[s];
1303     incr(str_use);
1304     @<Move string |r| back so that |str_start[r]=p|; make |p| the location
1305      after the end of the string@>;
1306   }
1307   @<Move the current string back so that it starts at |p|@>;
1308   if ( needed<mp->pool_size ) {
1309     @<Make sure that there is room for another string with |needed| characters@>;
1310   }
1311   @<Account for the compaction and make sure the statistics agree with the
1312      global versions@>;
1313   mp->strs_used_up=str_use;
1314 }
1315
1316 @ @<Advance |last_fixed_str| as far as possible and set |str_use|@>=
1317 t=mp->next_str[mp->last_fixed_str];
1318 while (t!=mp->str_ptr && mp->str_ref[t]==max_str_ref) {
1319   incr(mp->fixed_str_use);
1320   mp->last_fixed_str=t;
1321   t=mp->next_str[t];
1322 }
1323 str_use=mp->fixed_str_use
1324
1325 @ Because of the way |flush_string| has been written, it should never be
1326 necessary to |break| here.  The extra line of code seems worthwhile to
1327 preserve the generality of |do_compaction|.
1328
1329 @<Advance |s| and add the old |s| to the list of free string numbers;...@>=
1330 {
1331 t=s;
1332 s=mp->next_str[s];
1333 mp->next_str[r]=s;
1334 mp->next_str[t]=mp->next_str[mp->str_ptr];
1335 mp->next_str[mp->str_ptr]=t;
1336 if ( s==mp->str_ptr ) break;
1337 }
1338
1339 @ The string currently starts at |str_start[r]| and ends just before
1340 |str_start[s]|.  We don't change |str_start[s]| because it might be needed
1341 to locate the next string.
1342
1343 @<Move string |r| back so that |str_start[r]=p|; make |p| the location...@>=
1344 q=mp->str_start[r];
1345 mp->str_start[r]=p;
1346 while ( q<mp->str_start[s] ) { 
1347   mp->str_pool[p]=mp->str_pool[q];
1348   incr(p); incr(q);
1349 }
1350
1351 @ Pointers |str_start[str_ptr]| and |pool_ptr| have not been updated.  When
1352 we do this, anything between them should be moved.
1353
1354 @ @<Move the current string back so that it starts at |p|@>=
1355 q=mp->str_start[mp->str_ptr];
1356 mp->str_start[mp->str_ptr]=p;
1357 while ( q<mp->pool_ptr ) { 
1358   mp->str_pool[p]=mp->str_pool[q];
1359   incr(p); incr(q);
1360 }
1361 mp->pool_ptr=p
1362
1363 @ We must remember that |str_ptr| is not allowed to reach |mp->max_strings|.
1364
1365 @<Make sure that there is room for another string with |needed| char...@>=
1366 if ( str_use>=mp->max_strings-1 )
1367   mp_reallocate_strings (mp,str_use);
1368 if ( mp->pool_ptr+needed>mp->max_pool_ptr ) {
1369   mp_reallocate_pool(mp, mp->pool_ptr+needed);
1370   mp->max_pool_ptr=mp->pool_ptr+needed;
1371 }
1372
1373 @ @<Declarations@>=
1374 void mp_reallocate_strings (MP mp, str_number str_use) ;
1375 void mp_reallocate_pool(MP mp, pool_pointer needed) ;
1376
1377 @ @c 
1378 void mp_reallocate_strings (MP mp, str_number str_use) { 
1379   while ( str_use>=mp->max_strings-1 ) {
1380     int l = mp->max_strings + (mp->max_strings>>2);
1381     XREALLOC (mp->str_ref,   l, int);
1382     XREALLOC (mp->str_start, l, pool_pointer);
1383     XREALLOC (mp->next_str,  l, str_number);
1384     mp->max_strings = l;
1385   }
1386 }
1387 void mp_reallocate_pool(MP mp, pool_pointer needed) {
1388   while ( needed>mp->pool_size ) {
1389     int l = mp->pool_size + (mp->pool_size>>2);
1390         XREALLOC (mp->str_pool, l, ASCII_code);
1391     mp->pool_size = l;
1392   }
1393 }
1394
1395 @ @<Account for the compaction and make sure the statistics agree with...@>=
1396 if ( (mp->str_start[mp->str_ptr]!=mp->pool_in_use)||(str_use!=mp->strs_in_use) )
1397   mp_confusion(mp, "string");
1398 @:this can't happen string}{\quad string@>
1399 incr(mp->pact_count);
1400 mp->pact_chars=mp->pact_chars+mp->pool_ptr-str_stop(mp->last_fixed_str);
1401 mp->pact_strs=mp->pact_strs+str_use-mp->fixed_str_use;
1402 #ifdef DEBUG
1403 s=mp->str_ptr; t=str_use;
1404 while ( s<=mp->max_str_ptr ){
1405   if ( t>mp->max_str_ptr ) mp_confusion(mp, "\"");
1406   incr(t); s=mp->next_str[s];
1407 };
1408 if ( t<=mp->max_str_ptr ) mp_confusion(mp, "\"");
1409 #endif
1410
1411 @ A few more global variables are needed to keep track of statistics when
1412 |stat| $\ldots$ |tats| blocks are not commented out.
1413
1414 @<Glob...@>=
1415 integer pact_count; /* number of string pool compactions so far */
1416 integer pact_chars; /* total number of characters moved during compactions */
1417 integer pact_strs; /* total number of strings moved during compactions */
1418
1419 @ @<Initialize compaction statistics@>=
1420 mp->pact_count=0;
1421 mp->pact_chars=0;
1422 mp->pact_strs=0;
1423
1424 @ The following subroutine compares string |s| with another string of the
1425 same length that appears in |buffer| starting at position |k|;
1426 the result is |true| if and only if the strings are equal.
1427
1428 @c 
1429 boolean mp_str_eq_buf (MP mp,str_number s, integer k) {
1430   /* test equality of strings */
1431   pool_pointer j; /* running index */
1432   j=mp->str_start[s];
1433   while ( j<str_stop(s) ) { 
1434     if ( mp->str_pool[j++]!=mp->buffer[k++] ) 
1435       return false;
1436   }
1437   return true;
1438 }
1439
1440 @ Here is a similar routine, but it compares two strings in the string pool,
1441 and it does not assume that they have the same length. If the first string
1442 is lexicographically greater than, less than, or equal to the second,
1443 the result is respectively positive, negative, or zero.
1444
1445 @c 
1446 integer mp_str_vs_str (MP mp, str_number s, str_number t) {
1447   /* test equality of strings */
1448   pool_pointer j,k; /* running indices */
1449   integer ls,lt; /* lengths */
1450   integer l; /* length remaining to test */
1451   ls=length(s); lt=length(t);
1452   if ( ls<=lt ) l=ls; else l=lt;
1453   j=mp->str_start[s]; k=mp->str_start[t];
1454   while ( l-->0 ) { 
1455     if ( mp->str_pool[j]!=mp->str_pool[k] ) {
1456        return (mp->str_pool[j]-mp->str_pool[k]); 
1457     }
1458     incr(j); incr(k);
1459   }
1460   return (ls-lt);
1461 }
1462
1463 @ The initial values of |str_pool|, |str_start|, |pool_ptr|,
1464 and |str_ptr| are computed by the \.{INIMP} program, based in part
1465 on the information that \.{WEB} has output while processing \MP.
1466 @.INIMP@>
1467 @^string pool@>
1468
1469 @c 
1470 void mp_get_strings_started (MP mp) { 
1471   /* initializes the string pool,
1472     but returns |false| if something goes wrong */
1473   int k; /* small indices or counters */
1474   str_number g; /* a new string */
1475   mp->pool_ptr=0; mp->str_ptr=0; mp->max_pool_ptr=0; mp->max_str_ptr=0;
1476   mp->str_start[0]=0;
1477   mp->next_str[0]=1;
1478   mp->pool_in_use=0; mp->strs_in_use=0;
1479   mp->max_pl_used=0; mp->max_strs_used=0;
1480   @<Initialize compaction statistics@>;
1481   mp->strs_used_up=0;
1482   @<Make the first 256 strings@>;
1483   g=mp_make_string(mp); /* string 256 == "" */
1484   mp->str_ref[g]=max_str_ref;
1485   mp->last_fixed_str=mp->str_ptr-1;
1486   mp->fixed_str_use=mp->str_ptr;
1487   return;
1488 }
1489
1490 @ @<Declarations@>=
1491 void mp_get_strings_started (MP mp);
1492
1493 @ The first 256 strings will consist of a single character only.
1494
1495 @<Make the first 256...@>=
1496 for (k=0;k<=255;k++) { 
1497   append_char(k);
1498   g=mp_make_string(mp); 
1499   mp->str_ref[g]=max_str_ref;
1500 }
1501
1502 @ The first 128 strings will contain 95 standard ASCII characters, and the
1503 other 33 characters will be printed in three-symbol form like `\.{\^\^A}'
1504 unless a system-dependent change is made here. Installations that have
1505 an extended character set, where for example |xchr[032]=@t\.{'^^Z'}@>|,
1506 would like string 032 to be printed as the single character 032 instead
1507 of the three characters 0136, 0136, 0132 (\.{\^\^Z}). On the other hand,
1508 even people with an extended character set will want to represent string
1509 015 by \.{\^\^M}, since 015 is ASCII's ``carriage return'' code; the idea is
1510 to produce visible strings instead of tabs or line-feeds or carriage-returns
1511 or bell-rings or characters that are treated anomalously in text files.
1512
1513 Unprintable characters of codes 128--255 are, similarly, rendered
1514 \.{\^\^80}--\.{\^\^ff}.
1515
1516 The boolean expression defined here should be |true| unless \MP\ internal
1517 code number~|k| corresponds to a non-troublesome visible symbol in the
1518 local character set.
1519 If character |k| cannot be printed, and |k<0200|, then character |k+0100| or
1520 |k-0100| must be printable; moreover, ASCII codes |[060..071, 0141..0146]|
1521 must be printable.
1522 @^character set dependencies@>
1523 @^system dependencies@>
1524
1525 @<Character |k| cannot be printed@>=
1526   (k<' ')||(k>'~')
1527
1528 @* \[5] On-line and off-line printing.
1529 Messages that are sent to a user's terminal and to the transcript-log file
1530 are produced by several `|print|' procedures. These procedures will
1531 direct their output to a variety of places, based on the setting of
1532 the global variable |selector|, which has the following possible
1533 values:
1534
1535 \yskip
1536 \hang |term_and_log|, the normal setting, prints on the terminal and on the
1537   transcript file.
1538
1539 \hang |log_only|, prints only on the transcript file.
1540
1541 \hang |term_only|, prints only on the terminal.
1542
1543 \hang |no_print|, doesn't print at all. This is used only in rare cases
1544   before the transcript file is open.
1545
1546 \hang |pseudo|, puts output into a cyclic buffer that is used
1547   by the |show_context| routine; when we get to that routine we shall discuss
1548   the reasoning behind this curious mode.
1549
1550 \hang |new_string|, appends the output to the current string in the
1551   string pool.
1552
1553 \hang |>=write_file| prints on one of the files used for the \&{write}
1554 @:write_}{\&{write} primitive@>
1555   command.
1556
1557 \yskip
1558 \noindent The symbolic names `|term_and_log|', etc., have been assigned
1559 numeric codes that satisfy the convenient relations |no_print+1=term_only|,
1560 |no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|.  These
1561 relations are not used when |selector| could be |pseudo|, or |new_string|.
1562 We need not check for unprintable characters when |selector<pseudo|.
1563
1564 Three additional global variables, |tally|, |term_offset| and |file_offset|
1565 record the number of characters that have been printed
1566 since they were most recently cleared to zero. We use |tally| to record
1567 the length of (possibly very long) stretches of printing; |term_offset|,
1568 and |file_offset|, on the other hand, keep track of how many
1569 characters have appeared so far on the current line that has been output
1570 to the terminal, the transcript file, or the \ps\ output file, respectively.
1571
1572 @d new_string 0 /* printing is deflected to the string pool */
1573 @d pseudo 2 /* special |selector| setting for |show_context| */
1574 @d no_print 3 /* |selector| setting that makes data disappear */
1575 @d term_only 4 /* printing is destined for the terminal only */
1576 @d log_only 5 /* printing is destined for the transcript file only */
1577 @d term_and_log 6 /* normal |selector| setting */
1578 @d write_file 7 /* first write file selector */
1579
1580 @<Glob...@>=
1581 void * log_file; /* transcript of \MP\ session */
1582 void * ps_file; /* the generic font output goes here */
1583 unsigned int selector; /* where to print a message */
1584 unsigned char dig[23]; /* digits in a number being output */
1585 integer tally; /* the number of characters recently printed */
1586 unsigned int term_offset;
1587   /* the number of characters on the current terminal line */
1588 unsigned int file_offset;
1589   /* the number of characters on the current file line */
1590 ASCII_code *trick_buf; /* circular buffer for pseudoprinting */
1591 integer trick_count; /* threshold for pseudoprinting, explained later */
1592 integer first_count; /* another variable for pseudoprinting */
1593
1594 @ @<Allocate or initialize ...@>=
1595 memset(mp->dig,0,23);
1596 mp->trick_buf = xmalloc((mp->error_line+1),sizeof(ASCII_code));
1597
1598 @ @<Dealloc variables@>=
1599 xfree(mp->trick_buf);
1600
1601 @ @<Initialize the output routines@>=
1602 mp->selector=term_only; mp->tally=0; mp->term_offset=0; mp->file_offset=0; 
1603
1604 @ Macro abbreviations for output to the terminal and to the log file are
1605 defined here for convenience. Some systems need special conventions
1606 for terminal output, and it is possible to adhere to those conventions
1607 by changing |wterm|, |wterm_ln|, and |wterm_cr| here.
1608 @^system dependencies@>
1609
1610 @d do_fprintf(f,b) (mp->write_ascii_file)(mp,f,b)
1611 @d wterm(A)     do_fprintf(mp->term_out,(A))
1612 @d wterm_chr(A) { unsigned char ss[2]; ss[0]=(A); ss[1]=0; do_fprintf(mp->term_out,(char *)ss); }
1613 @d wterm_cr     do_fprintf(mp->term_out,"\n")
1614 @d wterm_ln(A)  { wterm_cr; do_fprintf(mp->term_out,(A)); }
1615 @d wlog(A)      do_fprintf(mp->log_file,(A))
1616 @d wlog_chr(A)  { unsigned char ss[2]; ss[0]=(A); ss[1]=0; do_fprintf(mp->log_file,(char *)ss); }
1617 @d wlog_cr      do_fprintf(mp->log_file, "\n")
1618 @d wlog_ln(A)   {wlog_cr; do_fprintf(mp->log_file,(A)); }
1619
1620
1621 @ To end a line of text output, we call |print_ln|.  Cases |0..max_write_files|
1622 use an array |wr_file| that will be declared later.
1623
1624 @d mp_print_text(A) mp_print_str(mp,text((A)))
1625
1626 @<Internal ...@>=
1627 void mp_print_ln (MP mp);
1628 void mp_print_visible_char (MP mp, ASCII_code s); 
1629 void mp_print_char (MP mp, ASCII_code k);
1630 void mp_print (MP mp, char *s);
1631 void mp_print_str (MP mp, str_number s);
1632 void mp_print_nl (MP mp, char *s);
1633 void mp_print_two (MP mp,scaled x, scaled y) ;
1634 void mp_print_scaled (MP mp,scaled s);
1635
1636 @ @<Basic print...@>=
1637 void mp_print_ln (MP mp) { /* prints an end-of-line */
1638  switch (mp->selector) {
1639   case term_and_log: 
1640     wterm_cr; wlog_cr;
1641     mp->term_offset=0;  mp->file_offset=0;
1642     break;
1643   case log_only: 
1644     wlog_cr; mp->file_offset=0;
1645     break;
1646   case term_only: 
1647     wterm_cr; mp->term_offset=0;
1648     break;
1649   case no_print:
1650   case pseudo: 
1651   case new_string: 
1652     break;
1653   default: 
1654     do_fprintf(mp->wr_file[(mp->selector-write_file)],"\n");
1655   }
1656 } /* note that |tally| is not affected */
1657
1658 @ The |print_visible_char| procedure sends one character to the desired
1659 destination, using the |xchr| array to map it into an external character
1660 compatible with |input_ln|.  (It assumes that it is always called with
1661 a visible ASCII character.)  All printing comes through |print_ln| or
1662 |print_char|, which ultimately calls |print_visible_char|, hence these
1663 routines are the ones that limit lines to at most |max_print_line| characters.
1664 But we must make an exception for the \ps\ output file since it is not safe
1665 to cut up lines arbitrarily in \ps.
1666
1667 Procedure |unit_str_room| needs to be declared |forward| here because it calls
1668 |do_compaction| and |do_compaction| can call the error routines.  Actually,
1669 |unit_str_room| avoids |overflow| errors but it can call |confusion|.
1670
1671 @<Basic printing...@>=
1672 void mp_print_visible_char (MP mp, ASCII_code s) { /* prints a single character */
1673   switch (mp->selector) {
1674   case term_and_log: 
1675     wterm_chr(xchr(s)); wlog_chr(xchr(s));
1676     incr(mp->term_offset); incr(mp->file_offset);
1677     if ( mp->term_offset==(unsigned)mp->max_print_line ) { 
1678        wterm_cr; mp->term_offset=0;
1679     };
1680     if ( mp->file_offset==(unsigned)mp->max_print_line ) { 
1681        wlog_cr; mp->file_offset=0;
1682     };
1683     break;
1684   case log_only: 
1685     wlog_chr(xchr(s)); incr(mp->file_offset);
1686     if ( mp->file_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1687     break;
1688   case term_only: 
1689     wterm_chr(xchr(s)); incr(mp->term_offset);
1690     if ( mp->term_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1691     break;
1692   case no_print: 
1693     break;
1694   case pseudo: 
1695     if ( mp->tally<mp->trick_count ) 
1696       mp->trick_buf[mp->tally % mp->error_line]=s;
1697     break;
1698   case new_string: 
1699     if ( mp->pool_ptr>=mp->max_pool_ptr ) { 
1700       mp_unit_str_room(mp);
1701       if ( mp->pool_ptr>=mp->pool_size ) 
1702         goto DONE; /* drop characters if string space is full */
1703     };
1704     append_char(s);
1705     break;
1706   default:
1707     { char ss[2]; ss[0] = xchr(s); ss[1]=0;
1708       do_fprintf(mp->wr_file[(mp->selector-write_file)],(char *)ss);
1709     }
1710   }
1711 DONE:
1712   incr(mp->tally);
1713 }
1714
1715 @ The |print_char| procedure sends one character to the desired destination.
1716 File names and string expressions might contain |ASCII_code| values that
1717 can't be printed using |print_visible_char|.  These characters will be
1718 printed in three- or four-symbol form like `\.{\^\^A}' or `\.{\^\^e4}'.
1719 (This procedure assumes that it is safe to bypass all checks for unprintable
1720 characters when |selector| is in the range |0..max_write_files-1|.
1721 The user might want to write unprintable characters.
1722
1723 @d print_lc_hex(A) do { l=(A);
1724     mp_print_visible_char(mp, (l<10 ? l+'0' : l-10+'a'));
1725   } while (0)
1726
1727 @<Basic printing...@>=
1728 void mp_print_char (MP mp, ASCII_code k) { /* prints a single character */
1729   int l; /* small index or counter */
1730   if ( mp->selector<pseudo || mp->selector>=write_file) {
1731     mp_print_visible_char(mp, k);
1732   } else if ( @<Character |k| cannot be printed@> ) { 
1733     mp_print(mp, "^^"); 
1734     if ( k<0100 ) { 
1735       mp_print_visible_char(mp, k+0100); 
1736     } else if ( k<0200 ) { 
1737       mp_print_visible_char(mp, k-0100); 
1738     } else { 
1739       print_lc_hex(k / 16);  
1740       print_lc_hex(k % 16); 
1741     }
1742   } else {
1743     mp_print_visible_char(mp, k);
1744   }
1745 };
1746
1747 @ An entire string is output by calling |print|. Note that if we are outputting
1748 the single standard ASCII character \.c, we could call |print("c")|, since
1749 |"c"=99| is the number of a single-character string, as explained above. But
1750 |print_char("c")| is quicker, so \MP\ goes directly to the |print_char|
1751 routine when it knows that this is safe. (The present implementation
1752 assumes that it is always safe to print a visible ASCII character.)
1753 @^system dependencies@>
1754
1755 @<Basic print...@>=
1756 void mp_do_print (MP mp, char *ss, unsigned int len) { /* prints string |s| */
1757   unsigned int j = 0;
1758   while ( j<len ){ 
1759     mp_print_char(mp, ss[j]); incr(j);
1760   }
1761 }
1762
1763
1764 @<Basic print...@>=
1765 void mp_print (MP mp, char *ss) {
1766   mp_do_print(mp, ss, strlen(ss));
1767 }
1768 void mp_print_str (MP mp, str_number s) {
1769   pool_pointer j; /* current character code position */
1770   if ( (s<0)||(s>mp->max_str_ptr) ) {
1771      mp_do_print(mp,"???",3); /* this can't happen */
1772 @.???@>
1773   }
1774   j=mp->str_start[s];
1775   mp_do_print(mp, (char *)(mp->str_pool+j), (str_stop(s)-j));
1776 }
1777
1778
1779 @ Here is the very first thing that \MP\ prints: a headline that identifies
1780 the version number and base name. The |term_offset| variable is temporarily
1781 incorrect, but the discrepancy is not serious since we assume that the banner
1782 and mem identifier together will occupy at most |max_print_line|
1783 character positions.
1784
1785 @<Initialize the output...@>=
1786 wterm (banner);
1787 wterm (version_string);
1788 if (mp->mem_ident!=NULL) 
1789   mp_print(mp,mp->mem_ident); 
1790 mp_print_ln(mp);
1791 update_terminal;
1792
1793 @ The procedure |print_nl| is like |print|, but it makes sure that the
1794 string appears at the beginning of a new line.
1795
1796 @<Basic print...@>=
1797 void mp_print_nl (MP mp, char *s) { /* prints string |s| at beginning of line */
1798   switch(mp->selector) {
1799   case term_and_log: 
1800     if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_ln(mp);
1801     break;
1802   case log_only: 
1803     if ( mp->file_offset>0 ) mp_print_ln(mp);
1804     break;
1805   case term_only: 
1806     if ( mp->term_offset>0 ) mp_print_ln(mp);
1807     break;
1808   case no_print:
1809   case pseudo:
1810   case new_string: 
1811         break;
1812   } /* there are no other cases */
1813   mp_print(mp, s);
1814 }
1815
1816 @ An array of digits in the range |0..9| is printed by |print_the_digs|.
1817
1818 @<Basic print...@>=
1819 void mp_print_the_digs (MP mp, eight_bits k) {
1820   /* prints |dig[k-1]|$\,\ldots\,$|dig[0]| */
1821   while ( k>0 ){ 
1822     decr(k); mp_print_char(mp, '0'+mp->dig[k]);
1823   }
1824 };
1825
1826 @ The following procedure, which prints out the decimal representation of a
1827 given integer |n|, has been written carefully so that it works properly
1828 if |n=0| or if |(-n)| would cause overflow. It does not apply |%| or |/|
1829 to negative arguments, since such operations are not implemented consistently
1830 on all platforms.
1831
1832 @<Basic print...@>=
1833 void mp_print_int (MP mp,integer n) { /* prints an integer in decimal form */
1834   integer m; /* used to negate |n| in possibly dangerous cases */
1835   int k = 0; /* index to current digit; we assume that $|n|<10^{23}$ */
1836   if ( n<0 ) { 
1837     mp_print_char(mp, '-');
1838     if ( n>-100000000 ) {
1839           negate(n);
1840     } else  { 
1841           m=-1-n; n=m / 10; m=(m % 10)+1; k=1;
1842       if ( m<10 ) {
1843         mp->dig[0]=m;
1844       } else { 
1845         mp->dig[0]=0; incr(n);
1846       }
1847     }
1848   }
1849   do {  
1850     mp->dig[k]=n % 10; n=n / 10; incr(k);
1851   } while (n!=0);
1852   mp_print_the_digs(mp, k);
1853 };
1854
1855 @ @<Internal ...@>=
1856 void mp_print_int (MP mp,integer n);
1857
1858 @ \MP\ also makes use of a trivial procedure to print two digits. The
1859 following subroutine is usually called with a parameter in the range |0<=n<=99|.
1860
1861 @c 
1862 void mp_print_dd (MP mp,integer n) { /* prints two least significant digits */
1863   n=abs(n) % 100; 
1864   mp_print_char(mp, '0'+(n / 10));
1865   mp_print_char(mp, '0'+(n % 10));
1866 }
1867
1868
1869 @ @<Internal ...@>=
1870 void mp_print_dd (MP mp,integer n);
1871
1872 @ Here is a procedure that asks the user to type a line of input,
1873 assuming that the |selector| setting is either |term_only| or |term_and_log|.
1874 The input is placed into locations |first| through |last-1| of the
1875 |buffer| array, and echoed on the transcript file if appropriate.
1876
1877 This procedure is never called when |interaction<mp_scroll_mode|.
1878
1879 @d prompt_input(A) do { 
1880     if (!mp->noninteractive) {
1881       wake_up_terminal; mp_print(mp, (A)); 
1882     }
1883     mp_term_input(mp);
1884   } while (0) /* prints a string and gets a line of input */
1885
1886 @c 
1887 void mp_term_input (MP mp) { /* gets a line from the terminal */
1888   size_t k; /* index into |buffer| */
1889   update_terminal; /* Now the user sees the prompt for sure */
1890   if (!mp_input_ln(mp, mp->term_in )) {
1891     if (!mp->noninteractive) {
1892           mp_fatal_error(mp, "End of file on the terminal!");
1893 @.End of file on the terminal@>
1894     } else { /* we are done with this input chunk */
1895           longjmp(mp->jump_buf,1);      
1896     }
1897   }
1898   if (!mp->noninteractive) {
1899     mp->term_offset=0; /* the user's line ended with \<\rm return> */
1900     decr(mp->selector); /* prepare to echo the input */
1901     if ( mp->last!=mp->first ) {
1902       for (k=mp->first;k<=mp->last-1;k++) {
1903         mp_print_char(mp, mp->buffer[k]);
1904       }
1905     }
1906     mp_print_ln(mp); 
1907     mp->buffer[mp->last]='%'; 
1908     incr(mp->selector); /* restore previous status */
1909   }
1910 }
1911
1912 @* \[6] Reporting errors.
1913 When something anomalous is detected, \MP\ typically does something like this:
1914 $$\vbox{\halign{#\hfil\cr
1915 |print_err("Something anomalous has been detected");|\cr
1916 |help3("This is the first line of my offer to help.")|\cr
1917 |("This is the second line. I'm trying to")|\cr
1918 |("explain the best way for you to proceed.");|\cr
1919 |error;|\cr}}$$
1920 A two-line help message would be given using |help2|, etc.; these informal
1921 helps should use simple vocabulary that complements the words used in the
1922 official error message that was printed. (Outside the U.S.A., the help
1923 messages should preferably be translated into the local vernacular. Each
1924 line of help is at most 60 characters long, in the present implementation,
1925 so that |max_print_line| will not be exceeded.)
1926
1927 The |print_err| procedure supplies a `\.!' before the official message,
1928 and makes sure that the terminal is awake if a stop is going to occur.
1929 The |error| procedure supplies a `\..' after the official message, then it
1930 shows the location of the error; and if |interaction=error_stop_mode|,
1931 it also enters into a dialog with the user, during which time the help
1932 message may be printed.
1933 @^system dependencies@>
1934
1935 @ The global variable |interaction| has four settings, representing increasing
1936 amounts of user interaction:
1937
1938 @<Exported types@>=
1939 enum mp_interaction_mode { 
1940  mp_unspecified_mode=0, /* extra value for command-line switch */
1941  mp_batch_mode, /* omits all stops and omits terminal output */
1942  mp_nonstop_mode, /* omits all stops */
1943  mp_scroll_mode, /* omits error stops */
1944  mp_error_stop_mode, /* stops at every opportunity to interact */
1945 };
1946
1947 @ @<Option variables@>=
1948 int interaction; /* current level of interaction */
1949 int noninteractive; /* do we have a terminal? */
1950
1951 @ Set it here so it can be overwritten by the commandline
1952
1953 @<Allocate or initialize ...@>=
1954 mp->interaction=opt->interaction;
1955 if (mp->interaction==mp_unspecified_mode || mp->interaction>mp_error_stop_mode) 
1956   mp->interaction=mp_error_stop_mode;
1957 if (mp->interaction<mp_unspecified_mode) 
1958   mp->interaction=mp_batch_mode;
1959 mp->noninteractive=opt->noninteractive;
1960
1961
1962
1963 @d print_err(A) mp_print_err(mp,(A))
1964
1965 @<Internal ...@>=
1966 void mp_print_err(MP mp, char * A);
1967
1968 @ @c
1969 void mp_print_err(MP mp, char * A) { 
1970   if ( mp->interaction==mp_error_stop_mode ) 
1971     wake_up_terminal;
1972   mp_print_nl(mp, "! "); 
1973   mp_print(mp, A);
1974 @.!\relax@>
1975 }
1976
1977
1978 @ \MP\ is careful not to call |error| when the print |selector| setting
1979 might be unusual. The only possible values of |selector| at the time of
1980 error messages are
1981
1982 \yskip\hang|no_print| (when |interaction=mp_batch_mode|
1983   and |log_file| not yet open);
1984
1985 \hang|term_only| (when |interaction>mp_batch_mode| and |log_file| not yet open);
1986
1987 \hang|log_only| (when |interaction=mp_batch_mode| and |log_file| is open);
1988
1989 \hang|term_and_log| (when |interaction>mp_batch_mode| and |log_file| is open).
1990
1991 @<Initialize the print |selector| based on |interaction|@>=
1992 if ( mp->interaction==mp_batch_mode ) mp->selector=no_print; else mp->selector=term_only
1993
1994 @ A global variable |deletions_allowed| is set |false| if the |get_next|
1995 routine is active when |error| is called; this ensures that |get_next|
1996 will never be called recursively.
1997 @^recursion@>
1998
1999 The global variable |history| records the worst level of error that
2000 has been detected. It has four possible values: |spotless|, |warning_issued|,
2001 |error_message_issued|, and |fatal_error_stop|.
2002
2003 Another global variable, |error_count|, is increased by one when an
2004 |error| occurs without an interactive dialog, and it is reset to zero at
2005 the end of every statement.  If |error_count| reaches 100, \MP\ decides
2006 that there is no point in continuing further.
2007
2008 @<Types...@>=
2009 enum mp_history_states {
2010   mp_spotless=0, /* |history| value when nothing has been amiss yet */
2011   mp_warning_issued, /* |history| value when |begin_diagnostic| has been called */
2012   mp_error_message_issued, /* |history| value when |error| has been called */
2013   mp_fatal_error_stop, /* |history| value when termination was premature */
2014 };
2015
2016 @ @<Glob...@>=
2017 boolean deletions_allowed; /* is it safe for |error| to call |get_next|? */
2018 int history; /* has the source input been clean so far? */
2019 int error_count; /* the number of scrolled errors since the last statement ended */
2020
2021 @ The value of |history| is initially |fatal_error_stop|, but it will
2022 be changed to |spotless| if \MP\ survives the initialization process.
2023
2024 @<Allocate or ...@>=
2025 mp->deletions_allowed=true; mp->error_count=0; /* |history| is initialized elsewhere */
2026
2027 @ Since errors can be detected almost anywhere in \MP, we want to declare the
2028 error procedures near the beginning of the program. But the error procedures
2029 in turn use some other procedures, which need to be declared |forward|
2030 before we get to |error| itself.
2031
2032 It is possible for |error| to be called recursively if some error arises
2033 when |get_next| is being used to delete a token, and/or if some fatal error
2034 occurs while \MP\ is trying to fix a non-fatal one. But such recursion
2035 @^recursion@>
2036 is never more than two levels deep.
2037
2038 @<Declarations@>=
2039 void mp_get_next (MP mp);
2040 void mp_term_input (MP mp);
2041 void mp_show_context (MP mp);
2042 void mp_begin_file_reading (MP mp);
2043 void mp_open_log_file (MP mp);
2044 void mp_clear_for_error_prompt (MP mp);
2045 void mp_debug_help (MP mp);
2046 @<Declare the procedure called |flush_string|@>
2047
2048 @ @<Internal ...@>=
2049 void mp_normalize_selector (MP mp);
2050
2051 @ Individual lines of help are recorded in the array |help_line|, which
2052 contains entries in positions |0..(help_ptr-1)|. They should be printed
2053 in reverse order, i.e., with |help_line[0]| appearing last.
2054
2055 @d hlp1(A) mp->help_line[0]=(A); }
2056 @d hlp2(A) mp->help_line[1]=(A); hlp1
2057 @d hlp3(A) mp->help_line[2]=(A); hlp2
2058 @d hlp4(A) mp->help_line[3]=(A); hlp3
2059 @d hlp5(A) mp->help_line[4]=(A); hlp4
2060 @d hlp6(A) mp->help_line[5]=(A); hlp5
2061 @d help0 mp->help_ptr=0 /* sometimes there might be no help */
2062 @d help1  { mp->help_ptr=1; hlp1 /* use this with one help line */
2063 @d help2  { mp->help_ptr=2; hlp2 /* use this with two help lines */
2064 @d help3  { mp->help_ptr=3; hlp3 /* use this with three help lines */
2065 @d help4  { mp->help_ptr=4; hlp4 /* use this with four help lines */
2066 @d help5  { mp->help_ptr=5; hlp5 /* use this with five help lines */
2067 @d help6  { mp->help_ptr=6; hlp6 /* use this with six help lines */
2068
2069 @<Glob...@>=
2070 char * help_line[6]; /* helps for the next |error| */
2071 unsigned int help_ptr; /* the number of help lines present */
2072 boolean use_err_help; /* should the |err_help| string be shown? */
2073 str_number err_help; /* a string set up by \&{errhelp} */
2074 str_number filename_template; /* a string set up by \&{filenametemplate} */
2075
2076 @ @<Allocate or ...@>=
2077 mp->help_ptr=0; mp->use_err_help=false; mp->err_help=0; mp->filename_template=0;
2078
2079 @ The |jump_out| procedure just cuts across all active procedure levels and
2080 goes to |end_of_MP|. This is the only nonlocal |goto| statement in the
2081 whole program. It is used when there is no recovery from a particular error.
2082
2083 The program uses a |jump_buf| to handle this, this is initialized at three
2084 spots: the start of |mp_new|, the start of |mp_initialize|, and the start 
2085 of |mp_run|. Those are the only library enty points.
2086
2087 @^system dependencies@>
2088
2089 @<Glob...@>=
2090 jmp_buf jump_buf;
2091
2092 @ @<Install and test the non-local jump buffer@>=
2093 if (setjmp(mp->jump_buf) != 0) { return mp->history; }
2094
2095
2096 @ @<Setup the non-local jump buffer in |mp_new|@>=
2097 if (setjmp(mp->jump_buf) != 0) return NULL;
2098
2099 @ If the array of internals is still |NULL| when |jump_out| is called, a
2100 crash occured during initialization, and it is not safe to run the normal
2101 cleanup routine.
2102
2103 @<Error hand...@>=
2104 void mp_jump_out (MP mp) { 
2105   if(mp->internal!=NULL)
2106     mp_close_files_and_terminate(mp);
2107   longjmp(mp->jump_buf,1);
2108 }
2109
2110 @ Here now is the general |error| routine.
2111
2112 @<Error hand...@>=
2113 void mp_error (MP mp) { /* completes the job of error reporting */
2114   ASCII_code c; /* what the user types */
2115   integer s1,s2,s3; /* used to save global variables when deleting tokens */
2116   pool_pointer j; /* character position being printed */
2117   if ( mp->history<mp_error_message_issued ) 
2118         mp->history=mp_error_message_issued;
2119   mp_print_char(mp, '.'); mp_show_context(mp);
2120   if ((!mp->noninteractive) && (mp->interaction==mp_error_stop_mode )) {
2121     @<Get user's advice and |return|@>;
2122   }
2123   incr(mp->error_count);
2124   if ( mp->error_count==100 ) { 
2125     mp_print_nl(mp,"(That makes 100 errors; please try again.)");
2126 @.That makes 100 errors...@>
2127     mp->history=mp_fatal_error_stop; mp_jump_out(mp);
2128   }
2129   @<Put help message on the transcript file@>;
2130 }
2131 void mp_warn (MP mp, char *msg) {
2132   int saved_selector = mp->selector;
2133   mp_normalize_selector(mp);
2134   mp_print_nl(mp,"Warning: ");
2135   mp_print(mp,msg);
2136   mp->selector = saved_selector;
2137 }
2138
2139 @ @<Exported function ...@>=
2140 void mp_error (MP mp);
2141 void mp_warn (MP mp, char *msg);
2142
2143
2144 @ @<Get user's advice...@>=
2145 while (1) { 
2146 CONTINUE:
2147   mp_clear_for_error_prompt(mp); prompt_input("? ");
2148 @.?\relax@>
2149   if ( mp->last==mp->first ) return;
2150   c=mp->buffer[mp->first];
2151   if ( c>='a' ) c=c+'A'-'a'; /* convert to uppercase */
2152   @<Interpret code |c| and |return| if done@>;
2153 }
2154
2155 @ It is desirable to provide an `\.E' option here that gives the user
2156 an easy way to return from \MP\ to the system editor, with the offending
2157 line ready to be edited. But such an extension requires some system
2158 wizardry, so the present implementation simply types out the name of the
2159 file that should be
2160 edited and the relevant line number.
2161 @^system dependencies@>
2162
2163 @<Exported types@>=
2164 typedef void (*mp_run_editor_command)(MP, char *, int);
2165
2166 @ @<Option variables@>=
2167 mp_run_editor_command run_editor;
2168
2169 @ @<Allocate or initialize ...@>=
2170 set_callback_option(run_editor);
2171
2172 @ @<Declarations@>=
2173 void mp_run_editor (MP mp, char *fname, int fline);
2174
2175 @ @c void mp_run_editor (MP mp, char *fname, int fline) {
2176     mp_print_nl(mp, "You want to edit file ");
2177 @.You want to edit file x@>
2178     mp_print(mp, fname);
2179     mp_print(mp, " at line "); 
2180     mp_print_int(mp, fline);
2181     mp->interaction=mp_scroll_mode; 
2182     mp_jump_out(mp);
2183 }
2184
2185
2186 There is a secret `\.D' option available when the debugging routines haven't
2187 been commented~out.
2188 @^debugging@>
2189
2190 @<Interpret code |c| and |return| if done@>=
2191 switch (c) {
2192 case '0': case '1': case '2': case '3': case '4':
2193 case '5': case '6': case '7': case '8': case '9': 
2194   if ( mp->deletions_allowed ) {
2195     @<Delete |c-"0"| tokens and |continue|@>;
2196   }
2197   break;
2198 #ifdef DEBUG
2199 case 'D': 
2200   mp_debug_help(mp); continue; 
2201   break;
2202 #endif
2203 case 'E': 
2204   if ( mp->file_ptr>0 ){ 
2205     (mp->run_editor)(mp, 
2206                      str(mp->input_stack[mp->file_ptr].name_field), 
2207                      mp_true_line(mp));
2208   }
2209   break;
2210 case 'H': 
2211   @<Print the help information and |continue|@>;
2212   break;
2213 case 'I':
2214   @<Introduce new material from the terminal and |return|@>;
2215   break;
2216 case 'Q': case 'R': case 'S':
2217   @<Change the interaction level and |return|@>;
2218   break;
2219 case 'X':
2220   mp->interaction=mp_scroll_mode; mp_jump_out(mp);
2221   break;
2222 default:
2223   break;
2224 }
2225 @<Print the menu of available options@>
2226
2227 @ @<Print the menu...@>=
2228
2229   mp_print(mp, "Type <return> to proceed, S to scroll future error messages,");
2230 @.Type <return> to proceed...@>
2231   mp_print_nl(mp, "R to run without stopping, Q to run quietly,");
2232   mp_print_nl(mp, "I to insert something, ");
2233   if ( mp->file_ptr>0 ) 
2234     mp_print(mp, "E to edit your file,");
2235   if ( mp->deletions_allowed )
2236     mp_print_nl(mp, "1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
2237   mp_print_nl(mp, "H for help, X to quit.");
2238 }
2239
2240 @ Here the author of \MP\ apologizes for making use of the numerical
2241 relation between |"Q"|, |"R"|, |"S"|, and the desired interaction settings
2242 |mp_batch_mode|, |mp_nonstop_mode|, |mp_scroll_mode|.
2243 @^Knuth, Donald Ervin@>
2244
2245 @<Change the interaction...@>=
2246
2247   mp->error_count=0; mp->interaction=mp_batch_mode+c-'Q';
2248   mp_print(mp, "OK, entering ");
2249   switch (c) {
2250   case 'Q': mp_print(mp, "batchmode"); decr(mp->selector); break;
2251   case 'R': mp_print(mp, "nonstopmode"); break;
2252   case 'S': mp_print(mp, "scrollmode"); break;
2253   } /* there are no other cases */
2254   mp_print(mp, "..."); mp_print_ln(mp); update_terminal; return;
2255 }
2256
2257 @ When the following code is executed, |buffer[(first+1)..(last-1)]| may
2258 contain the material inserted by the user; otherwise another prompt will
2259 be given. In order to understand this part of the program fully, you need
2260 to be familiar with \MP's input stacks.
2261
2262 @<Introduce new material...@>=
2263
2264   mp_begin_file_reading(mp); /* enter a new syntactic level for terminal input */
2265   if ( mp->last>mp->first+1 ) { 
2266     loc=mp->first+1; mp->buffer[mp->first]=' ';
2267   } else { 
2268    prompt_input("insert>"); loc=mp->first;
2269 @.insert>@>
2270   };
2271   mp->first=mp->last+1; mp->cur_input.limit_field=mp->last; return;
2272 }
2273
2274 @ We allow deletion of up to 99 tokens at a time.
2275
2276 @<Delete |c-"0"| tokens...@>=
2277
2278   s1=mp->cur_cmd; s2=mp->cur_mod; s3=mp->cur_sym; mp->OK_to_interrupt=false;
2279   if ( (mp->last>mp->first+1) && (mp->buffer[mp->first+1]>='0')&&(mp->buffer[mp->first+1]<='9') )
2280     c=c*10+mp->buffer[mp->first+1]-'0'*11;
2281   else 
2282     c=c-'0';
2283   while ( c>0 ) { 
2284     mp_get_next(mp); /* one-level recursive call of |error| is possible */
2285     @<Decrease the string reference count, if the current token is a string@>;
2286     decr(c);
2287   };
2288   mp->cur_cmd=s1; mp->cur_mod=s2; mp->cur_sym=s3; mp->OK_to_interrupt=true;
2289   help2("I have just deleted some text, as you asked.")
2290        ("You can now delete more, or insert, or whatever.");
2291   mp_show_context(mp); 
2292   goto CONTINUE;
2293 }
2294
2295 @ @<Print the help info...@>=
2296
2297   if ( mp->use_err_help ) { 
2298     @<Print the string |err_help|, possibly on several lines@>;
2299     mp->use_err_help=false;
2300   } else { 
2301     if ( mp->help_ptr==0 ) {
2302       help2("Sorry, I don't know how to help in this situation.")
2303            ("Maybe you should try asking a human?");
2304      }
2305     do { 
2306       decr(mp->help_ptr); mp_print(mp, mp->help_line[mp->help_ptr]); mp_print_ln(mp);
2307     } while (mp->help_ptr!=0);
2308   };
2309   help4("Sorry, I already gave what help I could...")
2310        ("Maybe you should try asking a human?")
2311        ("An error might have occurred before I noticed any problems.")
2312        ("``If all else fails, read the instructions.''");
2313   goto CONTINUE;
2314 }
2315
2316 @ @<Print the string |err_help|, possibly on several lines@>=
2317 j=mp->str_start[mp->err_help];
2318 while ( j<str_stop(mp->err_help) ) { 
2319   if ( mp->str_pool[j]!='%' ) mp_print_str(mp, mp->str_pool[j]);
2320   else if ( j+1==str_stop(mp->err_help) ) mp_print_ln(mp);
2321   else if ( mp->str_pool[j+1]!='%' ) mp_print_ln(mp);
2322   else  { incr(j); mp_print_char(mp, '%'); };
2323   incr(j);
2324 }
2325
2326 @ @<Put help message on the transcript file@>=
2327 if ( mp->interaction>mp_batch_mode ) decr(mp->selector); /* avoid terminal output */
2328 if ( mp->use_err_help ) { 
2329   mp_print_nl(mp, "");
2330   @<Print the string |err_help|, possibly on several lines@>;
2331 } else { 
2332   while ( mp->help_ptr>0 ){ 
2333     decr(mp->help_ptr); mp_print_nl(mp, mp->help_line[mp->help_ptr]);
2334   };
2335 }
2336 mp_print_ln(mp);
2337 if ( mp->interaction>mp_batch_mode ) incr(mp->selector); /* re-enable terminal output */
2338 mp_print_ln(mp)
2339
2340 @ In anomalous cases, the print selector might be in an unknown state;
2341 the following subroutine is called to fix things just enough to keep
2342 running a bit longer.
2343
2344 @c 
2345 void mp_normalize_selector (MP mp) { 
2346   if ( mp->log_opened ) mp->selector=term_and_log;
2347   else mp->selector=term_only;
2348   if ( mp->job_name==NULL ) mp_open_log_file(mp);
2349   if ( mp->interaction==mp_batch_mode ) decr(mp->selector);
2350 }
2351
2352 @ The following procedure prints \MP's last words before dying.
2353
2354 @d succumb { if ( mp->interaction==mp_error_stop_mode )
2355     mp->interaction=mp_scroll_mode; /* no more interaction */
2356   if ( mp->log_opened ) mp_error(mp);
2357   /*| if ( mp->interaction>mp_batch_mode ) mp_debug_help(mp); |*/
2358   mp->history=mp_fatal_error_stop; mp_jump_out(mp); /* irrecoverable error */
2359   }
2360
2361 @<Error hand...@>=
2362 void mp_fatal_error (MP mp, char *s) { /* prints |s|, and that's it */
2363   mp_normalize_selector(mp);
2364   print_err("Emergency stop"); help1(s); succumb;
2365 @.Emergency stop@>
2366 }
2367
2368 @ @<Exported function ...@>=
2369 void mp_fatal_error (MP mp, char *s);
2370
2371
2372 @ Here is the most dreaded error message.
2373
2374 @<Error hand...@>=
2375 void mp_overflow (MP mp, char *s, integer n) { /* stop due to finiteness */
2376   mp_normalize_selector(mp);
2377   print_err("MetaPost capacity exceeded, sorry [");
2378 @.MetaPost capacity exceeded ...@>
2379   mp_print(mp, s); mp_print_char(mp, '='); mp_print_int(mp, n); mp_print_char(mp, ']');
2380   help2("If you really absolutely need more capacity,")
2381        ("you can ask a wizard to enlarge me.");
2382   succumb;
2383 }
2384
2385 @ @<Internal library declarations@>=
2386 void mp_overflow (MP mp, char *s, integer n);
2387
2388 @ The program might sometime run completely amok, at which point there is
2389 no choice but to stop. If no previous error has been detected, that's bad
2390 news; a message is printed that is really intended for the \MP\
2391 maintenance person instead of the user (unless the user has been
2392 particularly diabolical).  The index entries for `this can't happen' may
2393 help to pinpoint the problem.
2394 @^dry rot@>
2395
2396 @<Internal library ...@>=
2397 void mp_confusion (MP mp,char *s);
2398
2399 @ @<Error hand...@>=
2400 void mp_confusion (MP mp,char *s) {
2401   /* consistency check violated; |s| tells where */
2402   mp_normalize_selector(mp);
2403   if ( mp->history<mp_error_message_issued ) { 
2404     print_err("This can't happen ("); mp_print(mp, s); mp_print_char(mp, ')');
2405 @.This can't happen@>
2406     help1("I'm broken. Please show this to someone who can fix can fix");
2407   } else { 
2408     print_err("I can\'t go on meeting you like this");
2409 @.I can't go on...@>
2410     help2("One of your faux pas seems to have wounded me deeply...")
2411          ("in fact, I'm barely conscious. Please fix it and try again.");
2412   }
2413   succumb;
2414 }
2415
2416 @ Users occasionally want to interrupt \MP\ while it's running.
2417 If the runtime system allows this, one can implement
2418 a routine that sets the global variable |interrupt| to some nonzero value
2419 when such an interrupt is signaled. Otherwise there is probably at least
2420 a way to make |interrupt| nonzero using the C debugger.
2421 @^system dependencies@>
2422 @^debugging@>
2423
2424 @d check_interrupt { if ( mp->interrupt!=0 )
2425    mp_pause_for_instructions(mp); }
2426
2427 @<Global...@>=
2428 integer interrupt; /* should \MP\ pause for instructions? */
2429 boolean OK_to_interrupt; /* should interrupts be observed? */
2430 integer run_state; /* are we processing input ?*/
2431
2432 @ @<Allocate or ...@>=
2433 mp->interrupt=0; mp->OK_to_interrupt=true; mp->run_state=0; 
2434
2435 @ When an interrupt has been detected, the program goes into its
2436 highest interaction level and lets the user have the full flexibility of
2437 the |error| routine.  \MP\ checks for interrupts only at times when it is
2438 safe to do this.
2439
2440 @c 
2441 void mp_pause_for_instructions (MP mp) { 
2442   if ( mp->OK_to_interrupt ) { 
2443     mp->interaction=mp_error_stop_mode;
2444     if ( (mp->selector==log_only)||(mp->selector==no_print) )
2445       incr(mp->selector);
2446     print_err("Interruption");
2447 @.Interruption@>
2448     help3("You rang?")
2449          ("Try to insert some instructions for me (e.g.,`I show x'),")
2450          ("unless you just want to quit by typing `X'.");
2451     mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
2452     mp->interrupt=0;
2453   }
2454 }
2455
2456 @ Many of \MP's error messages state that a missing token has been
2457 inserted behind the scenes. We can save string space and program space
2458 by putting this common code into a subroutine.
2459
2460 @c 
2461 void mp_missing_err (MP mp, char *s) { 
2462   print_err("Missing `"); mp_print(mp, s); mp_print(mp, "' has been inserted");
2463 @.Missing...inserted@>
2464 }
2465
2466 @* \[7] Arithmetic with scaled numbers.
2467 The principal computations performed by \MP\ are done entirely in terms of
2468 integers less than $2^{31}$ in magnitude; thus, the arithmetic specified in this
2469 program can be carried out in exactly the same way on a wide variety of
2470 computers, including some small ones.
2471 @^small computers@>
2472
2473 But C does not rigidly define the |/| operation in the case of negative
2474 dividends; for example, the result of |(-2*n-1) / 2| is |-(n+1)| on some
2475 computers and |-n| on others (is this true ?).  There are two principal
2476 types of arithmetic: ``translation-preserving,'' in which the identity
2477 |(a+q*b)/b=(a/b)+q| is valid; and ``negation-preserving,'' in which
2478 |(-a)/b=-(a/b)|. This leads to two \MP s, which can produce
2479 different results, although the differences should be negligible when the
2480 language is being used properly.  The \TeX\ processor has been defined
2481 carefully so that both varieties of arithmetic will produce identical
2482 output, but it would be too inefficient to constrain \MP\ in a similar way.
2483
2484 @d el_gordo   017777777777 /* $2^{31}-1$, the largest value that \MP\ likes */
2485
2486 @ One of \MP's most common operations is the calculation of
2487 $\lfloor{a+b\over2}\rfloor$,
2488 the midpoint of two given integers |a| and~|b|. The most decent way to do
2489 this is to write `|(a+b)/2|'; but on many machines it is more efficient 
2490 to calculate `|(a+b)>>1|'.
2491
2492 Therefore the midpoint operation will always be denoted by `|half(a+b)|'
2493 in this program. If \MP\ is being implemented with languages that permit
2494 binary shifting, the |half| macro should be changed to make this operation
2495 as efficient as possible.  Since some systems have shift operators that can
2496 only be trusted to work on positive numbers, there is also a macro |halfp|
2497 that is used only when the quantity being halved is known to be positive
2498 or zero.
2499
2500 @d half(A) ((A) / 2)
2501 @d halfp(A) ((A) >> 1)
2502
2503 @ A single computation might use several subroutine calls, and it is
2504 desirable to avoid producing multiple error messages in case of arithmetic
2505 overflow. So the routines below set the global variable |arith_error| to |true|
2506 instead of reporting errors directly to the user.
2507
2508 @<Glob...@>=
2509 boolean arith_error; /* has arithmetic overflow occurred recently? */
2510
2511 @ @<Allocate or ...@>=
2512 mp->arith_error=false;
2513
2514 @ At crucial points the program will say |check_arith|, to test if
2515 an arithmetic error has been detected.
2516
2517 @d check_arith { if ( mp->arith_error ) mp_clear_arith(mp); }
2518
2519 @c 
2520 void mp_clear_arith (MP mp) { 
2521   print_err("Arithmetic overflow");
2522 @.Arithmetic overflow@>
2523   help4("Uh, oh. A little while ago one of the quantities that I was")
2524        ("computing got too large, so I'm afraid your answers will be")
2525        ("somewhat askew. You'll probably have to adopt different")
2526        ("tactics next time. But I shall try to carry on anyway.");
2527   mp_error(mp); 
2528   mp->arith_error=false;
2529 }
2530
2531 @ Addition is not always checked to make sure that it doesn't overflow,
2532 but in places where overflow isn't too unlikely the |slow_add| routine
2533 is used.
2534
2535 @c integer mp_slow_add (MP mp,integer x, integer y) { 
2536   if ( x>=0 )  {
2537     if ( y<=el_gordo-x ) { 
2538       return x+y;
2539     } else  { 
2540       mp->arith_error=true; 
2541           return el_gordo;
2542     }
2543   } else  if ( -y<=el_gordo+x ) {
2544     return x+y;
2545   } else { 
2546     mp->arith_error=true; 
2547         return -el_gordo;
2548   }
2549 }
2550
2551 @ Fixed-point arithmetic is done on {\sl scaled integers\/} that are multiples
2552 of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
2553 positions from the right end of a binary computer word.
2554
2555 @d quarter_unit   040000 /* $2^{14}$, represents 0.250000 */
2556 @d half_unit   0100000 /* $2^{15}$, represents 0.50000 */
2557 @d three_quarter_unit   0140000 /* $3\cdot2^{14}$, represents 0.75000 */
2558 @d unity   0200000 /* $2^{16}$, represents 1.00000 */
2559 @d two   0400000 /* $2^{17}$, represents 2.00000 */
2560 @d three   0600000 /* $2^{17}+2^{16}$, represents 3.00000 */
2561
2562 @<Types...@>=
2563 typedef integer scaled; /* this type is used for scaled integers */
2564 typedef unsigned char small_number; /* this type is self-explanatory */
2565
2566 @ The following function is used to create a scaled integer from a given decimal
2567 fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is
2568 given in |dig[i]|, and the calculation produces a correctly rounded result.
2569
2570 @c 
2571 scaled mp_round_decimals (MP mp,small_number k) {
2572   /* converts a decimal fraction */
2573  integer a = 0; /* the accumulator */
2574  while ( k-->0 ) { 
2575     a=(a+mp->dig[k]*two) / 10;
2576   }
2577   return halfp(a+1);
2578 }
2579
2580 @ Conversely, here is a procedure analogous to |print_int|. If the output
2581 of this procedure is subsequently read by \MP\ and converted by the
2582 |round_decimals| routine above, it turns out that the original value will
2583 be reproduced exactly. A decimal point is printed only if the value is
2584 not an integer. If there is more than one way to print the result with
2585 the optimum number of digits following the decimal point, the closest
2586 possible value is given.
2587
2588 The invariant relation in the \&{repeat} loop is that a sequence of
2589 decimal digits yet to be printed will yield the original number if and only if
2590 they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
2591 We can stop if and only if $f=0$ satisfies this condition; the loop will
2592 terminate before $s$ can possibly become zero.
2593
2594 @<Basic printing...@>=
2595 void mp_print_scaled (MP mp,scaled s) { /* prints scaled real, rounded to five  digits */
2596   scaled delta; /* amount of allowable inaccuracy */
2597   if ( s<0 ) { 
2598         mp_print_char(mp, '-'); 
2599     negate(s); /* print the sign, if negative */
2600   }
2601   mp_print_int(mp, s / unity); /* print the integer part */
2602   s=10*(s % unity)+5;
2603   if ( s!=5 ) { 
2604     delta=10; 
2605     mp_print_char(mp, '.');
2606     do {  
2607       if ( delta>unity )
2608         s=s+0100000-(delta / 2); /* round the final digit */
2609       mp_print_char(mp, '0'+(s / unity)); 
2610       s=10*(s % unity); 
2611       delta=delta*10;
2612     } while (s>delta);
2613   }
2614 }
2615
2616 @ We often want to print two scaled quantities in parentheses,
2617 separated by a comma.
2618
2619 @<Basic printing...@>=
2620 void mp_print_two (MP mp,scaled x, scaled y) { /* prints `|(x,y)|' */
2621   mp_print_char(mp, '('); 
2622   mp_print_scaled(mp, x); 
2623   mp_print_char(mp, ','); 
2624   mp_print_scaled(mp, y);
2625   mp_print_char(mp, ')');
2626 }
2627
2628 @ The |scaled| quantities in \MP\ programs are generally supposed to be
2629 less than $2^{12}$ in absolute value, so \MP\ does much of its internal
2630 arithmetic with 28~significant bits of precision. A |fraction| denotes
2631 a scaled integer whose binary point is assumed to be 28 bit positions
2632 from the right.
2633
2634 @d fraction_half 01000000000 /* $2^{27}$, represents 0.50000000 */
2635 @d fraction_one 02000000000 /* $2^{28}$, represents 1.00000000 */
2636 @d fraction_two 04000000000 /* $2^{29}$, represents 2.00000000 */
2637 @d fraction_three 06000000000 /* $3\cdot2^{28}$, represents 3.00000000 */
2638 @d fraction_four 010000000000 /* $2^{30}$, represents 4.00000000 */
2639
2640 @<Types...@>=
2641 typedef integer fraction; /* this type is used for scaled fractions */
2642
2643 @ In fact, the two sorts of scaling discussed above aren't quite
2644 sufficient; \MP\ has yet another, used internally to keep track of angles
2645 in units of $2^{-20}$ degrees.
2646
2647 @d forty_five_deg 0264000000 /* $45\cdot2^{20}$, represents $45^\circ$ */
2648 @d ninety_deg 0550000000 /* $90\cdot2^{20}$, represents $90^\circ$ */
2649 @d one_eighty_deg 01320000000 /* $180\cdot2^{20}$, represents $180^\circ$ */
2650 @d three_sixty_deg 02640000000 /* $360\cdot2^{20}$, represents $360^\circ$ */
2651
2652 @<Types...@>=
2653 typedef integer angle; /* this type is used for scaled angles */
2654
2655 @ The |make_fraction| routine produces the |fraction| equivalent of
2656 |p/q|, given integers |p| and~|q|; it computes the integer
2657 $f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are
2658 positive. If |p| and |q| are both of the same scaled type |t|,
2659 the ``type relation'' |make_fraction(t,t)=fraction| is valid;
2660 and it's also possible to use the subroutine ``backwards,'' using
2661 the relation |make_fraction(t,fraction)=t| between scaled types.
2662
2663 If the result would have magnitude $2^{31}$ or more, |make_fraction|
2664 sets |arith_error:=true|. Most of \MP's internal computations have
2665 been designed to avoid this sort of error.
2666
2667 If this subroutine were programmed in assembly language on a typical
2668 machine, we could simply compute |(@t$2^{28}$@>*p)div q|, since a
2669 double-precision product can often be input to a fixed-point division
2670 instruction. But when we are restricted to int-eger arithmetic it
2671 is necessary either to resort to multiple-precision maneuvering
2672 or to use a simple but slow iteration. The multiple-precision technique
2673 would be about three times faster than the code adopted here, but it
2674 would be comparatively long and tricky, involving about sixteen
2675 additional multiplications and divisions.
2676
2677 This operation is part of \MP's ``inner loop''; indeed, it will
2678 consume nearly 10\pct! of the running time (exclusive of input and output)
2679 if the code below is left unchanged. A machine-dependent recoding
2680 will therefore make \MP\ run faster. The present implementation
2681 is highly portable, but slow; it avoids multiplication and division
2682 except in the initial stage. System wizards should be careful to
2683 replace it with a routine that is guaranteed to produce identical
2684 results in all cases.
2685 @^system dependencies@>
2686
2687 As noted below, a few more routines should also be replaced by machine-dependent
2688 code, for efficiency. But when a procedure is not part of the ``inner loop,''
2689 such changes aren't advisable; simplicity and robustness are
2690 preferable to trickery, unless the cost is too high.
2691 @^inner loop@>
2692
2693 @<Internal ...@>=
2694 fraction mp_make_fraction (MP mp,integer p, integer q);
2695 integer mp_take_scaled (MP mp,integer q, scaled f) ;
2696
2697 @ If FIXPT is not defined, we need these preprocessor values
2698
2699 @d ELGORDO  0x7fffffff
2700 @d TWEXP31  2147483648.0
2701 @d TWEXP28  268435456.0
2702 @d TWEXP16 65536.0
2703 @d TWEXP_16 (1.0/65536.0)
2704 @d TWEXP_28 (1.0/268435456.0)
2705
2706
2707 @c 
2708 fraction mp_make_fraction (MP mp,integer p, integer q) {
2709 #ifdef FIXPT
2710   integer f; /* the fraction bits, with a leading 1 bit */
2711   integer n; /* the integer part of $\vert p/q\vert$ */
2712   integer be_careful; /* disables certain compiler optimizations */
2713   boolean negative = false; /* should the result be negated? */
2714   if ( p<0 ) {
2715     negate(p); negative=true;
2716   }
2717   if ( q<=0 ) { 
2718 #ifdef DEBUG
2719     if ( q==0 ) mp_confusion(mp, '/');
2720 #endif
2721 @:this can't happen /}{\quad \./@>
2722     negate(q); negative = ! negative;
2723   };
2724   n=p / q; p=p % q;
2725   if ( n>=8 ){ 
2726     mp->arith_error=true;
2727     return ( negative ? -el_gordo : el_gordo);
2728   } else { 
2729     n=(n-1)*fraction_one;
2730     @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>;
2731     return (negative ? (-(f+n)) : (f+n));
2732   }
2733 #else /* FIXPT */
2734     register double d;
2735         register integer i;
2736 #ifdef DEBUG
2737         if (q==0) mp_confusion(mp,'/'); 
2738 #endif /* DEBUG */
2739         d = TWEXP28 * (double)p /(double)q;
2740         if ((p^q) >= 0) {
2741                 d += 0.5;
2742                 if (d>=TWEXP31) {mp->arith_error=true; return ELGORDO;}
2743                 i = (integer) d;
2744                 if (d==i && ( ((q>0 ? -q : q)&077777)
2745                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
2746         } else {
2747                 d -= 0.5;
2748                 if (d<= -TWEXP31) {mp->arith_error=true; return -ELGORDO;}
2749                 i = (integer) d;
2750                 if (d==i && ( ((q>0 ? q : -q)&077777)
2751                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
2752         }
2753         return i;
2754 #endif /* FIXPT */
2755 }
2756
2757 @ The |repeat| loop here preserves the following invariant relations
2758 between |f|, |p|, and~|q|:
2759 (i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and
2760 $p_0$ is the original value of~$p$.
2761
2762 Notice that the computation specifies
2763 |(p-q)+p| instead of |(p+p)-q|, because the latter could overflow.
2764 Let us hope that optimizing compilers do not miss this point; a
2765 special variable |be_careful| is used to emphasize the necessary
2766 order of computation. Optimizing compilers should keep |be_careful|
2767 in a register, not store it in memory.
2768 @^inner loop@>
2769
2770 @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>=
2771 {
2772   f=1;
2773   do {  
2774     be_careful=p-q; p=be_careful+p;
2775     if ( p>=0 ) { 
2776       f=f+f+1;
2777     } else  { 
2778       f+=f; p=p+q;
2779     }
2780   } while (f<fraction_one);
2781   be_careful=p-q;
2782   if ( be_careful+p>=0 ) incr(f);
2783 }
2784
2785 @ The dual of |make_fraction| is |take_fraction|, which multiplies a
2786 given integer~|q| by a fraction~|f|. When the operands are positive, it
2787 computes $p=\lfloor qf/2^{28}+{1\over2}\rfloor$, a symmetric function
2788 of |q| and~|f|.
2789
2790 This routine is even more ``inner loopy'' than |make_fraction|;
2791 the present implementation consumes almost 20\pct! of \MP's computation
2792 time during typical jobs, so a machine-language substitute is advisable.
2793 @^inner loop@> @^system dependencies@>
2794
2795 @<Declarations@>=
2796 integer mp_take_fraction (MP mp,integer q, fraction f) ;
2797
2798 @ @c 
2799 #ifdef FIXPT
2800 integer mp_take_fraction (MP mp,integer q, fraction f) {
2801   integer p; /* the fraction so far */
2802   boolean negative; /* should the result be negated? */
2803   integer n; /* additional multiple of $q$ */
2804   integer be_careful; /* disables certain compiler optimizations */
2805   @<Reduce to the case that |f>=0| and |q>0|@>;
2806   if ( f<fraction_one ) { 
2807     n=0;
2808   } else { 
2809     n=f / fraction_one; f=f % fraction_one;
2810     if ( q<=el_gordo / n ) { 
2811       n=n*q ; 
2812     } else { 
2813       mp->arith_error=true; n=el_gordo;
2814     }
2815   }
2816   f=f+fraction_one;
2817   @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>;
2818   be_careful=n-el_gordo;
2819   if ( be_careful+p>0 ){ 
2820     mp->arith_error=true; n=el_gordo-p;
2821   }
2822   if ( negative ) 
2823         return (-(n+p));
2824   else 
2825     return (n+p);
2826 #else /* FIXPT */
2827 integer mp_take_fraction (MP mp,integer p, fraction q) {
2828     register double d;
2829         register integer i;
2830         d = (double)p * (double)q * TWEXP_28;
2831         if ((p^q) >= 0) {
2832                 d += 0.5;
2833                 if (d>=TWEXP31) {
2834                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2835                                 mp->arith_error = true;
2836                         return ELGORDO;
2837                 }
2838                 i = (integer) d;
2839                 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
2840         } else {
2841                 d -= 0.5;
2842                 if (d<= -TWEXP31) {
2843                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2844                                 mp->arith_error = true;
2845                         return -ELGORDO;
2846                 }
2847                 i = (integer) d;
2848                 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2849         }
2850         return i;
2851 #endif /* FIXPT */
2852 }
2853
2854 @ @<Reduce to the case that |f>=0| and |q>0|@>=
2855 if ( f>=0 ) {
2856   negative=false;
2857 } else { 
2858   negate( f); negative=true;
2859 }
2860 if ( q<0 ) { 
2861   negate(q); negative=! negative;
2862 }
2863
2864 @ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor
2865 =\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and
2866 $f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$.
2867 @^inner loop@>
2868
2869 @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>=
2870 p=fraction_half; /* that's $2^{27}$; the invariants hold now with $k=28$ */
2871 if ( q<fraction_four ) {
2872   do {  
2873     if ( odd(f) ) p=halfp(p+q); else p=halfp(p);
2874     f=halfp(f);
2875   } while (f!=1);
2876 } else  {
2877   do {  
2878     if ( odd(f) ) p=p+halfp(q-p); else p=halfp(p);
2879     f=halfp(f);
2880   } while (f!=1);
2881 }
2882
2883
2884 @ When we want to multiply something by a |scaled| quantity, we use a scheme
2885 analogous to |take_fraction| but with a different scaling.
2886 Given positive operands, |take_scaled|
2887 computes the quantity $p=\lfloor qf/2^{16}+{1\over2}\rfloor$.
2888
2889 Once again it is a good idea to use a machine-language replacement if
2890 possible; otherwise |take_scaled| will use more than 2\pct! of the running time
2891 when the Computer Modern fonts are being generated.
2892 @^inner loop@>
2893
2894 @c 
2895 #ifdef FIXPT
2896 integer mp_take_scaled (MP mp,integer q, scaled f) {
2897   integer p; /* the fraction so far */
2898   boolean negative; /* should the result be negated? */
2899   integer n; /* additional multiple of $q$ */
2900   integer be_careful; /* disables certain compiler optimizations */
2901   @<Reduce to the case that |f>=0| and |q>0|@>;
2902   if ( f<unity ) { 
2903     n=0;
2904   } else  { 
2905     n=f / unity; f=f % unity;
2906     if ( q<=el_gordo / n ) {
2907       n=n*q;
2908     } else  { 
2909       mp->arith_error=true; n=el_gordo;
2910     }
2911   }
2912   f=f+unity;
2913   @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>;
2914   be_careful=n-el_gordo;
2915   if ( be_careful+p>0 ) { 
2916     mp->arith_error=true; n=el_gordo-p;
2917   }
2918   return ( negative ?(-(n+p)) :(n+p));
2919 #else /* FIXPT */
2920 integer mp_take_scaled (MP mp,integer p, scaled q) {
2921     register double d;
2922         register integer i;
2923         d = (double)p * (double)q * TWEXP_16;
2924         if ((p^q) >= 0) {
2925                 d += 0.5;
2926                 if (d>=TWEXP31) {
2927                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2928                                 mp->arith_error = true;
2929                         return ELGORDO;
2930                 }
2931                 i = (integer) d;
2932                 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
2933         } else {
2934                 d -= 0.5;
2935                 if (d<= -TWEXP31) {
2936                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2937                                 mp->arith_error = true;
2938                         return -ELGORDO;
2939                 }
2940                 i = (integer) d;
2941                 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2942         }
2943         return i;
2944 #endif /* FIXPT */
2945 }
2946
2947 @ @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>=
2948 p=half_unit; /* that's $2^{15}$; the invariants hold now with $k=16$ */
2949 @^inner loop@>
2950 if ( q<fraction_four ) {
2951   do {  
2952     p = (odd(f) ? halfp(p+q) : halfp(p));
2953     f=halfp(f);
2954   } while (f!=1);
2955 } else {
2956   do {  
2957     p = (odd(f) ? p+halfp(q-p) : halfp(p));
2958     f=halfp(f);
2959   } while (f!=1);
2960 }
2961
2962 @ For completeness, there's also |make_scaled|, which computes a
2963 quotient as a |scaled| number instead of as a |fraction|.
2964 In other words, the result is $\lfloor2^{16}p/q+{1\over2}\rfloor$, if the
2965 operands are positive. \ (This procedure is not used especially often,
2966 so it is not part of \MP's inner loop.)
2967
2968 @<Internal library ...@>=
2969 scaled mp_make_scaled (MP mp,integer p, integer q) ;
2970
2971 @ @c 
2972 scaled mp_make_scaled (MP mp,integer p, integer q) {
2973 #ifdef FIXPT 
2974   integer f; /* the fraction bits, with a leading 1 bit */
2975   integer n; /* the integer part of $\vert p/q\vert$ */
2976   boolean negative; /* should the result be negated? */
2977   integer be_careful; /* disables certain compiler optimizations */
2978   if ( p>=0 ) negative=false;
2979   else  { negate(p); negative=true; };
2980   if ( q<=0 ) { 
2981 #ifdef DEBUG 
2982     if ( q==0 ) mp_confusion(mp, "/");
2983 @:this can't happen /}{\quad \./@>
2984 #endif
2985     negate(q); negative=! negative;
2986   }
2987   n=p / q; p=p % q;
2988   if ( n>=0100000 ) { 
2989     mp->arith_error=true;
2990     return (negative ? (-el_gordo) : el_gordo);
2991   } else  { 
2992     n=(n-1)*unity;
2993     @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>;
2994     return ( negative ? (-(f+n)) :(f+n));
2995   }
2996 #else /* FIXPT */
2997     register double d;
2998         register integer i;
2999 #ifdef DEBUG
3000         if (q==0) mp_confusion(mp,"/"); 
3001 #endif /* DEBUG */
3002         d = TWEXP16 * (double)p /(double)q;
3003         if ((p^q) >= 0) {
3004                 d += 0.5;
3005                 if (d>=TWEXP31) {mp->arith_error=true; return ELGORDO;}
3006                 i = (integer) d;
3007                 if (d==i && ( ((q>0 ? -q : q)&077777)
3008                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
3009         } else {
3010                 d -= 0.5;
3011                 if (d<= -TWEXP31) {mp->arith_error=true; return -ELGORDO;}
3012                 i = (integer) d;
3013                 if (d==i && ( ((q>0 ? q : -q)&077777)
3014                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
3015         }
3016         return i;
3017 #endif /* FIXPT */
3018 }
3019
3020 @ @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>=
3021 f=1;
3022 do {  
3023   be_careful=p-q; p=be_careful+p;
3024   if ( p>=0 ) f=f+f+1;
3025   else  { f+=f; p=p+q; };
3026 } while (f<unity);
3027 be_careful=p-q;
3028 if ( be_careful+p>=0 ) incr(f)
3029
3030 @ Here is a typical example of how the routines above can be used.
3031 It computes the function
3032 $${1\over3\tau}f(\theta,\phi)=
3033 {\tau^{-1}\bigl(2+\sqrt2\,(\sin\theta-{1\over16}\sin\phi)
3034  (\sin\phi-{1\over16}\sin\theta)(\cos\theta-\cos\phi)\bigr)\over
3035 3\,\bigl(1+{1\over2}(\sqrt5-1)\cos\theta+{1\over2}(3-\sqrt5\,)\cos\phi\bigr)},$$
3036 where $\tau$ is a |scaled| ``tension'' parameter. This is \MP's magic
3037 fudge factor for placing the first control point of a curve that starts
3038 at an angle $\theta$ and ends at an angle $\phi$ from the straight path.
3039 (Actually, if the stated quantity exceeds 4, \MP\ reduces it to~4.)
3040
3041 The trigonometric quantity to be multiplied by $\sqrt2$ is less than $\sqrt2$.
3042 (It's a sum of eight terms whose absolute values can be bounded using
3043 relations such as $\sin\theta\cos\theta\L{1\over2}$.) Thus the numerator
3044 is positive; and since the tension $\tau$ is constrained to be at least
3045 $3\over4$, the numerator is less than $16\over3$. The denominator is
3046 nonnegative and at most~6.  Hence the fixed-point calculations below
3047 are guaranteed to stay within the bounds of a 32-bit computer word.
3048
3049 The angles $\theta$ and $\phi$ are given implicitly in terms of |fraction|
3050 arguments |st|, |ct|, |sf|, and |cf|, representing $\sin\theta$, $\cos\theta$,
3051 $\sin\phi$, and $\cos\phi$, respectively.
3052
3053 @c 
3054 fraction mp_velocity (MP mp,fraction st, fraction ct, fraction sf,
3055                       fraction cf, scaled t) {
3056   integer acc,num,denom; /* registers for intermediate calculations */
3057   acc=mp_take_fraction(mp, st-(sf / 16), sf-(st / 16));
3058   acc=mp_take_fraction(mp, acc,ct-cf);
3059   num=fraction_two+mp_take_fraction(mp, acc,379625062);
3060                    /* $2^{28}\sqrt2\approx379625062.497$ */
3061   denom=fraction_three+mp_take_fraction(mp, ct,497706707)+mp_take_fraction(mp, cf,307599661);
3062                       /* $3\cdot2^{27}\cdot(\sqrt5-1)\approx497706706.78$ and
3063                          $3\cdot2^{27}\cdot(3-\sqrt5\,)\approx307599661.22$ */
3064   if ( t!=unity ) num=mp_make_scaled(mp, num,t);
3065   /* |make_scaled(fraction,scaled)=fraction| */
3066   if ( num / 4>=denom ) 
3067     return fraction_four;
3068   else 
3069     return mp_make_fraction(mp, num, denom);
3070 }
3071
3072 @ The following somewhat different subroutine tests rigorously if $ab$ is
3073 greater than, equal to, or less than~$cd$,
3074 given integers $(a,b,c,d)$. In most cases a quick decision is reached.
3075 The result is $+1$, 0, or~$-1$ in the three respective cases.
3076
3077 @d mp_ab_vs_cd(M,A,B,C,D) mp_do_ab_vs_cd(A,B,C,D)
3078
3079 @c 
3080 integer mp_do_ab_vs_cd (integer a,integer b, integer c, integer d) {
3081   integer q,r; /* temporary registers */
3082   @<Reduce to the case that |a,c>=0|, |b,d>0|@>;
3083   while (1) { 
3084     q = a / d; r = c / b;
3085     if ( q!=r )
3086       return ( q>r ? 1 : -1);
3087     q = a % d; r = c % b;
3088     if ( r==0 )
3089       return (q ? 1 : 0);
3090     if ( q==0 ) return -1;
3091     a=b; b=q; c=d; d=r;
3092   } /* now |a>d>0| and |c>b>0| */
3093 }
3094
3095 @ @<Reduce to the case that |a...@>=
3096 if ( a<0 ) { negate(a); negate(b);  };
3097 if ( c<0 ) { negate(c); negate(d);  };
3098 if ( d<=0 ) { 
3099   if ( b>=0 ) {
3100     if ( (a==0||b==0)&&(c==0||d==0) ) return 0;
3101     else return 1;
3102   }
3103   if ( d==0 )
3104     return ( a==0 ? 0 : -1);
3105   q=a; a=c; c=q; q=-b; b=-d; d=q;
3106 } else if ( b<=0 ) { 
3107   if ( b<0 ) if ( a>0 ) return -1;
3108   return (c==0 ? 0 : -1);
3109 }
3110
3111 @ We conclude this set of elementary routines with some simple rounding
3112 and truncation operations.
3113
3114 @<Internal library declarations@>=
3115 #define mp_floor_scaled(M,i) ((i)&(-65536))
3116 #define mp_round_unscaled(M,i) (((i>>15)+1)>>1)
3117 #define mp_round_fraction(M,i) (((i>>11)+1)>>1)
3118
3119
3120 @* \[8] Algebraic and transcendental functions.
3121 \MP\ computes all of the necessary special functions from scratch, without
3122 relying on |real| arithmetic or system subroutines for sines, cosines, etc.
3123
3124 @ To get the square root of a |scaled| number |x|, we want to calculate
3125 $s=\lfloor 2^8\!\sqrt x +{1\over2}\rfloor$. If $x>0$, this is the unique
3126 integer such that $2^{16}x-s\L s^2<2^{16}x+s$. The following subroutine
3127 determines $s$ by an iterative method that maintains the invariant
3128 relations $x=2^{46-2k}x_0\bmod 2^{30}$, $0<y=\lfloor 2^{16-2k}x_0\rfloor
3129 -s^2+s\L q=2s$, where $x_0$ is the initial value of $x$. The value of~$y$
3130 might, however, be zero at the start of the first iteration.
3131
3132 @<Declarations@>=
3133 scaled mp_square_rt (MP mp,scaled x) ;
3134
3135 @ @c 
3136 scaled mp_square_rt (MP mp,scaled x) {
3137   small_number k; /* iteration control counter */
3138   integer y,q; /* registers for intermediate calculations */
3139   if ( x<=0 ) { 
3140     @<Handle square root of zero or negative argument@>;
3141   } else { 
3142     k=23; q=2;
3143     while ( x<fraction_two ) { /* i.e., |while x<@t$2^{29}$@>|\unskip */
3144       decr(k); x=x+x+x+x;
3145     }
3146     if ( x<fraction_four ) y=0;
3147     else  { x=x-fraction_four; y=1; };
3148     do {  
3149       @<Decrease |k| by 1, maintaining the invariant
3150       relations between |x|, |y|, and~|q|@>;
3151     } while (k!=0);
3152     return (halfp(q));
3153   }
3154 }
3155
3156 @ @<Handle square root of zero...@>=
3157
3158   if ( x<0 ) { 
3159     print_err("Square root of ");
3160 @.Square root...replaced by 0@>
3161     mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3162     help2("Since I don't take square roots of negative numbers,")
3163          ("I'm zeroing this one. Proceed, with fingers crossed.");
3164     mp_error(mp);
3165   };
3166   return 0;
3167 }
3168
3169 @ @<Decrease |k| by 1, maintaining...@>=
3170 x+=x; y+=y;
3171 if ( x>=fraction_four ) { /* note that |fraction_four=@t$2^{30}$@>| */
3172   x=x-fraction_four; incr(y);
3173 };
3174 x+=x; y=y+y-q; q+=q;
3175 if ( x>=fraction_four ) { x=x-fraction_four; incr(y); };
3176 if ( y>q ){ y=y-q; q=q+2; }
3177 else if ( y<=0 )  { q=q-2; y=y+q;  };
3178 decr(k)
3179
3180 @ Pythagorean addition $\psqrt{a^2+b^2}$ is implemented by an elegant
3181 iterative scheme due to Cleve Moler and Donald Morrison [{\sl IBM Journal
3182 @^Moler, Cleve Barry@>
3183 @^Morrison, Donald Ross@>
3184 of Research and Development\/ \bf27} (1983), 577--581]. It modifies |a| and~|b|
3185 in such a way that their Pythagorean sum remains invariant, while the
3186 smaller argument decreases.
3187
3188 @<Internal library ...@>=
3189 integer mp_pyth_add (MP mp,integer a, integer b);
3190
3191
3192 @ @c 
3193 integer mp_pyth_add (MP mp,integer a, integer b) {
3194   fraction r; /* register used to transform |a| and |b| */
3195   boolean big; /* is the result dangerously near $2^{31}$? */
3196   a=abs(a); b=abs(b);
3197   if ( a<b ) { r=b; b=a; a=r; }; /* now |0<=b<=a| */
3198   if ( b>0 ) {
3199     if ( a<fraction_two ) {
3200       big=false;
3201     } else { 
3202       a=a / 4; b=b / 4; big=true;
3203     }; /* we reduced the precision to avoid arithmetic overflow */
3204     @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>;
3205     if ( big ) {
3206       if ( a<fraction_two ) {
3207         a=a+a+a+a;
3208       } else  { 
3209         mp->arith_error=true; a=el_gordo;
3210       };
3211     }
3212   }
3213   return a;
3214 }
3215
3216 @ The key idea here is to reflect the vector $(a,b)$ about the
3217 line through $(a,b/2)$.
3218
3219 @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>=
3220 while (1) {  
3221   r=mp_make_fraction(mp, b,a);
3222   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3223   if ( r==0 ) break;
3224   r=mp_make_fraction(mp, r,fraction_four+r);
3225   a=a+mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3226 }
3227
3228
3229 @ Here is a similar algorithm for $\psqrt{a^2-b^2}$.
3230 It converges slowly when $b$ is near $a$, but otherwise it works fine.
3231
3232 @c 
3233 integer mp_pyth_sub (MP mp,integer a, integer b) {
3234   fraction r; /* register used to transform |a| and |b| */
3235   boolean big; /* is the input dangerously near $2^{31}$? */
3236   a=abs(a); b=abs(b);
3237   if ( a<=b ) {
3238     @<Handle erroneous |pyth_sub| and set |a:=0|@>;
3239   } else { 
3240     if ( a<fraction_four ) {
3241       big=false;
3242     } else  { 
3243       a=halfp(a); b=halfp(b); big=true;
3244     }
3245     @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>;
3246     if ( big ) double(a);
3247   }
3248   return a;
3249 }
3250
3251 @ @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>=
3252 while (1) { 
3253   r=mp_make_fraction(mp, b,a);
3254   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3255   if ( r==0 ) break;
3256   r=mp_make_fraction(mp, r,fraction_four-r);
3257   a=a-mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3258 }
3259
3260 @ @<Handle erroneous |pyth_sub| and set |a:=0|@>=
3261
3262   if ( a<b ){ 
3263     print_err("Pythagorean subtraction "); mp_print_scaled(mp, a);
3264     mp_print(mp, "+-+"); mp_print_scaled(mp, b); 
3265     mp_print(mp, " has been replaced by 0");
3266 @.Pythagorean...@>
3267     help2("Since I don't take square roots of negative numbers,")
3268          ("I'm zeroing this one. Proceed, with fingers crossed.");
3269     mp_error(mp);
3270   }
3271   a=0;
3272 }
3273
3274 @ The subroutines for logarithm and exponential involve two tables.
3275 The first is simple: |two_to_the[k]| equals $2^k$. The second involves
3276 a bit more calculation, which the author claims to have done correctly:
3277 |spec_log[k]| is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)=
3278 2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the
3279 nearest integer.
3280
3281 @d two_to_the(A) (1<<(A))
3282
3283 @<Constants ...@>=
3284 static const integer spec_log[29] = { 0, /* special logarithms */
3285 93032640, 38612034, 17922280, 8662214, 4261238, 2113709,
3286 1052693, 525315, 262400, 131136, 65552, 32772, 16385,
3287 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 1 };
3288
3289 @ @<Local variables for initialization@>=
3290 integer k; /* all-purpose loop index */
3291
3292
3293 @ Here is the routine that calculates $2^8$ times the natural logarithm
3294 of a |scaled| quantity; it is an integer approximation to $2^{24}\ln(x/2^{16})$,
3295 when |x| is a given positive integer.
3296
3297 The method is based on exercise 1.2.2--25 in {\sl The Art of Computer
3298 Programming\/}: During the main iteration we have $1\L 2^{-30}x<1/(1-2^{1-k})$,
3299 and the logarithm of $2^{30}x$ remains to be added to an accumulator
3300 register called~$y$. Three auxiliary bits of accuracy are retained in~$y$
3301 during the calculation, and sixteen auxiliary bits to extend |y| are
3302 kept in~|z| during the initial argument reduction. (We add
3303 $100\cdot2^{16}=6553600$ to~|z| and subtract 100 from~|y| so that |z| will
3304 not become negative; also, the actual amount subtracted from~|y| is~96,
3305 not~100, because we want to add~4 for rounding before the final division by~8.)
3306
3307 @c 
3308 scaled mp_m_log (MP mp,scaled x) {
3309   integer y,z; /* auxiliary registers */
3310   integer k; /* iteration counter */
3311   if ( x<=0 ) {
3312      @<Handle non-positive logarithm@>;
3313   } else  { 
3314     y=1302456956+4-100; /* $14\times2^{27}\ln2\approx1302456956.421063$ */
3315     z=27595+6553600; /* and $2^{16}\times .421063\approx 27595$ */
3316     while ( x<fraction_four ) {
3317        double(x); y-=93032639; z-=48782;
3318     } /* $2^{27}\ln2\approx 93032639.74436163$ and $2^{16}\times.74436163\approx 48782$ */
3319     y=y+(z / unity); k=2;
3320     while ( x>fraction_four+4 ) {
3321       @<Increase |k| until |x| can be multiplied by a
3322         factor of $2^{-k}$, and adjust $y$ accordingly@>;
3323     }
3324     return (y / 8);
3325   }
3326 }
3327
3328 @ @<Increase |k| until |x| can...@>=
3329
3330   z=((x-1) / two_to_the(k))+1; /* $z=\lceil x/2^k\rceil$ */
3331   while ( x<fraction_four+z ) { z=halfp(z+1); incr(k); };
3332   y+=spec_log[k]; x-=z;
3333 }
3334
3335 @ @<Handle non-positive logarithm@>=
3336
3337   print_err("Logarithm of ");
3338 @.Logarithm...replaced by 0@>
3339   mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3340   help2("Since I don't take logs of non-positive numbers,")
3341        ("I'm zeroing this one. Proceed, with fingers crossed.");
3342   mp_error(mp); 
3343   return 0;
3344 }
3345
3346 @ Conversely, the exponential routine calculates $\exp(x/2^8)$,
3347 when |x| is |scaled|. The result is an integer approximation to
3348 $2^{16}\exp(x/2^{24})$, when |x| is regarded as an integer.
3349
3350 @c 
3351 scaled mp_m_exp (MP mp,scaled x) {
3352   small_number k; /* loop control index */
3353   integer y,z; /* auxiliary registers */
3354   if ( x>174436200 ) {
3355     /* $2^{24}\ln((2^{31}-1)/2^{16})\approx 174436199.51$ */
3356     mp->arith_error=true; 
3357     return el_gordo;
3358   } else if ( x<-197694359 ) {
3359         /* $2^{24}\ln(2^{-1}/2^{16})\approx-197694359.45$ */
3360     return 0;
3361   } else { 
3362     if ( x<=0 ) { 
3363        z=-8*x; y=04000000; /* $y=2^{20}$ */
3364     } else { 
3365       if ( x<=127919879 ) { 
3366         z=1023359037-8*x;
3367         /* $2^{27}\ln((2^{31}-1)/2^{20})\approx 1023359037.125$ */
3368       } else {
3369        z=8*(174436200-x); /* |z| is always nonnegative */
3370       }
3371       y=el_gordo;
3372     };
3373     @<Multiply |y| by $\exp(-z/2^{27})$@>;
3374     if ( x<=127919879 ) 
3375        return ((y+8) / 16);
3376      else 
3377        return y;
3378   }
3379 }
3380
3381 @ The idea here is that subtracting |spec_log[k]| from |z| corresponds
3382 to multiplying |y| by $1-2^{-k}$.
3383
3384 A subtle point (which had to be checked) was that if $x=127919879$, the
3385 value of~|y| will decrease so that |y+8| doesn't overflow. In fact,
3386 $z$ will be 5 in this case, and |y| will decrease by~64 when |k=25|
3387 and by~16 when |k=27|.
3388
3389 @<Multiply |y| by...@>=
3390 k=1;
3391 while ( z>0 ) { 
3392   while ( z>=spec_log[k] ) { 
3393     z-=spec_log[k];
3394     y=y-1-((y-two_to_the(k-1)) / two_to_the(k));
3395   }
3396   incr(k);
3397 }
3398
3399 @ The trigonometric subroutines use an auxiliary table such that
3400 |spec_atan[k]| contains an approximation to the |angle| whose tangent
3401 is~$1/2^k$. $\arctan2^{-k}$ times $2^{20}\cdot180/\pi$ 
3402
3403 @<Constants ...@>=
3404 static const angle spec_atan[27] = { 0, 27855475, 14718068, 7471121, 3750058, 
3405 1876857, 938658, 469357, 234682, 117342, 58671, 29335, 14668, 7334, 3667, 
3406 1833, 917, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1 };
3407
3408 @ Given integers |x| and |y|, not both zero, the |n_arg| function
3409 returns the |angle| whose tangent points in the direction $(x,y)$.
3410 This subroutine first determines the correct octant, then solves the
3411 problem for |0<=y<=x|, then converts the result appropriately to
3412 return an answer in the range |-one_eighty_deg<=@t$\theta$@><=one_eighty_deg|.
3413 (The answer is |+one_eighty_deg| if |y=0| and |x<0|, but an answer of
3414 |-one_eighty_deg| is possible if, for example, |y=-1| and $x=-2^{30}$.)
3415
3416 The octants are represented in a ``Gray code,'' since that turns out
3417 to be computationally simplest.
3418
3419 @d negate_x 1
3420 @d negate_y 2
3421 @d switch_x_and_y 4
3422 @d first_octant 1
3423 @d second_octant (first_octant+switch_x_and_y)
3424 @d third_octant (first_octant+switch_x_and_y+negate_x)
3425 @d fourth_octant (first_octant+negate_x)
3426 @d fifth_octant (first_octant+negate_x+negate_y)
3427 @d sixth_octant (first_octant+switch_x_and_y+negate_x+negate_y)
3428 @d seventh_octant (first_octant+switch_x_and_y+negate_y)
3429 @d eighth_octant (first_octant+negate_y)
3430
3431 @c 
3432 angle mp_n_arg (MP mp,integer x, integer y) {
3433   angle z; /* auxiliary register */
3434   integer t; /* temporary storage */
3435   small_number k; /* loop counter */
3436   int octant; /* octant code */
3437   if ( x>=0 ) {
3438     octant=first_octant;
3439   } else { 
3440     negate(x); octant=first_octant+negate_x;
3441   }
3442   if ( y<0 ) { 
3443     negate(y); octant=octant+negate_y;
3444   }
3445   if ( x<y ) { 
3446     t=y; y=x; x=t; octant=octant+switch_x_and_y;
3447   }
3448   if ( x==0 ) { 
3449     @<Handle undefined arg@>; 
3450   } else { 
3451     @<Set variable |z| to the arg of $(x,y)$@>;
3452     @<Return an appropriate answer based on |z| and |octant|@>;
3453   }
3454 }
3455
3456 @ @<Handle undefined arg@>=
3457
3458   print_err("angle(0,0) is taken as zero");
3459 @.angle(0,0)...zero@>
3460   help2("The `angle' between two identical points is undefined.")
3461        ("I'm zeroing this one. Proceed, with fingers crossed.");
3462   mp_error(mp); 
3463   return 0;
3464 }
3465
3466 @ @<Return an appropriate answer...@>=
3467 switch (octant) {
3468 case first_octant: return z;
3469 case second_octant: return (ninety_deg-z);
3470 case third_octant: return (ninety_deg+z);
3471 case fourth_octant: return (one_eighty_deg-z);
3472 case fifth_octant: return (z-one_eighty_deg);
3473 case sixth_octant: return (-z-ninety_deg);
3474 case seventh_octant: return (z-ninety_deg);
3475 case eighth_octant: return (-z);
3476 }; /* there are no other cases */
3477 return 0
3478
3479 @ At this point we have |x>=y>=0|, and |x>0|. The numbers are scaled up
3480 or down until $2^{28}\L x<2^{29}$, so that accurate fixed-point calculations
3481 will be made.
3482
3483 @<Set variable |z| to the arg...@>=
3484 while ( x>=fraction_two ) { 
3485   x=halfp(x); y=halfp(y);
3486 }
3487 z=0;
3488 if ( y>0 ) { 
3489  while ( x<fraction_one ) { 
3490     x+=x; y+=y; 
3491  };
3492  @<Increase |z| to the arg of $(x,y)$@>;
3493 }
3494
3495 @ During the calculations of this section, variables |x| and~|y|
3496 represent actual coordinates $(x,2^{-k}y)$. We will maintain the
3497 condition |x>=y|, so that the tangent will be at most $2^{-k}$.
3498 If $x<2y$, the tangent is greater than $2^{-k-1}$. The transformation
3499 $(a,b)\mapsto(a+b\tan\phi,b-a\tan\phi)$ replaces $(a,b)$ by
3500 coordinates whose angle has decreased by~$\phi$; in the special case
3501 $a=x$, $b=2^{-k}y$, and $\tan\phi=2^{-k-1}$, this operation reduces
3502 to the particularly simple iteration shown here. [Cf.~John E. Meggitt,
3503 @^Meggitt, John E.@>
3504 {\sl IBM Journal of Research and Development\/ \bf6} (1962), 210--226.]
3505
3506 The initial value of |x| will be multiplied by at most
3507 $(1+{1\over2})(1+{1\over8})(1+{1\over32})\cdots\approx 1.7584$; hence
3508 there is no chance of integer overflow.
3509
3510 @<Increase |z|...@>=
3511 k=0;
3512 do {  
3513   y+=y; incr(k);
3514   if ( y>x ){ 
3515     z=z+spec_atan[k]; t=x; x=x+(y / two_to_the(k+k)); y=y-t;
3516   };
3517 } while (k!=15);
3518 do {  
3519   y+=y; incr(k);
3520   if ( y>x ) { z=z+spec_atan[k]; y=y-x; };
3521 } while (k!=26)
3522
3523 @ Conversely, the |n_sin_cos| routine takes an |angle| and produces the sine
3524 and cosine of that angle. The results of this routine are
3525 stored in global integer variables |n_sin| and |n_cos|.
3526
3527 @<Glob...@>=
3528 fraction n_sin;fraction n_cos; /* results computed by |n_sin_cos| */
3529
3530 @ Given an integer |z| that is $2^{20}$ times an angle $\theta$ in degrees,
3531 the purpose of |n_sin_cos(z)| is to set
3532 |x=@t$r\cos\theta$@>| and |y=@t$r\sin\theta$@>| (approximately),
3533 for some rather large number~|r|. The maximum of |x| and |y|
3534 will be between $2^{28}$ and $2^{30}$, so that there will be hardly
3535 any loss of accuracy. Then |x| and~|y| are divided by~|r|.
3536
3537 @c 
3538 void mp_n_sin_cos (MP mp,angle z) { /* computes a multiple of the sine
3539                                        and cosine */ 
3540   small_number k; /* loop control variable */
3541   int q; /* specifies the quadrant */
3542   fraction r; /* magnitude of |(x,y)| */
3543   integer x,y,t; /* temporary registers */
3544   while ( z<0 ) z=z+three_sixty_deg;
3545   z=z % three_sixty_deg; /* now |0<=z<three_sixty_deg| */
3546   q=z / forty_five_deg; z=z % forty_five_deg;
3547   x=fraction_one; y=x;
3548   if ( ! odd(q) ) z=forty_five_deg-z;
3549   @<Subtract angle |z| from |(x,y)|@>;
3550   @<Convert |(x,y)| to the octant determined by~|q|@>;
3551   r=mp_pyth_add(mp, x,y); 
3552   mp->n_cos=mp_make_fraction(mp, x,r); 
3553   mp->n_sin=mp_make_fraction(mp, y,r);
3554 }
3555
3556 @ In this case the octants are numbered sequentially.
3557
3558 @<Convert |(x,...@>=
3559 switch (q) {
3560 case 0: break;
3561 case 1: t=x; x=y; y=t; break;
3562 case 2: t=x; x=-y; y=t; break;
3563 case 3: negate(x); break;
3564 case 4: negate(x); negate(y); break;
3565 case 5: t=x; x=-y; y=-t; break;
3566 case 6: t=x; x=y; y=-t; break;
3567 case 7: negate(y); break;
3568 } /* there are no other cases */
3569
3570 @ The main iteration of |n_sin_cos| is similar to that of |n_arg| but
3571 applied in reverse. The values of |spec_atan[k]| decrease slowly enough
3572 that this loop is guaranteed to terminate before the (nonexistent) value
3573 |spec_atan[27]| would be required.
3574
3575 @<Subtract angle |z|...@>=
3576 k=1;
3577 while ( z>0 ){ 
3578   if ( z>=spec_atan[k] ) { 
3579     z=z-spec_atan[k]; t=x;
3580     x=t+y / two_to_the(k);
3581     y=y-t / two_to_the(k);
3582   }
3583   incr(k);
3584 }
3585 if ( y<0 ) y=0 /* this precaution may never be needed */
3586
3587 @ And now let's complete our collection of numeric utility routines
3588 by considering random number generation.
3589 \MP\ generates pseudo-random numbers with the additive scheme recommended
3590 in Section 3.6 of {\sl The Art of Computer Programming}; however, the
3591 results are random fractions between 0 and |fraction_one-1|, inclusive.
3592
3593 There's an auxiliary array |randoms| that contains 55 pseudo-random
3594 fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$,
3595 we generate batches of 55 new $x_n$'s at a time by calling |new_randoms|.
3596 The global variable |j_random| tells which element has most recently
3597 been consumed.
3598 The global variable |random_seed| was introduced in version 0.9,
3599 for the sole reason of stressing the fact that the initial value of the
3600 random seed is system-dependant. The initialization code below will initialize
3601 this variable to |(internal[mp_time] div unity)+internal[mp_day]|, but this 
3602 is not good enough on modern fast machines that are capable of running
3603 multiple MetaPost processes within the same second.
3604 @^system dependencies@>
3605
3606 @<Glob...@>=
3607 fraction randoms[55]; /* the last 55 random values generated */
3608 int j_random; /* the number of unused |randoms| */
3609
3610 @ @<Option variables@>=
3611 int random_seed; /* the default random seed */
3612
3613 @ @<Allocate or initialize ...@>=
3614 mp->random_seed = (scaled)opt->random_seed;
3615
3616 @ To consume a random fraction, the program below will say `|next_random|'
3617 and then it will fetch |randoms[j_random]|.
3618
3619 @d next_random { if ( mp->j_random==0 ) mp_new_randoms(mp);
3620   else decr(mp->j_random); }
3621
3622 @c 
3623 void mp_new_randoms (MP mp) {
3624   int k; /* index into |randoms| */
3625   fraction x; /* accumulator */
3626   for (k=0;k<=23;k++) { 
3627    x=mp->randoms[k]-mp->randoms[k+31];
3628     if ( x<0 ) x=x+fraction_one;
3629     mp->randoms[k]=x;
3630   }
3631   for (k=24;k<= 54;k++){ 
3632     x=mp->randoms[k]-mp->randoms[k-24];
3633     if ( x<0 ) x=x+fraction_one;
3634     mp->randoms[k]=x;
3635   }
3636   mp->j_random=54;
3637 }
3638
3639 @ @<Declarations@>=
3640 void mp_init_randoms (MP mp,scaled seed);
3641
3642 @ To initialize the |randoms| table, we call the following routine.
3643
3644 @c 
3645 void mp_init_randoms (MP mp,scaled seed) {
3646   fraction j,jj,k; /* more or less random integers */
3647   int i; /* index into |randoms| */
3648   j=abs(seed);
3649   while ( j>=fraction_one ) j=halfp(j);
3650   k=1;
3651   for (i=0;i<=54;i++ ){ 
3652     jj=k; k=j-k; j=jj;
3653     if ( k<0 ) k=k+fraction_one;
3654     mp->randoms[(i*21)% 55]=j;
3655   }
3656   mp_new_randoms(mp); 
3657   mp_new_randoms(mp); 
3658   mp_new_randoms(mp); /* ``warm up'' the array */
3659 }
3660
3661 @ To produce a uniform random number in the range |0<=u<x| or |0>=u>x|
3662 or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here.
3663
3664 Note that the call of |take_fraction| will produce the values 0 and~|x|
3665 with about half the probability that it will produce any other particular
3666 values between 0 and~|x|, because it rounds its answers.
3667
3668 @c 
3669 scaled mp_unif_rand (MP mp,scaled x) {
3670   scaled y; /* trial value */
3671   next_random; y=mp_take_fraction(mp, abs(x),mp->randoms[mp->j_random]);
3672   if ( y==abs(x) ) return 0;
3673   else if ( x>0 ) return y;
3674   else return (-y);
3675 }
3676
3677 @ Finally, a normal deviate with mean zero and unit standard deviation
3678 can readily be obtained with the ratio method (Algorithm 3.4.1R in
3679 {\sl The Art of Computer Programming\/}).
3680
3681 @c 
3682 scaled mp_norm_rand (MP mp) {
3683   integer x,u,l; /* what the book would call $2^{16}X$, $2^{28}U$, and $-2^{24}\ln U$ */
3684   do { 
3685     do {  
3686       next_random;
3687       x=mp_take_fraction(mp, 112429,mp->randoms[mp->j_random]-fraction_half);
3688       /* $2^{16}\sqrt{8/e}\approx 112428.82793$ */
3689       next_random; u=mp->randoms[mp->j_random];
3690     } while (abs(x)>=u);
3691     x=mp_make_fraction(mp, x,u);
3692     l=139548960-mp_m_log(mp, u); /* $2^{24}\cdot12\ln2\approx139548959.6165$ */
3693   } while (mp_ab_vs_cd(mp, 1024,l,x,x)<0);
3694   return x;
3695 }
3696
3697 @* \[9] Packed data.
3698 In order to make efficient use of storage space, \MP\ bases its major data
3699 structures on a |memory_word|, which contains either a (signed) integer,
3700 possibly scaled, or a small number of fields that are one half or one
3701 quarter of the size used for storing integers.
3702
3703 If |x| is a variable of type |memory_word|, it contains up to four
3704 fields that can be referred to as follows:
3705 $$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr
3706 |x|&.|int|&(an |integer|)\cr
3707 |x|&.|sc|\qquad&(a |scaled| integer)\cr
3708 |x.hh.lh|, |x.hh|&.|rh|&(two halfword fields)\cr
3709 |x.hh.b0|, |x.hh.b1|, |x.hh|&.|rh|&(two quarterword fields, one halfword
3710   field)\cr
3711 |x.qqqq.b0|, |x.qqqq.b1|, |x.qqqq|&.|b2|, |x.qqqq.b3|\hskip-100pt
3712   &\qquad\qquad\qquad(four quarterword fields)\cr}}$$
3713 This is somewhat cumbersome to write, and not very readable either, but
3714 macros will be used to make the notation shorter and more transparent.
3715 The code below gives a formal definition of |memory_word| and
3716 its subsidiary types, using packed variant records. \MP\ makes no
3717 assumptions about the relative positions of the fields within a word.
3718
3719 @d max_quarterword 0x3FFF /* largest allowable value in a |quarterword| */
3720 @d max_halfword 0xFFFFFFF /* largest allowable value in a |halfword| */
3721
3722 @ Here are the inequalities that the quarterword and halfword values
3723 must satisfy (or rather, the inequalities that they mustn't satisfy):
3724
3725 @<Check the ``constant''...@>=
3726 if (mp->ini_version) {
3727   if ( mp->mem_max!=mp->mem_top ) mp->bad=8;
3728 } else {
3729   if ( mp->mem_max<mp->mem_top ) mp->bad=8;
3730 }
3731 if ( max_quarterword<255 ) mp->bad=9;
3732 if ( max_halfword<65535 ) mp->bad=10;
3733 if ( max_quarterword>max_halfword ) mp->bad=11;
3734 if ( mp->mem_max>=max_halfword ) mp->bad=12;
3735 if ( mp->max_strings>max_halfword ) mp->bad=13;
3736
3737 @ The macros |qi| and |qo| are used for input to and output 
3738 from quarterwords. These are legacy macros.
3739 @^system dependencies@>
3740
3741 @d qo(A) (A) /* to read eight bits from a quarterword */
3742 @d qi(A) (A) /* to store eight bits in a quarterword */
3743
3744 @ The reader should study the following definitions closely:
3745 @^system dependencies@>
3746
3747 @d sc cint /* |scaled| data is equivalent to |integer| */
3748
3749 @<Types...@>=
3750 typedef short quarterword; /* 1/4 of a word */
3751 typedef int halfword; /* 1/2 of a word */
3752 typedef union {
3753   struct {
3754     halfword RH, LH;
3755   } v;
3756   struct { /* Make B0,B1 overlap the most significant bytes of LH.  */
3757     halfword junk;
3758     quarterword B0, B1;
3759   } u;
3760 } two_halves;
3761 typedef struct {
3762   struct {
3763     quarterword B2, B3, B0, B1;
3764   } u;
3765 } four_quarters;
3766 typedef union {
3767   two_halves hh;
3768   integer cint;
3769   four_quarters qqqq;
3770 } memory_word;
3771 #define b0 u.B0
3772 #define b1 u.B1
3773 #define b2 u.B2
3774 #define b3 u.B3
3775 #define rh v.RH
3776 #define lh v.LH
3777
3778 @ When debugging, we may want to print a |memory_word| without knowing
3779 what type it is; so we print it in all modes.
3780 @^debugging@>
3781
3782 @c 
3783 void mp_print_word (MP mp,memory_word w) {
3784   /* prints |w| in all ways */
3785   mp_print_int(mp, w.cint); mp_print_char(mp, ' ');
3786   mp_print_scaled(mp, w.sc); mp_print_char(mp, ' '); 
3787   mp_print_scaled(mp, w.sc / 010000); mp_print_ln(mp);
3788   mp_print_int(mp, w.hh.lh); mp_print_char(mp, '='); 
3789   mp_print_int(mp, w.hh.b0); mp_print_char(mp, ':');
3790   mp_print_int(mp, w.hh.b1); mp_print_char(mp, ';'); 
3791   mp_print_int(mp, w.hh.rh); mp_print_char(mp, ' ');
3792   mp_print_int(mp, w.qqqq.b0); mp_print_char(mp, ':'); 
3793   mp_print_int(mp, w.qqqq.b1); mp_print_char(mp, ':');
3794   mp_print_int(mp, w.qqqq.b2); mp_print_char(mp, ':'); 
3795   mp_print_int(mp, w.qqqq.b3);
3796 }
3797
3798
3799 @* \[10] Dynamic memory allocation.
3800
3801 The \MP\ system does nearly all of its own memory allocation, so that it
3802 can readily be transported into environments that do not have automatic
3803 facilities for strings, garbage collection, etc., and so that it can be in
3804 control of what error messages the user receives. The dynamic storage
3805 requirements of \MP\ are handled by providing a large array |mem| in
3806 which consecutive blocks of words are used as nodes by the \MP\ routines.
3807
3808 Pointer variables are indices into this array, or into another array
3809 called |eqtb| that will be explained later. A pointer variable might
3810 also be a special flag that lies outside the bounds of |mem|, so we
3811 allow pointers to assume any |halfword| value. The minimum memory
3812 index represents a null pointer.
3813
3814 @d null 0 /* the null pointer */
3815 @d mp_void (null+1) /* a null pointer different from |null| */
3816
3817
3818 @<Types...@>=
3819 typedef halfword pointer; /* a flag or a location in |mem| or |eqtb| */
3820
3821 @ The |mem| array is divided into two regions that are allocated separately,
3822 but the dividing line between these two regions is not fixed; they grow
3823 together until finding their ``natural'' size in a particular job.
3824 Locations less than or equal to |lo_mem_max| are used for storing
3825 variable-length records consisting of two or more words each. This region
3826 is maintained using an algorithm similar to the one described in exercise
3827 2.5--19 of {\sl The Art of Computer Programming}. However, no size field
3828 appears in the allocated nodes; the program is responsible for knowing the
3829 relevant size when a node is freed. Locations greater than or equal to
3830 |hi_mem_min| are used for storing one-word records; a conventional
3831 \.{AVAIL} stack is used for allocation in this region.
3832
3833 Locations of |mem| between |0| and |mem_top| may be dumped as part
3834 of preloaded format files, by the \.{INIMP} preprocessor.
3835 @.INIMP@>
3836 Production versions of \MP\ may extend the memory at the top end in order to
3837 provide more space; these locations, between |mem_top| and |mem_max|,
3838 are always used for single-word nodes.
3839
3840 The key pointers that govern |mem| allocation have a prescribed order:
3841 $$\hbox{|null=0<lo_mem_max<hi_mem_min<mem_top<=mem_end<=mem_max|.}$$
3842
3843 @<Glob...@>=
3844 memory_word *mem; /* the big dynamic storage area */
3845 pointer lo_mem_max; /* the largest location of variable-size memory in use */
3846 pointer hi_mem_min; /* the smallest location of one-word memory in use */
3847
3848
3849
3850 @d xfree(A) do { mp_xfree(A); A=NULL; } while (0)
3851 @d xrealloc(P,A,B) mp_xrealloc(mp,P,A,B)
3852 @d xmalloc(A,B)  mp_xmalloc(mp,A,B)
3853 @d xstrdup(A)  mp_xstrdup(mp,A)
3854 @d XREALLOC(a,b,c) a = xrealloc(a,(b+1),sizeof(c));
3855
3856 @<Declare helpers@>=
3857 void mp_xfree (void *x);
3858 void *mp_xrealloc (MP mp, void *p, size_t nmem, size_t size) ;
3859 void *mp_xmalloc (MP mp, size_t nmem, size_t size) ;
3860 char *mp_xstrdup(MP mp, const char *s);
3861
3862 @ The |max_size_test| guards against overflow, on the assumption that
3863 |size_t| is at least 31bits wide.
3864
3865 @d max_size_test 0x7FFFFFFF
3866
3867 @c
3868 void mp_xfree (void *x) {
3869   if (x!=NULL) free(x);
3870 }
3871 void  *mp_xrealloc (MP mp, void *p, size_t nmem, size_t size) {
3872   void *w ; 
3873   if ((max_size_test/size)<nmem) {
3874     do_fprintf(mp->err_out,"Memory size overflow!\n");
3875     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3876   }
3877   w = realloc (p,(nmem*size));
3878   if (w==NULL) {
3879     do_fprintf(mp->err_out,"Out of memory!\n");
3880     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3881   }
3882   return w;
3883 }
3884 void  *mp_xmalloc (MP mp, size_t nmem, size_t size) {
3885   void *w;
3886   if ((max_size_test/size)<nmem) {
3887     do_fprintf(mp->err_out,"Memory size overflow!\n");
3888     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3889   }
3890   w = malloc (nmem*size);
3891   if (w==NULL) {
3892     do_fprintf(mp->err_out,"Out of memory!\n");
3893     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3894   }
3895   return w;
3896 }
3897 char *mp_xstrdup(MP mp, const char *s) {
3898   char *w; 
3899   if (s==NULL)
3900     return NULL;
3901   w = strdup(s);
3902   if (w==NULL) {
3903     do_fprintf(mp->err_out,"Out of memory!\n");
3904     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3905   }
3906   return w;
3907 }
3908
3909
3910
3911 @<Allocate or initialize ...@>=
3912 mp->mem = xmalloc ((mp->mem_max+1),sizeof (memory_word));
3913 memset(mp->mem,0,(mp->mem_max+1)*sizeof (memory_word));
3914
3915 @ @<Dealloc variables@>=
3916 xfree(mp->mem);
3917
3918 @ Users who wish to study the memory requirements of particular applications can
3919 can use optional special features that keep track of current and
3920 maximum memory usage. When code between the delimiters |stat| $\ldots$
3921 |tats| is not ``commented out,'' \MP\ will run a bit slower but it will
3922 report these statistics when |mp_tracing_stats| is positive.
3923
3924 @<Glob...@>=
3925 integer var_used; integer dyn_used; /* how much memory is in use */
3926
3927 @ Let's consider the one-word memory region first, since it's the
3928 simplest. The pointer variable |mem_end| holds the highest-numbered location
3929 of |mem| that has ever been used. The free locations of |mem| that
3930 occur between |hi_mem_min| and |mem_end|, inclusive, are of type
3931 |two_halves|, and we write |info(p)| and |link(p)| for the |lh|
3932 and |rh| fields of |mem[p]| when it is of this type. The single-word
3933 free locations form a linked list
3934 $$|avail|,\;\hbox{|link(avail)|},\;\hbox{|link(link(avail))|},\;\ldots$$
3935 terminated by |null|.
3936
3937 @d link(A)   mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3938 @d info(A)   mp->mem[(A)].hh.lh /* the |info| field of a memory word */
3939
3940 @<Glob...@>=
3941 pointer avail; /* head of the list of available one-word nodes */
3942 pointer mem_end; /* the last one-word node used in |mem| */
3943
3944 @ If one-word memory is exhausted, it might mean that the user has forgotten
3945 a token like `\&{enddef}' or `\&{endfor}'. We will define some procedures
3946 later that try to help pinpoint the trouble.
3947
3948 @c 
3949 @<Declare the procedure called |show_token_list|@>;
3950 @<Declare the procedure called |runaway|@>
3951
3952 @ The function |get_avail| returns a pointer to a new one-word node whose
3953 |link| field is null. However, \MP\ will halt if there is no more room left.
3954 @^inner loop@>
3955
3956 @c 
3957 pointer mp_get_avail (MP mp) { /* single-word node allocation */
3958   pointer p; /* the new node being got */
3959   p=mp->avail; /* get top location in the |avail| stack */
3960   if ( p!=null ) {
3961     mp->avail=link(mp->avail); /* and pop it off */
3962   } else if ( mp->mem_end<mp->mem_max ) { /* or go into virgin territory */
3963     incr(mp->mem_end); p=mp->mem_end;
3964   } else { 
3965     decr(mp->hi_mem_min); p=mp->hi_mem_min;
3966     if ( mp->hi_mem_min<=mp->lo_mem_max ) { 
3967       mp_runaway(mp); /* if memory is exhausted, display possible runaway text */
3968       mp_overflow(mp, "main memory size",mp->mem_max);
3969       /* quit; all one-word nodes are busy */
3970 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
3971     }
3972   }
3973   link(p)=null; /* provide an oft-desired initialization of the new node */
3974   incr(mp->dyn_used);/* maintain statistics */
3975   return p;
3976 };
3977
3978 @ Conversely, a one-word node is recycled by calling |free_avail|.
3979
3980 @d free_avail(A)  /* single-word node liberation */
3981   { link((A))=mp->avail; mp->avail=(A); decr(mp->dyn_used);  }
3982
3983 @ There's also a |fast_get_avail| routine, which saves the procedure-call
3984 overhead at the expense of extra programming. This macro is used in
3985 the places that would otherwise account for the most calls of |get_avail|.
3986 @^inner loop@>
3987
3988 @d fast_get_avail(A) { 
3989   (A)=mp->avail; /* avoid |get_avail| if possible, to save time */
3990   if ( (A)==null ) { (A)=mp_get_avail(mp); } 
3991   else { mp->avail=link((A)); link((A))=null;  incr(mp->dyn_used); }
3992   }
3993
3994 @ The available-space list that keeps track of the variable-size portion
3995 of |mem| is a nonempty, doubly-linked circular list of empty nodes,
3996 pointed to by the roving pointer |rover|.
3997
3998 Each empty node has size 2 or more; the first word contains the special
3999 value |max_halfword| in its |link| field and the size in its |info| field;
4000 the second word contains the two pointers for double linking.
4001
4002 Each nonempty node also has size 2 or more. Its first word is of type
4003 |two_halves|\kern-1pt, and its |link| field is never equal to |max_halfword|.
4004 Otherwise there is complete flexibility with respect to the contents
4005 of its other fields and its other words.
4006
4007 (We require |mem_max<max_halfword| because terrible things can happen
4008 when |max_halfword| appears in the |link| field of a nonempty node.)
4009
4010 @d empty_flag   max_halfword /* the |link| of an empty variable-size node */
4011 @d is_empty(A)   (link((A))==empty_flag) /* tests for empty node */
4012 @d node_size   info /* the size field in empty variable-size nodes */
4013 @d llink(A)   info((A)+1) /* left link in doubly-linked list of empty nodes */
4014 @d rlink(A)   link((A)+1) /* right link in doubly-linked list of empty nodes */
4015
4016 @<Glob...@>=
4017 pointer rover; /* points to some node in the list of empties */
4018
4019 @ A call to |get_node| with argument |s| returns a pointer to a new node
4020 of size~|s|, which must be 2~or more. The |link| field of the first word
4021 of this new node is set to null. An overflow stop occurs if no suitable
4022 space exists.
4023
4024 If |get_node| is called with $s=2^{30}$, it simply merges adjacent free
4025 areas and returns the value |max_halfword|.
4026
4027 @<Internal library declarations@>=
4028 pointer mp_get_node (MP mp,integer s) ;
4029
4030 @ @c 
4031 pointer mp_get_node (MP mp,integer s) { /* variable-size node allocation */
4032   pointer p; /* the node currently under inspection */
4033   pointer q;  /* the node physically after node |p| */
4034   integer r; /* the newly allocated node, or a candidate for this honor */
4035   integer t,tt; /* temporary registers */
4036 @^inner loop@>
4037  RESTART: 
4038   p=mp->rover; /* start at some free node in the ring */
4039   do {  
4040     @<Try to allocate within node |p| and its physical successors,
4041      and |goto found| if allocation was possible@>;
4042     if (rlink(p)==null || rlink(p)==p) {
4043       print_err("Free list garbled");
4044       help3("I found an entry in the list of free nodes that links")
4045        ("badly. I will try to ignore the broken link, but something")
4046        ("is seriously amiss. It is wise to warn the maintainers.")
4047           mp_error(mp);
4048       rlink(p)=mp->rover;
4049     }
4050         p=rlink(p); /* move to the next node in the ring */
4051   } while (p!=mp->rover); /* repeat until the whole list has been traversed */
4052   if ( s==010000000000 ) { 
4053     return max_halfword;
4054   };
4055   if ( mp->lo_mem_max+2<mp->hi_mem_min ) {
4056     if ( mp->lo_mem_max+2<=max_halfword ) {
4057       @<Grow more variable-size memory and |goto restart|@>;
4058     }
4059   }
4060   mp_overflow(mp, "main memory size",mp->mem_max);
4061   /* sorry, nothing satisfactory is left */
4062 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
4063 FOUND: 
4064   link(r)=null; /* this node is now nonempty */
4065   mp->var_used+=s; /* maintain usage statistics */
4066   return r;
4067 }
4068
4069 @ The lower part of |mem| grows by 1000 words at a time, unless
4070 we are very close to going under. When it grows, we simply link
4071 a new node into the available-space list. This method of controlled
4072 growth helps to keep the |mem| usage consecutive when \MP\ is
4073 implemented on ``virtual memory'' systems.
4074 @^virtual memory@>
4075
4076 @<Grow more variable-size memory and |goto restart|@>=
4077
4078   if ( mp->hi_mem_min-mp->lo_mem_max>=1998 ) {
4079     t=mp->lo_mem_max+1000;
4080   } else {
4081     t=mp->lo_mem_max+1+(mp->hi_mem_min-mp->lo_mem_max) / 2; 
4082     /* |lo_mem_max+2<=t<hi_mem_min| */
4083   }
4084   if ( t>max_halfword ) t=max_halfword;
4085   p=llink(mp->rover); q=mp->lo_mem_max; rlink(p)=q; llink(mp->rover)=q;
4086   rlink(q)=mp->rover; llink(q)=p; link(q)=empty_flag; 
4087   node_size(q)=t-mp->lo_mem_max;
4088   mp->lo_mem_max=t; link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4089   mp->rover=q; 
4090   goto RESTART;
4091 }
4092
4093 @ @<Try to allocate...@>=
4094 q=p+node_size(p); /* find the physical successor */
4095 while ( is_empty(q) ) { /* merge node |p| with node |q| */
4096   t=rlink(q); tt=llink(q);
4097 @^inner loop@>
4098   if ( q==mp->rover ) mp->rover=t;
4099   llink(t)=tt; rlink(tt)=t;
4100   q=q+node_size(q);
4101 }
4102 r=q-s;
4103 if ( r>p+1 ) {
4104   @<Allocate from the top of node |p| and |goto found|@>;
4105 }
4106 if ( r==p ) { 
4107   if ( rlink(p)!=p ) {
4108     @<Allocate entire node |p| and |goto found|@>;
4109   }
4110 }
4111 node_size(p)=q-p /* reset the size in case it grew */
4112
4113 @ @<Allocate from the top...@>=
4114
4115   node_size(p)=r-p; /* store the remaining size */
4116   mp->rover=p; /* start searching here next time */
4117   goto FOUND;
4118 }
4119
4120 @ Here we delete node |p| from the ring, and let |rover| rove around.
4121
4122 @<Allocate entire...@>=
4123
4124   mp->rover=rlink(p); t=llink(p);
4125   llink(mp->rover)=t; rlink(t)=mp->rover;
4126   goto FOUND;
4127 }
4128
4129 @ Conversely, when some variable-size node |p| of size |s| is no longer needed,
4130 the operation |free_node(p,s)| will make its words available, by inserting
4131 |p| as a new empty node just before where |rover| now points.
4132
4133 @<Internal library declarations@>=
4134 void mp_free_node (MP mp, pointer p, halfword s) ;
4135
4136 @ @c 
4137 void mp_free_node (MP mp, pointer p, halfword s) { /* variable-size node
4138   liberation */
4139   pointer q; /* |llink(rover)| */
4140   node_size(p)=s; link(p)=empty_flag;
4141 @^inner loop@>
4142   q=llink(mp->rover); llink(p)=q; rlink(p)=mp->rover; /* set both links */
4143   llink(mp->rover)=p; rlink(q)=p; /* insert |p| into the ring */
4144   mp->var_used-=s; /* maintain statistics */
4145 }
4146
4147 @ Just before \.{INIMP} writes out the memory, it sorts the doubly linked
4148 available space list. The list is probably very short at such times, so a
4149 simple insertion sort is used. The smallest available location will be
4150 pointed to by |rover|, the next-smallest by |rlink(rover)|, etc.
4151
4152 @c 
4153 void mp_sort_avail (MP mp) { /* sorts the available variable-size nodes
4154   by location */
4155   pointer p,q,r; /* indices into |mem| */
4156   pointer old_rover; /* initial |rover| setting */
4157   p=mp_get_node(mp, 010000000000); /* merge adjacent free areas */
4158   p=rlink(mp->rover); rlink(mp->rover)=max_halfword; old_rover=mp->rover;
4159   while ( p!=old_rover ) {
4160     @<Sort |p| into the list starting at |rover|
4161      and advance |p| to |rlink(p)|@>;
4162   }
4163   p=mp->rover;
4164   while ( rlink(p)!=max_halfword ) { 
4165     llink(rlink(p))=p; p=rlink(p);
4166   };
4167   rlink(p)=mp->rover; llink(mp->rover)=p;
4168 }
4169
4170 @ The following |while| loop is guaranteed to
4171 terminate, since the list that starts at
4172 |rover| ends with |max_halfword| during the sorting procedure.
4173
4174 @<Sort |p|...@>=
4175 if ( p<mp->rover ) { 
4176   q=p; p=rlink(q); rlink(q)=mp->rover; mp->rover=q;
4177 } else  { 
4178   q=mp->rover;
4179   while ( rlink(q)<p ) q=rlink(q);
4180   r=rlink(p); rlink(p)=rlink(q); rlink(q)=p; p=r;
4181 }
4182
4183 @* \[11] Memory layout.
4184 Some areas of |mem| are dedicated to fixed usage, since static allocation is
4185 more efficient than dynamic allocation when we can get away with it. For
4186 example, locations |0| to |1| are always used to store a
4187 two-word dummy token whose second word is zero.
4188 The following macro definitions accomplish the static allocation by giving
4189 symbolic names to the fixed positions. Static variable-size nodes appear
4190 in locations |0| through |lo_mem_stat_max|, and static single-word nodes
4191 appear in locations |hi_mem_stat_min| through |mem_top|, inclusive.
4192
4193 @d null_dash (2) /* the first two words are reserved for a null value */
4194 @d dep_head (null_dash+3) /* we will define |dash_node_size=3| */
4195 @d zero_val (dep_head+2) /* two words for a permanently zero value */
4196 @d temp_val (zero_val+2) /* two words for a temporary value node */
4197 @d end_attr temp_val /* we use |end_attr+2| only */
4198 @d inf_val (end_attr+2) /* and |inf_val+1| only */
4199 @d test_pen (inf_val+2)
4200   /* nine words for a pen used when testing the turning number */
4201 @d bad_vardef (test_pen+9) /* two words for \&{vardef} error recovery */
4202 @d lo_mem_stat_max (bad_vardef+1)  /* largest statically
4203   allocated word in the variable-size |mem| */
4204 @#
4205 @d sentinel mp->mem_top /* end of sorted lists */
4206 @d temp_head (mp->mem_top-1) /* head of a temporary list of some kind */
4207 @d hold_head (mp->mem_top-2) /* head of a temporary list of another kind */
4208 @d spec_head (mp->mem_top-3) /* head of a list of unprocessed \&{special} items */
4209 @d hi_mem_stat_min (mp->mem_top-3) /* smallest statically allocated word in
4210   the one-word |mem| */
4211
4212 @ The following code gets the dynamic part of |mem| off to a good start,
4213 when \MP\ is initializing itself the slow way.
4214
4215 @<Initialize table entries (done by \.{INIMP} only)@>=
4216 @^data structure assumptions@>
4217 mp->rover=lo_mem_stat_max+1; /* initialize the dynamic memory */
4218 link(mp->rover)=empty_flag;
4219 node_size(mp->rover)=1000; /* which is a 1000-word available node */
4220 llink(mp->rover)=mp->rover; rlink(mp->rover)=mp->rover;
4221 mp->lo_mem_max=mp->rover+1000; 
4222 link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4223 for (k=hi_mem_stat_min;k<=(int)mp->mem_top;k++) {
4224   mp->mem[k]=mp->mem[mp->lo_mem_max]; /* clear list heads */
4225 }
4226 mp->avail=null; mp->mem_end=mp->mem_top;
4227 mp->hi_mem_min=hi_mem_stat_min; /* initialize the one-word memory */
4228 mp->var_used=lo_mem_stat_max+1; 
4229 mp->dyn_used=mp->mem_top+1-(hi_mem_stat_min);  /* initialize statistics */
4230 @<Initialize a pen at |test_pen| so that it fits in nine words@>;
4231
4232 @ The procedure |flush_list(p)| frees an entire linked list of one-word
4233 nodes that starts at a given position, until coming to |sentinel| or a
4234 pointer that is not in the one-word region. Another procedure,
4235 |flush_node_list|, frees an entire linked list of one-word and two-word
4236 nodes, until coming to a |null| pointer.
4237 @^inner loop@>
4238
4239 @c 
4240 void mp_flush_list (MP mp,pointer p) { /* makes list of single-word nodes  available */
4241   pointer q,r; /* list traversers */
4242   if ( p>=mp->hi_mem_min ) if ( p!=sentinel ) { 
4243     r=p;
4244     do {  
4245       q=r; r=link(r); 
4246       decr(mp->dyn_used);
4247       if ( r<mp->hi_mem_min ) break;
4248     } while (r!=sentinel);
4249   /* now |q| is the last node on the list */
4250     link(q)=mp->avail; mp->avail=p;
4251   }
4252 }
4253 @#
4254 void mp_flush_node_list (MP mp,pointer p) {
4255   pointer q; /* the node being recycled */
4256   while ( p!=null ){ 
4257     q=p; p=link(p);
4258     if ( q<mp->hi_mem_min ) 
4259       mp_free_node(mp, q,2);
4260     else 
4261       free_avail(q);
4262   }
4263 }
4264
4265 @ If \MP\ is extended improperly, the |mem| array might get screwed up.
4266 For example, some pointers might be wrong, or some ``dead'' nodes might not
4267 have been freed when the last reference to them disappeared. Procedures
4268 |check_mem| and |search_mem| are available to help diagnose such
4269 problems. These procedures make use of two arrays called |free| and
4270 |was_free| that are present only if \MP's debugging routines have
4271 been included. (You may want to decrease the size of |mem| while you
4272 @^debugging@>
4273 are debugging.)
4274
4275 Because |boolean|s are typedef-d as ints, it is better to use
4276 unsigned chars here.
4277
4278 @<Glob...@>=
4279 unsigned char *free; /* free cells */
4280 unsigned char *was_free; /* previously free cells */
4281 pointer was_mem_end; pointer was_lo_max; pointer was_hi_min;
4282   /* previous |mem_end|, |lo_mem_max|,and |hi_mem_min| */
4283 boolean panicking; /* do we want to check memory constantly? */
4284
4285 @ @<Allocate or initialize ...@>=
4286 mp->free = xmalloc ((mp->mem_max+1),sizeof (unsigned char));
4287 mp->was_free = xmalloc ((mp->mem_max+1), sizeof (unsigned char));
4288
4289 @ @<Dealloc variables@>=
4290 xfree(mp->free);
4291 xfree(mp->was_free);
4292
4293 @ @<Allocate or ...@>=
4294 mp->was_mem_end=0; /* indicate that everything was previously free */
4295 mp->was_lo_max=0; mp->was_hi_min=mp->mem_max;
4296 mp->panicking=false;
4297
4298 @ @<Declare |mp_reallocate| functions@>=
4299 void mp_reallocate_memory(MP mp, int l) ;
4300
4301 @ @c
4302 void mp_reallocate_memory(MP mp, int l) {
4303    XREALLOC(mp->free,     l, unsigned char);
4304    XREALLOC(mp->was_free, l, unsigned char);
4305    if (mp->mem) {
4306          int newarea = l-mp->mem_max;
4307      XREALLOC(mp->mem,      l, memory_word);
4308      memset (mp->mem+(mp->mem_max+1),0,sizeof(memory_word)*(newarea));
4309    } else {
4310      XREALLOC(mp->mem,      l, memory_word);
4311      memset(mp->mem,0,sizeof(memory_word)*(l+1));
4312    }
4313    mp->mem_max = l;
4314    if (mp->ini_version) 
4315      mp->mem_top = l;
4316 }
4317
4318
4319
4320 @ Procedure |check_mem| makes sure that the available space lists of
4321 |mem| are well formed, and it optionally prints out all locations
4322 that are reserved now but were free the last time this procedure was called.
4323
4324 @c 
4325 void mp_check_mem (MP mp,boolean print_locs ) {
4326   pointer p,q,r; /* current locations of interest in |mem| */
4327   boolean clobbered; /* is something amiss? */
4328   for (p=0;p<=mp->lo_mem_max;p++) {
4329     mp->free[p]=false; /* you can probably do this faster */
4330   }
4331   for (p=mp->hi_mem_min;p<= mp->mem_end;p++) {
4332     mp->free[p]=false; /* ditto */
4333   }
4334   @<Check single-word |avail| list@>;
4335   @<Check variable-size |avail| list@>;
4336   @<Check flags of unavailable nodes@>;
4337   @<Check the list of linear dependencies@>;
4338   if ( print_locs ) {
4339     @<Print newly busy locations@>;
4340   }
4341   memcpy(mp->was_free,mp->free, sizeof(char)*(mp->mem_end+1));
4342   mp->was_mem_end=mp->mem_end; 
4343   mp->was_lo_max=mp->lo_mem_max; 
4344   mp->was_hi_min=mp->hi_mem_min;
4345 }
4346
4347 @ @<Check single-word...@>=
4348 p=mp->avail; q=null; clobbered=false;
4349 while ( p!=null ) { 
4350   if ( (p>mp->mem_end)||(p<mp->hi_mem_min) ) clobbered=true;
4351   else if ( mp->free[p] ) clobbered=true;
4352   if ( clobbered ) { 
4353     mp_print_nl(mp, "AVAIL list clobbered at ");
4354 @.AVAIL list clobbered...@>
4355     mp_print_int(mp, q); break;
4356   }
4357   mp->free[p]=true; q=p; p=link(q);
4358 }
4359
4360 @ @<Check variable-size...@>=
4361 p=mp->rover; q=null; clobbered=false;
4362 do {  
4363   if ( (p>=mp->lo_mem_max)||(p<0) ) clobbered=true;
4364   else if ( (rlink(p)>=mp->lo_mem_max)||(rlink(p)<0) ) clobbered=true;
4365   else if (  !(is_empty(p))||(node_size(p)<2)||
4366    (p+node_size(p)>mp->lo_mem_max)|| (llink(rlink(p))!=p) ) clobbered=true;
4367   if ( clobbered ) { 
4368     mp_print_nl(mp, "Double-AVAIL list clobbered at ");
4369 @.Double-AVAIL list clobbered...@>
4370     mp_print_int(mp, q); break;
4371   }
4372   for (q=p;q<=p+node_size(p)-1;q++) { /* mark all locations free */
4373     if ( mp->free[q] ) { 
4374       mp_print_nl(mp, "Doubly free location at ");
4375 @.Doubly free location...@>
4376       mp_print_int(mp, q); break;
4377     }
4378     mp->free[q]=true;
4379   }
4380   q=p; p=rlink(p);
4381 } while (p!=mp->rover)
4382
4383
4384 @ @<Check flags...@>=
4385 p=0;
4386 while ( p<=mp->lo_mem_max ) { /* node |p| should not be empty */
4387   if ( is_empty(p) ) {
4388     mp_print_nl(mp, "Bad flag at "); mp_print_int(mp, p);
4389 @.Bad flag...@>
4390   }
4391   while ( (p<=mp->lo_mem_max) && ! mp->free[p] ) incr(p);
4392   while ( (p<=mp->lo_mem_max) && mp->free[p] ) incr(p);
4393 }
4394
4395 @ @<Print newly busy...@>=
4396
4397   @<Do intialization required before printing new busy locations@>;
4398   mp_print_nl(mp, "New busy locs:");
4399 @.New busy locs@>
4400   for (p=0;p<= mp->lo_mem_max;p++ ) {
4401     if ( ! mp->free[p] && ((p>mp->was_lo_max) || mp->was_free[p]) ) {
4402       @<Indicate that |p| is a new busy location@>;
4403     }
4404   }
4405   for (p=mp->hi_mem_min;p<=mp->mem_end;p++ ) {
4406     if ( ! mp->free[p] &&
4407         ((p<mp->was_hi_min) || (p>mp->was_mem_end) || mp->was_free[p]) ) {
4408       @<Indicate that |p| is a new busy location@>;
4409     }
4410   }
4411   @<Finish printing new busy locations@>;
4412 }
4413
4414 @ There might be many new busy locations so we are careful to print contiguous
4415 blocks compactly.  During this operation |q| is the last new busy location and
4416 |r| is the start of the block containing |q|.
4417
4418 @<Indicate that |p| is a new busy location@>=
4419
4420   if ( p>q+1 ) { 
4421     if ( q>r ) { 
4422       mp_print(mp, ".."); mp_print_int(mp, q);
4423     }
4424     mp_print_char(mp, ' '); mp_print_int(mp, p);
4425     r=p;
4426   }
4427   q=p;
4428 }
4429
4430 @ @<Do intialization required before printing new busy locations@>=
4431 q=mp->mem_max; r=mp->mem_max
4432
4433 @ @<Finish printing new busy locations@>=
4434 if ( q>r ) { 
4435   mp_print(mp, ".."); mp_print_int(mp, q);
4436 }
4437
4438 @ The |search_mem| procedure attempts to answer the question ``Who points
4439 to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem|
4440 that might not be of type |two_halves|. Strictly speaking, this is
4441 undefined, and it can lead to ``false drops'' (words that seem to
4442 point to |p| purely by coincidence). But for debugging purposes, we want
4443 to rule out the places that do {\sl not\/} point to |p|, so a few false
4444 drops are tolerable.
4445
4446 @c
4447 void mp_search_mem (MP mp, pointer p) { /* look for pointers to |p| */
4448   integer q; /* current position being searched */
4449   for (q=0;q<=mp->lo_mem_max;q++) { 
4450     if ( link(q)==p ){ 
4451       mp_print_nl(mp, "LINK("); mp_print_int(mp, q); mp_print_char(mp, ')');
4452     }
4453     if ( info(q)==p ) { 
4454       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, ')');
4455     }
4456   }
4457   for (q=mp->hi_mem_min;q<=mp->mem_end;q++) {
4458     if ( link(q)==p ) {
4459       mp_print_nl(mp, "LINK("); mp_print_int(mp, q); mp_print_char(mp, ')');
4460     }
4461     if ( info(q)==p ) {
4462       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, ')');
4463     }
4464   }
4465   @<Search |eqtb| for equivalents equal to |p|@>;
4466 }
4467
4468 @* \[12] The command codes.
4469 Before we can go much further, we need to define symbolic names for the internal
4470 code numbers that represent the various commands obeyed by \MP. These codes
4471 are somewhat arbitrary, but not completely so. For example,
4472 some codes have been made adjacent so that |case| statements in the
4473 program need not consider cases that are widely spaced, or so that |case|
4474 statements can be replaced by |if| statements. A command can begin an
4475 expression if and only if its code lies between |min_primary_command| and
4476 |max_primary_command|, inclusive. The first token of a statement that doesn't
4477 begin with an expression has a command code between |min_command| and
4478 |max_statement_command|, inclusive. Anything less than |min_command| is
4479 eliminated during macro expansions, and anything no more than |max_pre_command|
4480 is eliminated when expanding \TeX\ material.  Ranges such as
4481 |min_secondary_command..max_secondary_command| are used when parsing
4482 expressions, but the relative ordering within such a range is generally not
4483 critical.
4484
4485 The ordering of the highest-numbered commands
4486 (|comma<semicolon<end_group<stop|) is crucial for the parsing and
4487 error-recovery methods of this program as is the ordering |if_test<fi_or_else|
4488 for the smallest two commands.  The ordering is also important in the ranges
4489 |numeric_token..plus_or_minus| and |left_brace..ampersand|.
4490
4491 At any rate, here is the list, for future reference.
4492
4493 @d start_tex 1 /* begin \TeX\ material (\&{btex}, \&{verbatimtex}) */
4494 @d etex_marker 2 /* end \TeX\ material (\&{etex}) */
4495 @d mpx_break 3 /* stop reading an \.{MPX} file (\&{mpxbreak}) */
4496 @d max_pre_command mpx_break
4497 @d if_test 4 /* conditional text (\&{if}) */
4498 @d fi_or_else 5 /* delimiters for conditionals (\&{elseif}, \&{else}, \&{fi} */
4499 @d input 6 /* input a source file (\&{input}, \&{endinput}) */
4500 @d iteration 7 /* iterate (\&{for}, \&{forsuffixes}, \&{forever}, \&{endfor}) */
4501 @d repeat_loop 8 /* special command substituted for \&{endfor} */
4502 @d exit_test 9 /* premature exit from a loop (\&{exitif}) */
4503 @d relax 10 /* do nothing (\.{\char`\\}) */
4504 @d scan_tokens 11 /* put a string into the input buffer */
4505 @d expand_after 12 /* look ahead one token */
4506 @d defined_macro 13 /* a macro defined by the user */
4507 @d min_command (defined_macro+1)
4508 @d save_command 14 /* save a list of tokens (\&{save}) */
4509 @d interim_command 15 /* save an internal quantity (\&{interim}) */
4510 @d let_command 16 /* redefine a symbolic token (\&{let}) */
4511 @d new_internal 17 /* define a new internal quantity (\&{newinternal}) */
4512 @d macro_def 18 /* define a macro (\&{def}, \&{vardef}, etc.) */
4513 @d ship_out_command 19 /* output a character (\&{shipout}) */
4514 @d add_to_command 20 /* add to edges (\&{addto}) */
4515 @d bounds_command 21  /* add bounding path to edges (\&{setbounds}, \&{clip}) */
4516 @d tfm_command 22 /* command for font metric info (\&{ligtable}, etc.) */
4517 @d protection_command 23 /* set protection flag (\&{outer}, \&{inner}) */
4518 @d show_command 24 /* diagnostic output (\&{show}, \&{showvariable}, etc.) */
4519 @d mode_command 25 /* set interaction level (\&{batchmode}, etc.) */
4520 @d mp_random_seed 26 /* initialize random number generator (\&{randomseed}) */
4521 @d message_command 27 /* communicate to user (\&{message}, \&{errmessage}) */
4522 @d every_job_command 28 /* designate a starting token (\&{everyjob}) */
4523 @d delimiters 29 /* define a pair of delimiters (\&{delimiters}) */
4524 @d special_command 30 /* output special info (\&{special})
4525                        or font map info (\&{fontmapfile}, \&{fontmapline}) */
4526 @d write_command 31 /* write text to a file (\&{write}) */
4527 @d type_name 32 /* declare a type (\&{numeric}, \&{pair}, etc. */
4528 @d max_statement_command type_name
4529 @d min_primary_command type_name
4530 @d left_delimiter 33 /* the left delimiter of a matching pair */
4531 @d begin_group 34 /* beginning of a group (\&{begingroup}) */
4532 @d nullary 35 /* an operator without arguments (e.g., \&{normaldeviate}) */
4533 @d unary 36 /* an operator with one argument (e.g., \&{sqrt}) */
4534 @d str_op 37 /* convert a suffix to a string (\&{str}) */
4535 @d cycle 38 /* close a cyclic path (\&{cycle}) */
4536 @d primary_binary 39 /* binary operation taking `\&{of}' (e.g., \&{point}) */
4537 @d capsule_token 40 /* a value that has been put into a token list */
4538 @d string_token 41 /* a string constant (e.g., |"hello"|) */
4539 @d internal_quantity 42 /* internal numeric parameter (e.g., \&{pausing}) */
4540 @d min_suffix_token internal_quantity
4541 @d tag_token 43 /* a symbolic token without a primitive meaning */
4542 @d numeric_token 44 /* a numeric constant (e.g., \.{3.14159}) */
4543 @d max_suffix_token numeric_token
4544 @d plus_or_minus 45 /* either `\.+' or `\.-' */
4545 @d max_primary_command plus_or_minus /* should also be |numeric_token+1| */
4546 @d min_tertiary_command plus_or_minus
4547 @d tertiary_secondary_macro 46 /* a macro defined by \&{secondarydef} */
4548 @d tertiary_binary 47 /* an operator at the tertiary level (e.g., `\.{++}') */
4549 @d max_tertiary_command tertiary_binary
4550 @d left_brace 48 /* the operator `\.{\char`\{}' */
4551 @d min_expression_command left_brace
4552 @d path_join 49 /* the operator `\.{..}' */
4553 @d ampersand 50 /* the operator `\.\&' */
4554 @d expression_tertiary_macro 51 /* a macro defined by \&{tertiarydef} */
4555 @d expression_binary 52 /* an operator at the expression level (e.g., `\.<') */
4556 @d equals 53 /* the operator `\.=' */
4557 @d max_expression_command equals
4558 @d and_command 54 /* the operator `\&{and}' */
4559 @d min_secondary_command and_command
4560 @d secondary_primary_macro 55 /* a macro defined by \&{primarydef} */
4561 @d slash 56 /* the operator `\./' */
4562 @d secondary_binary 57 /* an operator at the binary level (e.g., \&{shifted}) */
4563 @d max_secondary_command secondary_binary
4564 @d param_type 58 /* type of parameter (\&{primary}, \&{expr}, \&{suffix}, etc.) */
4565 @d controls 59 /* specify control points explicitly (\&{controls}) */
4566 @d tension 60 /* specify tension between knots (\&{tension}) */
4567 @d at_least 61 /* bounded tension value (\&{atleast}) */
4568 @d curl_command 62 /* specify curl at an end knot (\&{curl}) */
4569 @d macro_special 63 /* special macro operators (\&{quote}, \.{\#\AT!}, etc.) */
4570 @d right_delimiter 64 /* the right delimiter of a matching pair */
4571 @d left_bracket 65 /* the operator `\.[' */
4572 @d right_bracket 66 /* the operator `\.]' */
4573 @d right_brace 67 /* the operator `\.{\char`\}}' */
4574 @d with_option 68 /* option for filling (\&{withpen}, \&{withweight}, etc.) */
4575 @d thing_to_add 69
4576   /* variant of \&{addto} (\&{contour}, \&{doublepath}, \&{also}) */
4577 @d of_token 70 /* the operator `\&{of}' */
4578 @d to_token 71 /* the operator `\&{to}' */
4579 @d step_token 72 /* the operator `\&{step}' */
4580 @d until_token 73 /* the operator `\&{until}' */
4581 @d within_token 74 /* the operator `\&{within}' */
4582 @d lig_kern_token 75
4583   /* the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}, etc. */
4584 @d assignment 76 /* the operator `\.{:=}' */
4585 @d skip_to 77 /* the operation `\&{skipto}' */
4586 @d bchar_label 78 /* the operator `\.{\char'174\char'174:}' */
4587 @d double_colon 79 /* the operator `\.{::}' */
4588 @d colon 80 /* the operator `\.:' */
4589 @#
4590 @d comma 81 /* the operator `\.,', must be |colon+1| */
4591 @d end_of_statement (mp->cur_cmd>comma)
4592 @d semicolon 82 /* the operator `\.;', must be |comma+1| */
4593 @d end_group 83 /* end a group (\&{endgroup}), must be |semicolon+1| */
4594 @d stop 84 /* end a job (\&{end}, \&{dump}), must be |end_group+1| */
4595 @d max_command_code stop
4596 @d outer_tag (max_command_code+1) /* protection code added to command code */
4597
4598 @<Types...@>=
4599 typedef int command_code;
4600
4601 @ Variables and capsules in \MP\ have a variety of ``types,''
4602 distinguished by the code numbers defined here. These numbers are also
4603 not completely arbitrary.  Things that get expanded must have types
4604 |>mp_independent|; a type remaining after expansion is numeric if and only if
4605 its code number is at least |numeric_type|; objects containing numeric
4606 parts must have types between |transform_type| and |pair_type|;
4607 all other types must be smaller than |transform_type|; and among the types
4608 that are not unknown or vacuous, the smallest two must be |boolean_type|
4609 and |string_type| in that order.
4610  
4611 @d undefined 0 /* no type has been declared */
4612 @d unknown_tag 1 /* this constant is added to certain type codes below */
4613 @d unknown_types mp_unknown_boolean: case mp_unknown_string:
4614   case mp_unknown_pen: case mp_unknown_picture: case mp_unknown_path
4615
4616 @<Types...@>=
4617 enum mp_variable_type {
4618 mp_vacuous=1, /* no expression was present */
4619 mp_boolean_type, /* \&{boolean} with a known value */
4620 mp_unknown_boolean,
4621 mp_string_type, /* \&{string} with a known value */
4622 mp_unknown_string,
4623 mp_pen_type, /* \&{pen} with a known value */
4624 mp_unknown_pen,
4625 mp_path_type, /* \&{path} with a known value */
4626 mp_unknown_path,
4627 mp_picture_type, /* \&{picture} with a known value */
4628 mp_unknown_picture,
4629 mp_transform_type, /* \&{transform} variable or capsule */
4630 mp_color_type, /* \&{color} variable or capsule */
4631 mp_cmykcolor_type, /* \&{cmykcolor} variable or capsule */
4632 mp_pair_type, /* \&{pair} variable or capsule */
4633 mp_numeric_type, /* variable that has been declared \&{numeric} but not used */
4634 mp_known, /* \&{numeric} with a known value */
4635 mp_dependent, /* a linear combination with |fraction| coefficients */
4636 mp_proto_dependent, /* a linear combination with |scaled| coefficients */
4637 mp_independent, /* \&{numeric} with unknown value */
4638 mp_token_list, /* variable name or suffix argument or text argument */
4639 mp_structured, /* variable with subscripts and attributes */
4640 mp_unsuffixed_macro, /* variable defined with \&{vardef} but no \.{\AT!\#} */
4641 mp_suffixed_macro /* variable defined with \&{vardef} and \.{\AT!\#} */
4642 } ;
4643
4644 @ @<Declarations@>=
4645 void mp_print_type (MP mp,small_number t) ;
4646
4647 @ @<Basic printing procedures@>=
4648 void mp_print_type (MP mp,small_number t) { 
4649   switch (t) {
4650   case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
4651   case mp_boolean_type:mp_print(mp, "boolean"); break;
4652   case mp_unknown_boolean:mp_print(mp, "unknown boolean"); break;
4653   case mp_string_type:mp_print(mp, "string"); break;
4654   case mp_unknown_string:mp_print(mp, "unknown string"); break;
4655   case mp_pen_type:mp_print(mp, "pen"); break;
4656   case mp_unknown_pen:mp_print(mp, "unknown pen"); break;
4657   case mp_path_type:mp_print(mp, "path"); break;
4658   case mp_unknown_path:mp_print(mp, "unknown path"); break;
4659   case mp_picture_type:mp_print(mp, "picture"); break;
4660   case mp_unknown_picture:mp_print(mp, "unknown picture"); break;
4661   case mp_transform_type:mp_print(mp, "transform"); break;
4662   case mp_color_type:mp_print(mp, "color"); break;
4663   case mp_cmykcolor_type:mp_print(mp, "cmykcolor"); break;
4664   case mp_pair_type:mp_print(mp, "pair"); break;
4665   case mp_known:mp_print(mp, "known numeric"); break;
4666   case mp_dependent:mp_print(mp, "dependent"); break;
4667   case mp_proto_dependent:mp_print(mp, "proto-dependent"); break;
4668   case mp_numeric_type:mp_print(mp, "numeric"); break;
4669   case mp_independent:mp_print(mp, "independent"); break;
4670   case mp_token_list:mp_print(mp, "token list"); break;
4671   case mp_structured:mp_print(mp, "mp_structured"); break;
4672   case mp_unsuffixed_macro:mp_print(mp, "unsuffixed macro"); break;
4673   case mp_suffixed_macro:mp_print(mp, "suffixed macro"); break;
4674   default: mp_print(mp, "undefined"); break;
4675   }
4676 }
4677
4678 @ Values inside \MP\ are stored in two-word nodes that have a |name_type|
4679 as well as a |type|. The possibilities for |name_type| are defined
4680 here; they will be explained in more detail later.
4681
4682 @<Types...@>=
4683 enum mp_name_type {
4684  mp_root=0, /* |name_type| at the top level of a variable */
4685  mp_saved_root, /* same, when the variable has been saved */
4686  mp_structured_root, /* |name_type| where a |mp_structured| branch occurs */
4687  mp_subscr, /* |name_type| in a subscript node */
4688  mp_attr, /* |name_type| in an attribute node */
4689  mp_x_part_sector, /* |name_type| in the \&{xpart} of a node */
4690  mp_y_part_sector, /* |name_type| in the \&{ypart} of a node */
4691  mp_xx_part_sector, /* |name_type| in the \&{xxpart} of a node */
4692  mp_xy_part_sector, /* |name_type| in the \&{xypart} of a node */
4693  mp_yx_part_sector, /* |name_type| in the \&{yxpart} of a node */
4694  mp_yy_part_sector, /* |name_type| in the \&{yypart} of a node */
4695  mp_red_part_sector, /* |name_type| in the \&{redpart} of a node */
4696  mp_green_part_sector, /* |name_type| in the \&{greenpart} of a node */
4697  mp_blue_part_sector, /* |name_type| in the \&{bluepart} of a node */
4698  mp_cyan_part_sector, /* |name_type| in the \&{redpart} of a node */
4699  mp_magenta_part_sector, /* |name_type| in the \&{greenpart} of a node */
4700  mp_yellow_part_sector, /* |name_type| in the \&{bluepart} of a node */
4701  mp_black_part_sector, /* |name_type| in the \&{greenpart} of a node */
4702  mp_grey_part_sector, /* |name_type| in the \&{bluepart} of a node */
4703  mp_capsule, /* |name_type| in stashed-away subexpressions */
4704  mp_token  /* |name_type| in a numeric token or string token */
4705 };
4706
4707 @ Primitive operations that produce values have a secondary identification
4708 code in addition to their command code; it's something like genera and species.
4709 For example, `\.*' has the command code |primary_binary|, and its
4710 secondary identification is |times|. The secondary codes start at 30 so that
4711 they don't overlap with the type codes; some type codes (e.g., |mp_string_type|)
4712 are used as operators as well as type identifications.  The relative values
4713 are not critical, except for |true_code..false_code|, |or_op..and_op|,
4714 and |filled_op..bounded_op|.  The restrictions are that
4715 |and_op-false_code=or_op-true_code|, that the ordering of
4716 |x_part...blue_part| must match that of |x_part_sector..mp_blue_part_sector|,
4717 and the ordering of |filled_op..bounded_op| must match that of the code
4718 values they test for.
4719
4720 @d true_code 30 /* operation code for \.{true} */
4721 @d false_code 31 /* operation code for \.{false} */
4722 @d null_picture_code 32 /* operation code for \.{nullpicture} */
4723 @d null_pen_code 33 /* operation code for \.{nullpen} */
4724 @d job_name_op 34 /* operation code for \.{jobname} */
4725 @d read_string_op 35 /* operation code for \.{readstring} */
4726 @d pen_circle 36 /* operation code for \.{pencircle} */
4727 @d normal_deviate 37 /* operation code for \.{normaldeviate} */
4728 @d read_from_op 38 /* operation code for \.{readfrom} */
4729 @d close_from_op 39 /* operation code for \.{closefrom} */
4730 @d odd_op 40 /* operation code for \.{odd} */
4731 @d known_op 41 /* operation code for \.{known} */
4732 @d unknown_op 42 /* operation code for \.{unknown} */
4733 @d not_op 43 /* operation code for \.{not} */
4734 @d decimal 44 /* operation code for \.{decimal} */
4735 @d reverse 45 /* operation code for \.{reverse} */
4736 @d make_path_op 46 /* operation code for \.{makepath} */
4737 @d make_pen_op 47 /* operation code for \.{makepen} */
4738 @d oct_op 48 /* operation code for \.{oct} */
4739 @d hex_op 49 /* operation code for \.{hex} */
4740 @d ASCII_op 50 /* operation code for \.{ASCII} */
4741 @d char_op 51 /* operation code for \.{char} */
4742 @d length_op 52 /* operation code for \.{length} */
4743 @d turning_op 53 /* operation code for \.{turningnumber} */
4744 @d color_model_part 54 /* operation code for \.{colormodel} */
4745 @d x_part 55 /* operation code for \.{xpart} */
4746 @d y_part 56 /* operation code for \.{ypart} */
4747 @d xx_part 57 /* operation code for \.{xxpart} */
4748 @d xy_part 58 /* operation code for \.{xypart} */
4749 @d yx_part 59 /* operation code for \.{yxpart} */
4750 @d yy_part 60 /* operation code for \.{yypart} */
4751 @d red_part 61 /* operation code for \.{redpart} */
4752 @d green_part 62 /* operation code for \.{greenpart} */
4753 @d blue_part 63 /* operation code for \.{bluepart} */
4754 @d cyan_part 64 /* operation code for \.{cyanpart} */
4755 @d magenta_part 65 /* operation code for \.{magentapart} */
4756 @d yellow_part 66 /* operation code for \.{yellowpart} */
4757 @d black_part 67 /* operation code for \.{blackpart} */
4758 @d grey_part 68 /* operation code for \.{greypart} */
4759 @d font_part 69 /* operation code for \.{fontpart} */
4760 @d text_part 70 /* operation code for \.{textpart} */
4761 @d path_part 71 /* operation code for \.{pathpart} */
4762 @d pen_part 72 /* operation code for \.{penpart} */
4763 @d dash_part 73 /* operation code for \.{dashpart} */
4764 @d sqrt_op 74 /* operation code for \.{sqrt} */
4765 @d m_exp_op 75 /* operation code for \.{mexp} */
4766 @d m_log_op 76 /* operation code for \.{mlog} */
4767 @d sin_d_op 77 /* operation code for \.{sind} */
4768 @d cos_d_op 78 /* operation code for \.{cosd} */
4769 @d floor_op 79 /* operation code for \.{floor} */
4770 @d uniform_deviate 80 /* operation code for \.{uniformdeviate} */
4771 @d char_exists_op 81 /* operation code for \.{charexists} */
4772 @d font_size 82 /* operation code for \.{fontsize} */
4773 @d ll_corner_op 83 /* operation code for \.{llcorner} */
4774 @d lr_corner_op 84 /* operation code for \.{lrcorner} */
4775 @d ul_corner_op 85 /* operation code for \.{ulcorner} */
4776 @d ur_corner_op 86 /* operation code for \.{urcorner} */
4777 @d arc_length 87 /* operation code for \.{arclength} */
4778 @d angle_op 88 /* operation code for \.{angle} */
4779 @d cycle_op 89 /* operation code for \.{cycle} */
4780 @d filled_op 90 /* operation code for \.{filled} */
4781 @d stroked_op 91 /* operation code for \.{stroked} */
4782 @d textual_op 92 /* operation code for \.{textual} */
4783 @d clipped_op 93 /* operation code for \.{clipped} */
4784 @d bounded_op 94 /* operation code for \.{bounded} */
4785 @d plus 95 /* operation code for \.+ */
4786 @d minus 96 /* operation code for \.- */
4787 @d times 97 /* operation code for \.* */
4788 @d over 98 /* operation code for \./ */
4789 @d pythag_add 99 /* operation code for \.{++} */
4790 @d pythag_sub 100 /* operation code for \.{+-+} */
4791 @d or_op 101 /* operation code for \.{or} */
4792 @d and_op 102 /* operation code for \.{and} */
4793 @d less_than 103 /* operation code for \.< */
4794 @d less_or_equal 104 /* operation code for \.{<=} */
4795 @d greater_than 105 /* operation code for \.> */
4796 @d greater_or_equal 106 /* operation code for \.{>=} */
4797 @d equal_to 107 /* operation code for \.= */
4798 @d unequal_to 108 /* operation code for \.{<>} */
4799 @d concatenate 109 /* operation code for \.\& */
4800 @d rotated_by 110 /* operation code for \.{rotated} */
4801 @d slanted_by 111 /* operation code for \.{slanted} */
4802 @d scaled_by 112 /* operation code for \.{scaled} */
4803 @d shifted_by 113 /* operation code for \.{shifted} */
4804 @d transformed_by 114 /* operation code for \.{transformed} */
4805 @d x_scaled 115 /* operation code for \.{xscaled} */
4806 @d y_scaled 116 /* operation code for \.{yscaled} */
4807 @d z_scaled 117 /* operation code for \.{zscaled} */
4808 @d in_font 118 /* operation code for \.{infont} */
4809 @d intersect 119 /* operation code for \.{intersectiontimes} */
4810 @d double_dot 120 /* operation code for improper \.{..} */
4811 @d substring_of 121 /* operation code for \.{substring} */
4812 @d min_of substring_of
4813 @d subpath_of 122 /* operation code for \.{subpath} */
4814 @d direction_time_of 123 /* operation code for \.{directiontime} */
4815 @d point_of 124 /* operation code for \.{point} */
4816 @d precontrol_of 125 /* operation code for \.{precontrol} */
4817 @d postcontrol_of 126 /* operation code for \.{postcontrol} */
4818 @d pen_offset_of 127 /* operation code for \.{penoffset} */
4819 @d arc_time_of 128 /* operation code for \.{arctime} */
4820 @d mp_version 129 /* operation code for \.{mpversion} */
4821 @d envelope_of 130 /* operation code for \.{envelope} */
4822
4823 @c void mp_print_op (MP mp,quarterword c) { 
4824   if (c<=mp_numeric_type ) {
4825     mp_print_type(mp, c);
4826   } else {
4827     switch (c) {
4828     case true_code:mp_print(mp, "true"); break;
4829     case false_code:mp_print(mp, "false"); break;
4830     case null_picture_code:mp_print(mp, "nullpicture"); break;
4831     case null_pen_code:mp_print(mp, "nullpen"); break;
4832     case job_name_op:mp_print(mp, "jobname"); break;
4833     case read_string_op:mp_print(mp, "readstring"); break;
4834     case pen_circle:mp_print(mp, "pencircle"); break;
4835     case normal_deviate:mp_print(mp, "normaldeviate"); break;
4836     case read_from_op:mp_print(mp, "readfrom"); break;
4837     case close_from_op:mp_print(mp, "closefrom"); break;
4838     case odd_op:mp_print(mp, "odd"); break;
4839     case known_op:mp_print(mp, "known"); break;
4840     case unknown_op:mp_print(mp, "unknown"); break;
4841     case not_op:mp_print(mp, "not"); break;
4842     case decimal:mp_print(mp, "decimal"); break;
4843     case reverse:mp_print(mp, "reverse"); break;
4844     case make_path_op:mp_print(mp, "makepath"); break;
4845     case make_pen_op:mp_print(mp, "makepen"); break;
4846     case oct_op:mp_print(mp, "oct"); break;
4847     case hex_op:mp_print(mp, "hex"); break;
4848     case ASCII_op:mp_print(mp, "ASCII"); break;
4849     case char_op:mp_print(mp, "char"); break;
4850     case length_op:mp_print(mp, "length"); break;
4851     case turning_op:mp_print(mp, "turningnumber"); break;
4852     case x_part:mp_print(mp, "xpart"); break;
4853     case y_part:mp_print(mp, "ypart"); break;
4854     case xx_part:mp_print(mp, "xxpart"); break;
4855     case xy_part:mp_print(mp, "xypart"); break;
4856     case yx_part:mp_print(mp, "yxpart"); break;
4857     case yy_part:mp_print(mp, "yypart"); break;
4858     case red_part:mp_print(mp, "redpart"); break;
4859     case green_part:mp_print(mp, "greenpart"); break;
4860     case blue_part:mp_print(mp, "bluepart"); break;
4861     case cyan_part:mp_print(mp, "cyanpart"); break;
4862     case magenta_part:mp_print(mp, "magentapart"); break;
4863     case yellow_part:mp_print(mp, "yellowpart"); break;
4864     case black_part:mp_print(mp, "blackpart"); break;
4865     case grey_part:mp_print(mp, "greypart"); break;
4866     case color_model_part:mp_print(mp, "colormodel"); break;
4867     case font_part:mp_print(mp, "fontpart"); break;
4868     case text_part:mp_print(mp, "textpart"); break;
4869     case path_part:mp_print(mp, "pathpart"); break;
4870     case pen_part:mp_print(mp, "penpart"); break;
4871     case dash_part:mp_print(mp, "dashpart"); break;
4872     case sqrt_op:mp_print(mp, "sqrt"); break;
4873     case m_exp_op:mp_print(mp, "mexp"); break;
4874     case m_log_op:mp_print(mp, "mlog"); break;
4875     case sin_d_op:mp_print(mp, "sind"); break;
4876     case cos_d_op:mp_print(mp, "cosd"); break;
4877     case floor_op:mp_print(mp, "floor"); break;
4878     case uniform_deviate:mp_print(mp, "uniformdeviate"); break;
4879     case char_exists_op:mp_print(mp, "charexists"); break;
4880     case font_size:mp_print(mp, "fontsize"); break;
4881     case ll_corner_op:mp_print(mp, "llcorner"); break;
4882     case lr_corner_op:mp_print(mp, "lrcorner"); break;
4883     case ul_corner_op:mp_print(mp, "ulcorner"); break;
4884     case ur_corner_op:mp_print(mp, "urcorner"); break;
4885     case arc_length:mp_print(mp, "arclength"); break;
4886     case angle_op:mp_print(mp, "angle"); break;
4887     case cycle_op:mp_print(mp, "cycle"); break;
4888     case filled_op:mp_print(mp, "filled"); break;
4889     case stroked_op:mp_print(mp, "stroked"); break;
4890     case textual_op:mp_print(mp, "textual"); break;
4891     case clipped_op:mp_print(mp, "clipped"); break;
4892     case bounded_op:mp_print(mp, "bounded"); break;
4893     case plus:mp_print_char(mp, '+'); break;
4894     case minus:mp_print_char(mp, '-'); break;
4895     case times:mp_print_char(mp, '*'); break;
4896     case over:mp_print_char(mp, '/'); break;
4897     case pythag_add:mp_print(mp, "++"); break;
4898     case pythag_sub:mp_print(mp, "+-+"); break;
4899     case or_op:mp_print(mp, "or"); break;
4900     case and_op:mp_print(mp, "and"); break;
4901     case less_than:mp_print_char(mp, '<'); break;
4902     case less_or_equal:mp_print(mp, "<="); break;
4903     case greater_than:mp_print_char(mp, '>'); break;
4904     case greater_or_equal:mp_print(mp, ">="); break;
4905     case equal_to:mp_print_char(mp, '='); break;
4906     case unequal_to:mp_print(mp, "<>"); break;
4907     case concatenate:mp_print(mp, "&"); break;
4908     case rotated_by:mp_print(mp, "rotated"); break;
4909     case slanted_by:mp_print(mp, "slanted"); break;
4910     case scaled_by:mp_print(mp, "scaled"); break;
4911     case shifted_by:mp_print(mp, "shifted"); break;
4912     case transformed_by:mp_print(mp, "transformed"); break;
4913     case x_scaled:mp_print(mp, "xscaled"); break;
4914     case y_scaled:mp_print(mp, "yscaled"); break;
4915     case z_scaled:mp_print(mp, "zscaled"); break;
4916     case in_font:mp_print(mp, "infont"); break;
4917     case intersect:mp_print(mp, "intersectiontimes"); break;
4918     case substring_of:mp_print(mp, "substring"); break;
4919     case subpath_of:mp_print(mp, "subpath"); break;
4920     case direction_time_of:mp_print(mp, "directiontime"); break;
4921     case point_of:mp_print(mp, "point"); break;
4922     case precontrol_of:mp_print(mp, "precontrol"); break;
4923     case postcontrol_of:mp_print(mp, "postcontrol"); break;
4924     case pen_offset_of:mp_print(mp, "penoffset"); break;
4925     case arc_time_of:mp_print(mp, "arctime"); break;
4926     case mp_version:mp_print(mp, "mpversion"); break;
4927     case envelope_of:mp_print(mp, "envelope"); break;
4928     default: mp_print(mp, ".."); break;
4929     }
4930   }
4931 }
4932
4933 @ \MP\ also has a bunch of internal parameters that a user might want to
4934 fuss with. Every such parameter has an identifying code number, defined here.
4935
4936 @<Types...@>=
4937 enum mp_given_internal {
4938   mp_tracing_titles=1, /* show titles online when they appear */
4939   mp_tracing_equations, /* show each variable when it becomes known */
4940   mp_tracing_capsules, /* show capsules too */
4941   mp_tracing_choices, /* show the control points chosen for paths */
4942   mp_tracing_specs, /* show path subdivision prior to filling with polygonal a pen */
4943   mp_tracing_commands, /* show commands and operations before they are performed */
4944   mp_tracing_restores, /* show when a variable or internal is restored */
4945   mp_tracing_macros, /* show macros before they are expanded */
4946   mp_tracing_output, /* show digitized edges as they are output */
4947   mp_tracing_stats, /* show memory usage at end of job */
4948   mp_tracing_lost_chars, /* show characters that aren't \&{infont} */
4949   mp_tracing_online, /* show long diagnostics on terminal and in the log file */
4950   mp_year, /* the current year (e.g., 1984) */
4951   mp_month, /* the current month (e.g, 3 $\equiv$ March) */
4952   mp_day, /* the current day of the month */
4953   mp_time, /* the number of minutes past midnight when this job started */
4954   mp_char_code, /* the number of the next character to be output */
4955   mp_char_ext, /* the extension code of the next character to be output */
4956   mp_char_wd, /* the width of the next character to be output */
4957   mp_char_ht, /* the height of the next character to be output */
4958   mp_char_dp, /* the depth of the next character to be output */
4959   mp_char_ic, /* the italic correction of the next character to be output */
4960   mp_design_size, /* the unit of measure used for |mp_char_wd..mp_char_ic|, in points */
4961   mp_pausing, /* positive to display lines on the terminal before they are read */
4962   mp_showstopping, /* positive to stop after each \&{show} command */
4963   mp_fontmaking, /* positive if font metric output is to be produced */
4964   mp_linejoin, /* as in \ps: 0 for mitered, 1 for round, 2 for beveled */
4965   mp_linecap, /* as in \ps: 0 for butt, 1 for round, 2 for square */
4966   mp_miterlimit, /* controls miter length as in \ps */
4967   mp_warning_check, /* controls error message when variable value is large */
4968   mp_boundary_char, /* the right boundary character for ligatures */
4969   mp_prologues, /* positive to output conforming PostScript using built-in fonts */
4970   mp_true_corners, /* positive to make \&{llcorner} etc. ignore \&{setbounds} */
4971   mp_default_color_model, /* the default color model for unspecified items */
4972   mp_restore_clip_color,
4973   mp_procset, /* wether or not create PostScript command shortcuts */
4974   mp_gtroffmode,  /* whether the user specified |-troff| on the command line */
4975 };
4976
4977 @
4978
4979 @d max_given_internal mp_gtroffmode
4980
4981 @<Glob...@>=
4982 scaled *internal;  /* the values of internal quantities */
4983 char **int_name;  /* their names */
4984 int int_ptr;  /* the maximum internal quantity defined so far */
4985 int max_internal; /* current maximum number of internal quantities */
4986
4987 @ @<Option variables@>=
4988 int troff_mode; 
4989
4990 @ @<Allocate or initialize ...@>=
4991 mp->max_internal=2*max_given_internal;
4992 mp->internal = xmalloc ((mp->max_internal+1), sizeof(scaled));
4993 mp->int_name = xmalloc ((mp->max_internal+1), sizeof(char *));
4994 mp->troff_mode=(opt->troff_mode>0 ? true : false);
4995
4996 @ @<Exported function ...@>=
4997 int mp_troff_mode(MP mp);
4998
4999 @ @c
5000 int mp_troff_mode(MP mp) { return mp->troff_mode; }
5001
5002 @ @<Set initial ...@>=
5003 for (k=0;k<= mp->max_internal; k++ ) { 
5004    mp->internal[k]=0; 
5005    mp->int_name[k]=NULL; 
5006 }
5007 mp->int_ptr=max_given_internal;
5008
5009 @ The symbolic names for internal quantities are put into \MP's hash table
5010 by using a routine called |primitive|, which will be defined later. Let us
5011 enter them now, so that we don't have to list all those names again
5012 anywhere else.
5013
5014 @<Put each of \MP's primitives into the hash table@>=
5015 mp_primitive(mp, "tracingtitles",internal_quantity,mp_tracing_titles);
5016 @:tracingtitles_}{\&{tracingtitles} primitive@>
5017 mp_primitive(mp, "tracingequations",internal_quantity,mp_tracing_equations);
5018 @:mp_tracing_equations_}{\&{tracingequations} primitive@>
5019 mp_primitive(mp, "tracingcapsules",internal_quantity,mp_tracing_capsules);
5020 @:mp_tracing_capsules_}{\&{tracingcapsules} primitive@>
5021 mp_primitive(mp, "tracingchoices",internal_quantity,mp_tracing_choices);
5022 @:mp_tracing_choices_}{\&{tracingchoices} primitive@>
5023 mp_primitive(mp, "tracingspecs",internal_quantity,mp_tracing_specs);
5024 @:mp_tracing_specs_}{\&{tracingspecs} primitive@>
5025 mp_primitive(mp, "tracingcommands",internal_quantity,mp_tracing_commands);
5026 @:mp_tracing_commands_}{\&{tracingcommands} primitive@>
5027 mp_primitive(mp, "tracingrestores",internal_quantity,mp_tracing_restores);
5028 @:mp_tracing_restores_}{\&{tracingrestores} primitive@>
5029 mp_primitive(mp, "tracingmacros",internal_quantity,mp_tracing_macros);
5030 @:mp_tracing_macros_}{\&{tracingmacros} primitive@>
5031 mp_primitive(mp, "tracingoutput",internal_quantity,mp_tracing_output);
5032 @:mp_tracing_output_}{\&{tracingoutput} primitive@>
5033 mp_primitive(mp, "tracingstats",internal_quantity,mp_tracing_stats);
5034 @:mp_tracing_stats_}{\&{tracingstats} primitive@>
5035 mp_primitive(mp, "tracinglostchars",internal_quantity,mp_tracing_lost_chars);
5036 @:mp_tracing_lost_chars_}{\&{tracinglostchars} primitive@>
5037 mp_primitive(mp, "tracingonline",internal_quantity,mp_tracing_online);
5038 @:mp_tracing_online_}{\&{tracingonline} primitive@>
5039 mp_primitive(mp, "year",internal_quantity,mp_year);
5040 @:mp_year_}{\&{year} primitive@>
5041 mp_primitive(mp, "month",internal_quantity,mp_month);
5042 @:mp_month_}{\&{month} primitive@>
5043 mp_primitive(mp, "day",internal_quantity,mp_day);
5044 @:mp_day_}{\&{day} primitive@>
5045 mp_primitive(mp, "time",internal_quantity,mp_time);
5046 @:time_}{\&{time} primitive@>
5047 mp_primitive(mp, "charcode",internal_quantity,mp_char_code);
5048 @:mp_char_code_}{\&{charcode} primitive@>
5049 mp_primitive(mp, "charext",internal_quantity,mp_char_ext);
5050 @:mp_char_ext_}{\&{charext} primitive@>
5051 mp_primitive(mp, "charwd",internal_quantity,mp_char_wd);
5052 @:mp_char_wd_}{\&{charwd} primitive@>
5053 mp_primitive(mp, "charht",internal_quantity,mp_char_ht);
5054 @:mp_char_ht_}{\&{charht} primitive@>
5055 mp_primitive(mp, "chardp",internal_quantity,mp_char_dp);
5056 @:mp_char_dp_}{\&{chardp} primitive@>
5057 mp_primitive(mp, "charic",internal_quantity,mp_char_ic);
5058 @:mp_char_ic_}{\&{charic} primitive@>
5059 mp_primitive(mp, "designsize",internal_quantity,mp_design_size);
5060 @:mp_design_size_}{\&{designsize} primitive@>
5061 mp_primitive(mp, "pausing",internal_quantity,mp_pausing);
5062 @:mp_pausing_}{\&{pausing} primitive@>
5063 mp_primitive(mp, "showstopping",internal_quantity,mp_showstopping);
5064 @:mp_showstopping_}{\&{showstopping} primitive@>
5065 mp_primitive(mp, "fontmaking",internal_quantity,mp_fontmaking);
5066 @:mp_fontmaking_}{\&{fontmaking} primitive@>
5067 mp_primitive(mp, "linejoin",internal_quantity,mp_linejoin);
5068 @:mp_linejoin_}{\&{linejoin} primitive@>
5069 mp_primitive(mp, "linecap",internal_quantity,mp_linecap);
5070 @:mp_linecap_}{\&{linecap} primitive@>
5071 mp_primitive(mp, "miterlimit",internal_quantity,mp_miterlimit);
5072 @:mp_miterlimit_}{\&{miterlimit} primitive@>
5073 mp_primitive(mp, "warningcheck",internal_quantity,mp_warning_check);
5074 @:mp_warning_check_}{\&{warningcheck} primitive@>
5075 mp_primitive(mp, "boundarychar",internal_quantity,mp_boundary_char);
5076 @:mp_boundary_char_}{\&{boundarychar} primitive@>
5077 mp_primitive(mp, "prologues",internal_quantity,mp_prologues);
5078 @:mp_prologues_}{\&{prologues} primitive@>
5079 mp_primitive(mp, "truecorners",internal_quantity,mp_true_corners);
5080 @:mp_true_corners_}{\&{truecorners} primitive@>
5081 mp_primitive(mp, "mpprocset",internal_quantity,mp_procset);
5082 @:mp_procset_}{\&{mpprocset} primitive@>
5083 mp_primitive(mp, "troffmode",internal_quantity,mp_gtroffmode);
5084 @:troffmode_}{\&{troffmode} primitive@>
5085 mp_primitive(mp, "defaultcolormodel",internal_quantity,mp_default_color_model);
5086 @:mp_default_color_model_}{\&{defaultcolormodel} primitive@>
5087 mp_primitive(mp, "restoreclipcolor",internal_quantity,mp_restore_clip_color);
5088 @:mp_restore_clip_color_}{\&{restoreclipcolor} primitive@>
5089
5090 @ Colors can be specified in four color models. In the special
5091 case of |no_model|, MetaPost does not output any color operator to
5092 the postscript output.
5093
5094 Note: these values are passed directly on to |with_option|. This only
5095 works because the other possible values passed to |with_option| are
5096 8 and 10 respectively (from |with_pen| and |with_picture|).
5097
5098 There is a first state, that is only used for |gs_colormodel|. It flags
5099 the fact that there has not been any kind of color specification by
5100 the user so far in the game.
5101
5102 @<Types...@>=
5103 enum mp_color_model {
5104   mp_no_model=1,
5105   mp_grey_model=3,
5106   mp_rgb_model=5,
5107   mp_cmyk_model=7,
5108   mp_uninitialized_model=9,
5109 };
5110
5111
5112 @ @<Initialize table entries (done by \.{INIMP} only)@>=
5113 mp->internal[mp_default_color_model]=(mp_rgb_model*unity);
5114 mp->internal[mp_restore_clip_color]=unity;
5115
5116 @ Well, we do have to list the names one more time, for use in symbolic
5117 printouts.
5118
5119 @<Initialize table...@>=
5120 mp->int_name[mp_tracing_titles]=xstrdup("tracingtitles");
5121 mp->int_name[mp_tracing_equations]=xstrdup("tracingequations");
5122 mp->int_name[mp_tracing_capsules]=xstrdup("tracingcapsules");
5123 mp->int_name[mp_tracing_choices]=xstrdup("tracingchoices");
5124 mp->int_name[mp_tracing_specs]=xstrdup("tracingspecs");
5125 mp->int_name[mp_tracing_commands]=xstrdup("tracingcommands");
5126 mp->int_name[mp_tracing_restores]=xstrdup("tracingrestores");
5127 mp->int_name[mp_tracing_macros]=xstrdup("tracingmacros");
5128 mp->int_name[mp_tracing_output]=xstrdup("tracingoutput");
5129 mp->int_name[mp_tracing_stats]=xstrdup("tracingstats");
5130 mp->int_name[mp_tracing_lost_chars]=xstrdup("tracinglostchars");
5131 mp->int_name[mp_tracing_online]=xstrdup("tracingonline");
5132 mp->int_name[mp_year]=xstrdup("year");
5133 mp->int_name[mp_month]=xstrdup("month");
5134 mp->int_name[mp_day]=xstrdup("day");
5135 mp->int_name[mp_time]=xstrdup("time");
5136 mp->int_name[mp_char_code]=xstrdup("charcode");
5137 mp->int_name[mp_char_ext]=xstrdup("charext");
5138 mp->int_name[mp_char_wd]=xstrdup("charwd");
5139 mp->int_name[mp_char_ht]=xstrdup("charht");
5140 mp->int_name[mp_char_dp]=xstrdup("chardp");
5141 mp->int_name[mp_char_ic]=xstrdup("charic");
5142 mp->int_name[mp_design_size]=xstrdup("designsize");
5143 mp->int_name[mp_pausing]=xstrdup("pausing");
5144 mp->int_name[mp_showstopping]=xstrdup("showstopping");
5145 mp->int_name[mp_fontmaking]=xstrdup("fontmaking");
5146 mp->int_name[mp_linejoin]=xstrdup("linejoin");
5147 mp->int_name[mp_linecap]=xstrdup("linecap");
5148 mp->int_name[mp_miterlimit]=xstrdup("miterlimit");
5149 mp->int_name[mp_warning_check]=xstrdup("warningcheck");
5150 mp->int_name[mp_boundary_char]=xstrdup("boundarychar");
5151 mp->int_name[mp_prologues]=xstrdup("prologues");
5152 mp->int_name[mp_true_corners]=xstrdup("truecorners");
5153 mp->int_name[mp_default_color_model]=xstrdup("defaultcolormodel");
5154 mp->int_name[mp_procset]=xstrdup("mpprocset");
5155 mp->int_name[mp_gtroffmode]=xstrdup("troffmode");
5156 mp->int_name[mp_restore_clip_color]=xstrdup("restoreclipcolor");
5157
5158 @ The following procedure, which is called just before \MP\ initializes its
5159 input and output, establishes the initial values of the date and time.
5160 @^system dependencies@>
5161
5162 Note that the values are |scaled| integers. Hence \MP\ can no longer
5163 be used after the year 32767.
5164
5165 @c 
5166 void mp_fix_date_and_time (MP mp) { 
5167   time_t clock = time ((time_t *) 0);
5168   struct tm *tmptr = localtime (&clock);
5169   mp->internal[mp_time]=
5170       (tmptr->tm_hour*60+tmptr->tm_min)*unity; /* minutes since midnight */
5171   mp->internal[mp_day]=(tmptr->tm_mday)*unity; /* fourth day of the month */
5172   mp->internal[mp_month]=(tmptr->tm_mon+1)*unity; /* seventh month of the year */
5173   mp->internal[mp_year]=(tmptr->tm_year+1900)*unity; /* Anno Domini */
5174 }
5175
5176 @ @<Declarations@>=
5177 void mp_fix_date_and_time (MP mp) ;
5178
5179 @ \MP\ is occasionally supposed to print diagnostic information that
5180 goes only into the transcript file, unless |mp_tracing_online| is positive.
5181 Now that we have defined |mp_tracing_online| we can define
5182 two routines that adjust the destination of print commands:
5183
5184 @<Declarations@>=
5185 void mp_begin_diagnostic (MP mp) ;
5186 void mp_end_diagnostic (MP mp,boolean blank_line);
5187 void mp_print_diagnostic (MP mp, char *s, char *t, boolean nuline) ;
5188
5189 @ @<Basic printing...@>=
5190 @<Declare a function called |true_line|@>;
5191 void mp_begin_diagnostic (MP mp) { /* prepare to do some tracing */
5192   mp->old_setting=mp->selector;
5193   if ((mp->internal[mp_tracing_online]<=0)&&(mp->selector==term_and_log)){ 
5194     decr(mp->selector);
5195     if ( mp->history==mp_spotless ) mp->history=mp_warning_issued;
5196   }
5197 }
5198 @#
5199 void mp_end_diagnostic (MP mp,boolean blank_line) {
5200   /* restore proper conditions after tracing */
5201   mp_print_nl(mp, "");
5202   if ( blank_line ) mp_print_ln(mp);
5203   mp->selector=mp->old_setting;
5204 }
5205
5206
5207
5208 @<Glob...@>=
5209 unsigned int old_setting;
5210
5211 @ We will occasionally use |begin_diagnostic| in connection with line-number
5212 printing, as follows. (The parameter |s| is typically |"Path"| or
5213 |"Cycle spec"|, etc.)
5214
5215 @<Basic printing...@>=
5216 void mp_print_diagnostic (MP mp, char *s, char *t, boolean nuline) { 
5217   mp_begin_diagnostic(mp);
5218   if ( nuline ) mp_print_nl(mp, s); else mp_print(mp, s);
5219   mp_print(mp, " at line "); 
5220   mp_print_int(mp, mp_true_line(mp));
5221   mp_print(mp, t); mp_print_char(mp, ':');
5222 }
5223
5224 @ The 256 |ASCII_code| characters are grouped into classes by means of
5225 the |char_class| table. Individual class numbers have no semantic
5226 or syntactic significance, except in a few instances defined here.
5227 There's also |max_class|, which can be used as a basis for additional
5228 class numbers in nonstandard extensions of \MP.
5229
5230 @d digit_class 0 /* the class number of \.{0123456789} */
5231 @d period_class 1 /* the class number of `\..' */
5232 @d space_class 2 /* the class number of spaces and nonstandard characters */
5233 @d percent_class 3 /* the class number of `\.\%' */
5234 @d string_class 4 /* the class number of `\."' */
5235 @d right_paren_class 8 /* the class number of `\.)' */
5236 @d isolated_classes 5: case 6: case 7: case 8 /* characters that make length-one tokens only */
5237 @d letter_class 9 /* letters and the underline character */
5238 @d left_bracket_class 17 /* `\.[' */
5239 @d right_bracket_class 18 /* `\.]' */
5240 @d invalid_class 20 /* bad character in the input */
5241 @d max_class 20 /* the largest class number */
5242
5243 @<Glob...@>=
5244 int char_class[256]; /* the class numbers */
5245
5246 @ If changes are made to accommodate non-ASCII character sets, they should
5247 follow the guidelines in Appendix~C of {\sl The {\logos METAFONT\/}book}.
5248 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
5249 @^system dependencies@>
5250
5251 @<Set initial ...@>=
5252 for (k='0';k<='9';k++) 
5253   mp->char_class[k]=digit_class;
5254 mp->char_class['.']=period_class;
5255 mp->char_class[' ']=space_class;
5256 mp->char_class['%']=percent_class;
5257 mp->char_class['"']=string_class;
5258 mp->char_class[',']=5;
5259 mp->char_class[';']=6;
5260 mp->char_class['(']=7;
5261 mp->char_class[')']=right_paren_class;
5262 for (k='A';k<= 'Z';k++ )
5263   mp->char_class[k]=letter_class;
5264 for (k='a';k<='z';k++) 
5265   mp->char_class[k]=letter_class;
5266 mp->char_class['_']=letter_class;
5267 mp->char_class['<']=10;
5268 mp->char_class['=']=10;
5269 mp->char_class['>']=10;
5270 mp->char_class[':']=10;
5271 mp->char_class['|']=10;
5272 mp->char_class['`']=11;
5273 mp->char_class['\'']=11;
5274 mp->char_class['+']=12;
5275 mp->char_class['-']=12;
5276 mp->char_class['/']=13;
5277 mp->char_class['*']=13;
5278 mp->char_class['\\']=13;
5279 mp->char_class['!']=14;
5280 mp->char_class['?']=14;
5281 mp->char_class['#']=15;
5282 mp->char_class['&']=15;
5283 mp->char_class['@@']=15;
5284 mp->char_class['$']=15;
5285 mp->char_class['^']=16;
5286 mp->char_class['~']=16;
5287 mp->char_class['[']=left_bracket_class;
5288 mp->char_class[']']=right_bracket_class;
5289 mp->char_class['{']=19;
5290 mp->char_class['}']=19;
5291 for (k=0;k<' ';k++)
5292   mp->char_class[k]=invalid_class;
5293 mp->char_class['\t']=space_class;
5294 mp->char_class['\f']=space_class;
5295 for (k=127;k<=255;k++)
5296   mp->char_class[k]=invalid_class;
5297
5298 @* \[13] The hash table.
5299 Symbolic tokens are stored and retrieved by means of a fairly standard hash
5300 table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
5301 in {\sl The Art of Computer Programming\/}). Once a symbolic token enters the
5302 table, it is never removed.
5303
5304 The actual sequence of characters forming a symbolic token is
5305 stored in the |str_pool| array together with all the other strings. An
5306 auxiliary array |hash| consists of items with two halfword fields per
5307 word. The first of these, called |next(p)|, points to the next identifier
5308 belonging to the same coalesced list as the identifier corresponding to~|p|;
5309 and the other, called |text(p)|, points to the |str_start| entry for
5310 |p|'s identifier. If position~|p| of the hash table is empty, we have
5311 |text(p)=0|; if position |p| is either empty or the end of a coalesced
5312 hash list, we have |next(p)=0|.
5313
5314 An auxiliary pointer variable called |hash_used| is maintained in such a
5315 way that all locations |p>=hash_used| are nonempty. The global variable
5316 |st_count| tells how many symbolic tokens have been defined, if statistics
5317 are being kept.
5318
5319 The first 256 locations of |hash| are reserved for symbols of length one.
5320
5321 There's a parallel array called |eqtb| that contains the current equivalent
5322 values of each symbolic token. The entries of this array consist of
5323 two halfwords called |eq_type| (a command code) and |equiv| (a secondary
5324 piece of information that qualifies the |eq_type|).
5325
5326 @d next(A)   mp->hash[(A)].lh /* link for coalesced lists */
5327 @d text(A)   mp->hash[(A)].rh /* string number for symbolic token name */
5328 @d eq_type(A)   mp->eqtb[(A)].lh /* the current ``meaning'' of a symbolic token */
5329 @d equiv(A)   mp->eqtb[(A)].rh /* parametric part of a token's meaning */
5330 @d hash_base 257 /* hashing actually starts here */
5331 @d hash_is_full   (mp->hash_used==hash_base) /* are all positions occupied? */
5332
5333 @<Glob...@>=
5334 pointer hash_used; /* allocation pointer for |hash| */
5335 integer st_count; /* total number of known identifiers */
5336
5337 @ Certain entries in the hash table are ``frozen'' and not redefinable,
5338 since they are used in error recovery.
5339
5340 @d hash_top (hash_base+mp->hash_size) /* the first location of the frozen area */
5341 @d frozen_inaccessible hash_top /* |hash| location to protect the frozen area */
5342 @d frozen_repeat_loop (hash_top+1) /* |hash| location of a loop-repeat token */
5343 @d frozen_right_delimiter (hash_top+2) /* |hash| location of a permanent `\.)' */
5344 @d frozen_left_bracket (hash_top+3) /* |hash| location of a permanent `\.[' */
5345 @d frozen_slash (hash_top+4) /* |hash| location of a permanent `\./' */
5346 @d frozen_colon (hash_top+5) /* |hash| location of a permanent `\.:' */
5347 @d frozen_semicolon (hash_top+6) /* |hash| location of a permanent `\.;' */
5348 @d frozen_end_for (hash_top+7) /* |hash| location of a permanent \&{endfor} */
5349 @d frozen_end_def (hash_top+8) /* |hash| location of a permanent \&{enddef} */
5350 @d frozen_fi (hash_top+9) /* |hash| location of a permanent \&{fi} */
5351 @d frozen_end_group (hash_top+10) /* |hash| location of a permanent `\.{endgroup}' */
5352 @d frozen_etex (hash_top+11) /* |hash| location of a permanent \&{etex} */
5353 @d frozen_mpx_break (hash_top+12) /* |hash| location of a permanent \&{mpxbreak} */
5354 @d frozen_bad_vardef (hash_top+13) /* |hash| location of `\.{a bad variable}' */
5355 @d frozen_undefined (hash_top+14) /* |hash| location that never gets defined */
5356 @d hash_end (hash_top+14) /* the actual size of the |hash| and |eqtb| arrays */
5357
5358 @<Glob...@>=
5359 two_halves *hash; /* the hash table */
5360 two_halves *eqtb; /* the equivalents */
5361
5362 @ @<Allocate or initialize ...@>=
5363 mp->hash = xmalloc((hash_end+1),sizeof(two_halves));
5364 mp->eqtb = xmalloc((hash_end+1),sizeof(two_halves));
5365
5366 @ @<Dealloc variables@>=
5367 xfree(mp->hash);
5368 xfree(mp->eqtb);
5369
5370 @ @<Set init...@>=
5371 next(1)=0; text(1)=0; eq_type(1)=tag_token; equiv(1)=null;
5372 for (k=2;k<=hash_end;k++)  { 
5373   mp->hash[k]=mp->hash[1]; mp->eqtb[k]=mp->eqtb[1];
5374 }
5375
5376 @ @<Initialize table entries...@>=
5377 mp->hash_used=frozen_inaccessible; /* nothing is used */
5378 mp->st_count=0;
5379 text(frozen_bad_vardef)=intern("a bad variable");
5380 text(frozen_etex)=intern("etex");
5381 text(frozen_mpx_break)=intern("mpxbreak");
5382 text(frozen_fi)=intern("fi");
5383 text(frozen_end_group)=intern("endgroup");
5384 text(frozen_end_def)=intern("enddef");
5385 text(frozen_end_for)=intern("endfor");
5386 text(frozen_semicolon)=intern(";");
5387 text(frozen_colon)=intern(":");
5388 text(frozen_slash)=intern("/");
5389 text(frozen_left_bracket)=intern("[");
5390 text(frozen_right_delimiter)=intern(")");
5391 text(frozen_inaccessible)=intern(" INACCESSIBLE");
5392 eq_type(frozen_right_delimiter)=right_delimiter;
5393
5394 @ @<Check the ``constant'' values...@>=
5395 if ( hash_end+mp->max_internal>max_halfword ) mp->bad=17;
5396
5397 @ Here is the subroutine that searches the hash table for an identifier
5398 that matches a given string of length~|l| appearing in |buffer[j..
5399 (j+l-1)]|. If the identifier is not found, it is inserted; hence it
5400 will always be found, and the corresponding hash table address
5401 will be returned.
5402
5403 @c 
5404 pointer mp_id_lookup (MP mp,integer j, integer l) { /* search the hash table */
5405   integer h; /* hash code */
5406   pointer p; /* index in |hash| array */
5407   pointer k; /* index in |buffer| array */
5408   if (l==1) {
5409     @<Treat special case of length 1 and |break|@>;
5410   }
5411   @<Compute the hash code |h|@>;
5412   p=h+hash_base; /* we start searching here; note that |0<=h<hash_prime| */
5413   while (true)  { 
5414         if (text(p)>0 && length(text(p))==l && mp_str_eq_buf(mp, text(p),j)) 
5415       break;
5416     if ( next(p)==0 ) {
5417       @<Insert a new symbolic token after |p|, then
5418         make |p| point to it and |break|@>;
5419     }
5420     p=next(p);
5421   }
5422   return p;
5423 };
5424
5425 @ @<Treat special case of length 1...@>=
5426  p=mp->buffer[j]+1; text(p)=p-1; return p;
5427
5428
5429 @ @<Insert a new symbolic...@>=
5430 {
5431 if ( text(p)>0 ) { 
5432   do {  
5433     if ( hash_is_full )
5434       mp_overflow(mp, "hash size",mp->hash_size);
5435 @:MetaPost capacity exceeded hash size}{\quad hash size@>
5436     decr(mp->hash_used);
5437   } while (text(mp->hash_used)!=0); /* search for an empty location in |hash| */
5438   next(p)=mp->hash_used; 
5439   p=mp->hash_used;
5440 }
5441 str_room(l);
5442 for (k=j;k<=j+l-1;k++) {
5443   append_char(mp->buffer[k]);
5444 }
5445 text(p)=mp_make_string(mp); 
5446 mp->str_ref[text(p)]=max_str_ref;
5447 incr(mp->st_count);
5448 break;
5449 }
5450
5451
5452 @ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
5453 should be a prime number.  The theory of hashing tells us to expect fewer
5454 than two table probes, on the average, when the search is successful.
5455 [See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
5456 @^Vitter, Jeffrey Scott@>
5457
5458 @<Compute the hash code |h|@>=
5459 h=mp->buffer[j];
5460 for (k=j+1;k<=j+l-1;k++){ 
5461   h=h+h+mp->buffer[k];
5462   while ( h>=mp->hash_prime ) h=h-mp->hash_prime;
5463 }
5464
5465 @ @<Search |eqtb| for equivalents equal to |p|@>=
5466 for (q=1;q<=hash_end;q++) { 
5467   if ( equiv(q)==p ) { 
5468     mp_print_nl(mp, "EQUIV("); 
5469     mp_print_int(mp, q); 
5470     mp_print_char(mp, ')');
5471   }
5472 }
5473
5474 @ We need to put \MP's ``primitive'' symbolic tokens into the hash
5475 table, together with their command code (which will be the |eq_type|)
5476 and an operand (which will be the |equiv|). The |primitive| procedure
5477 does this, in a way that no \MP\ user can. The global value |cur_sym|
5478 contains the new |eqtb| pointer after |primitive| has acted.
5479
5480 @c 
5481 void mp_primitive (MP mp, char *ss, halfword c, halfword o) {
5482   pool_pointer k; /* index into |str_pool| */
5483   small_number j; /* index into |buffer| */
5484   small_number l; /* length of the string */
5485   str_number s;
5486   s = intern(ss);
5487   k=mp->str_start[s]; l=str_stop(s)-k;
5488   /* we will move |s| into the (empty) |buffer| */
5489   for (j=0;j<=l-1;j++) {
5490     mp->buffer[j]=mp->str_pool[k+j];
5491   }
5492   mp->cur_sym=mp_id_lookup(mp, 0,l);
5493   if ( s>=256 ) { /* we don't want to have the string twice */
5494     mp_flush_string(mp, text(mp->cur_sym)); text(mp->cur_sym)=s;
5495   };
5496   eq_type(mp->cur_sym)=c; 
5497   equiv(mp->cur_sym)=o;
5498 }
5499
5500
5501 @ Many of \MP's primitives need no |equiv|, since they are identifiable
5502 by their |eq_type| alone. These primitives are loaded into the hash table
5503 as follows:
5504
5505 @<Put each of \MP's primitives into the hash table@>=
5506 mp_primitive(mp, "..",path_join,0);
5507 @:.._}{\.{..} primitive@>
5508 mp_primitive(mp, "[",left_bracket,0); mp->eqtb[frozen_left_bracket]=mp->eqtb[mp->cur_sym];
5509 @:[ }{\.{[} primitive@>
5510 mp_primitive(mp, "]",right_bracket,0);
5511 @:] }{\.{]} primitive@>
5512 mp_primitive(mp, "}",right_brace,0);
5513 @:]]}{\.{\char`\}} primitive@>
5514 mp_primitive(mp, "{",left_brace,0);
5515 @:][}{\.{\char`\{} primitive@>
5516 mp_primitive(mp, ":",colon,0); mp->eqtb[frozen_colon]=mp->eqtb[mp->cur_sym];
5517 @:: }{\.{:} primitive@>
5518 mp_primitive(mp, "::",double_colon,0);
5519 @::: }{\.{::} primitive@>
5520 mp_primitive(mp, "||:",bchar_label,0);
5521 @:::: }{\.{\char'174\char'174:} primitive@>
5522 mp_primitive(mp, ":=",assignment,0);
5523 @::=_}{\.{:=} primitive@>
5524 mp_primitive(mp, ",",comma,0);
5525 @:, }{\., primitive@>
5526 mp_primitive(mp, ";",semicolon,0); mp->eqtb[frozen_semicolon]=mp->eqtb[mp->cur_sym];
5527 @:; }{\.; primitive@>
5528 mp_primitive(mp, "\\",relax,0);
5529 @:]]\\}{\.{\char`\\} primitive@>
5530 @#
5531 mp_primitive(mp, "addto",add_to_command,0);
5532 @:add_to_}{\&{addto} primitive@>
5533 mp_primitive(mp, "atleast",at_least,0);
5534 @:at_least_}{\&{atleast} primitive@>
5535 mp_primitive(mp, "begingroup",begin_group,0); mp->bg_loc=mp->cur_sym;
5536 @:begin_group_}{\&{begingroup} primitive@>
5537 mp_primitive(mp, "controls",controls,0);
5538 @:controls_}{\&{controls} primitive@>
5539 mp_primitive(mp, "curl",curl_command,0);
5540 @:curl_}{\&{curl} primitive@>
5541 mp_primitive(mp, "delimiters",delimiters,0);
5542 @:delimiters_}{\&{delimiters} primitive@>
5543 mp_primitive(mp, "endgroup",end_group,0);
5544  mp->eqtb[frozen_end_group]=mp->eqtb[mp->cur_sym]; mp->eg_loc=mp->cur_sym;
5545 @:endgroup_}{\&{endgroup} primitive@>
5546 mp_primitive(mp, "everyjob",every_job_command,0);
5547 @:every_job_}{\&{everyjob} primitive@>
5548 mp_primitive(mp, "exitif",exit_test,0);
5549 @:exit_if_}{\&{exitif} primitive@>
5550 mp_primitive(mp, "expandafter",expand_after,0);
5551 @:expand_after_}{\&{expandafter} primitive@>
5552 mp_primitive(mp, "interim",interim_command,0);
5553 @:interim_}{\&{interim} primitive@>
5554 mp_primitive(mp, "let",let_command,0);
5555 @:let_}{\&{let} primitive@>
5556 mp_primitive(mp, "newinternal",new_internal,0);
5557 @:new_internal_}{\&{newinternal} primitive@>
5558 mp_primitive(mp, "of",of_token,0);
5559 @:of_}{\&{of} primitive@>
5560 mp_primitive(mp, "randomseed",mp_random_seed,0);
5561 @:mp_random_seed_}{\&{randomseed} primitive@>
5562 mp_primitive(mp, "save",save_command,0);
5563 @:save_}{\&{save} primitive@>
5564 mp_primitive(mp, "scantokens",scan_tokens,0);
5565 @:scan_tokens_}{\&{scantokens} primitive@>
5566 mp_primitive(mp, "shipout",ship_out_command,0);
5567 @:ship_out_}{\&{shipout} primitive@>
5568 mp_primitive(mp, "skipto",skip_to,0);
5569 @:skip_to_}{\&{skipto} primitive@>
5570 mp_primitive(mp, "special",special_command,0);
5571 @:special}{\&{special} primitive@>
5572 mp_primitive(mp, "fontmapfile",special_command,1);
5573 @:fontmapfile}{\&{fontmapfile} primitive@>
5574 mp_primitive(mp, "fontmapline",special_command,2);
5575 @:fontmapline}{\&{fontmapline} primitive@>
5576 mp_primitive(mp, "step",step_token,0);
5577 @:step_}{\&{step} primitive@>
5578 mp_primitive(mp, "str",str_op,0);
5579 @:str_}{\&{str} primitive@>
5580 mp_primitive(mp, "tension",tension,0);
5581 @:tension_}{\&{tension} primitive@>
5582 mp_primitive(mp, "to",to_token,0);
5583 @:to_}{\&{to} primitive@>
5584 mp_primitive(mp, "until",until_token,0);
5585 @:until_}{\&{until} primitive@>
5586 mp_primitive(mp, "within",within_token,0);
5587 @:within_}{\&{within} primitive@>
5588 mp_primitive(mp, "write",write_command,0);
5589 @:write_}{\&{write} primitive@>
5590
5591 @ Each primitive has a corresponding inverse, so that it is possible to
5592 display the cryptic numeric contents of |eqtb| in symbolic form.
5593 Every call of |primitive| in this program is therefore accompanied by some
5594 straightforward code that forms part of the |print_cmd_mod| routine
5595 explained below.
5596
5597 @<Cases of |print_cmd_mod| for symbolic printing of primitives@>=
5598 case add_to_command:mp_print(mp, "addto"); break;
5599 case assignment:mp_print(mp, ":="); break;
5600 case at_least:mp_print(mp, "atleast"); break;
5601 case bchar_label:mp_print(mp, "||:"); break;
5602 case begin_group:mp_print(mp, "begingroup"); break;
5603 case colon:mp_print(mp, ":"); break;
5604 case comma:mp_print(mp, ","); break;
5605 case controls:mp_print(mp, "controls"); break;
5606 case curl_command:mp_print(mp, "curl"); break;
5607 case delimiters:mp_print(mp, "delimiters"); break;
5608 case double_colon:mp_print(mp, "::"); break;
5609 case end_group:mp_print(mp, "endgroup"); break;
5610 case every_job_command:mp_print(mp, "everyjob"); break;
5611 case exit_test:mp_print(mp, "exitif"); break;
5612 case expand_after:mp_print(mp, "expandafter"); break;
5613 case interim_command:mp_print(mp, "interim"); break;
5614 case left_brace:mp_print(mp, "{"); break;
5615 case left_bracket:mp_print(mp, "["); break;
5616 case let_command:mp_print(mp, "let"); break;
5617 case new_internal:mp_print(mp, "newinternal"); break;
5618 case of_token:mp_print(mp, "of"); break;
5619 case path_join:mp_print(mp, ".."); break;
5620 case mp_random_seed:mp_print(mp, "randomseed"); break;
5621 case relax:mp_print_char(mp, '\\'); break;
5622 case right_brace:mp_print(mp, "}"); break;
5623 case right_bracket:mp_print(mp, "]"); break;
5624 case save_command:mp_print(mp, "save"); break;
5625 case scan_tokens:mp_print(mp, "scantokens"); break;
5626 case semicolon:mp_print(mp, ";"); break;
5627 case ship_out_command:mp_print(mp, "shipout"); break;
5628 case skip_to:mp_print(mp, "skipto"); break;
5629 case special_command: if ( m==2 ) mp_print(mp, "fontmapline"); else
5630                  if ( m==1 ) mp_print(mp, "fontmapfile"); else
5631                  mp_print(mp, "special"); break;
5632 case step_token:mp_print(mp, "step"); break;
5633 case str_op:mp_print(mp, "str"); break;
5634 case tension:mp_print(mp, "tension"); break;
5635 case to_token:mp_print(mp, "to"); break;
5636 case until_token:mp_print(mp, "until"); break;
5637 case within_token:mp_print(mp, "within"); break;
5638 case write_command:mp_print(mp, "write"); break;
5639
5640 @ We will deal with the other primitives later, at some point in the program
5641 where their |eq_type| and |equiv| values are more meaningful.  For example,
5642 the primitives for macro definitions will be loaded when we consider the
5643 routines that define macros.
5644 It is easy to find where each particular
5645 primitive was treated by looking in the index at the end; for example, the
5646 section where |"def"| entered |eqtb| is listed under `\&{def} primitive'.
5647
5648 @* \[14] Token lists.
5649 A \MP\ token is either symbolic or numeric or a string, or it denotes
5650 a macro parameter or capsule; so there are five corresponding ways to encode it
5651 @^token@>
5652 internally: (1)~A symbolic token whose hash code is~|p|
5653 is represented by the number |p|, in the |info| field of a single-word
5654 node in~|mem|. (2)~A numeric token whose |scaled| value is~|v| is
5655 represented in a two-word node of~|mem|; the |type| field is |known|,
5656 the |name_type| field is |token|, and the |value| field holds~|v|.
5657 The fact that this token appears in a two-word node rather than a
5658 one-word node is, of course, clear from the node address.
5659 (3)~A string token is also represented in a two-word node; the |type|
5660 field is |mp_string_type|, the |name_type| field is |token|, and the
5661 |value| field holds the corresponding |str_number|.  (4)~Capsules have
5662 |name_type=capsule|, and their |type| and |value| fields represent
5663 arbitrary values (in ways to be explained later).  (5)~Macro parameters
5664 are like symbolic tokens in that they appear in |info| fields of
5665 one-word nodes. The $k$th parameter is represented by |expr_base+k| if it
5666 is of type \&{expr}, or by |suffix_base+k| if it is of type \&{suffix}, or
5667 by |text_base+k| if it is of type \&{text}.  (Here |0<=k<param_size|.)
5668 Actual values of these parameters are kept in a separate stack, as we will
5669 see later.  The constants |expr_base|, |suffix_base|, and |text_base| are,
5670 of course, chosen so that there will be no confusion between symbolic
5671 tokens and parameters of various types.
5672
5673 Note that
5674 the `\\{type}' field of a node has nothing to do with ``type'' in a
5675 printer's sense. It's curious that the same word is used in such different ways.
5676
5677 @d type(A)   mp->mem[(A)].hh.b0 /* identifies what kind of value this is */
5678 @d name_type(A)   mp->mem[(A)].hh.b1 /* a clue to the name of this value */
5679 @d token_node_size 2 /* the number of words in a large token node */
5680 @d value_loc(A) ((A)+1) /* the word that contains the |value| field */
5681 @d value(A) mp->mem[value_loc((A))].cint /* the value stored in a large token node */
5682 @d expr_base (hash_end+1) /* code for the zeroth \&{expr} parameter */
5683 @d suffix_base (expr_base+mp->param_size) /* code for the zeroth \&{suffix} parameter */
5684 @d text_base (suffix_base+mp->param_size) /* code for the zeroth \&{text} parameter */
5685
5686 @<Check the ``constant''...@>=
5687 if ( text_base+mp->param_size>max_halfword ) mp->bad=18;
5688
5689 @ We have set aside a two word node beginning at |null| so that we can have
5690 |value(null)=0|.  We will make use of this coincidence later.
5691
5692 @<Initialize table entries...@>=
5693 link(null)=null; value(null)=0;
5694
5695 @ A numeric token is created by the following trivial routine.
5696
5697 @c 
5698 pointer mp_new_num_tok (MP mp,scaled v) {
5699   pointer p; /* the new node */
5700   p=mp_get_node(mp, token_node_size); value(p)=v;
5701   type(p)=mp_known; name_type(p)=mp_token; 
5702   return p;
5703 }
5704
5705 @ A token list is a singly linked list of nodes in |mem|, where
5706 each node contains a token and a link.  Here's a subroutine that gets rid
5707 of a token list when it is no longer needed.
5708
5709 @c void mp_flush_token_list (MP mp,pointer p) {
5710   pointer q; /* the node being recycled */
5711   while ( p!=null ) { 
5712     q=p; p=link(p);
5713     if ( q>=mp->hi_mem_min ) {
5714      free_avail(q);
5715     } else { 
5716       switch (type(q)) {
5717       case mp_vacuous: case mp_boolean_type: case mp_known:
5718         break;
5719       case mp_string_type:
5720         delete_str_ref(value(q));
5721         break;
5722       case unknown_types: case mp_pen_type: case mp_path_type: 
5723       case mp_picture_type: case mp_pair_type: case mp_color_type:
5724       case mp_cmykcolor_type: case mp_transform_type: case mp_dependent:
5725       case mp_proto_dependent: case mp_independent:
5726         mp_recycle_value(mp,q);
5727         break;
5728       default: mp_confusion(mp, "token");
5729 @:this can't happen token}{\quad token@>
5730       }
5731       mp_free_node(mp, q,token_node_size);
5732     }
5733   }
5734 }
5735
5736 @ The procedure |show_token_list|, which prints a symbolic form of
5737 the token list that starts at a given node |p|, illustrates these
5738 conventions. The token list being displayed should not begin with a reference
5739 count. However, the procedure is intended to be fairly robust, so that if the
5740 memory links are awry or if |p| is not really a pointer to a token list,
5741 almost nothing catastrophic can happen.
5742
5743 An additional parameter |q| is also given; this parameter is either null
5744 or it points to a node in the token list where a certain magic computation
5745 takes place that will be explained later. (Basically, |q| is non-null when
5746 we are printing the two-line context information at the time of an error
5747 message; |q| marks the place corresponding to where the second line
5748 should begin.)
5749
5750 The generation will stop, and `\.{\char`\ ETC.}' will be printed, if the length
5751 of printing exceeds a given limit~|l|; the length of printing upon entry is
5752 assumed to be a given amount called |null_tally|. (Note that
5753 |show_token_list| sometimes uses itself recursively to print
5754 variable names within a capsule.)
5755 @^recursion@>
5756
5757 Unusual entries are printed in the form of all-caps tokens
5758 preceded by a space, e.g., `\.{\char`\ BAD}'.
5759
5760 @<Declare the procedure called |show_token_list|@>=
5761 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5762                          integer null_tally) ;
5763
5764 @ @c
5765 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5766                          integer null_tally) {
5767   small_number class,c; /* the |char_class| of previous and new tokens */
5768   integer r,v; /* temporary registers */
5769   class=percent_class;
5770   mp->tally=null_tally;
5771   while ( (p!=null) && (mp->tally<l) ) { 
5772     if ( p==q ) 
5773       @<Do magic computation@>;
5774     @<Display token |p| and set |c| to its class;
5775       but |return| if there are problems@>;
5776     class=c; p=link(p);
5777   }
5778   if ( p!=null ) 
5779      mp_print(mp, " ETC.");
5780 @.ETC@>
5781   return;
5782 };
5783
5784 @ @<Display token |p| and set |c| to its class...@>=
5785 c=letter_class; /* the default */
5786 if ( (p<0)||(p>mp->mem_end) ) { 
5787   mp_print(mp, " CLOBBERED"); return;
5788 @.CLOBBERED@>
5789 }
5790 if ( p<mp->hi_mem_min ) { 
5791   @<Display two-word token@>;
5792 } else { 
5793   r=info(p);
5794   if ( r>=expr_base ) {
5795      @<Display a parameter token@>;
5796   } else {
5797     if ( r<1 ) {
5798       if ( r==0 ) { 
5799         @<Display a collective subscript@>
5800       } else {
5801         mp_print(mp, " IMPOSSIBLE");
5802 @.IMPOSSIBLE@>
5803       }
5804     } else { 
5805       r=text(r);
5806       if ( (r<0)||(r>mp->max_str_ptr) ) {
5807         mp_print(mp, " NONEXISTENT");
5808 @.NONEXISTENT@>
5809       } else {
5810        @<Print string |r| as a symbolic token
5811         and set |c| to its class@>;
5812       }
5813     }
5814   }
5815 }
5816
5817 @ @<Display two-word token@>=
5818 if ( name_type(p)==mp_token ) {
5819   if ( type(p)==mp_known ) {
5820     @<Display a numeric token@>;
5821   } else if ( type(p)!=mp_string_type ) {
5822     mp_print(mp, " BAD");
5823 @.BAD@>
5824   } else { 
5825     mp_print_char(mp, '"'); mp_print_str(mp, value(p)); mp_print_char(mp, '"');
5826     c=string_class;
5827   }
5828 } else if ((name_type(p)!=mp_capsule)||(type(p)<mp_vacuous)||(type(p)>mp_independent) ) {
5829   mp_print(mp, " BAD");
5830 } else { 
5831   mp_print_capsule(mp,p); c=right_paren_class;
5832 }
5833
5834 @ @<Display a numeric token@>=
5835 if ( class==digit_class ) 
5836   mp_print_char(mp, ' ');
5837 v=value(p);
5838 if ( v<0 ){ 
5839   if ( class==left_bracket_class ) 
5840     mp_print_char(mp, ' ');
5841   mp_print_char(mp, '['); mp_print_scaled(mp, v); mp_print_char(mp, ']');
5842   c=right_bracket_class;
5843 } else { 
5844   mp_print_scaled(mp, v); c=digit_class;
5845 }
5846
5847
5848 @ Strictly speaking, a genuine token will never have |info(p)=0|.
5849 But we will see later (in the |print_variable_name| routine) that
5850 it is convenient to let |info(p)=0| stand for `\.{[]}'.
5851
5852 @<Display a collective subscript@>=
5853 {
5854 if ( class==left_bracket_class ) 
5855   mp_print_char(mp, ' ');
5856 mp_print(mp, "[]"); c=right_bracket_class;
5857 }
5858
5859 @ @<Display a parameter token@>=
5860 {
5861 if ( r<suffix_base ) { 
5862   mp_print(mp, "(EXPR"); r=r-(expr_base);
5863 @.EXPR@>
5864 } else if ( r<text_base ) { 
5865   mp_print(mp, "(SUFFIX"); r=r-(suffix_base);
5866 @.SUFFIX@>
5867 } else { 
5868   mp_print(mp, "(TEXT"); r=r-(text_base);
5869 @.TEXT@>
5870 }
5871 mp_print_int(mp, r); mp_print_char(mp, ')'); c=right_paren_class;
5872 }
5873
5874
5875 @ @<Print string |r| as a symbolic token...@>=
5876
5877 c=mp->char_class[mp->str_pool[mp->str_start[r]]];
5878 if ( c==class ) {
5879   switch (c) {
5880   case letter_class:mp_print_char(mp, '.'); break;
5881   case isolated_classes: break;
5882   default: mp_print_char(mp, ' '); break;
5883   }
5884 }
5885 mp_print_str(mp, r);
5886 }
5887
5888 @ @<Declarations@>=
5889 void mp_print_capsule (MP mp, pointer p);
5890
5891 @ @<Declare miscellaneous procedures that were declared |forward|@>=
5892 void mp_print_capsule (MP mp, pointer p) { 
5893   mp_print_char(mp, '('); mp_print_exp(mp,p,0); mp_print_char(mp, ')');
5894 }
5895
5896 @ Macro definitions are kept in \MP's memory in the form of token lists
5897 that have a few extra one-word nodes at the beginning.
5898
5899 The first node contains a reference count that is used to tell when the
5900 list is no longer needed. To emphasize the fact that a reference count is
5901 present, we shall refer to the |info| field of this special node as the
5902 |ref_count| field.
5903 @^reference counts@>
5904
5905 The next node or nodes after the reference count serve to describe the
5906 formal parameters. They either contain a code word that specifies all
5907 of the parameters, or they contain zero or more parameter tokens followed
5908 by the code `|general_macro|'.
5909
5910 @d ref_count info
5911   /* reference count preceding a macro definition or picture header */
5912 @d add_mac_ref(A) incr(ref_count((A))) /* make a new reference to a macro list */
5913 @d general_macro 0 /* preface to a macro defined with a parameter list */
5914 @d primary_macro 1 /* preface to a macro with a \&{primary} parameter */
5915 @d secondary_macro 2 /* preface to a macro with a \&{secondary} parameter */
5916 @d tertiary_macro 3 /* preface to a macro with a \&{tertiary} parameter */
5917 @d expr_macro 4 /* preface to a macro with an undelimited \&{expr} parameter */
5918 @d of_macro 5 /* preface to a macro with
5919   undelimited `\&{expr} |x| \&{of}~|y|' parameters */
5920 @d suffix_macro 6 /* preface to a macro with an undelimited \&{suffix} parameter */
5921 @d text_macro 7 /* preface to a macro with an undelimited \&{text} parameter */
5922
5923 @c 
5924 void mp_delete_mac_ref (MP mp,pointer p) {
5925   /* |p| points to the reference count of a macro list that is
5926     losing one reference */
5927   if ( ref_count(p)==null ) mp_flush_token_list(mp, p);
5928   else decr(ref_count(p));
5929 }
5930
5931 @ The following subroutine displays a macro, given a pointer to its
5932 reference count.
5933
5934 @c 
5935 @<Declare the procedure called |print_cmd_mod|@>;
5936 void mp_show_macro (MP mp, pointer p, integer q, integer l) {
5937   pointer r; /* temporary storage */
5938   p=link(p); /* bypass the reference count */
5939   while ( info(p)>text_macro ){ 
5940     r=link(p); link(p)=null;
5941     mp_show_token_list(mp, p,null,l,0); link(p)=r; p=r;
5942     if ( l>0 ) l=l-mp->tally; else return;
5943   } /* control printing of `\.{ETC.}' */
5944 @.ETC@>
5945   mp->tally=0;
5946   switch(info(p)) {
5947   case general_macro:mp_print(mp, "->"); break;
5948 @.->@>
5949   case primary_macro: case secondary_macro: case tertiary_macro:
5950     mp_print_char(mp, '<');
5951     mp_print_cmd_mod(mp, param_type,info(p)); 
5952     mp_print(mp, ">->");
5953     break;
5954   case expr_macro:mp_print(mp, "<expr>->"); break;
5955   case of_macro:mp_print(mp, "<expr>of<primary>->"); break;
5956   case suffix_macro:mp_print(mp, "<suffix>->"); break;
5957   case text_macro:mp_print(mp, "<text>->"); break;
5958   } /* there are no other cases */
5959   mp_show_token_list(mp, link(p),q,l-mp->tally,0);
5960 }
5961
5962 @* \[15] Data structures for variables.
5963 The variables of \MP\ programs can be simple, like `\.x', or they can
5964 combine the structural properties of arrays and records, like `\.{x20a.b}'.
5965 A \MP\ user assigns a type to a variable like \.{x20a.b} by saying, for
5966 example, `\.{boolean} \.{x20a.b}'. It's time for us to study how such
5967 things are represented inside of the computer.
5968
5969 Each variable value occupies two consecutive words, either in a two-word
5970 node called a value node, or as a two-word subfield of a larger node.  One
5971 of those two words is called the |value| field; it is an integer,
5972 containing either a |scaled| numeric value or the representation of some
5973 other type of quantity. (It might also be subdivided into halfwords, in
5974 which case it is referred to by other names instead of |value|.) The other
5975 word is broken into subfields called |type|, |name_type|, and |link|.  The
5976 |type| field is a quarterword that specifies the variable's type, and
5977 |name_type| is a quarterword from which \MP\ can reconstruct the
5978 variable's name (sometimes by using the |link| field as well).  Thus, only
5979 1.25 words are actually devoted to the value itself; the other
5980 three-quarters of a word are overhead, but they aren't wasted because they
5981 allow \MP\ to deal with sparse arrays and to provide meaningful diagnostics.
5982
5983 In this section we shall be concerned only with the structural aspects of
5984 variables, not their values. Later parts of the program will change the
5985 |type| and |value| fields, but we shall treat those fields as black boxes
5986 whose contents should not be touched.
5987
5988 However, if the |type| field is |mp_structured|, there is no |value| field,
5989 and the second word is broken into two pointer fields called |attr_head|
5990 and |subscr_head|. Those fields point to additional nodes that
5991 contain structural information, as we shall see.
5992
5993 @d subscr_head_loc(A)   (A)+1 /* where |value|, |subscr_head| and |attr_head| are */
5994 @d attr_head(A)   info(subscr_head_loc((A))) /* pointer to attribute info */
5995 @d subscr_head(A)   link(subscr_head_loc((A))) /* pointer to subscript info */
5996 @d value_node_size 2 /* the number of words in a value node */
5997
5998 @ An attribute node is three words long. Two of these words contain |type|
5999 and |value| fields as described above, and the third word contains
6000 additional information:  There is an |attr_loc| field, which contains the
6001 hash address of the token that names this attribute; and there's also a
6002 |parent| field, which points to the value node of |mp_structured| type at the
6003 next higher level (i.e., at the level to which this attribute is
6004 subsidiary).  The |name_type| in an attribute node is `|attr|'.  The
6005 |link| field points to the next attribute with the same parent; these are
6006 arranged in increasing order, so that |attr_loc(link(p))>attr_loc(p)|. The
6007 final attribute node links to the constant |end_attr|, whose |attr_loc|
6008 field is greater than any legal hash address. The |attr_head| in the
6009 parent points to a node whose |name_type| is |mp_structured_root|; this
6010 node represents the null attribute, i.e., the variable that is relevant
6011 when no attributes are attached to the parent. The |attr_head| node is either
6012 a value node, a subscript node, or an attribute node, depending on what
6013 the parent would be if it were not structured; but the subscript and
6014 attribute fields are ignored, so it effectively contains only the data of
6015 a value node. The |link| field in this special node points to an attribute
6016 node whose |attr_loc| field is zero; the latter node represents a collective
6017 subscript `\.{[]}' attached to the parent, and its |link| field points to
6018 the first non-special attribute node (or to |end_attr| if there are none).
6019
6020 A subscript node likewise occupies three words, with |type| and |value| fields
6021 plus extra information; its |name_type| is |subscr|. In this case the
6022 third word is called the |subscript| field, which is a |scaled| integer.
6023 The |link| field points to the subscript node with the next larger
6024 subscript, if any; otherwise the |link| points to the attribute node
6025 for collective subscripts at this level. We have seen that the latter node
6026 contains an upward pointer, so that the parent can be deduced.
6027
6028 The |name_type| in a parent-less value node is |root|, and the |link|
6029 is the hash address of the token that names this value.
6030
6031 In other words, variables have a hierarchical structure that includes
6032 enough threads running around so that the program is able to move easily
6033 between siblings, parents, and children. An example should be helpful:
6034 (The reader is advised to draw a picture while reading the following
6035 description, since that will help to firm up the ideas.)
6036 Suppose that `\.x' and `\.{x.a}' and `\.{x[]b}' and `\.{x5}'
6037 and `\.{x20b}' have been mentioned in a user's program, where
6038 \.{x[]b} has been declared to be of \&{boolean} type. Let |h(x)|, |h(a)|,
6039 and |h(b)| be the hash addresses of \.x, \.a, and~\.b. Then
6040 |eq_type(h(x))=name| and |equiv(h(x))=p|, where |p|~is a two-word value
6041 node with |name_type(p)=root| and |link(p)=h(x)|. We have |type(p)=mp_structured|,
6042 |attr_head(p)=q|, and |subscr_head(p)=r|, where |q| points to a value
6043 node and |r| to a subscript node. (Are you still following this? Use
6044 a pencil to draw a diagram.) The lone variable `\.x' is represented by
6045 |type(q)| and |value(q)|; furthermore
6046 |name_type(q)=mp_structured_root| and |link(q)=q1|, where |q1| points
6047 to an attribute node representing `\.{x[]}'. Thus |name_type(q1)=attr|,
6048 |attr_loc(q1)=collective_subscript=0|, |parent(q1)=p|,
6049 |type(q1)=mp_structured|, |attr_head(q1)=qq|, and |subscr_head(q1)=qq1|;
6050 |qq| is a value node with |type(qq)=mp_numeric_type| (assuming that \.{x5} is
6051 numeric, because |qq| represents `\.{x[]}' with no further attributes),
6052 |name_type(qq)=mp_structured_root|, and
6053 |link(qq)=qq1|. (Now pay attention to the next part.) Node |qq1| is
6054 an attribute node representing `\.{x[][]}', which has never yet
6055 occurred; its |type| field is |undefined|, and its |value| field is
6056 undefined. We have |name_type(qq1)=attr|, |attr_loc(qq1)=collective_subscript|,
6057 |parent(qq1)=q1|, and |link(qq1)=qq2|. Since |qq2| represents
6058 `\.{x[]b}', |type(qq2)=mp_unknown_boolean|; also |attr_loc(qq2)=h(b)|,
6059 |parent(qq2)=q1|, |name_type(qq2)=attr|, |link(qq2)=end_attr|.
6060 (Maybe colored lines will help untangle your picture.)
6061  Node |r| is a subscript node with |type| and |value|
6062 representing `\.{x5}'; |name_type(r)=subscr|, |subscript(r)=5.0|,
6063 and |link(r)=r1| is another subscript node. To complete the picture,
6064 see if you can guess what |link(r1)| is; give up? It's~|q1|.
6065 Furthermore |subscript(r1)=20.0|, |name_type(r1)=subscr|,
6066 |type(r1)=mp_structured|, |attr_head(r1)=qqq|, |subscr_head(r1)=qqq1|,
6067 and we finish things off with three more nodes
6068 |qqq|, |qqq1|, and |qqq2| hung onto~|r1|. (Perhaps you should start again
6069 with a larger sheet of paper.) The value of variable \.{x20b}
6070 appears in node~|qqq2|, as you can well imagine.
6071
6072 If the example in the previous paragraph doesn't make things crystal
6073 clear, a glance at some of the simpler subroutines below will reveal how
6074 things work out in practice.
6075
6076 The only really unusual thing about these conventions is the use of
6077 collective subscript attributes. The idea is to avoid repeating a lot of
6078 type information when many elements of an array are identical macros
6079 (for which distinct values need not be stored) or when they don't have
6080 all of the possible attributes. Branches of the structure below collective
6081 subscript attributes do not carry actual values except for macro identifiers;
6082 branches of the structure below subscript nodes do not carry significant
6083 information in their collective subscript attributes.
6084
6085 @d attr_loc_loc(A) ((A)+2) /* where the |attr_loc| and |parent| fields are */
6086 @d attr_loc(A) info(attr_loc_loc((A))) /* hash address of this attribute */
6087 @d parent(A) link(attr_loc_loc((A))) /* pointer to |mp_structured| variable */
6088 @d subscript_loc(A) ((A)+2) /* where the |subscript| field lives */
6089 @d subscript(A) mp->mem[subscript_loc((A))].sc /* subscript of this variable */
6090 @d attr_node_size 3 /* the number of words in an attribute node */
6091 @d subscr_node_size 3 /* the number of words in a subscript node */
6092 @d collective_subscript 0 /* code for the attribute `\.{[]}' */
6093
6094 @<Initialize table...@>=
6095 attr_loc(end_attr)=hash_end+1; parent(end_attr)=null;
6096
6097 @ Variables of type \&{pair} will have values that point to four-word
6098 nodes containing two numeric values. The first of these values has
6099 |name_type=mp_x_part_sector| and the second has |name_type=mp_y_part_sector|;
6100 the |link| in the first points back to the node whose |value| points
6101 to this four-word node.
6102
6103 Variables of type \&{transform} are similar, but in this case their
6104 |value| points to a 12-word node containing six values, identified by
6105 |x_part_sector|, |y_part_sector|, |mp_xx_part_sector|, |mp_xy_part_sector|,
6106 |mp_yx_part_sector|, and |mp_yy_part_sector|.
6107 Finally, variables of type \&{color} have 3~values in 6~words
6108 identified by |mp_red_part_sector|, |mp_green_part_sector|, and |mp_blue_part_sector|.
6109
6110 When an entire structured variable is saved, the |root| indication
6111 is temporarily replaced by |saved_root|.
6112
6113 Some variables have no name; they just are used for temporary storage
6114 while expressions are being evaluated. We call them {\sl capsules}.
6115
6116 @d x_part_loc(A) (A) /* where the \&{xpart} is found in a pair or transform node */
6117 @d y_part_loc(A) ((A)+2) /* where the \&{ypart} is found in a pair or transform node */
6118 @d xx_part_loc(A) ((A)+4) /* where the \&{xxpart} is found in a transform node */
6119 @d xy_part_loc(A) ((A)+6) /* where the \&{xypart} is found in a transform node */
6120 @d yx_part_loc(A) ((A)+8) /* where the \&{yxpart} is found in a transform node */
6121 @d yy_part_loc(A) ((A)+10) /* where the \&{yypart} is found in a transform node */
6122 @d red_part_loc(A) (A) /* where the \&{redpart} is found in a color node */
6123 @d green_part_loc(A) ((A)+2) /* where the \&{greenpart} is found in a color node */
6124 @d blue_part_loc(A) ((A)+4) /* where the \&{bluepart} is found in a color node */
6125 @d cyan_part_loc(A) (A) /* where the \&{cyanpart} is found in a color node */
6126 @d magenta_part_loc(A) ((A)+2) /* where the \&{magentapart} is found in a color node */
6127 @d yellow_part_loc(A) ((A)+4) /* where the \&{yellowpart} is found in a color node */
6128 @d black_part_loc(A) ((A)+6) /* where the \&{blackpart} is found in a color node */
6129 @d grey_part_loc(A) (A) /* where the \&{greypart} is found in a color node */
6130 @#
6131 @d pair_node_size 4 /* the number of words in a pair node */
6132 @d transform_node_size 12 /* the number of words in a transform node */
6133 @d color_node_size 6 /* the number of words in a color node */
6134 @d cmykcolor_node_size 8 /* the number of words in a color node */
6135
6136 @<Glob...@>=
6137 small_number big_node_size[mp_pair_type+1];
6138 small_number sector0[mp_pair_type+1];
6139 small_number sector_offset[mp_black_part_sector+1];
6140
6141 @ The |sector0| array gives for each big node type, |name_type| values
6142 for its first subfield; the |sector_offset| array gives for each
6143 |name_type| value, the offset from the first subfield in words;
6144 and the |big_node_size| array gives the size in words for each type of
6145 big node.
6146
6147 @<Set init...@>=
6148 mp->big_node_size[mp_transform_type]=transform_node_size;
6149 mp->big_node_size[mp_pair_type]=pair_node_size;
6150 mp->big_node_size[mp_color_type]=color_node_size;
6151 mp->big_node_size[mp_cmykcolor_type]=cmykcolor_node_size;
6152 mp->sector0[mp_transform_type]=mp_x_part_sector;
6153 mp->sector0[mp_pair_type]=mp_x_part_sector;
6154 mp->sector0[mp_color_type]=mp_red_part_sector;
6155 mp->sector0[mp_cmykcolor_type]=mp_cyan_part_sector;
6156 for (k=mp_x_part_sector;k<= mp_yy_part_sector;k++ ) {
6157   mp->sector_offset[k]=2*(k-mp_x_part_sector);
6158 }
6159 for (k=mp_red_part_sector;k<= mp_blue_part_sector ; k++) {
6160   mp->sector_offset[k]=2*(k-mp_red_part_sector);
6161 }
6162 for (k=mp_cyan_part_sector;k<= mp_black_part_sector;k++ ) {
6163   mp->sector_offset[k]=2*(k-mp_cyan_part_sector);
6164 }
6165
6166 @ If |type(p)=mp_pair_type| or |mp_transform_type| and if |value(p)=null|, the
6167 procedure call |init_big_node(p)| will allocate a pair or transform node
6168 for~|p|.  The individual parts of such nodes are initially of type
6169 |mp_independent|.
6170
6171 @c 
6172 void mp_init_big_node (MP mp,pointer p) {
6173   pointer q; /* the new node */
6174   small_number s; /* its size */
6175   s=mp->big_node_size[type(p)]; q=mp_get_node(mp, s);
6176   do {  
6177     s=s-2; 
6178     @<Make variable |q+s| newly independent@>;
6179     name_type(q+s)=halfp(s)+mp->sector0[type(p)]; 
6180     link(q+s)=null;
6181   } while (s!=0);
6182   link(q)=p; value(p)=q;
6183 }
6184
6185 @ The |id_transform| function creates a capsule for the
6186 identity transformation.
6187
6188 @c 
6189 pointer mp_id_transform (MP mp) {
6190   pointer p,q,r; /* list manipulation registers */
6191   p=mp_get_node(mp, value_node_size); type(p)=mp_transform_type;
6192   name_type(p)=mp_capsule; value(p)=null; mp_init_big_node(mp, p); q=value(p);
6193   r=q+transform_node_size;
6194   do {  
6195     r=r-2;
6196     type(r)=mp_known; value(r)=0;
6197   } while (r!=q);
6198   value(xx_part_loc(q))=unity; 
6199   value(yy_part_loc(q))=unity;
6200   return p;
6201 }
6202
6203 @ Tokens are of type |tag_token| when they first appear, but they point
6204 to |null| until they are first used as the root of a variable.
6205 The following subroutine establishes the root node on such grand occasions.
6206
6207 @c 
6208 void mp_new_root (MP mp,pointer x) {
6209   pointer p; /* the new node */
6210   p=mp_get_node(mp, value_node_size); type(p)=undefined; name_type(p)=mp_root;
6211   link(p)=x; equiv(x)=p;
6212 }
6213
6214 @ These conventions for variable representation are illustrated by the
6215 |print_variable_name| routine, which displays the full name of a
6216 variable given only a pointer to its two-word value packet.
6217
6218 @<Declarations@>=
6219 void mp_print_variable_name (MP mp, pointer p);
6220
6221 @ @c 
6222 void mp_print_variable_name (MP mp, pointer p) {
6223   pointer q; /* a token list that will name the variable's suffix */
6224   pointer r; /* temporary for token list creation */
6225   while ( name_type(p)>=mp_x_part_sector ) {
6226     @<Preface the output with a part specifier; |return| in the
6227       case of a capsule@>;
6228   }
6229   q=null;
6230   while ( name_type(p)>mp_saved_root ) {
6231     @<Ascend one level, pushing a token onto list |q|
6232      and replacing |p| by its parent@>;
6233   }
6234   r=mp_get_avail(mp); info(r)=link(p); link(r)=q;
6235   if ( name_type(p)==mp_saved_root ) mp_print(mp, "(SAVED)");
6236 @.SAVED@>
6237   mp_show_token_list(mp, r,null,el_gordo,mp->tally); 
6238   mp_flush_token_list(mp, r);
6239 }
6240
6241 @ @<Ascend one level, pushing a token onto list |q|...@>=
6242
6243   if ( name_type(p)==mp_subscr ) { 
6244     r=mp_new_num_tok(mp, subscript(p));
6245     do {  
6246       p=link(p);
6247     } while (name_type(p)!=mp_attr);
6248   } else if ( name_type(p)==mp_structured_root ) {
6249     p=link(p); goto FOUND;
6250   } else { 
6251     if ( name_type(p)!=mp_attr ) mp_confusion(mp, "var");
6252 @:this can't happen var}{\quad var@>
6253     r=mp_get_avail(mp); info(r)=attr_loc(p);
6254   }
6255   link(r)=q; q=r;
6256 FOUND:  
6257   p=parent(p);
6258 }
6259
6260 @ @<Preface the output with a part specifier...@>=
6261 { switch (name_type(p)) {
6262   case mp_x_part_sector: mp_print_char(mp, 'x'); break;
6263   case mp_y_part_sector: mp_print_char(mp, 'y'); break;
6264   case mp_xx_part_sector: mp_print(mp, "xx"); break;
6265   case mp_xy_part_sector: mp_print(mp, "xy"); break;
6266   case mp_yx_part_sector: mp_print(mp, "yx"); break;
6267   case mp_yy_part_sector: mp_print(mp, "yy"); break;
6268   case mp_red_part_sector: mp_print(mp, "red"); break;
6269   case mp_green_part_sector: mp_print(mp, "green"); break;
6270   case mp_blue_part_sector: mp_print(mp, "blue"); break;
6271   case mp_cyan_part_sector: mp_print(mp, "cyan"); break;
6272   case mp_magenta_part_sector: mp_print(mp, "magenta"); break;
6273   case mp_yellow_part_sector: mp_print(mp, "yellow"); break;
6274   case mp_black_part_sector: mp_print(mp, "black"); break;
6275   case mp_grey_part_sector: mp_print(mp, "grey"); break;
6276   case mp_capsule: 
6277     mp_print(mp, "%CAPSULE"); mp_print_int(mp, p-null); return;
6278     break;
6279 @.CAPSULE@>
6280   } /* there are no other cases */
6281   mp_print(mp, "part "); 
6282   p=link(p-mp->sector_offset[name_type(p)]);
6283 }
6284
6285 @ The |interesting| function returns |true| if a given variable is not
6286 in a capsule, or if the user wants to trace capsules.
6287
6288 @c 
6289 boolean mp_interesting (MP mp,pointer p) {
6290   small_number t; /* a |name_type| */
6291   if ( mp->internal[mp_tracing_capsules]>0 ) {
6292     return true;
6293   } else { 
6294     t=name_type(p);
6295     if ( t>=mp_x_part_sector ) if ( t!=mp_capsule )
6296       t=name_type(link(p-mp->sector_offset[t]));
6297     return (t!=mp_capsule);
6298   }
6299 }
6300
6301 @ Now here is a subroutine that converts an unstructured type into an
6302 equivalent structured type, by inserting a |mp_structured| node that is
6303 capable of growing. This operation is done only when |name_type(p)=root|,
6304 |subscr|, or |attr|.
6305
6306 The procedure returns a pointer to the new node that has taken node~|p|'s
6307 place in the structure. Node~|p| itself does not move, nor are its
6308 |value| or |type| fields changed in any way.
6309
6310 @c 
6311 pointer mp_new_structure (MP mp,pointer p) {
6312   pointer q,r=0; /* list manipulation registers */
6313   switch (name_type(p)) {
6314   case mp_root: 
6315     q=link(p); r=mp_get_node(mp, value_node_size); equiv(q)=r;
6316     break;
6317   case mp_subscr: 
6318     @<Link a new subscript node |r| in place of node |p|@>;
6319     break;
6320   case mp_attr: 
6321     @<Link a new attribute node |r| in place of node |p|@>;
6322     break;
6323   default: 
6324     mp_confusion(mp, "struct");
6325 @:this can't happen struct}{\quad struct@>
6326     break;
6327   }
6328   link(r)=link(p); type(r)=mp_structured; name_type(r)=name_type(p);
6329   attr_head(r)=p; name_type(p)=mp_structured_root;
6330   q=mp_get_node(mp, attr_node_size); link(p)=q; subscr_head(r)=q;
6331   parent(q)=r; type(q)=undefined; name_type(q)=mp_attr; link(q)=end_attr;
6332   attr_loc(q)=collective_subscript; 
6333   return r;
6334 };
6335
6336 @ @<Link a new subscript node |r| in place of node |p|@>=
6337
6338   q=p;
6339   do {  
6340     q=link(q);
6341   } while (name_type(q)!=mp_attr);
6342   q=parent(q); r=subscr_head_loc(q); /* |link(r)=subscr_head(q)| */
6343   do {  
6344     q=r; r=link(r);
6345   } while (r!=p);
6346   r=mp_get_node(mp, subscr_node_size);
6347   link(q)=r; subscript(r)=subscript(p);
6348 }
6349
6350 @ If the attribute is |collective_subscript|, there are two pointers to
6351 node~|p|, so we must change both of them.
6352
6353 @<Link a new attribute node |r| in place of node |p|@>=
6354
6355   q=parent(p); r=attr_head(q);
6356   do {  
6357     q=r; r=link(r);
6358   } while (r!=p);
6359   r=mp_get_node(mp, attr_node_size); link(q)=r;
6360   mp->mem[attr_loc_loc(r)]=mp->mem[attr_loc_loc(p)]; /* copy |attr_loc| and |parent| */
6361   if ( attr_loc(p)==collective_subscript ) { 
6362     q=subscr_head_loc(parent(p));
6363     while ( link(q)!=p ) q=link(q);
6364     link(q)=r;
6365   }
6366 }
6367
6368 @ The |find_variable| routine is given a pointer~|t| to a nonempty token
6369 list of suffixes; it returns a pointer to the corresponding two-word
6370 value. For example, if |t| points to token \.x followed by a numeric
6371 token containing the value~7, |find_variable| finds where the value of
6372 \.{x7} is stored in memory. This may seem a simple task, and it
6373 usually is, except when \.{x7} has never been referenced before.
6374 Indeed, \.x may never have even been subscripted before; complexities
6375 arise with respect to updating the collective subscript information.
6376
6377 If a macro type is detected anywhere along path~|t|, or if the first
6378 item on |t| isn't a |tag_token|, the value |null| is returned.
6379 Otherwise |p| will be a non-null pointer to a node such that
6380 |undefined<type(p)<mp_structured|.
6381
6382 @d abort_find { return null; }
6383
6384 @c 
6385 pointer mp_find_variable (MP mp,pointer t) {
6386   pointer p,q,r,s; /* nodes in the ``value'' line */
6387   pointer pp,qq,rr,ss; /* nodes in the ``collective'' line */
6388   integer n; /* subscript or attribute */
6389   memory_word save_word; /* temporary storage for a word of |mem| */
6390 @^inner loop@>
6391   p=info(t); t=link(t);
6392   if ( (eq_type(p) % outer_tag) != tag_token ) abort_find;
6393   if ( equiv(p)==null ) mp_new_root(mp, p);
6394   p=equiv(p); pp=p;
6395   while ( t!=null ) { 
6396     @<Make sure that both nodes |p| and |pp| are of |mp_structured| type@>;
6397     if ( t<mp->hi_mem_min ) {
6398       @<Descend one level for the subscript |value(t)|@>
6399     } else {
6400       @<Descend one level for the attribute |info(t)|@>;
6401     }
6402     t=link(t);
6403   }
6404   if ( type(pp)>=mp_structured ) {
6405     if ( type(pp)==mp_structured ) pp=attr_head(pp); else abort_find;
6406   }
6407   if ( type(p)==mp_structured ) p=attr_head(p);
6408   if ( type(p)==undefined ) { 
6409     if ( type(pp)==undefined ) { type(pp)=mp_numeric_type; value(pp)=null; };
6410     type(p)=type(pp); value(p)=null;
6411   };
6412   return p;
6413 }
6414
6415 @ Although |pp| and |p| begin together, they diverge when a subscript occurs;
6416 |pp|~stays in the collective line while |p|~goes through actual subscript
6417 values.
6418
6419 @<Make sure that both nodes |p| and |pp|...@>=
6420 if ( type(pp)!=mp_structured ) { 
6421   if ( type(pp)>mp_structured ) abort_find;
6422   ss=mp_new_structure(mp, pp);
6423   if ( p==pp ) p=ss;
6424   pp=ss;
6425 }; /* now |type(pp)=mp_structured| */
6426 if ( type(p)!=mp_structured ) /* it cannot be |>mp_structured| */
6427   p=mp_new_structure(mp, p) /* now |type(p)=mp_structured| */
6428
6429 @ We want this part of the program to be reasonably fast, in case there are
6430 @^inner loop@>
6431 lots of subscripts at the same level of the data structure. Therefore
6432 we store an ``infinite'' value in the word that appears at the end of the
6433 subscript list, even though that word isn't part of a subscript node.
6434
6435 @<Descend one level for the subscript |value(t)|@>=
6436
6437   n=value(t);
6438   pp=link(attr_head(pp)); /* now |attr_loc(pp)=collective_subscript| */
6439   q=link(attr_head(p)); save_word=mp->mem[subscript_loc(q)];
6440   subscript(q)=el_gordo; s=subscr_head_loc(p); /* |link(s)=subscr_head(p)| */
6441   do {  
6442     r=s; s=link(s);
6443   } while (n>subscript(s));
6444   if ( n==subscript(s) ) {
6445     p=s;
6446   } else { 
6447     p=mp_get_node(mp, subscr_node_size); link(r)=p; link(p)=s;
6448     subscript(p)=n; name_type(p)=mp_subscr; type(p)=undefined;
6449   }
6450   mp->mem[subscript_loc(q)]=save_word;
6451 }
6452
6453 @ @<Descend one level for the attribute |info(t)|@>=
6454
6455   n=info(t);
6456   ss=attr_head(pp);
6457   do {  
6458     rr=ss; ss=link(ss);
6459   } while (n>attr_loc(ss));
6460   if ( n<attr_loc(ss) ) { 
6461     qq=mp_get_node(mp, attr_node_size); link(rr)=qq; link(qq)=ss;
6462     attr_loc(qq)=n; name_type(qq)=mp_attr; type(qq)=undefined;
6463     parent(qq)=pp; ss=qq;
6464   }
6465   if ( p==pp ) { 
6466     p=ss; pp=ss;
6467   } else { 
6468     pp=ss; s=attr_head(p);
6469     do {  
6470       r=s; s=link(s);
6471     } while (n>attr_loc(s));
6472     if ( n==attr_loc(s) ) {
6473       p=s;
6474     } else { 
6475       q=mp_get_node(mp, attr_node_size); link(r)=q; link(q)=s;
6476       attr_loc(q)=n; name_type(q)=mp_attr; type(q)=undefined;
6477       parent(q)=p; p=q;
6478     }
6479   }
6480 }
6481
6482 @ Variables lose their former values when they appear in a type declaration,
6483 or when they are defined to be macros or \&{let} equal to something else.
6484 A subroutine will be defined later that recycles the storage associated
6485 with any particular |type| or |value|; our goal now is to study a higher
6486 level process called |flush_variable|, which selectively frees parts of a
6487 variable structure.
6488
6489 This routine has some complexity because of examples such as
6490 `\hbox{\tt numeric x[]a[]b}'
6491 which recycles all variables of the form \.{x[i]a[j]b} (and no others), while
6492 `\hbox{\tt vardef x[]a[]=...}'
6493 discards all variables of the form \.{x[i]a[j]} followed by an arbitrary
6494 suffix, except for the collective node \.{x[]a[]} itself. The obvious way
6495 to handle such examples is to use recursion; so that's what we~do.
6496 @^recursion@>
6497
6498 Parameter |p| points to the root information of the variable;
6499 parameter |t| points to a list of one-word nodes that represent
6500 suffixes, with |info=collective_subscript| for subscripts.
6501
6502 @<Declarations@>=
6503 @<Declare subroutines for printing expressions@>
6504 @<Declare basic dependency-list subroutines@>
6505 @<Declare the recycling subroutines@>
6506 void mp_flush_cur_exp (MP mp,scaled v) ;
6507 @<Declare the procedure called |flush_below_variable|@>
6508
6509 @ @c 
6510 void mp_flush_variable (MP mp,pointer p, pointer t, boolean discard_suffixes) {
6511   pointer q,r; /* list manipulation */
6512   halfword n; /* attribute to match */
6513   while ( t!=null ) { 
6514     if ( type(p)!=mp_structured ) return;
6515     n=info(t); t=link(t);
6516     if ( n==collective_subscript ) { 
6517       r=subscr_head_loc(p); q=link(r); /* |q=subscr_head(p)| */
6518       while ( name_type(q)==mp_subscr ){ 
6519         mp_flush_variable(mp, q,t,discard_suffixes);
6520         if ( t==null ) {
6521           if ( type(q)==mp_structured ) r=q;
6522           else  { link(r)=link(q); mp_free_node(mp, q,subscr_node_size);   }
6523         } else {
6524           r=q;
6525         }
6526         q=link(r);
6527       }
6528     }
6529     p=attr_head(p);
6530     do {  
6531       r=p; p=link(p);
6532     } while (attr_loc(p)<n);
6533     if ( attr_loc(p)!=n ) return;
6534   }
6535   if ( discard_suffixes ) {
6536     mp_flush_below_variable(mp, p);
6537   } else { 
6538     if ( type(p)==mp_structured ) p=attr_head(p);
6539     mp_recycle_value(mp, p);
6540   }
6541 }
6542
6543 @ The next procedure is simpler; it wipes out everything but |p| itself,
6544 which becomes undefined.
6545
6546 @<Declare the procedure called |flush_below_variable|@>=
6547 void mp_flush_below_variable (MP mp, pointer p);
6548
6549 @ @c
6550 void mp_flush_below_variable (MP mp,pointer p) {
6551    pointer q,r; /* list manipulation registers */
6552   if ( type(p)!=mp_structured ) {
6553     mp_recycle_value(mp, p); /* this sets |type(p)=undefined| */
6554   } else { 
6555     q=subscr_head(p);
6556     while ( name_type(q)==mp_subscr ) { 
6557       mp_flush_below_variable(mp, q); r=q; q=link(q);
6558       mp_free_node(mp, r,subscr_node_size);
6559     }
6560     r=attr_head(p); q=link(r); mp_recycle_value(mp, r);
6561     if ( name_type(p)<=mp_saved_root ) mp_free_node(mp, r,value_node_size);
6562     else mp_free_node(mp, r,subscr_node_size);
6563     /* we assume that |subscr_node_size=attr_node_size| */
6564     do {  
6565       mp_flush_below_variable(mp, q); r=q; q=link(q); mp_free_node(mp, r,attr_node_size);
6566     } while (q!=end_attr);
6567     type(p)=undefined;
6568   }
6569 }
6570
6571 @ Just before assigning a new value to a variable, we will recycle the
6572 old value and make the old value undefined. The |und_type| routine
6573 determines what type of undefined value should be given, based on
6574 the current type before recycling.
6575
6576 @c 
6577 small_number mp_und_type (MP mp,pointer p) { 
6578   switch (type(p)) {
6579   case undefined: case mp_vacuous:
6580     return undefined;
6581   case mp_boolean_type: case mp_unknown_boolean:
6582     return mp_unknown_boolean;
6583   case mp_string_type: case mp_unknown_string:
6584     return mp_unknown_string;
6585   case mp_pen_type: case mp_unknown_pen:
6586     return mp_unknown_pen;
6587   case mp_path_type: case mp_unknown_path:
6588     return mp_unknown_path;
6589   case mp_picture_type: case mp_unknown_picture:
6590     return mp_unknown_picture;
6591   case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
6592   case mp_pair_type: case mp_numeric_type: 
6593     return type(p);
6594   case mp_known: case mp_dependent: case mp_proto_dependent: case mp_independent:
6595     return mp_numeric_type;
6596   } /* there are no other cases */
6597   return 0;
6598 }
6599
6600 @ The |clear_symbol| routine is used when we want to redefine the equivalent
6601 of a symbolic token. It must remove any variable structure or macro
6602 definition that is currently attached to that symbol. If the |saving|
6603 parameter is true, a subsidiary structure is saved instead of destroyed.
6604
6605 @c 
6606 void mp_clear_symbol (MP mp,pointer p, boolean saving) {
6607   pointer q; /* |equiv(p)| */
6608   q=equiv(p);
6609   switch (eq_type(p) % outer_tag)  {
6610   case defined_macro:
6611   case secondary_primary_macro:
6612   case tertiary_secondary_macro:
6613   case expression_tertiary_macro: 
6614     if ( ! saving ) mp_delete_mac_ref(mp, q);
6615     break;
6616   case tag_token:
6617     if ( q!=null ) {
6618       if ( saving ) {
6619         name_type(q)=mp_saved_root;
6620       } else { 
6621         mp_flush_below_variable(mp, q); mp_free_node(mp,q,value_node_size); 
6622       }
6623     }
6624     break;
6625   default:
6626     break;
6627   }
6628   mp->eqtb[p]=mp->eqtb[frozen_undefined];
6629 };
6630
6631 @* \[16] Saving and restoring equivalents.
6632 The nested structure given by \&{begingroup} and \&{endgroup}
6633 allows |eqtb| entries to be saved and restored, so that temporary changes
6634 can be made without difficulty.  When the user requests a current value to
6635 be saved, \MP\ puts that value into its ``save stack.'' An appearance of
6636 \&{endgroup} ultimately causes the old values to be removed from the save
6637 stack and put back in their former places.
6638
6639 The save stack is a linked list containing three kinds of entries,
6640 distinguished by their |info| fields. If |p| points to a saved item,
6641 then
6642
6643 \smallskip\hang
6644 |info(p)=0| stands for a group boundary; each \&{begingroup} contributes
6645 such an item to the save stack and each \&{endgroup} cuts back the stack
6646 until the most recent such entry has been removed.
6647
6648 \smallskip\hang
6649 |info(p)=q|, where |1<=q<=hash_end|, means that |mem[p+1]| holds the former
6650 contents of |eqtb[q]|. Such save stack entries are generated by \&{save}
6651 commands or suitable \&{interim} commands.
6652
6653 \smallskip\hang
6654 |info(p)=hash_end+q|, where |q>0|, means that |value(p)| is a |scaled|
6655 integer to be restored to internal parameter number~|q|. Such entries
6656 are generated by \&{interim} commands.
6657
6658 \smallskip\noindent
6659 The global variable |save_ptr| points to the top item on the save stack.
6660
6661 @d save_node_size 2 /* number of words per non-boundary save-stack node */
6662 @d saved_equiv(A) mp->mem[(A)+1].hh /* where an |eqtb| entry gets saved */
6663 @d save_boundary_item(A) { (A)=mp_get_avail(mp); info((A))=0;
6664   link((A))=mp->save_ptr; mp->save_ptr=(A);
6665   }
6666
6667 @<Glob...@>=
6668 pointer save_ptr; /* the most recently saved item */
6669
6670 @ @<Set init...@>=mp->save_ptr=null;
6671
6672 @ The |save_variable| routine is given a hash address |q|; it salts this
6673 address in the save stack, together with its current equivalent,
6674 then makes token~|q| behave as though it were brand new.
6675
6676 Nothing is stacked when |save_ptr=null|, however; there's no way to remove
6677 things from the stack when the program is not inside a group, so there's
6678 no point in wasting the space.
6679
6680 @c void mp_save_variable (MP mp,pointer q) {
6681   pointer p; /* temporary register */
6682   if ( mp->save_ptr!=null ){ 
6683     p=mp_get_node(mp, save_node_size); info(p)=q; link(p)=mp->save_ptr;
6684     saved_equiv(p)=mp->eqtb[q]; mp->save_ptr=p;
6685   }
6686   mp_clear_symbol(mp, q,(mp->save_ptr!=null));
6687 }
6688
6689 @ Similarly, |save_internal| is given the location |q| of an internal
6690 quantity like |mp_tracing_pens|. It creates a save stack entry of the
6691 third kind.
6692
6693 @c void mp_save_internal (MP mp,halfword q) {
6694   pointer p; /* new item for the save stack */
6695   if ( mp->save_ptr!=null ){ 
6696      p=mp_get_node(mp, save_node_size); info(p)=hash_end+q;
6697     link(p)=mp->save_ptr; value(p)=mp->internal[q]; mp->save_ptr=p;
6698   }
6699 }
6700
6701 @ At the end of a group, the |unsave| routine restores all of the saved
6702 equivalents in reverse order. This routine will be called only when there
6703 is at least one boundary item on the save stack.
6704
6705 @c 
6706 void mp_unsave (MP mp) {
6707   pointer q; /* index to saved item */
6708   pointer p; /* temporary register */
6709   while ( info(mp->save_ptr)!=0 ) {
6710     q=info(mp->save_ptr);
6711     if ( q>hash_end ) {
6712       if ( mp->internal[mp_tracing_restores]>0 ) {
6713         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6714         mp_print(mp, mp->int_name[q-(hash_end)]); mp_print_char(mp, '=');
6715         mp_print_scaled(mp, value(mp->save_ptr)); mp_print_char(mp, '}');
6716         mp_end_diagnostic(mp, false);
6717       }
6718       mp->internal[q-(hash_end)]=value(mp->save_ptr);
6719     } else { 
6720       if ( mp->internal[mp_tracing_restores]>0 ) {
6721         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6722         mp_print_text(q); mp_print_char(mp, '}');
6723         mp_end_diagnostic(mp, false);
6724       }
6725       mp_clear_symbol(mp, q,false);
6726       mp->eqtb[q]=saved_equiv(mp->save_ptr);
6727       if ( eq_type(q) % outer_tag==tag_token ) {
6728         p=equiv(q);
6729         if ( p!=null ) name_type(p)=mp_root;
6730       }
6731     }
6732     p=link(mp->save_ptr); 
6733     mp_free_node(mp, mp->save_ptr,save_node_size); mp->save_ptr=p;
6734   }
6735   p=link(mp->save_ptr); free_avail(mp->save_ptr); mp->save_ptr=p;
6736 }
6737
6738 @* \[17] Data structures for paths.
6739 When a \MP\ user specifies a path, \MP\ will create a list of knots
6740 and control points for the associated cubic spline curves. If the
6741 knots are $z_0$, $z_1$, \dots, $z_n$, there are control points
6742 $z_k^+$ and $z_{k+1}^-$ such that the cubic splines between knots
6743 $z_k$ and $z_{k+1}$ are defined by B\'ezier's formula
6744 @:Bezier}{B\'ezier, Pierre Etienne@>
6745 $$\eqalign{z(t)&=B(z_k,z_k^+,z_{k+1}^-,z_{k+1};t)\cr
6746 &=(1-t)^3z_k+3(1-t)^2tz_k^++3(1-t)t^2z_{k+1}^-+t^3z_{k+1}\cr}$$
6747 for |0<=t<=1|.
6748
6749 There is a 8-word node for each knot $z_k$, containing one word of
6750 control information and six words for the |x| and |y| coordinates of
6751 $z_k^-$ and $z_k$ and~$z_k^+$. The control information appears in the
6752 |left_type| and |right_type| fields, which each occupy a quarter of
6753 the first word in the node; they specify properties of the curve as it
6754 enters and leaves the knot. There's also a halfword |link| field,
6755 which points to the following knot, and a final supplementary word (of
6756 which only a quarter is used).
6757
6758 If the path is a closed contour, knots 0 and |n| are identical;
6759 i.e., the |link| in knot |n-1| points to knot~0. But if the path
6760 is not closed, the |left_type| of knot~0 and the |right_type| of knot~|n|
6761 are equal to |endpoint|. In the latter case the |link| in knot~|n| points
6762 to knot~0, and the control points $z_0^-$ and $z_n^+$ are not used.
6763
6764 @d left_type(A)   mp->mem[(A)].hh.b0 /* characterizes the path entering this knot */
6765 @d right_type(A)   mp->mem[(A)].hh.b1 /* characterizes the path leaving this knot */
6766 @d x_coord(A)   mp->mem[(A)+1].sc /* the |x| coordinate of this knot */
6767 @d y_coord(A)   mp->mem[(A)+2].sc /* the |y| coordinate of this knot */
6768 @d left_x(A)   mp->mem[(A)+3].sc /* the |x| coordinate of previous control point */
6769 @d left_y(A)   mp->mem[(A)+4].sc /* the |y| coordinate of previous control point */
6770 @d right_x(A)   mp->mem[(A)+5].sc /* the |x| coordinate of next control point */
6771 @d right_y(A)   mp->mem[(A)+6].sc /* the |y| coordinate of next control point */
6772 @d x_loc(A)   ((A)+1) /* where the |x| coordinate is stored in a knot */
6773 @d y_loc(A)   ((A)+2) /* where the |y| coordinate is stored in a knot */
6774 @d knot_coord(A)   mp->mem[(A)].sc /* |x| or |y| coordinate given |x_loc| or |y_loc| */
6775 @d left_coord(A)   mp->mem[(A)+2].sc
6776   /* coordinate of previous control point given |x_loc| or |y_loc| */
6777 @d right_coord(A)   mp->mem[(A)+4].sc
6778   /* coordinate of next control point given |x_loc| or |y_loc| */
6779 @d knot_node_size 8 /* number of words in a knot node */
6780
6781 @<Types...@>=
6782 enum mp_knot_type {
6783  mp_endpoint=0, /* |left_type| at path beginning and |right_type| at path end */
6784  mp_explicit, /* |left_type| or |right_type| when control points are known */
6785  mp_given, /* |left_type| or |right_type| when a direction is given */
6786  mp_curl, /* |left_type| or |right_type| when a curl is desired */
6787  mp_open, /* |left_type| or |right_type| when \MP\ should choose the direction */
6788  mp_end_cycle
6789 } ;
6790
6791 @ Before the B\'ezier control points have been calculated, the memory
6792 space they will ultimately occupy is taken up by information that can be
6793 used to compute them. There are four cases:
6794
6795 \yskip
6796 \textindent{$\bullet$} If |right_type=mp_open|, the curve should leave
6797 the knot in the same direction it entered; \MP\ will figure out a
6798 suitable direction.
6799
6800 \yskip
6801 \textindent{$\bullet$} If |right_type=mp_curl|, the curve should leave the
6802 knot in a direction depending on the angle at which it enters the next
6803 knot and on the curl parameter stored in |right_curl|.
6804
6805 \yskip
6806 \textindent{$\bullet$} If |right_type=mp_given|, the curve should leave the
6807 knot in a nonzero direction stored as an |angle| in |right_given|.
6808
6809 \yskip
6810 \textindent{$\bullet$} If |right_type=mp_explicit|, the B\'ezier control
6811 point for leaving this knot has already been computed; it is in the
6812 |right_x| and |right_y| fields.
6813
6814 \yskip\noindent
6815 The rules for |left_type| are similar, but they refer to the curve entering
6816 the knot, and to \\{left} fields instead of \\{right} fields.
6817
6818 Non-|explicit| control points will be chosen based on ``tension'' parameters
6819 in the |left_tension| and |right_tension| fields. The
6820 `\&{atleast}' option is represented by negative tension values.
6821 @:at_least_}{\&{atleast} primitive@>
6822
6823 For example, the \MP\ path specification
6824 $$\.{z0..z1..tension atleast 1..\{curl 2\}z2..z3\{-1,-2\}..tension
6825   3 and 4..p},$$
6826 where \.p is the path `\.{z4..controls z45 and z54..z5}', will be represented
6827 by the six knots
6828 \def\lodash{\hbox to 1.1em{\thinspace\hrulefill\thinspace}}
6829 $$\vbox{\halign{#\hfil&&\qquad#\hfil\cr
6830 |left_type|&\\{left} info&|x_coord,y_coord|&|right_type|&\\{right} info\cr
6831 \noalign{\yskip}
6832 |endpoint|&\lodash$,\,$\lodash&$x_0,y_0$&|curl|&$1.0,1.0$\cr
6833 |open|&\lodash$,1.0$&$x_1,y_1$&|open|&\lodash$,-1.0$\cr
6834 |curl|&$2.0,-1.0$&$x_2,y_2$&|curl|&$2.0,1.0$\cr
6835 |given|&$d,1.0$&$x_3,y_3$&|given|&$d,3.0$\cr
6836 |open|&\lodash$,4.0$&$x_4,y_4$&|explicit|&$x_{45},y_{45}$\cr
6837 |explicit|&$x_{54},y_{54}$&$x_5,y_5$&|endpoint|&\lodash$,\,$\lodash\cr}}$$
6838 Here |d| is the |angle| obtained by calling |n_arg(-unity,-two)|.
6839 Of course, this example is more complicated than anything a normal user
6840 would ever write.
6841
6842 These types must satisfy certain restrictions because of the form of \MP's
6843 path syntax:
6844 (i)~|open| type never appears in the same node together with |endpoint|,
6845 |given|, or |curl|.
6846 (ii)~The |right_type| of a node is |explicit| if and only if the
6847 |left_type| of the following node is |explicit|.
6848 (iii)~|endpoint| types occur only at the ends, as mentioned above.
6849
6850 @d left_curl left_x /* curl information when entering this knot */
6851 @d left_given left_x /* given direction when entering this knot */
6852 @d left_tension left_y /* tension information when entering this knot */
6853 @d right_curl right_x /* curl information when leaving this knot */
6854 @d right_given right_x /* given direction when leaving this knot */
6855 @d right_tension right_y /* tension information when leaving this knot */
6856
6857 @ Knots can be user-supplied, or they can be created by program code,
6858 like the |split_cubic| function, or |copy_path|. The distinction is
6859 needed for the cleanup routine that runs after |split_cubic|, because
6860 it should only delete knots it has previously inserted, and never
6861 anything that was user-supplied. In order to be able to differentiate
6862 one knot from another, we will set |originator(p):=mp_metapost_user| when
6863 it appeared in the actual metapost program, and
6864 |originator(p):=mp_program_code| in all other cases.
6865
6866 @d originator(A)   mp->mem[(A)+7].hh.b0 /* the creator of this knot */
6867
6868 @<Types...@>=
6869 enum {
6870   mp_program_code=0, /* not created by a user */
6871   mp_metapost_user, /* created by a user */
6872 };
6873
6874 @ Here is a routine that prints a given knot list
6875 in symbolic form. It illustrates the conventions discussed above,
6876 and checks for anomalies that might arise while \MP\ is being debugged.
6877
6878 @<Declare subroutines for printing expressions@>=
6879 void mp_pr_path (MP mp,pointer h);
6880
6881 @ @c
6882 void mp_pr_path (MP mp,pointer h) {
6883   pointer p,q; /* for list traversal */
6884   p=h;
6885   do {  
6886     q=link(p);
6887     if ( (p==null)||(q==null) ) { 
6888       mp_print_nl(mp, "???"); return; /* this won't happen */
6889 @.???@>
6890     }
6891     @<Print information for adjacent knots |p| and |q|@>;
6892   DONE1:
6893     p=q;
6894     if ( (p!=h)||(left_type(h)!=mp_endpoint) ) {
6895       @<Print two dots, followed by |given| or |curl| if present@>;
6896     }
6897   } while (p!=h);
6898   if ( left_type(h)!=mp_endpoint ) 
6899     mp_print(mp, "cycle");
6900 }
6901
6902 @ @<Print information for adjacent knots...@>=
6903 mp_print_two(mp, x_coord(p),y_coord(p));
6904 switch (right_type(p)) {
6905 case mp_endpoint: 
6906   if ( left_type(p)==mp_open ) mp_print(mp, "{open?}"); /* can't happen */
6907 @.open?@>
6908   if ( (left_type(q)!=mp_endpoint)||(q!=h) ) q=null; /* force an error */
6909   goto DONE1;
6910   break;
6911 case mp_explicit: 
6912   @<Print control points between |p| and |q|, then |goto done1|@>;
6913   break;
6914 case mp_open: 
6915   @<Print information for a curve that begins |open|@>;
6916   break;
6917 case mp_curl:
6918 case mp_given: 
6919   @<Print information for a curve that begins |curl| or |given|@>;
6920   break;
6921 default:
6922   mp_print(mp, "???"); /* can't happen */
6923 @.???@>
6924   break;
6925 }
6926 if ( left_type(q)<=mp_explicit ) {
6927   mp_print(mp, "..control?"); /* can't happen */
6928 @.control?@>
6929 } else if ( (right_tension(p)!=unity)||(left_tension(q)!=unity) ) {
6930   @<Print tension between |p| and |q|@>;
6931 }
6932
6933 @ Since |n_sin_cos| produces |fraction| results, which we will print as if they
6934 were |scaled|, the magnitude of a |given| direction vector will be~4096.
6935
6936 @<Print two dots...@>=
6937
6938   mp_print_nl(mp, " ..");
6939   if ( left_type(p)==mp_given ) { 
6940     mp_n_sin_cos(mp, left_given(p)); mp_print_char(mp, '{');
6941     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, ',');
6942     mp_print_scaled(mp, mp->n_sin); mp_print_char(mp, '}');
6943   } else if ( left_type(p)==mp_curl ){ 
6944     mp_print(mp, "{curl "); 
6945     mp_print_scaled(mp, left_curl(p)); mp_print_char(mp, '}');
6946   }
6947 }
6948
6949 @ @<Print tension between |p| and |q|@>=
6950
6951   mp_print(mp, "..tension ");
6952   if ( right_tension(p)<0 ) mp_print(mp, "atleast");
6953   mp_print_scaled(mp, abs(right_tension(p)));
6954   if ( right_tension(p)!=left_tension(q) ){ 
6955     mp_print(mp, " and ");
6956     if ( left_tension(q)<0 ) mp_print(mp, "atleast");
6957     mp_print_scaled(mp, abs(left_tension(q)));
6958   }
6959 }
6960
6961 @ @<Print control points between |p| and |q|, then |goto done1|@>=
6962
6963   mp_print(mp, "..controls "); 
6964   mp_print_two(mp, right_x(p),right_y(p)); 
6965   mp_print(mp, " and ");
6966   if ( left_type(q)!=mp_explicit ) { 
6967     mp_print(mp, "??"); /* can't happen */
6968 @.??@>
6969   } else {
6970     mp_print_two(mp, left_x(q),left_y(q));
6971   }
6972   goto DONE1;
6973 }
6974
6975 @ @<Print information for a curve that begins |open|@>=
6976 if ( (left_type(p)!=mp_explicit)&&(left_type(p)!=mp_open) ) {
6977   mp_print(mp, "{open?}"); /* can't happen */
6978 @.open?@>
6979 }
6980
6981 @ A curl of 1 is shown explicitly, so that the user sees clearly that
6982 \MP's default curl is present.
6983
6984 The code here uses the fact that |left_curl==left_given| and
6985 |right_curl==right_given|.
6986
6987 @<Print information for a curve that begins |curl|...@>=
6988
6989   if ( left_type(p)==mp_open )  
6990     mp_print(mp, "??"); /* can't happen */
6991 @.??@>
6992   if ( right_type(p)==mp_curl ) { 
6993     mp_print(mp, "{curl "); mp_print_scaled(mp, right_curl(p));
6994   } else { 
6995     mp_n_sin_cos(mp, right_given(p)); mp_print_char(mp, '{');
6996     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, ','); 
6997     mp_print_scaled(mp, mp->n_sin);
6998   }
6999   mp_print_char(mp, '}');
7000 }
7001
7002 @ It is convenient to have another version of |pr_path| that prints the path
7003 as a diagnostic message.
7004
7005 @<Declare subroutines for printing expressions@>=
7006 void mp_print_path (MP mp,pointer h, char *s, boolean nuline) { 
7007   mp_print_diagnostic(mp, "Path", s, nuline); mp_print_ln(mp);
7008 @.Path at line...@>
7009   mp_pr_path(mp, h);
7010   mp_end_diagnostic(mp, true);
7011 }
7012
7013 @ If we want to duplicate a knot node, we can say |copy_knot|:
7014
7015 @c 
7016 pointer mp_copy_knot (MP mp,pointer p) {
7017   pointer q; /* the copy */
7018   int k; /* runs through the words of a knot node */
7019   q=mp_get_node(mp, knot_node_size);
7020   for (k=0;k<knot_node_size;k++) {
7021     mp->mem[q+k]=mp->mem[p+k];
7022   }
7023   originator(q)=originator(p);
7024   return q;
7025 }
7026
7027 @ The |copy_path| routine makes a clone of a given path.
7028
7029 @c 
7030 pointer mp_copy_path (MP mp, pointer p) {
7031   pointer q,pp,qq; /* for list manipulation */
7032   q=mp_copy_knot(mp, p);
7033   qq=q; pp=link(p);
7034   while ( pp!=p ) { 
7035     link(qq)=mp_copy_knot(mp, pp);
7036     qq=link(qq);
7037     pp=link(pp);
7038   }
7039   link(qq)=q;
7040   return q;
7041 }
7042
7043
7044 @ Just before |ship_out|, knot lists are exported for printing.
7045
7046 The |gr_XXXX| macros are defined in |mppsout.h|.
7047
7048 @c 
7049 struct mp_knot *mp_export_knot (MP mp,pointer p) {
7050   struct mp_knot *q; /* the copy */
7051   if (p==null)
7052      return NULL;
7053   q = mp_xmalloc(mp, 1, sizeof (struct mp_knot));
7054   memset(q,0,sizeof (struct mp_knot));
7055   gr_left_type(q)  = left_type(p);
7056   gr_right_type(q) = right_type(p);
7057   gr_x_coord(q)    = x_coord(p);
7058   gr_y_coord(q)    = y_coord(p);
7059   gr_left_x(q)     = left_x(p);
7060   gr_left_y(q)     = left_y(p);
7061   gr_right_x(q)    = right_x(p);
7062   gr_right_y(q)    = right_y(p);
7063   gr_originator(q) = originator(p);
7064   return q;
7065 }
7066
7067 @ The |export_knot_list| routine therefore also makes a clone 
7068 of a given path.
7069
7070 @c 
7071 struct mp_knot *mp_export_knot_list (MP mp, pointer p) {
7072   struct mp_knot *q, *qq; /* for list manipulation */
7073   pointer pp; /* for list manipulation */
7074   if (p==null)
7075      return NULL;
7076   q=mp_export_knot(mp, p);
7077   qq=q; pp=link(p);
7078   while ( pp!=p ) { 
7079     gr_next_knot(qq)=mp_export_knot(mp, pp);
7080     qq=gr_next_knot(qq);
7081     pp=link(pp);
7082   }
7083   gr_next_knot(qq)=q;
7084   return q;
7085 }
7086
7087
7088 @ Similarly, there's a way to copy the {\sl reverse\/} of a path. This procedure
7089 returns a pointer to the first node of the copy, if the path is a cycle,
7090 but to the final node of a non-cyclic copy. The global
7091 variable |path_tail| will point to the final node of the original path;
7092 this trick makes it easier to implement `\&{doublepath}'.
7093
7094 All node types are assumed to be |endpoint| or |explicit| only.
7095
7096 @c 
7097 pointer mp_htap_ypoc (MP mp,pointer p) {
7098   pointer q,pp,qq,rr; /* for list manipulation */
7099   q=mp_get_node(mp, knot_node_size); /* this will correspond to |p| */
7100   qq=q; pp=p;
7101   while (1) { 
7102     right_type(qq)=left_type(pp); left_type(qq)=right_type(pp);
7103     x_coord(qq)=x_coord(pp); y_coord(qq)=y_coord(pp);
7104     right_x(qq)=left_x(pp); right_y(qq)=left_y(pp);
7105     left_x(qq)=right_x(pp); left_y(qq)=right_y(pp);
7106     originator(qq)=originator(pp);
7107     if ( link(pp)==p ) { 
7108       link(q)=qq; mp->path_tail=pp; return q;
7109     }
7110     rr=mp_get_node(mp, knot_node_size); link(rr)=qq; qq=rr; pp=link(pp);
7111   }
7112 }
7113
7114 @ @<Glob...@>=
7115 pointer path_tail; /* the node that links to the beginning of a path */
7116
7117 @ When a cyclic list of knot nodes is no longer needed, it can be recycled by
7118 calling the following subroutine.
7119
7120 @<Declare the recycling subroutines@>=
7121 void mp_toss_knot_list (MP mp,pointer p) ;
7122
7123 @ @c
7124 void mp_toss_knot_list (MP mp,pointer p) {
7125   pointer q; /* the node being freed */
7126   pointer r; /* the next node */
7127   q=p;
7128   do {  
7129     r=link(q); 
7130     mp_free_node(mp, q,knot_node_size); q=r;
7131   } while (q!=p);
7132 }
7133
7134 @* \[18] Choosing control points.
7135 Now we must actually delve into one of \MP's more difficult routines,
7136 the |make_choices| procedure that chooses angles and control points for
7137 the splines of a curve when the user has not specified them explicitly.
7138 The parameter to |make_choices| points to a list of knots and
7139 path information, as described above.
7140
7141 A path decomposes into independent segments at ``breakpoint'' knots,
7142 which are knots whose left and right angles are both prespecified in
7143 some way (i.e., their |left_type| and |right_type| aren't both open).
7144
7145 @c 
7146 @<Declare the procedure called |solve_choices|@>;
7147 void mp_make_choices (MP mp,pointer knots) {
7148   pointer h; /* the first breakpoint */
7149   pointer p,q; /* consecutive breakpoints being processed */
7150   @<Other local variables for |make_choices|@>;
7151   check_arith; /* make sure that |arith_error=false| */
7152   if ( mp->internal[mp_tracing_choices]>0 )
7153     mp_print_path(mp, knots,", before choices",true);
7154   @<If consecutive knots are equal, join them explicitly@>;
7155   @<Find the first breakpoint, |h|, on the path;
7156     insert an artificial breakpoint if the path is an unbroken cycle@>;
7157   p=h;
7158   do {  
7159     @<Fill in the control points between |p| and the next breakpoint,
7160       then advance |p| to that breakpoint@>;
7161   } while (p!=h);
7162   if ( mp->internal[mp_tracing_choices]>0 )
7163     mp_print_path(mp, knots,", after choices",true);
7164   if ( mp->arith_error ) {
7165     @<Report an unexpected problem during the choice-making@>;
7166   }
7167 }
7168
7169 @ @<Report an unexpected problem during the choice...@>=
7170
7171   print_err("Some number got too big");
7172 @.Some number got too big@>
7173   help2("The path that I just computed is out of range.")
7174        ("So it will probably look funny. Proceed, for a laugh.");
7175   mp_put_get_error(mp); mp->arith_error=false;
7176 }
7177
7178 @ Two knots in a row with the same coordinates will always be joined
7179 by an explicit ``curve'' whose control points are identical with the
7180 knots.
7181
7182 @<If consecutive knots are equal, join them explicitly@>=
7183 p=knots;
7184 do {  
7185   q=link(p);
7186   if ( x_coord(p)==x_coord(q) && y_coord(p)==y_coord(q) && right_type(p)>mp_explicit ) { 
7187     right_type(p)=mp_explicit;
7188     if ( left_type(p)==mp_open ) { 
7189       left_type(p)=mp_curl; left_curl(p)=unity;
7190     }
7191     left_type(q)=mp_explicit;
7192     if ( right_type(q)==mp_open ) { 
7193       right_type(q)=mp_curl; right_curl(q)=unity;
7194     }
7195     right_x(p)=x_coord(p); left_x(q)=x_coord(p);
7196     right_y(p)=y_coord(p); left_y(q)=y_coord(p);
7197   }
7198   p=q;
7199 } while (p!=knots)
7200
7201 @ If there are no breakpoints, it is necessary to compute the direction
7202 angles around an entire cycle. In this case the |left_type| of the first
7203 node is temporarily changed to |end_cycle|.
7204
7205 @<Find the first breakpoint, |h|, on the path...@>=
7206 h=knots;
7207 while (1) { 
7208   if ( left_type(h)!=mp_open ) break;
7209   if ( right_type(h)!=mp_open ) break;
7210   h=link(h);
7211   if ( h==knots ) { 
7212     left_type(h)=mp_end_cycle; break;
7213   }
7214 }
7215
7216 @ If |right_type(p)<given| and |q=link(p)|, we must have
7217 |right_type(p)=left_type(q)=mp_explicit| or |endpoint|.
7218
7219 @<Fill in the control points between |p| and the next breakpoint...@>=
7220 q=link(p);
7221 if ( right_type(p)>=mp_given ) { 
7222   while ( (left_type(q)==mp_open)&&(right_type(q)==mp_open) ) q=link(q);
7223   @<Fill in the control information between
7224     consecutive breakpoints |p| and |q|@>;
7225 } else if ( right_type(p)==mp_endpoint ) {
7226   @<Give reasonable values for the unused control points between |p| and~|q|@>;
7227 }
7228 p=q
7229
7230 @ This step makes it possible to transform an explicitly computed path without
7231 checking the |left_type| and |right_type| fields.
7232
7233 @<Give reasonable values for the unused control points between |p| and~|q|@>=
7234
7235   right_x(p)=x_coord(p); right_y(p)=y_coord(p);
7236   left_x(q)=x_coord(q); left_y(q)=y_coord(q);
7237 }
7238
7239 @ Before we can go further into the way choices are made, we need to
7240 consider the underlying theory. The basic ideas implemented in |make_choices|
7241 are due to John Hobby, who introduced the notion of ``mock curvature''
7242 @^Hobby, John Douglas@>
7243 at a knot. Angles are chosen so that they preserve mock curvature when
7244 a knot is passed, and this has been found to produce excellent results.
7245
7246 It is convenient to introduce some notations that simplify the necessary
7247 formulas. Let $d_{k,k+1}=\vert z\k-z_k\vert$ be the (nonzero) distance
7248 between knots |k| and |k+1|; and let
7249 $${z\k-z_k\over z_k-z_{k-1}}={d_{k,k+1}\over d_{k-1,k}}e^{i\psi_k}$$
7250 so that a polygonal line from $z_{k-1}$ to $z_k$ to $z\k$ turns left
7251 through an angle of~$\psi_k$. We assume that $\vert\psi_k\vert\L180^\circ$.
7252 The control points for the spline from $z_k$ to $z\k$ will be denoted by
7253 $$\eqalign{z_k^+&=z_k+
7254   \textstyle{1\over3}\rho_k e^{i\theta_k}(z\k-z_k),\cr
7255  z\k^-&=z\k-
7256   \textstyle{1\over3}\sigma\k e^{-i\phi\k}(z\k-z_k),\cr}$$
7257 where $\rho_k$ and $\sigma\k$ are nonnegative ``velocity ratios'' at the
7258 beginning and end of the curve, while $\theta_k$ and $\phi\k$ are the
7259 corresponding ``offset angles.'' These angles satisfy the condition
7260 $$\theta_k+\phi_k+\psi_k=0,\eqno(*)$$
7261 whenever the curve leaves an intermediate knot~|k| in the direction that
7262 it enters.
7263
7264 @ Let $\alpha_k$ and $\beta\k$ be the reciprocals of the ``tension'' of
7265 the curve at its beginning and ending points. This means that
7266 $\rho_k=\alpha_k f(\theta_k,\phi\k)$ and $\sigma\k=\beta\k f(\phi\k,\theta_k)$,
7267 where $f(\theta,\phi)$ is \MP's standard velocity function defined in
7268 the |velocity| subroutine. The cubic spline $B(z_k^{\phantom+},z_k^+,
7269 z\k^-,z\k^{\phantom+};t)$
7270 has curvature
7271 @^curvature@>
7272 $${2\sigma\k\sin(\theta_k+\phi\k)-6\sin\theta_k\over\rho_k^2d_{k,k+1}}
7273 \qquad{\rm and}\qquad
7274 {2\rho_k\sin(\theta_k+\phi\k)-6\sin\phi\k\over\sigma\k^2d_{k,k+1}}$$
7275 at |t=0| and |t=1|, respectively. The mock curvature is the linear
7276 @^mock curvature@>
7277 approximation to this true curvature that arises in the limit for
7278 small $\theta_k$ and~$\phi\k$, if second-order terms are discarded.
7279 The standard velocity function satisfies
7280 $$f(\theta,\phi)=1+O(\theta^2+\theta\phi+\phi^2);$$
7281 hence the mock curvatures are respectively
7282 $${2\beta\k(\theta_k+\phi\k)-6\theta_k\over\alpha_k^2d_{k,k+1}}
7283 \qquad{\rm and}\qquad
7284 {2\alpha_k(\theta_k+\phi\k)-6\phi\k\over\beta\k^2d_{k,k+1}}.\eqno(**)$$
7285
7286 @ The turning angles $\psi_k$ are given, and equation $(*)$ above
7287 determines $\phi_k$ when $\theta_k$ is known, so the task of
7288 angle selection is essentially to choose appropriate values for each
7289 $\theta_k$. When equation~$(*)$ is used to eliminate $\phi$~variables
7290 from $(**)$, we obtain a system of linear equations of the form
7291 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7292 where
7293 $$A_k={\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7294 \qquad B_k={3-\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7295 \qquad C_k={3-\beta\k\over\alpha_k^2d_{k,k+1}},
7296 \qquad D_k={\beta\k\over\alpha_k^2d_{k,k+1}}.$$
7297 The tensions are always $3\over4$ or more, hence each $\alpha$ and~$\beta$
7298 will be at most $4\over3$. It follows that $B_k\G{5\over4}A_k$ and
7299 $C_k\G{5\over4}D_k$; hence the equations are diagonally dominant;
7300 hence they have a unique solution. Moreover, in most cases the tensions
7301 are equal to~1, so that $B_k=2A_k$ and $C_k=2D_k$. This makes the
7302 solution numerically stable, and there is an exponential damping
7303 effect: The data at knot $k\pm j$ affects the angle at knot~$k$ by
7304 a factor of~$O(2^{-j})$.
7305
7306 @ However, we still must consider the angles at the starting and ending
7307 knots of a non-cyclic path. These angles might be given explicitly, or
7308 they might be specified implicitly in terms of an amount of ``curl.''
7309
7310 Let's assume that angles need to be determined for a non-cyclic path
7311 starting at $z_0$ and ending at~$z_n$. Then equations of the form
7312 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta_{k+1}=R_k$$
7313 have been given for $0<k<n$, and it will be convenient to introduce
7314 equations of the same form for $k=0$ and $k=n$, where
7315 $$A_0=B_0=C_n=D_n=0.$$
7316 If $\theta_0$ is supposed to have a given value $E_0$, we simply
7317 define $C_0=0$, $D_0=0$, and $R_0=E_0$. Otherwise a curl
7318 parameter, $\gamma_0$, has been specified at~$z_0$; this means
7319 that the mock curvature at $z_0$ should be $\gamma_0$ times the
7320 mock curvature at $z_1$; i.e.,
7321 $${2\beta_1(\theta_0+\phi_1)-6\theta_0\over\alpha_0^2d_{01}}
7322 =\gamma_0{2\alpha_0(\theta_0+\phi_1)-6\phi_1\over\beta_1^2d_{01}}.$$
7323 This equation simplifies to
7324 $$(\alpha_0\chi_0+3-\beta_1)\theta_0+
7325  \bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\theta_1=
7326  -\bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\psi_1,$$
7327 where $\chi_0=\alpha_0^2\gamma_0/\beta_1^2$; so we can set $C_0=
7328 \chi_0\alpha_0+3-\beta_1$, $D_0=(3-\alpha_0)\chi_0+\beta_1$, $R_0=-D_0\psi_1$.
7329 It can be shown that $C_0>0$ and $C_0B_1-A_1D_0>0$ when $\gamma_0\G0$,
7330 hence the linear equations remain nonsingular.
7331
7332 Similar considerations apply at the right end, when the final angle $\phi_n$
7333 may or may not need to be determined. It is convenient to let $\psi_n=0$,
7334 hence $\theta_n=-\phi_n$. We either have an explicit equation $\theta_n=E_n$,
7335 or we have
7336 $$\bigl((3-\beta_n)\chi_n+\alpha_{n-1}\bigr)\theta_{n-1}+
7337 (\beta_n\chi_n+3-\alpha_{n-1})\theta_n=0,\qquad
7338   \chi_n={\beta_n^2\gamma_n\over\alpha_{n-1}^2}.$$
7339
7340 When |make_choices| chooses angles, it must compute the coefficients of
7341 these linear equations, then solve the equations. To compute the coefficients,
7342 it is necessary to compute arctangents of the given turning angles~$\psi_k$.
7343 When the equations are solved, the chosen directions $\theta_k$ are put
7344 back into the form of control points by essentially computing sines and
7345 cosines.
7346
7347 @ OK, we are ready to make the hard choices of |make_choices|.
7348 Most of the work is relegated to an auxiliary procedure
7349 called |solve_choices|, which has been introduced to keep
7350 |make_choices| from being extremely long.
7351
7352 @<Fill in the control information between...@>=
7353 @<Calculate the turning angles $\psi_k$ and the distances $d_{k,k+1}$;
7354   set $n$ to the length of the path@>;
7355 @<Remove |open| types at the breakpoints@>;
7356 mp_solve_choices(mp, p,q,n)
7357
7358 @ It's convenient to precompute quantities that will be needed several
7359 times later. The values of |delta_x[k]| and |delta_y[k]| will be the
7360 coordinates of $z\k-z_k$, and the magnitude of this vector will be
7361 |delta[k]=@t$d_{k,k+1}$@>|. The path angle $\psi_k$ between $z_k-z_{k-1}$
7362 and $z\k-z_k$ will be stored in |psi[k]|.
7363
7364 @<Glob...@>=
7365 int path_size; /* maximum number of knots between breakpoints of a path */
7366 scaled *delta_x;
7367 scaled *delta_y;
7368 scaled *delta; /* knot differences */
7369 angle  *psi; /* turning angles */
7370
7371 @ @<Allocate or initialize ...@>=
7372 mp->delta_x = NULL;
7373 mp->delta_y = NULL;
7374 mp->delta = NULL;
7375 mp->psi = NULL;
7376
7377 @ @<Dealloc variables@>=
7378 xfree(mp->delta_x);
7379 xfree(mp->delta_y);
7380 xfree(mp->delta);
7381 xfree(mp->psi);
7382
7383 @ @<Other local variables for |make_choices|@>=
7384   int k,n; /* current and final knot numbers */
7385   pointer s,t; /* registers for list traversal */
7386   scaled delx,dely; /* directions where |open| meets |explicit| */
7387   fraction sine,cosine; /* trig functions of various angles */
7388
7389 @ @<Calculate the turning angles...@>=
7390 {
7391 RESTART:
7392   k=0; s=p; n=mp->path_size;
7393   do {  
7394     t=link(s);
7395     mp->delta_x[k]=x_coord(t)-x_coord(s);
7396     mp->delta_y[k]=y_coord(t)-y_coord(s);
7397     mp->delta[k]=mp_pyth_add(mp, mp->delta_x[k],mp->delta_y[k]);
7398     if ( k>0 ) { 
7399       sine=mp_make_fraction(mp, mp->delta_y[k-1],mp->delta[k-1]);
7400       cosine=mp_make_fraction(mp, mp->delta_x[k-1],mp->delta[k-1]);
7401       mp->psi[k]=mp_n_arg(mp, mp_take_fraction(mp, mp->delta_x[k],cosine)+
7402         mp_take_fraction(mp, mp->delta_y[k],sine),
7403         mp_take_fraction(mp, mp->delta_y[k],cosine)-
7404           mp_take_fraction(mp, mp->delta_x[k],sine));
7405     }
7406     incr(k); s=t;
7407     if ( k==mp->path_size ) {
7408       mp_reallocate_paths(mp, mp->path_size+(mp->path_size>>2));
7409       goto RESTART; /* retry, loop size has changed */
7410     }
7411     if ( s==q ) n=k;
7412   } while (!((k>=n)&&(left_type(s)!=mp_end_cycle)));
7413   if ( k==n ) mp->psi[n]=0; else mp->psi[k]=mp->psi[1];
7414 }
7415
7416 @ When we get to this point of the code, |right_type(p)| is either
7417 |given| or |curl| or |open|. If it is |open|, we must have
7418 |left_type(p)=mp_end_cycle| or |left_type(p)=mp_explicit|. In the latter
7419 case, the |open| type is converted to |given|; however, if the
7420 velocity coming into this knot is zero, the |open| type is
7421 converted to a |curl|, since we don't know the incoming direction.
7422
7423 Similarly, |left_type(q)| is either |given| or |curl| or |open| or
7424 |mp_end_cycle|. The |open| possibility is reduced either to |given| or to |curl|.
7425
7426 @<Remove |open| types at the breakpoints@>=
7427 if ( left_type(q)==mp_open ) { 
7428   delx=right_x(q)-x_coord(q); dely=right_y(q)-y_coord(q);
7429   if ( (delx==0)&&(dely==0) ) { 
7430     left_type(q)=mp_curl; left_curl(q)=unity;
7431   } else { 
7432     left_type(q)=mp_given; left_given(q)=mp_n_arg(mp, delx,dely);
7433   }
7434 }
7435 if ( (right_type(p)==mp_open)&&(left_type(p)==mp_explicit) ) { 
7436   delx=x_coord(p)-left_x(p); dely=y_coord(p)-left_y(p);
7437   if ( (delx==0)&&(dely==0) ) { 
7438     right_type(p)=mp_curl; right_curl(p)=unity;
7439   } else { 
7440     right_type(p)=mp_given; right_given(p)=mp_n_arg(mp, delx,dely);
7441   }
7442 }
7443
7444 @ Linear equations need to be solved whenever |n>1|; and also when |n=1|
7445 and exactly one of the breakpoints involves a curl. The simplest case occurs
7446 when |n=1| and there is a curl at both breakpoints; then we simply draw
7447 a straight line.
7448
7449 But before coding up the simple cases, we might as well face the general case,
7450 since we must deal with it sooner or later, and since the general case
7451 is likely to give some insight into the way simple cases can be handled best.
7452
7453 When there is no cycle, the linear equations to be solved form a tridiagonal
7454 system, and we can apply the standard technique of Gaussian elimination
7455 to convert that system to a sequence of equations of the form
7456 $$\theta_0+u_0\theta_1=v_0,\quad
7457 \theta_1+u_1\theta_2=v_1,\quad\ldots,\quad
7458 \theta_{n-1}+u_{n-1}\theta_n=v_{n-1},\quad
7459 \theta_n=v_n.$$
7460 It is possible to do this diagonalization while generating the equations.
7461 Once $\theta_n$ is known, it is easy to determine $\theta_{n-1}$, \dots,
7462 $\theta_1$, $\theta_0$; thus, the equations will be solved.
7463
7464 The procedure is slightly more complex when there is a cycle, but the
7465 basic idea will be nearly the same. In the cyclic case the right-hand
7466 sides will be $v_k+w_k\theta_0$ instead of simply $v_k$, and we will start
7467 the process off with $u_0=v_0=0$, $w_0=1$. The final equation will be not
7468 $\theta_n=v_n$ but $\theta_n+u_n\theta_1=v_n+w_n\theta_0$; an appropriate
7469 ending routine will take account of the fact that $\theta_n=\theta_0$ and
7470 eliminate the $w$'s from the system, after which the solution can be
7471 obtained as before.
7472
7473 When $u_k$, $v_k$, and $w_k$ are being computed, the three pointer
7474 variables |r|, |s|,~|t| will point respectively to knots |k-1|, |k|,
7475 and~|k+1|. The $u$'s and $w$'s are scaled by $2^{28}$, i.e., they are
7476 of type |fraction|; the $\theta$'s and $v$'s are of type |angle|.
7477
7478 @<Glob...@>=
7479 angle *theta; /* values of $\theta_k$ */
7480 fraction *uu; /* values of $u_k$ */
7481 angle *vv; /* values of $v_k$ */
7482 fraction *ww; /* values of $w_k$ */
7483
7484 @ @<Allocate or initialize ...@>=
7485 mp->theta = NULL;
7486 mp->uu = NULL;
7487 mp->vv = NULL;
7488 mp->ww = NULL;
7489
7490 @ @<Dealloc variables@>=
7491 xfree(mp->theta);
7492 xfree(mp->uu);
7493 xfree(mp->vv);
7494 xfree(mp->ww);
7495
7496 @ @<Declare |mp_reallocate| functions@>=
7497 void mp_reallocate_paths (MP mp, int l);
7498
7499 @ @c
7500 void mp_reallocate_paths (MP mp, int l) {
7501   XREALLOC (mp->delta_x, l, scaled);
7502   XREALLOC (mp->delta_y, l, scaled);
7503   XREALLOC (mp->delta,   l, scaled);
7504   XREALLOC (mp->psi,     l, angle);
7505   XREALLOC (mp->theta,   l, angle);
7506   XREALLOC (mp->uu,      l, fraction);
7507   XREALLOC (mp->vv,      l, angle);
7508   XREALLOC (mp->ww,      l, fraction);
7509   mp->path_size = l;
7510 }
7511
7512 @ Our immediate problem is to get the ball rolling by setting up the
7513 first equation or by realizing that no equations are needed, and to fit
7514 this initialization into a framework suitable for the overall computation.
7515
7516 @<Declare the procedure called |solve_choices|@>=
7517 @<Declare subroutines needed by |solve_choices|@>;
7518 void mp_solve_choices (MP mp,pointer p, pointer q, halfword n) {
7519   int k; /* current knot number */
7520   pointer r,s,t; /* registers for list traversal */
7521   @<Other local variables for |solve_choices|@>;
7522   k=0; s=p; r=0;
7523   while (1) { 
7524     t=link(s);
7525     if ( k==0 ) {
7526       @<Get the linear equations started; or |return|
7527         with the control points in place, if linear equations
7528         needn't be solved@>
7529     } else  { 
7530       switch (left_type(s)) {
7531       case mp_end_cycle: case mp_open:
7532         @<Set up equation to match mock curvatures
7533           at $z_k$; then |goto found| with $\theta_n$
7534           adjusted to equal $\theta_0$, if a cycle has ended@>;
7535         break;
7536       case mp_curl:
7537         @<Set up equation for a curl at $\theta_n$
7538           and |goto found|@>;
7539         break;
7540       case mp_given:
7541         @<Calculate the given value of $\theta_n$
7542           and |goto found|@>;
7543         break;
7544       } /* there are no other cases */
7545     }
7546     r=s; s=t; incr(k);
7547   }
7548 FOUND:
7549   @<Finish choosing angles and assigning control points@>;
7550 }
7551
7552 @ On the first time through the loop, we have |k=0| and |r| is not yet
7553 defined. The first linear equation, if any, will have $A_0=B_0=0$.
7554
7555 @<Get the linear equations started...@>=
7556 switch (right_type(s)) {
7557 case mp_given: 
7558   if ( left_type(t)==mp_given ) {
7559     @<Reduce to simple case of two givens  and |return|@>
7560   } else {
7561     @<Set up the equation for a given value of $\theta_0$@>;
7562   }
7563   break;
7564 case mp_curl: 
7565   if ( left_type(t)==mp_curl ) {
7566     @<Reduce to simple case of straight line and |return|@>
7567   } else {
7568     @<Set up the equation for a curl at $\theta_0$@>;
7569   }
7570   break;
7571 case mp_open: 
7572   mp->uu[0]=0; mp->vv[0]=0; mp->ww[0]=fraction_one;
7573   /* this begins a cycle */
7574   break;
7575 } /* there are no other cases */
7576
7577 @ The general equation that specifies equality of mock curvature at $z_k$ is
7578 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7579 as derived above. We want to combine this with the already-derived equation
7580 $\theta_{k-1}+u_{k-1}\theta_k=v_{k-1}+w_{k-1}\theta_0$ in order to obtain
7581 a new equation
7582 $\theta_k+u_k\theta\k=v_k+w_k\theta_0$. This can be done by dividing the
7583 equation
7584 $$(B_k-u_{k-1}A_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k-A_kv_{k-1}
7585     -A_kw_{k-1}\theta_0$$
7586 by $B_k-u_{k-1}A_k+C_k$. The trick is to do this carefully with
7587 fixed-point arithmetic, avoiding the chance of overflow while retaining
7588 suitable precision.
7589
7590 The calculations will be performed in several registers that
7591 provide temporary storage for intermediate quantities.
7592
7593 @<Other local variables for |solve_choices|@>=
7594 fraction aa,bb,cc,ff,acc; /* temporary registers */
7595 scaled dd,ee; /* likewise, but |scaled| */
7596 scaled lt,rt; /* tension values */
7597
7598 @ @<Set up equation to match mock curvatures...@>=
7599 { @<Calculate the values $\\{aa}=A_k/B_k$, $\\{bb}=D_k/C_k$,
7600     $\\{dd}=(3-\alpha_{k-1})d_{k,k+1}$, $\\{ee}=(3-\beta\k)d_{k-1,k}$,
7601     and $\\{cc}=(B_k-u_{k-1}A_k)/B_k$@>;
7602   @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>;
7603   mp->uu[k]=mp_take_fraction(mp, ff,bb);
7604   @<Calculate the values of $v_k$ and $w_k$@>;
7605   if ( left_type(s)==mp_end_cycle ) {
7606     @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>;
7607   }
7608 }
7609
7610 @ Since tension values are never less than 3/4, the values |aa| and
7611 |bb| computed here are never more than 4/5.
7612
7613 @<Calculate the values $\\{aa}=...@>=
7614 if ( abs(right_tension(r))==unity) { 
7615   aa=fraction_half; dd=2*mp->delta[k];
7616 } else { 
7617   aa=mp_make_fraction(mp, unity,3*abs(right_tension(r))-unity);
7618   dd=mp_take_fraction(mp, mp->delta[k],
7619     fraction_three-mp_make_fraction(mp, unity,abs(right_tension(r))));
7620 }
7621 if ( abs(left_tension(t))==unity ){ 
7622   bb=fraction_half; ee=2*mp->delta[k-1];
7623 } else { 
7624   bb=mp_make_fraction(mp, unity,3*abs(left_tension(t))-unity);
7625   ee=mp_take_fraction(mp, mp->delta[k-1],
7626     fraction_three-mp_make_fraction(mp, unity,abs(left_tension(t))));
7627 }
7628 cc=fraction_one-mp_take_fraction(mp, mp->uu[k-1],aa)
7629
7630 @ The ratio to be calculated in this step can be written in the form
7631 $$\beta_k^2\cdot\\{ee}\over\beta_k^2\cdot\\{ee}+\alpha_k^2\cdot
7632   \\{cc}\cdot\\{dd},$$
7633 because of the quantities just calculated. The values of |dd| and |ee|
7634 will not be needed after this step has been performed.
7635
7636 @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>=
7637 dd=mp_take_fraction(mp, dd,cc); lt=abs(left_tension(s)); rt=abs(right_tension(s));
7638 if ( lt!=rt ) { /* $\beta_k^{-1}\ne\alpha_k^{-1}$ */
7639   if ( lt<rt ) { 
7640     ff=mp_make_fraction(mp, lt,rt);
7641     ff=mp_take_fraction(mp, ff,ff); /* $\alpha_k^2/\beta_k^2$ */
7642     dd=mp_take_fraction(mp, dd,ff);
7643   } else { 
7644     ff=mp_make_fraction(mp, rt,lt);
7645     ff=mp_take_fraction(mp, ff,ff); /* $\beta_k^2/\alpha_k^2$ */
7646     ee=mp_take_fraction(mp, ee,ff);
7647   }
7648 }
7649 ff=mp_make_fraction(mp, ee,ee+dd)
7650
7651 @ The value of $u_{k-1}$ will be |<=1| except when $k=1$ and the previous
7652 equation was specified by a curl. In that case we must use a special
7653 method of computation to prevent overflow.
7654
7655 Fortunately, the calculations turn out to be even simpler in this ``hard''
7656 case. The curl equation makes $w_0=0$ and $v_0=-u_0\psi_1$, hence
7657 $-B_1\psi_1-A_1v_0=-(B_1-u_0A_1)\psi_1=-\\{cc}\cdot B_1\psi_1$.
7658
7659 @<Calculate the values of $v_k$ and $w_k$@>=
7660 acc=-mp_take_fraction(mp, mp->psi[k+1],mp->uu[k]);
7661 if ( right_type(r)==mp_curl ) { 
7662   mp->ww[k]=0;
7663   mp->vv[k]=acc-mp_take_fraction(mp, mp->psi[1],fraction_one-ff);
7664 } else { 
7665   ff=mp_make_fraction(mp, fraction_one-ff,cc); /* this is
7666     $B_k/(C_k+B_k-u_{k-1}A_k)<5$ */
7667   acc=acc-mp_take_fraction(mp, mp->psi[k],ff);
7668   ff=mp_take_fraction(mp, ff,aa); /* this is $A_k/(C_k+B_k-u_{k-1}A_k)$ */
7669   mp->vv[k]=acc-mp_take_fraction(mp, mp->vv[k-1],ff);
7670   if ( mp->ww[k-1]==0 ) mp->ww[k]=0;
7671   else mp->ww[k]=-mp_take_fraction(mp, mp->ww[k-1],ff);
7672 }
7673
7674 @ When a complete cycle has been traversed, we have $\theta_k+u_k\theta\k=
7675 v_k+w_k\theta_0$, for |1<=k<=n|. We would like to determine the value of
7676 $\theta_n$ and reduce the system to the form $\theta_k+u_k\theta\k=v_k$
7677 for |0<=k<n|, so that the cyclic case can be finished up just as if there
7678 were no cycle.
7679
7680 The idea in the following code is to observe that
7681 $$\eqalign{\theta_n&=v_n+w_n\theta_0-u_n\theta_1=\cdots\cr
7682 &=v_n+w_n\theta_0-u_n\bigl(v_1+w_1\theta_0-u_1(v_2+\cdots
7683   -u_{n-2}(v_{n-1}+w_{n-1}\theta_0-u_{n-1}\theta_0))\bigr),\cr}$$
7684 so we can solve for $\theta_n=\theta_0$.
7685
7686 @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>=
7687
7688 aa=0; bb=fraction_one; /* we have |k=n| */
7689 do {  decr(k);
7690 if ( k==0 ) k=n;
7691   aa=mp->vv[k]-mp_take_fraction(mp, aa,mp->uu[k]);
7692   bb=mp->ww[k]-mp_take_fraction(mp, bb,mp->uu[k]);
7693 } while (k!=n); /* now $\theta_n=\\{aa}+\\{bb}\cdot\theta_n$ */
7694 aa=mp_make_fraction(mp, aa,fraction_one-bb);
7695 mp->theta[n]=aa; mp->vv[0]=aa;
7696 for (k=1;k<=n-1;k++) {
7697   mp->vv[k]=mp->vv[k]+mp_take_fraction(mp, aa,mp->ww[k]);
7698 }
7699 goto FOUND;
7700 }
7701
7702 @ @d reduce_angle(A) if ( abs((A))>one_eighty_deg ) {
7703   if ( (A)>0 ) (A)=(A)-three_sixty_deg; else (A)=(A)+three_sixty_deg; }
7704
7705 @<Calculate the given value of $\theta_n$...@>=
7706
7707   mp->theta[n]=left_given(s)-mp_n_arg(mp, mp->delta_x[n-1],mp->delta_y[n-1]);
7708   reduce_angle(mp->theta[n]);
7709   goto FOUND;
7710 }
7711
7712 @ @<Set up the equation for a given value of $\theta_0$@>=
7713
7714   mp->vv[0]=right_given(s)-mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7715   reduce_angle(mp->vv[0]);
7716   mp->uu[0]=0; mp->ww[0]=0;
7717 }
7718
7719 @ @<Set up the equation for a curl at $\theta_0$@>=
7720 { cc=right_curl(s); lt=abs(left_tension(t)); rt=abs(right_tension(s));
7721   if ( (rt==unity)&&(lt==unity) )
7722     mp->uu[0]=mp_make_fraction(mp, cc+cc+unity,cc+two);
7723   else 
7724     mp->uu[0]=mp_curl_ratio(mp, cc,rt,lt);
7725   mp->vv[0]=-mp_take_fraction(mp, mp->psi[1],mp->uu[0]); mp->ww[0]=0;
7726 }
7727
7728 @ @<Set up equation for a curl at $\theta_n$...@>=
7729 { cc=left_curl(s); lt=abs(left_tension(s)); rt=abs(right_tension(r));
7730   if ( (rt==unity)&&(lt==unity) )
7731     ff=mp_make_fraction(mp, cc+cc+unity,cc+two);
7732   else 
7733     ff=mp_curl_ratio(mp, cc,lt,rt);
7734   mp->theta[n]=-mp_make_fraction(mp, mp_take_fraction(mp, mp->vv[n-1],ff),
7735     fraction_one-mp_take_fraction(mp, ff,mp->uu[n-1]));
7736   goto FOUND;
7737 }
7738
7739 @ The |curl_ratio| subroutine has three arguments, which our previous notation
7740 encourages us to call $\gamma$, $\alpha^{-1}$, and $\beta^{-1}$. It is
7741 a somewhat tedious program to calculate
7742 $${(3-\alpha)\alpha^2\gamma+\beta^3\over
7743   \alpha^3\gamma+(3-\beta)\beta^2},$$
7744 with the result reduced to 4 if it exceeds 4. (This reduction of curl
7745 is necessary only if the curl and tension are both large.)
7746 The values of $\alpha$ and $\beta$ will be at most~4/3.
7747
7748 @<Declare subroutines needed by |solve_choices|@>=
7749 fraction mp_curl_ratio (MP mp,scaled gamma, scaled a_tension, 
7750                         scaled b_tension) {
7751   fraction alpha,beta,num,denom,ff; /* registers */
7752   alpha=mp_make_fraction(mp, unity,a_tension);
7753   beta=mp_make_fraction(mp, unity,b_tension);
7754   if ( alpha<=beta ) {
7755     ff=mp_make_fraction(mp, alpha,beta); ff=mp_take_fraction(mp, ff,ff);
7756     gamma=mp_take_fraction(mp, gamma,ff);
7757     beta=beta / 010000; /* convert |fraction| to |scaled| */
7758     denom=mp_take_fraction(mp, gamma,alpha)+three-beta;
7759     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7760   } else { 
7761     ff=mp_make_fraction(mp, beta,alpha); ff=mp_take_fraction(mp, ff,ff);
7762     beta=mp_take_fraction(mp, beta,ff) / 010000; /* convert |fraction| to |scaled| */
7763     denom=mp_take_fraction(mp, gamma,alpha)+(ff / 1365)-beta;
7764       /* $1365\approx 2^{12}/3$ */
7765     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7766   }
7767   if ( num>=denom+denom+denom+denom ) return fraction_four;
7768   else return mp_make_fraction(mp, num,denom);
7769 }
7770
7771 @ We're in the home stretch now.
7772
7773 @<Finish choosing angles and assigning control points@>=
7774 for (k=n-1;k>=0;k--) {
7775   mp->theta[k]=mp->vv[k]-mp_take_fraction(mp,mp->theta[k+1],mp->uu[k]);
7776 }
7777 s=p; k=0;
7778 do {  
7779   t=link(s);
7780   mp_n_sin_cos(mp, mp->theta[k]); mp->st=mp->n_sin; mp->ct=mp->n_cos;
7781   mp_n_sin_cos(mp, -mp->psi[k+1]-mp->theta[k+1]); mp->sf=mp->n_sin; mp->cf=mp->n_cos;
7782   mp_set_controls(mp, s,t,k);
7783   incr(k); s=t;
7784 } while (k!=n)
7785
7786 @ The |set_controls| routine actually puts the control points into
7787 a pair of consecutive nodes |p| and~|q|. Global variables are used to
7788 record the values of $\sin\theta$, $\cos\theta$, $\sin\phi$, and
7789 $\cos\phi$ needed in this calculation.
7790
7791 @<Glob...@>=
7792 fraction st;
7793 fraction ct;
7794 fraction sf;
7795 fraction cf; /* sines and cosines */
7796
7797 @ @<Declare subroutines needed by |solve_choices|@>=
7798 void mp_set_controls (MP mp,pointer p, pointer q, integer k) {
7799   fraction rr,ss; /* velocities, divided by thrice the tension */
7800   scaled lt,rt; /* tensions */
7801   fraction sine; /* $\sin(\theta+\phi)$ */
7802   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7803   rr=mp_velocity(mp, mp->st,mp->ct,mp->sf,mp->cf,rt);
7804   ss=mp_velocity(mp, mp->sf,mp->cf,mp->st,mp->ct,lt);
7805   if ( (right_tension(p)<0)||(left_tension(q)<0) ) {
7806     @<Decrease the velocities,
7807       if necessary, to stay inside the bounding triangle@>;
7808   }
7809   right_x(p)=x_coord(p)+mp_take_fraction(mp, 
7810                           mp_take_fraction(mp, mp->delta_x[k],mp->ct)-
7811                           mp_take_fraction(mp, mp->delta_y[k],mp->st),rr);
7812   right_y(p)=y_coord(p)+mp_take_fraction(mp, 
7813                           mp_take_fraction(mp, mp->delta_y[k],mp->ct)+
7814                           mp_take_fraction(mp, mp->delta_x[k],mp->st),rr);
7815   left_x(q)=x_coord(q)-mp_take_fraction(mp, 
7816                          mp_take_fraction(mp, mp->delta_x[k],mp->cf)+
7817                          mp_take_fraction(mp, mp->delta_y[k],mp->sf),ss);
7818   left_y(q)=y_coord(q)-mp_take_fraction(mp, 
7819                          mp_take_fraction(mp, mp->delta_y[k],mp->cf)-
7820                          mp_take_fraction(mp, mp->delta_x[k],mp->sf),ss);
7821   right_type(p)=mp_explicit; left_type(q)=mp_explicit;
7822 }
7823
7824 @ The boundedness conditions $\\{rr}\L\sin\phi\,/\sin(\theta+\phi)$ and
7825 $\\{ss}\L\sin\theta\,/\sin(\theta+\phi)$ are to be enforced if $\sin\theta$,
7826 $\sin\phi$, and $\sin(\theta+\phi)$ all have the same sign. Otherwise
7827 there is no ``bounding triangle.''
7828 @:at_least_}{\&{atleast} primitive@>
7829
7830 @<Decrease the velocities, if necessary...@>=
7831 if (((mp->st>=0)&&(mp->sf>=0))||((mp->st<=0)&&(mp->sf<=0)) ) {
7832   sine=mp_take_fraction(mp, abs(mp->st),mp->cf)+
7833                             mp_take_fraction(mp, abs(mp->sf),mp->ct);
7834   if ( sine>0 ) {
7835     sine=mp_take_fraction(mp, sine,fraction_one+unity); /* safety factor */
7836     if ( right_tension(p)<0 )
7837      if ( mp_ab_vs_cd(mp, abs(mp->sf),fraction_one,rr,sine)<0 )
7838       rr=mp_make_fraction(mp, abs(mp->sf),sine);
7839     if ( left_tension(q)<0 )
7840      if ( mp_ab_vs_cd(mp, abs(mp->st),fraction_one,ss,sine)<0 )
7841       ss=mp_make_fraction(mp, abs(mp->st),sine);
7842   }
7843 }
7844
7845 @ Only the simple cases remain to be handled.
7846
7847 @<Reduce to simple case of two givens and |return|@>=
7848
7849   aa=mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7850   mp_n_sin_cos(mp, right_given(p)-aa); mp->ct=mp->n_cos; mp->st=mp->n_sin;
7851   mp_n_sin_cos(mp, left_given(q)-aa); mp->cf=mp->n_cos; mp->sf=-mp->n_sin;
7852   mp_set_controls(mp, p,q,0); return;
7853 }
7854
7855 @ @<Reduce to simple case of straight line and |return|@>=
7856
7857   right_type(p)=mp_explicit; left_type(q)=mp_explicit;
7858   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7859   if ( rt==unity ) {
7860     if ( mp->delta_x[0]>=0 ) right_x(p)=x_coord(p)+((mp->delta_x[0]+1) / 3);
7861     else right_x(p)=x_coord(p)+((mp->delta_x[0]-1) / 3);
7862     if ( mp->delta_y[0]>=0 ) right_y(p)=y_coord(p)+((mp->delta_y[0]+1) / 3);
7863     else right_y(p)=y_coord(p)+((mp->delta_y[0]-1) / 3);
7864   } else { 
7865     ff=mp_make_fraction(mp, unity,3*rt); /* $\alpha/3$ */
7866     right_x(p)=x_coord(p)+mp_take_fraction(mp, mp->delta_x[0],ff);
7867     right_y(p)=y_coord(p)+mp_take_fraction(mp, mp->delta_y[0],ff);
7868   }
7869   if ( lt==unity ) {
7870     if ( mp->delta_x[0]>=0 ) left_x(q)=x_coord(q)-((mp->delta_x[0]+1) / 3);
7871     else left_x(q)=x_coord(q)-((mp->delta_x[0]-1) / 3);
7872     if ( mp->delta_y[0]>=0 ) left_y(q)=y_coord(q)-((mp->delta_y[0]+1) / 3);
7873     else left_y(q)=y_coord(q)-((mp->delta_y[0]-1) / 3);
7874   } else  { 
7875     ff=mp_make_fraction(mp, unity,3*lt); /* $\beta/3$ */
7876     left_x(q)=x_coord(q)-mp_take_fraction(mp, mp->delta_x[0],ff);
7877     left_y(q)=y_coord(q)-mp_take_fraction(mp, mp->delta_y[0],ff);
7878   }
7879   return;
7880 }
7881
7882 @* \[19] Measuring paths.
7883 \MP's \&{llcorner}, \&{lrcorner}, \&{ulcorner}, and \&{urcorner} operators
7884 allow the user to measure the bounding box of anything that can go into a
7885 picture.  It's easy to get rough bounds on the $x$ and $y$ extent of a path
7886 by just finding the bounding box of the knots and the control points. We
7887 need a more accurate version of the bounding box, but we can still use the
7888 easy estimate to save time by focusing on the interesting parts of the path.
7889
7890 @ Computing an accurate bounding box involves a theme that will come up again
7891 and again. Given a Bernshte{\u\i}n polynomial
7892 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
7893 $$B(z_0,z_1,\ldots,z_n;t)=\sum_k{n\choose k}t^k(1-t)^{n-k}z_k,$$
7894 we can conveniently bisect its range as follows:
7895
7896 \smallskip
7897 \textindent{1)} Let $z_k^{(0)}=z_k$, for |0<=k<=n|.
7898
7899 \smallskip
7900 \textindent{2)} Let $z_k^{(j+1)}={1\over2}(z_k^{(j)}+z\k^{(j)})$, for
7901 |0<=k<n-j|, for |0<=j<n|.
7902
7903 \smallskip\noindent
7904 Then
7905 $$B(z_0,z_1,\ldots,z_n;t)=B(z_0^{(0)},z_0^{(1)},\ldots,z_0^{(n)};2t)
7906  =B(z_0^{(n)},z_1^{(n-1)},\ldots,z_n^{(0)};2t-1).$$
7907 This formula gives us the coefficients of polynomials to use over the ranges
7908 $0\L t\L{1\over2}$ and ${1\over2}\L t\L1$.
7909
7910 @ Now here's a subroutine that's handy for all sorts of path computations:
7911 Given a quadratic polynomial $B(a,b,c;t)$, the |crossing_point| function
7912 returns the unique |fraction| value |t| between 0 and~1 at which
7913 $B(a,b,c;t)$ changes from positive to negative, or returns
7914 |t=fraction_one+1| if no such value exists. If |a<0| (so that $B(a,b,c;t)$
7915 is already negative at |t=0|), |crossing_point| returns the value zero.
7916
7917 @d no_crossing {  return (fraction_one+1); }
7918 @d one_crossing { return fraction_one; }
7919 @d zero_crossing { return 0; }
7920 @d mp_crossing_point(M,A,B,C) mp_do_crossing_point(A,B,C)
7921
7922 @c fraction mp_do_crossing_point (integer a, integer b, integer c) {
7923   integer d; /* recursive counter */
7924   integer x,xx,x0,x1,x2; /* temporary registers for bisection */
7925   if ( a<0 ) zero_crossing;
7926   if ( c>=0 ) { 
7927     if ( b>=0 ) {
7928       if ( c>0 ) { no_crossing; }
7929       else if ( (a==0)&&(b==0) ) { no_crossing;} 
7930       else { one_crossing; } 
7931     }
7932     if ( a==0 ) zero_crossing;
7933   } else if ( a==0 ) {
7934     if ( b<=0 ) zero_crossing;
7935   }
7936   @<Use bisection to find the crossing point, if one exists@>;
7937 }
7938
7939 @ The general bisection method is quite simple when $n=2$, hence
7940 |crossing_point| does not take much time. At each stage in the
7941 recursion we have a subinterval defined by |l| and~|j| such that
7942 $B(a,b,c;2^{-l}(j+t))=B(x_0,x_1,x_2;t)$, and we want to ``zero in'' on
7943 the subinterval where $x_0\G0$ and $\min(x_1,x_2)<0$.
7944
7945 It is convenient for purposes of calculation to combine the values
7946 of |l| and~|j| in a single variable $d=2^l+j$, because the operation
7947 of bisection then corresponds simply to doubling $d$ and possibly
7948 adding~1. Furthermore it proves to be convenient to modify
7949 our previous conventions for bisection slightly, maintaining the
7950 variables $X_0=2^lx_0$, $X_1=2^l(x_0-x_1)$, and $X_2=2^l(x_1-x_2)$.
7951 With these variables the conditions $x_0\ge0$ and $\min(x_1,x_2)<0$ are
7952 equivalent to $\max(X_1,X_1+X_2)>X_0\ge0$.
7953
7954 The following code maintains the invariant relations
7955 $0\L|x0|<\max(|x1|,|x1|+|x2|)$,
7956 $\vert|x1|\vert<2^{30}$, $\vert|x2|\vert<2^{30}$;
7957 it has been constructed in such a way that no arithmetic overflow
7958 will occur if the inputs satisfy
7959 $a<2^{30}$, $\vert a-b\vert<2^{30}$, and $\vert b-c\vert<2^{30}$.
7960
7961 @<Use bisection to find the crossing point...@>=
7962 d=1; x0=a; x1=a-b; x2=b-c;
7963 do {  
7964   x=half(x1+x2);
7965   if ( x1-x0>x0 ) { 
7966     x2=x; x0+=x0; d+=d;  
7967   } else { 
7968     xx=x1+x-x0;
7969     if ( xx>x0 ) { 
7970       x2=x; x0+=x0; d+=d;
7971     }  else { 
7972       x0=x0-xx;
7973       if ( x<=x0 ) { if ( x+x2<=x0 ) no_crossing; }
7974       x1=x; d=d+d+1;
7975     }
7976   }
7977 } while (d<fraction_one);
7978 return (d-fraction_one)
7979
7980 @ Here is a routine that computes the $x$ or $y$ coordinate of the point on
7981 a cubic corresponding to the |fraction| value~|t|.
7982
7983 It is convenient to define a \.{WEB} macro |t_of_the_way| such that
7984 |t_of_the_way(a,b)| expands to |a-(a-b)*t|, i.e., to |t[a,b]|.
7985
7986 @d t_of_the_way(A,B) ((A)-mp_take_fraction(mp,((A)-(B)),t))
7987
7988 @c scaled mp_eval_cubic (MP mp,pointer p, pointer q, fraction t) {
7989   scaled x1,x2,x3; /* intermediate values */
7990   x1=t_of_the_way(knot_coord(p),right_coord(p));
7991   x2=t_of_the_way(right_coord(p),left_coord(q));
7992   x3=t_of_the_way(left_coord(q),knot_coord(q));
7993   x1=t_of_the_way(x1,x2);
7994   x2=t_of_the_way(x2,x3);
7995   return t_of_the_way(x1,x2);
7996 }
7997
7998 @ The actual bounding box information is stored in global variables.
7999 Since it is convenient to address the $x$ and $y$ information
8000 separately, we define arrays indexed by |x_code..y_code| and use
8001 macros to give them more convenient names.
8002
8003 @<Types...@>=
8004 enum mp_bb_code  {
8005   mp_x_code=0, /* index for |minx| and |maxx| */
8006   mp_y_code /* index for |miny| and |maxy| */
8007 } ;
8008
8009
8010 @d minx mp->bbmin[mp_x_code]
8011 @d maxx mp->bbmax[mp_x_code]
8012 @d miny mp->bbmin[mp_y_code]
8013 @d maxy mp->bbmax[mp_y_code]
8014
8015 @<Glob...@>=
8016 scaled bbmin[mp_y_code+1];
8017 scaled bbmax[mp_y_code+1]; 
8018 /* the result of procedures that compute bounding box information */
8019
8020 @ Now we're ready for the key part of the bounding box computation.
8021 The |bound_cubic| procedure updates |bbmin[c]| and |bbmax[c]| based on
8022 $$B(\hbox{|knot_coord(p)|}, \hbox{|right_coord(p)|},
8023     \hbox{|left_coord(q)|}, \hbox{|knot_coord(q)|};t)
8024 $$
8025 for $0<t\le1$.  In other words, the procedure adjusts the bounds to
8026 accommodate |knot_coord(q)| and any extremes over the range $0<t<1$.
8027 The |c| parameter is |x_code| or |y_code|.
8028
8029 @c void mp_bound_cubic (MP mp,pointer p, pointer q, small_number c) {
8030   boolean wavy; /* whether we need to look for extremes */
8031   scaled del1,del2,del3,del,dmax; /* proportional to the control
8032      points of a quadratic derived from a cubic */
8033   fraction t,tt; /* where a quadratic crosses zero */
8034   scaled x; /* a value that |bbmin[c]| and |bbmax[c]| must accommodate */
8035   x=knot_coord(q);
8036   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8037   @<Check the control points against the bounding box and set |wavy:=true|
8038     if any of them lie outside@>;
8039   if ( wavy ) {
8040     del1=right_coord(p)-knot_coord(p);
8041     del2=left_coord(q)-right_coord(p);
8042     del3=knot_coord(q)-left_coord(q);
8043     @<Scale up |del1|, |del2|, and |del3| for greater accuracy;
8044       also set |del| to the first nonzero element of |(del1,del2,del3)|@>;
8045     if ( del<0 ) {
8046       negate(del1); negate(del2); negate(del3);
8047     };
8048     t=mp_crossing_point(mp, del1,del2,del3);
8049     if ( t<fraction_one ) {
8050       @<Test the extremes of the cubic against the bounding box@>;
8051     }
8052   }
8053 }
8054
8055 @ @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>=
8056 if ( x<mp->bbmin[c] ) mp->bbmin[c]=x;
8057 if ( x>mp->bbmax[c] ) mp->bbmax[c]=x
8058
8059 @ @<Check the control points against the bounding box and set...@>=
8060 wavy=true;
8061 if ( mp->bbmin[c]<=right_coord(p) )
8062   if ( right_coord(p)<=mp->bbmax[c] )
8063     if ( mp->bbmin[c]<=left_coord(q) )
8064       if ( left_coord(q)<=mp->bbmax[c] )
8065         wavy=false
8066
8067 @ If |del1=del2=del3=0|, it's impossible to obey the title of this
8068 section. We just set |del=0| in that case.
8069
8070 @<Scale up |del1|, |del2|, and |del3| for greater accuracy...@>=
8071 if ( del1!=0 ) del=del1;
8072 else if ( del2!=0 ) del=del2;
8073 else del=del3;
8074 if ( del!=0 ) {
8075   dmax=abs(del1);
8076   if ( abs(del2)>dmax ) dmax=abs(del2);
8077   if ( abs(del3)>dmax ) dmax=abs(del3);
8078   while ( dmax<fraction_half ) {
8079     dmax+=dmax; del1+=del1; del2+=del2; del3+=del3;
8080   }
8081 }
8082
8083 @ Since |crossing_point| has tried to choose |t| so that
8084 $B(|del1|,|del2|,|del3|;\tau)$ crosses zero at $\tau=|t|$ with negative
8085 slope, the value of |del2| computed below should not be positive.
8086 But rounding error could make it slightly positive in which case we
8087 must cut it to zero to avoid confusion.
8088
8089 @<Test the extremes of the cubic against the bounding box@>=
8090
8091   x=mp_eval_cubic(mp, p,q,t);
8092   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8093   del2=t_of_the_way(del2,del3);
8094     /* now |0,del2,del3| represent the derivative on the remaining interval */
8095   if ( del2>0 ) del2=0;
8096   tt=mp_crossing_point(mp, 0,-del2,-del3);
8097   if ( tt<fraction_one ) {
8098     @<Test the second extreme against the bounding box@>;
8099   }
8100 }
8101
8102 @ @<Test the second extreme against the bounding box@>=
8103 {
8104    x=mp_eval_cubic(mp, p,q,t_of_the_way(tt,fraction_one));
8105   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8106 }
8107
8108 @ Finding the bounding box of a path is basically a matter of applying
8109 |bound_cubic| twice for each pair of adjacent knots.
8110
8111 @c void mp_path_bbox (MP mp,pointer h) {
8112   pointer p,q; /* a pair of adjacent knots */
8113    minx=x_coord(h); miny=y_coord(h);
8114   maxx=minx; maxy=miny;
8115   p=h;
8116   do {  
8117     if ( right_type(p)==mp_endpoint ) return;
8118     q=link(p);
8119     mp_bound_cubic(mp, x_loc(p),x_loc(q),mp_x_code);
8120     mp_bound_cubic(mp, y_loc(p),y_loc(q),mp_y_code);
8121     p=q;
8122   } while (p!=h);
8123 }
8124
8125 @ Another important way to measure a path is to find its arc length.  This
8126 is best done by using the general bisection algorithm to subdivide the path
8127 until obtaining ``well behaved'' subpaths whose arc lengths can be approximated
8128 by simple means.
8129
8130 Since the arc length is the integral with respect to time of the magnitude of
8131 the velocity, it is natural to use Simpson's rule for the approximation.
8132 @^Simpson's rule@>
8133 If $\dot B(t)$ is the spline velocity, Simpson's rule gives
8134 $$ \vb\dot B(0)\vb + 4\vb\dot B({1\over2})\vb + \vb\dot B(1)\vb \over 6 $$
8135 for the arc length of a path of length~1.  For a cubic spline
8136 $B(z_0,z_1,z_2,z_3;t)$, the time derivative $\dot B(t)$ is
8137 $3B(dz_0,dz_1,dz_2;t)$, where $dz_i=z_{i+1}-z_i$.  Hence the arc length
8138 approximation is
8139 $$ {\vb dz_0\vb \over 2} + 2\vb dz_{02}\vb + {\vb dz_2\vb \over 2}, $$
8140 where
8141 $$ dz_{02}={1\over2}\left({dz_0+dz_1\over 2}+{dz_1+dz_2\over 2}\right)$$
8142 is the result of the bisection algorithm.
8143
8144 @ The remaining problem is how to decide when a subpath is ``well behaved.''
8145 This could be done via the theoretical error bound for Simpson's rule,
8146 @^Simpson's rule@>
8147 but this is impractical because it requires an estimate of the fourth
8148 derivative of the quantity being integrated.  It is much easier to just perform
8149 a bisection step and see how much the arc length estimate changes.  Since the
8150 error for Simpson's rule is proportional to the fourth power of the sample
8151 spacing, the remaining error is typically about $1\over16$ of the amount of
8152 the change.  We say ``typically'' because the error has a pseudo-random behavior
8153 that could cause the two estimates to agree when each contain large errors.
8154
8155 To protect against disasters such as undetected cusps, the bisection process
8156 should always continue until all the $dz_i$ vectors belong to a single
8157 $90^\circ$ sector.  This ensures that no point on the spline can have velocity
8158 less than 70\% of the minimum of $\vb dz_0\vb$, $\vb dz_1\vb$ and $\vb dz_2\vb$.
8159 If such a spline happens to produce an erroneous arc length estimate that
8160 is little changed by bisection, the amount of the error is likely to be fairly
8161 small.  We will try to arrange things so that freak accidents of this type do
8162 not destroy the inverse relationship between the \&{arclength} and
8163 \&{arctime} operations.
8164 @:arclength_}{\&{arclength} primitive@>
8165 @:arctime_}{\&{arctime} primitive@>
8166
8167 @ The \&{arclength} and \&{arctime} operations are both based on a recursive
8168 @^recursion@>
8169 function that finds the arc length of a cubic spline given $dz_0$, $dz_1$,
8170 $dz_2$. This |arc_test| routine also takes an arc length goal |a_goal| and
8171 returns the time when the arc length reaches |a_goal| if there is such a time.
8172 Thus the return value is either an arc length less than |a_goal| or, if the
8173 arc length would be at least |a_goal|, it returns a time value decreased by
8174 |two|.  This allows the caller to use the sign of the result to distinguish
8175 between arc lengths and time values.  On certain types of overflow, it is
8176 possible for |a_goal| and the result of |arc_test| both to be |el_gordo|.
8177 Otherwise, the result is always less than |a_goal|.
8178
8179 Rather than halving the control point coordinates on each recursive call to
8180 |arc_test|, it is better to keep them proportional to velocity on the original
8181 curve and halve the results instead.  This means that recursive calls can
8182 potentially use larger error tolerances in their arc length estimates.  How
8183 much larger depends on to what extent the errors behave as though they are
8184 independent of each other.  To save computing time, we use optimistic assumptions
8185 and increase the tolerance by a factor of about $\sqrt2$ for each recursive
8186 call.
8187
8188 In addition to the tolerance parameter, |arc_test| should also have parameters
8189 for ${1\over3}\vb\dot B(0)\vb$, ${2\over3}\vb\dot B({1\over2})\vb$, and
8190 ${1\over3}\vb\dot B(1)\vb$.  These quantities are relatively expensive to compute
8191 and they are needed in different instances of |arc_test|.
8192
8193 @c @t\4@>@<Declare subroutines needed by |arc_test|@>;
8194 scaled mp_arc_test (MP mp, scaled dx0, scaled dy0, scaled dx1, scaled dy1, 
8195                     scaled dx2, scaled dy2, scaled  v0, scaled v02, 
8196                     scaled v2, scaled a_goal, scaled tol) {
8197   boolean simple; /* are the control points confined to a $90^\circ$ sector? */
8198   scaled dx01, dy01, dx12, dy12, dx02, dy02;  /* bisection results */
8199   scaled v002, v022;
8200     /* twice the velocity magnitudes at $t={1\over4}$ and $t={3\over4}$ */
8201   scaled arc; /* best arc length estimate before recursion */
8202   @<Other local variables in |arc_test|@>;
8203   @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,
8204     |dx2|, |dy2|@>;
8205   @<Initialize |v002|, |v022|, and the arc length estimate |arc|; if it overflows
8206     set |arc_test| and |return|@>;
8207   @<Test if the control points are confined to one quadrant or rotating them
8208     $45^\circ$ would put them in one quadrant.  Then set |simple| appropriately@>;
8209   if ( simple && (abs(arc-v02-halfp(v0+v2)) <= tol) ) {
8210     if ( arc < a_goal ) {
8211       return arc;
8212     } else {
8213        @<Estimate when the arc length reaches |a_goal| and set |arc_test| to
8214          that time minus |two|@>;
8215     }
8216   } else {
8217     @<Use one or two recursive calls to compute the |arc_test| function@>;
8218   }
8219 }
8220
8221 @ The |tol| value should by multiplied by $\sqrt 2$ before making recursive
8222 calls, but $1.5$ is an adequate approximation.  It is best to avoid using
8223 |make_fraction| in this inner loop.
8224 @^inner loop@>
8225
8226 @<Use one or two recursive calls to compute the |arc_test| function@>=
8227
8228   @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is as
8229     large as possible@>;
8230   tol = tol + halfp(tol);
8231   a = mp_arc_test(mp, dx0,dy0, dx01,dy01, dx02,dy02, v0, v002, 
8232                   halfp(v02), a_new, tol);
8233   if ( a<0 )  {
8234      return (-halfp(two-a));
8235   } else { 
8236     @<Update |a_new| to reduce |a_new+a_aux| by |a|@>;
8237     b = mp_arc_test(mp, dx02,dy02, dx12,dy12, dx2,dy2,
8238                     halfp(v02), v022, v2, a_new, tol);
8239     if ( b<0 )  
8240       return (-halfp(-b) - half_unit);
8241     else  
8242       return (a + half(b-a));
8243   }
8244 }
8245
8246 @ @<Other local variables in |arc_test|@>=
8247 scaled a,b; /* results of recursive calls */
8248 scaled a_new,a_aux; /* the sum of these gives the |a_goal| */
8249
8250 @ @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is...@>=
8251 a_aux = el_gordo - a_goal;
8252 if ( a_goal > a_aux ) {
8253   a_aux = a_goal - a_aux;
8254   a_new = el_gordo;
8255 } else { 
8256   a_new = a_goal + a_goal;
8257   a_aux = 0;
8258 }
8259
8260 @ There is no need to maintain |a_aux| at this point so we use it as a temporary
8261 to force the additions and subtractions to be done in an order that avoids
8262 overflow.
8263
8264 @<Update |a_new| to reduce |a_new+a_aux| by |a|@>=
8265 if ( a > a_aux ) {
8266   a_aux = a_aux - a;
8267   a_new = a_new + a_aux;
8268 }
8269
8270 @ This code assumes all {\it dx} and {\it dy} variables have magnitude less than
8271 |fraction_four|.  To simplify the rest of the |arc_test| routine, we strengthen
8272 this assumption by requiring the norm of each $({\it dx},{\it dy})$ pair to obey
8273 this bound.  Note that recursive calls will maintain this invariant.
8274
8275 @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,...@>=
8276 dx01 = half(dx0 + dx1);
8277 dx12 = half(dx1 + dx2);
8278 dx02 = half(dx01 + dx12);
8279 dy01 = half(dy0 + dy1);
8280 dy12 = half(dy1 + dy2);
8281 dy02 = half(dy01 + dy12)
8282
8283 @ We should be careful to keep |arc<el_gordo| so that calling |arc_test| with
8284 |a_goal=el_gordo| is guaranteed to yield the arc length.
8285
8286 @<Initialize |v002|, |v022|, and the arc length estimate |arc|;...@>=
8287 v002 = mp_pyth_add(mp, dx01+half(dx0+dx02), dy01+half(dy0+dy02));
8288 v022 = mp_pyth_add(mp, dx12+half(dx02+dx2), dy12+half(dy02+dy2));
8289 tmp = halfp(v02+2);
8290 arc1 = v002 + half(halfp(v0+tmp) - v002);
8291 arc = v022 + half(halfp(v2+tmp) - v022);
8292 if ( (arc < el_gordo-arc1) )  {
8293   arc = arc+arc1;
8294 } else { 
8295   mp->arith_error = true;
8296   if ( a_goal==el_gordo )  return (el_gordo);
8297   else return (-two);
8298 }
8299
8300 @ @<Other local variables in |arc_test|@>=
8301 scaled tmp, tmp2; /* all purpose temporary registers */
8302 scaled arc1; /* arc length estimate for the first half */
8303
8304 @ @<Test if the control points are confined to one quadrant or rotating...@>=
8305 simple = ((dx0>=0) && (dx1>=0) && (dx2>=0)) ||
8306          ((dx0<=0) && (dx1<=0) && (dx2<=0));
8307 if ( simple )
8308   simple = ((dy0>=0) && (dy1>=0) && (dy2>=0)) ||
8309            ((dy0<=0) && (dy1<=0) && (dy2<=0));
8310 if ( ! simple ) {
8311   simple = ((dx0>=dy0) && (dx1>=dy1) && (dx2>=dy2)) ||
8312            ((dx0<=dy0) && (dx1<=dy1) && (dx2<=dy2));
8313   if ( simple ) 
8314     simple = ((-dx0>=dy0) && (-dx1>=dy1) && (-dx2>=dy2)) ||
8315              ((-dx0<=dy0) && (-dx1<=dy1) && (-dx2<=dy2));
8316 }
8317
8318 @ Since Simpson's rule is based on approximating the integrand by a parabola,
8319 @^Simpson's rule@>
8320 it is appropriate to use the same approximation to decide when the integral
8321 reaches the intermediate value |a_goal|.  At this point
8322 $$\eqalign{
8323     {\vb\dot B(0)\vb\over 3} &= \hbox{|v0|}, \qquad
8324     {\vb\dot B({1\over4})\vb\over 3} = {\hbox{|v002|}\over 2}, \qquad
8325     {\vb\dot B({1\over2})\vb\over 3} = {\hbox{|v02|}\over 2}, \cr
8326     {\vb\dot B({3\over4})\vb\over 3} &= {\hbox{|v022|}\over 2}, \qquad
8327     {\vb\dot B(1)\vb\over 3} = \hbox{|v2|} \cr
8328 }
8329 $$
8330 and
8331 $$ {\vb\dot B(t)\vb\over 3} \approx
8332   \cases{B\left(\hbox{|v0|},
8333       \hbox{|v002|}-{1\over 2}\hbox{|v0|}-{1\over 4}\hbox{|v02|},
8334       {1\over 2}\hbox{|v02|}; 2t \right)&
8335     if $t\le{1\over 2}$\cr
8336   B\left({1\over 2}\hbox{|v02|},
8337       \hbox{|v022|}-{1\over 4}\hbox{|v02|}-{1\over 2}\hbox{|v2|},
8338       \hbox{|v2|}; 2t-1 \right)&
8339     if $t\ge{1\over 2}$.\cr}
8340  \eqno (*)
8341 $$
8342 We can integrate $\vb\dot B(t)\vb$ by using
8343 $$\int 3B(a,b,c;\tau)\,dt =
8344   {B(0,a,a+b,a+b+c;\tau) + {\rm constant} \over {d\tau\over dt}}.
8345 $$
8346
8347 This construction allows us to find the time when the arc length reaches
8348 |a_goal| by solving a cubic equation of the form
8349 $$ B(0,a,a+b,a+b+c;\tau) = x, $$
8350 where $\tau$ is $2t$ or $2t+1$, $x$ is |a_goal| or |a_goal-arc1|, and $a$, $b$,
8351 and $c$ are the Bernshte{\u\i}n coefficients from $(*)$ divided by
8352 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
8353 $d\tau\over dt$.  We shall define a function |solve_rising_cubic| that finds
8354 $\tau$ given $a$, $b$, $c$, and $x$.
8355
8356 @<Estimate when the arc length reaches |a_goal| and set |arc_test| to...@>=
8357
8358   tmp = (v02 + 2) / 4;
8359   if ( a_goal<=arc1 ) {
8360     tmp2 = halfp(v0);
8361     return 
8362       (halfp(mp_solve_rising_cubic(mp, tmp2, arc1-tmp2-tmp, tmp, a_goal))- two);
8363   } else { 
8364     tmp2 = halfp(v2);
8365     return ((half_unit - two) +
8366       halfp(mp_solve_rising_cubic(mp, tmp, arc-arc1-tmp-tmp2, tmp2, a_goal-arc1)));
8367   }
8368 }
8369
8370 @ Here is the |solve_rising_cubic| routine that finds the time~$t$ when
8371 $$ B(0, a, a+b, a+b+c; t) = x. $$
8372 This routine is based on |crossing_point| but is simplified by the
8373 assumptions that $B(a,b,c;t)\ge0$ for $0\le t\le1$ and that |0<=x<=a+b+c|.
8374 If rounding error causes this condition to be violated slightly, we just ignore
8375 it and proceed with binary search.  This finds a time when the function value
8376 reaches |x| and the slope is positive.
8377
8378 @<Declare subroutines needed by |arc_test|@>=
8379 scaled mp_solve_rising_cubic (MP mp,scaled a, scaled b,  scaled c, scaled x) {
8380   scaled ab, bc, ac; /* bisection results */
8381   integer t; /* $2^k+q$ where unscaled answer is in $[q2^{-k},(q+1)2^{-k})$ */
8382   integer xx; /* temporary for updating |x| */
8383   if ( (a<0) || (c<0) ) mp_confusion(mp, "rising?");
8384 @:this can't happen rising?}{\quad rising?@>
8385   if ( x<=0 ) {
8386         return 0;
8387   } else if ( x >= a+b+c ) {
8388     return unity;
8389   } else { 
8390     t = 1;
8391     @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than
8392       |el_gordo div 3|@>;
8393     do {  
8394       t+=t;
8395       @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>;
8396       xx = x - a - ab - ac;
8397       if ( xx < -x ) { x+=x; b=ab; c=ac;  }
8398       else { x = x + xx;  a=ac; b=mp->bc; t = t+1; };
8399     } while (t < unity);
8400     return (t - unity);
8401   }
8402 }
8403
8404 @ @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>=
8405 ab = half(a+b);
8406 bc = half(b+c);
8407 ac = half(ab+bc)
8408
8409 @ @d one_third_el_gordo 05252525252 /* upper bound on |a|, |b|, and |c| */
8410
8411 @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than...@>=
8412 while ((a>one_third_el_gordo)||(b>one_third_el_gordo)||(c>one_third_el_gordo)) { 
8413   a = halfp(a);
8414   b = half(b);
8415   c = halfp(c);
8416   x = halfp(x);
8417 }
8418
8419 @ It is convenient to have a simpler interface to |arc_test| that requires no
8420 unnecessary arguments and ensures that each $({\it dx},{\it dy})$ pair has
8421 length less than |fraction_four|.
8422
8423 @d arc_tol   16  /* quit when change in arc length estimate reaches this */
8424
8425 @c scaled mp_do_arc_test (MP mp,scaled dx0, scaled dy0, scaled dx1, 
8426                           scaled dy1, scaled dx2, scaled dy2, scaled a_goal) {
8427   scaled v0,v1,v2; /* length of each $({\it dx},{\it dy})$ pair */
8428   scaled v02; /* twice the norm of the quadratic at $t={1\over2}$ */
8429   v0 = mp_pyth_add(mp, dx0,dy0);
8430   v1 = mp_pyth_add(mp, dx1,dy1);
8431   v2 = mp_pyth_add(mp, dx2,dy2);
8432   if ( (v0>=fraction_four) || (v1>=fraction_four) || (v2>=fraction_four) ) { 
8433     mp->arith_error = true;
8434     if ( a_goal==el_gordo )  return el_gordo;
8435     else return (-two);
8436   } else { 
8437     v02 = mp_pyth_add(mp, dx1+half(dx0+dx2), dy1+half(dy0+dy2));
8438     return (mp_arc_test(mp, dx0,dy0, dx1,dy1, dx2,dy2,
8439                                  v0, v02, v2, a_goal, arc_tol));
8440   }
8441 }
8442
8443 @ Now it is easy to find the arc length of an entire path.
8444
8445 @c scaled mp_get_arc_length (MP mp,pointer h) {
8446   pointer p,q; /* for traversing the path */
8447   scaled a,a_tot; /* current and total arc lengths */
8448   a_tot = 0;
8449   p = h;
8450   while ( right_type(p)!=mp_endpoint ){ 
8451     q = link(p);
8452     a = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8453       left_x(q)-right_x(p), left_y(q)-right_y(p),
8454       x_coord(q)-left_x(q), y_coord(q)-left_y(q), el_gordo);
8455     a_tot = mp_slow_add(mp, a, a_tot);
8456     if ( q==h ) break;  else p=q;
8457   }
8458   check_arith;
8459   return a_tot;
8460 }
8461
8462 @ The inverse operation of finding the time on a path~|h| when the arc length
8463 reaches some value |arc0| can also be accomplished via |do_arc_test|.  Some care
8464 is required to handle very large times or negative times on cyclic paths.  For
8465 non-cyclic paths, |arc0| values that are negative or too large cause
8466 |get_arc_time| to return 0 or the length of path~|h|.
8467
8468 If |arc0| is greater than the arc length of a cyclic path~|h|, the result is a
8469 time value greater than the length of the path.  Since it could be much greater,
8470 we must be prepared to compute the arc length of path~|h| and divide this into
8471 |arc0| to find how many multiples of the length of path~|h| to add.
8472
8473 @c scaled mp_get_arc_time (MP mp,pointer h, scaled  arc0) {
8474   pointer p,q; /* for traversing the path */
8475   scaled t_tot; /* accumulator for the result */
8476   scaled t; /* the result of |do_arc_test| */
8477   scaled arc; /* portion of |arc0| not used up so far */
8478   integer n; /* number of extra times to go around the cycle */
8479   if ( arc0<0 ) {
8480     @<Deal with a negative |arc0| value and |return|@>;
8481   }
8482   if ( arc0==el_gordo ) decr(arc0);
8483   t_tot = 0;
8484   arc = arc0;
8485   p = h;
8486   while ( (right_type(p)!=mp_endpoint) && (arc>0) ) {
8487     q = link(p);
8488     t = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8489       left_x(q)-right_x(p), left_y(q)-right_y(p),
8490       x_coord(q)-left_x(q), y_coord(q)-left_y(q), arc);
8491     @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>;
8492     if ( q==h ) {
8493       @<Update |t_tot| and |arc| to avoid going around the cyclic
8494         path too many times but set |arith_error:=true| and |goto done| on
8495         overflow@>;
8496     }
8497     p = q;
8498   }
8499   check_arith;
8500   return t_tot;
8501 }
8502
8503 @ @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>=
8504 if ( t<0 ) { t_tot = t_tot + t + two;  arc = 0;  }
8505 else { t_tot = t_tot + unity;  arc = arc - t;  }
8506
8507 @ @<Deal with a negative |arc0| value and |return|@>=
8508
8509   if ( left_type(h)==mp_endpoint ) {
8510     t_tot=0;
8511   } else { 
8512     p = mp_htap_ypoc(mp, h);
8513     t_tot = -mp_get_arc_time(mp, p, -arc0);
8514     mp_toss_knot_list(mp, p);
8515   }
8516   check_arith;
8517   return t_tot;
8518 }
8519
8520 @ @<Update |t_tot| and |arc| to avoid going around the cyclic...@>=
8521 if ( arc>0 ) { 
8522   n = arc / (arc0 - arc);
8523   arc = arc - n*(arc0 - arc);
8524   if ( t_tot > el_gordo / (n+1) ) { 
8525     mp->arith_error = true;
8526     t_tot = el_gordo;
8527     break;
8528   }
8529   t_tot = (n + 1)*t_tot;
8530 }
8531
8532 @* \[20] Data structures for pens.
8533 A Pen in \MP\ can be either elliptical or polygonal.  Elliptical pens result
8534 in \ps\ \&{stroke} commands, while anything drawn with a polygonal pen is
8535 @:stroke}{\&{stroke} command@>
8536 converted into an area fill as described in the next part of this program.
8537 The mathematics behind this process is based on simple aspects of the theory
8538 of tracings developed by Leo Guibas, Lyle Ramshaw, and Jorge Stolfi
8539 [``A kinematic framework for computational geometry,'' Proc.\ IEEE Symp.\
8540 Foundations of Computer Science {\bf 24} (1983), 100--111].
8541
8542 Polygonal pens are created from paths via \MP's \&{makepen} primitive.
8543 @:makepen_}{\&{makepen} primitive@>
8544 This path representation is almost sufficient for our purposes except that
8545 a pen path should always be a convex polygon with the vertices in
8546 counter-clockwise order.
8547 Since we will need to scan pen polygons both forward and backward, a pen
8548 should be represented as a doubly linked ring of knot nodes.  There is
8549 room for the extra back pointer because we do not need the
8550 |left_type| or |right_type| fields.  In fact, we don't need the |left_x|,
8551 |left_y|, |right_x|, or |right_y| fields either but we leave these alone
8552 so that certain procedures can operate on both pens and paths.  In particular,
8553 pens can be copied using |copy_path| and recycled using |toss_knot_list|.
8554
8555 @d knil info
8556   /* this replaces the |left_type| and |right_type| fields in a pen knot */
8557
8558 @ The |make_pen| procedure turns a path into a pen by initializing
8559 the |knil| pointers and making sure the knots form a convex polygon.
8560 Thus each cubic in the given path becomes a straight line and the control
8561 points are ignored.  If the path is not cyclic, the ends are connected by a
8562 straight line.
8563
8564 @d copy_pen(A) mp_make_pen(mp, mp_copy_path(mp, (A)),false)
8565
8566 @c @<Declare a function called |convex_hull|@>;
8567 pointer mp_make_pen (MP mp,pointer h, boolean need_hull) {
8568   pointer p,q; /* two consecutive knots */
8569   q=h;
8570   do {  
8571     p=q; q=link(q);
8572     knil(q)=p;
8573   } while (q!=h);
8574   if ( need_hull ){ 
8575     h=mp_convex_hull(mp, h);
8576     @<Make sure |h| isn't confused with an elliptical pen@>;
8577   }
8578   return h;
8579 }
8580
8581 @ The only information required about an elliptical pen is the overall
8582 transformation that has been applied to the original \&{pencircle}.
8583 @:pencircle_}{\&{pencircle} primitive@>
8584 Since it suffices to keep track of how the three points $(0,0)$, $(1,0)$,
8585 and $(0,1)$ are transformed, an elliptical pen can be stored in a single
8586 knot node and transformed as if it were a path.
8587
8588 @d pen_is_elliptical(A) ((A)==link((A)))
8589
8590 @c pointer mp_get_pen_circle (MP mp,scaled diam) {
8591   pointer h; /* the knot node to return */
8592   h=mp_get_node(mp, knot_node_size);
8593   link(h)=h; knil(h)=h;
8594   originator(h)=mp_program_code;
8595   x_coord(h)=0; y_coord(h)=0;
8596   left_x(h)=diam; left_y(h)=0;
8597   right_x(h)=0; right_y(h)=diam;
8598   return h;
8599 }
8600
8601 @ If the polygon being returned by |make_pen| has only one vertex, it will
8602 be interpreted as an elliptical pen.  This is no problem since a degenerate
8603 polygon can equally well be thought of as a degenerate ellipse.  We need only
8604 initialize the |left_x|, |left_y|, |right_x|, and |right_y| fields.
8605
8606 @<Make sure |h| isn't confused with an elliptical pen@>=
8607 if ( pen_is_elliptical( h) ){ 
8608   left_x(h)=x_coord(h); left_y(h)=y_coord(h);
8609   right_x(h)=x_coord(h); right_y(h)=y_coord(h);
8610 }
8611
8612 @ We have to cheat a little here but most operations on pens only use
8613 the first three words in each knot node.
8614 @^data structure assumptions@>
8615
8616 @<Initialize a pen at |test_pen| so that it fits in nine words@>=
8617 x_coord(test_pen)=-half_unit;
8618 y_coord(test_pen)=0;
8619 x_coord(test_pen+3)=half_unit;
8620 y_coord(test_pen+3)=0;
8621 x_coord(test_pen+6)=0;
8622 y_coord(test_pen+6)=unity;
8623 link(test_pen)=test_pen+3;
8624 link(test_pen+3)=test_pen+6;
8625 link(test_pen+6)=test_pen;
8626 knil(test_pen)=test_pen+6;
8627 knil(test_pen+3)=test_pen;
8628 knil(test_pen+6)=test_pen+3
8629
8630 @ Printing a polygonal pen is very much like printing a path
8631
8632 @<Declare subroutines for printing expressions@>=
8633 void mp_pr_pen (MP mp,pointer h) {
8634   pointer p,q; /* for list traversal */
8635   if ( pen_is_elliptical(h) ) {
8636     @<Print the elliptical pen |h|@>;
8637   } else { 
8638     p=h;
8639     do {  
8640       mp_print_two(mp, x_coord(p),y_coord(p));
8641       mp_print_nl(mp, " .. ");
8642       @<Advance |p| making sure the links are OK and |return| if there is
8643         a problem@>;
8644      } while (p!=h);
8645      mp_print(mp, "cycle");
8646   }
8647 }
8648
8649 @ @<Advance |p| making sure the links are OK and |return| if there is...@>=
8650 q=link(p);
8651 if ( (q==null) || (knil(q)!=p) ) { 
8652   mp_print_nl(mp, "???"); return; /* this won't happen */
8653 @.???@>
8654 }
8655 p=q
8656
8657 @ @<Print the elliptical pen |h|@>=
8658
8659 mp_print(mp, "pencircle transformed (");
8660 mp_print_scaled(mp, x_coord(h));
8661 mp_print_char(mp, ',');
8662 mp_print_scaled(mp, y_coord(h));
8663 mp_print_char(mp, ',');
8664 mp_print_scaled(mp, left_x(h)-x_coord(h));
8665 mp_print_char(mp, ',');
8666 mp_print_scaled(mp, right_x(h)-x_coord(h));
8667 mp_print_char(mp, ',');
8668 mp_print_scaled(mp, left_y(h)-y_coord(h));
8669 mp_print_char(mp, ',');
8670 mp_print_scaled(mp, right_y(h)-y_coord(h));
8671 mp_print_char(mp, ')');
8672 }
8673
8674 @ Here us another version of |pr_pen| that prints the pen as a diagnostic
8675 message.
8676
8677 @<Declare subroutines for printing expressions@>=
8678 void mp_print_pen (MP mp,pointer h, char *s, boolean nuline) { 
8679   mp_print_diagnostic(mp, "Pen",s,nuline); mp_print_ln(mp);
8680 @.Pen at line...@>
8681   mp_pr_pen(mp, h);
8682   mp_end_diagnostic(mp, true);
8683 }
8684
8685 @ Making a polygonal pen into a path involves restoring the |left_type| and
8686 |right_type| fields and setting the control points so as to make a polygonal
8687 path.
8688
8689 @c 
8690 void mp_make_path (MP mp,pointer h) {
8691   pointer p; /* for traversing the knot list */
8692   small_number k; /* a loop counter */
8693   @<Other local variables in |make_path|@>;
8694   if ( pen_is_elliptical(h) ) {
8695     @<Make the elliptical pen |h| into a path@>;
8696   } else { 
8697     p=h;
8698     do {  
8699       left_type(p)=mp_explicit;
8700       right_type(p)=mp_explicit;
8701       @<copy the coordinates of knot |p| into its control points@>;
8702        p=link(p);
8703     } while (p!=h);
8704   }
8705 }
8706
8707 @ @<copy the coordinates of knot |p| into its control points@>=
8708 left_x(p)=x_coord(p);
8709 left_y(p)=y_coord(p);
8710 right_x(p)=x_coord(p);
8711 right_y(p)=y_coord(p)
8712
8713 @ We need an eight knot path to get a good approximation to an ellipse.
8714
8715 @<Make the elliptical pen |h| into a path@>=
8716
8717   @<Extract the transformation parameters from the elliptical pen~|h|@>;
8718   p=h;
8719   for (k=0;k<=7;k++ ) { 
8720     @<Initialize |p| as the |k|th knot of a circle of unit diameter,
8721       transforming it appropriately@>;
8722     if ( k==7 ) link(p)=h;  else link(p)=mp_get_node(mp, knot_node_size);
8723     p=link(p);
8724   }
8725 }
8726
8727 @ @<Extract the transformation parameters from the elliptical pen~|h|@>=
8728 center_x=x_coord(h);
8729 center_y=y_coord(h);
8730 width_x=left_x(h)-center_x;
8731 width_y=left_y(h)-center_y;
8732 height_x=right_x(h)-center_x;
8733 height_y=right_y(h)-center_y
8734
8735 @ @<Other local variables in |make_path|@>=
8736 scaled center_x,center_y; /* translation parameters for an elliptical pen */
8737 scaled width_x,width_y; /* the effect of a unit change in $x$ */
8738 scaled height_x,height_y; /* the effect of a unit change in $y$ */
8739 scaled dx,dy; /* the vector from knot |p| to its right control point */
8740 integer kk;
8741   /* |k| advanced $270^\circ$ around the ring (cf. $\sin\theta=\cos(\theta+270)$) */
8742
8743 @ The only tricky thing here are the tables |half_cos| and |d_cos| used to
8744 find the point $k/8$ of the way around the circle and the direction vector
8745 to use there.
8746
8747 @<Initialize |p| as the |k|th knot of a circle of unit diameter,...@>=
8748 kk=(k+6)% 8;
8749 x_coord(p)=center_x+mp_take_fraction(mp, mp->half_cos[k],width_x)
8750            +mp_take_fraction(mp, mp->half_cos[kk],height_x);
8751 y_coord(p)=center_y+mp_take_fraction(mp, mp->half_cos[k],width_y)
8752            +mp_take_fraction(mp, mp->half_cos[kk],height_y);
8753 dx=-mp_take_fraction(mp, mp->d_cos[kk],width_x)
8754    +mp_take_fraction(mp, mp->d_cos[k],height_x);
8755 dy=-mp_take_fraction(mp, mp->d_cos[kk],width_y)
8756    +mp_take_fraction(mp, mp->d_cos[k],height_y);
8757 right_x(p)=x_coord(p)+dx;
8758 right_y(p)=y_coord(p)+dy;
8759 left_x(p)=x_coord(p)-dx;
8760 left_y(p)=y_coord(p)-dy;
8761 left_type(p)=mp_explicit;
8762 right_type(p)=mp_explicit;
8763 originator(p)=mp_program_code
8764
8765 @ @<Glob...@>=
8766 fraction half_cos[8]; /* ${1\over2}\cos(45k)$ */
8767 fraction d_cos[8]; /* a magic constant times $\cos(45k)$ */
8768
8769 @ The magic constant for |d_cos| is the distance between $({1\over2},0)$ and
8770 $({1\over4}\sqrt2,{1\over4}\sqrt2)$ times the result of the |velocity|
8771 function for $\theta=\phi=22.5^\circ$.  This comes out to be
8772 $$ d = {\sqrt{2-\sqrt2}\over 3+3\cos22.5^\circ}
8773   \approx 0.132608244919772.
8774 $$
8775
8776 @<Set init...@>=
8777 mp->half_cos[0]=fraction_half;
8778 mp->half_cos[1]=94906266; /* $2^{26}\sqrt2\approx94906265.62$ */
8779 mp->half_cos[2]=0;
8780 mp->d_cos[0]=35596755; /* $2^{28}d\approx35596754.69$ */
8781 mp->d_cos[1]=25170707; /* $2^{27}\sqrt2\,d\approx25170706.63$ */
8782 mp->d_cos[2]=0;
8783 for (k=3;k<= 4;k++ ) { 
8784   mp->half_cos[k]=-mp->half_cos[4-k];
8785   mp->d_cos[k]=-mp->d_cos[4-k];
8786 }
8787 for (k=5;k<= 7;k++ ) { 
8788   mp->half_cos[k]=mp->half_cos[8-k];
8789   mp->d_cos[k]=mp->d_cos[8-k];
8790 }
8791
8792 @ The |convex_hull| function forces a pen polygon to be convex when it is
8793 returned by |make_pen| and after any subsequent transformation where rounding
8794 error might allow the convexity to be lost.
8795 The convex hull algorithm used here is described by F.~P. Preparata and
8796 M.~I. Shamos [{\sl Computational Geometry}, Springer-Verlag, 1985].
8797
8798 @<Declare a function called |convex_hull|@>=
8799 @<Declare a procedure called |move_knot|@>;
8800 pointer mp_convex_hull (MP mp,pointer h) { /* Make a polygonal pen convex */
8801   pointer l,r; /* the leftmost and rightmost knots */
8802   pointer p,q; /* knots being scanned */
8803   pointer s; /* the starting point for an upcoming scan */
8804   scaled dx,dy; /* a temporary pointer */
8805   if ( pen_is_elliptical(h) ) {
8806      return h;
8807   } else { 
8808     @<Set |l| to the leftmost knot in polygon~|h|@>;
8809     @<Set |r| to the rightmost knot in polygon~|h|@>;
8810     if ( l!=r ) { 
8811       s=link(r);
8812       @<Find any knots on the path from |l| to |r| above the |l|-|r| line and
8813         move them past~|r|@>;
8814       @<Find any knots on the path from |s| to |l| below the |l|-|r| line and
8815         move them past~|l|@>;
8816       @<Sort the path from |l| to |r| by increasing $x$@>;
8817       @<Sort the path from |r| to |l| by decreasing $x$@>;
8818     }
8819     if ( l!=link(l) ) {
8820       @<Do a Gramm scan and remove vertices where there is no left turn@>;
8821     }
8822     return l;
8823   }
8824 }
8825
8826 @ All comparisons are done primarily on $x$ and secondarily on $y$.
8827
8828 @<Set |l| to the leftmost knot in polygon~|h|@>=
8829 l=h;
8830 p=link(h);
8831 while ( p!=h ) { 
8832   if ( x_coord(p)<=x_coord(l) )
8833     if ( (x_coord(p)<x_coord(l)) || (y_coord(p)<y_coord(l)) )
8834       l=p;
8835   p=link(p);
8836 }
8837
8838 @ @<Set |r| to the rightmost knot in polygon~|h|@>=
8839 r=h;
8840 p=link(h);
8841 while ( p!=h ) { 
8842   if ( x_coord(p)>=x_coord(r) )
8843     if ( (x_coord(p)>x_coord(r)) || (y_coord(p)>y_coord(r)) )
8844       r=p;
8845   p=link(p);
8846 }
8847
8848 @ @<Find any knots on the path from |l| to |r| above the |l|-|r| line...@>=
8849 dx=x_coord(r)-x_coord(l);
8850 dy=y_coord(r)-y_coord(l);
8851 p=link(l);
8852 while ( p!=r ) { 
8853   q=link(p);
8854   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))>0 )
8855     mp_move_knot(mp, p, r);
8856   p=q;
8857 }
8858
8859 @ The |move_knot| procedure removes |p| from a doubly linked list and inserts
8860 it after |q|.
8861
8862 @ @<Declare a procedure called |move_knot|@>=
8863 void mp_move_knot (MP mp,pointer p, pointer q) { 
8864   link(knil(p))=link(p);
8865   knil(link(p))=knil(p);
8866   knil(p)=q;
8867   link(p)=link(q);
8868   link(q)=p;
8869   knil(link(p))=p;
8870 }
8871
8872 @ @<Find any knots on the path from |s| to |l| below the |l|-|r| line...@>=
8873 p=s;
8874 while ( p!=l ) { 
8875   q=link(p);
8876   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))<0 )
8877     mp_move_knot(mp, p,l);
8878   p=q;
8879 }
8880
8881 @ The list is likely to be in order already so we just do linear insertions.
8882 Secondary comparisons on $y$ ensure that the sort is consistent with the
8883 choice of |l| and |r|.
8884
8885 @<Sort the path from |l| to |r| by increasing $x$@>=
8886 p=link(l);
8887 while ( p!=r ) { 
8888   q=knil(p);
8889   while ( x_coord(q)>x_coord(p) ) q=knil(q);
8890   while ( x_coord(q)==x_coord(p) ) {
8891     if ( y_coord(q)>y_coord(p) ) q=knil(q); else break;
8892   }
8893   if ( q==knil(p) ) p=link(p);
8894   else { p=link(p); mp_move_knot(mp, knil(p),q); };
8895 }
8896
8897 @ @<Sort the path from |r| to |l| by decreasing $x$@>=
8898 p=link(r);
8899 while ( p!=l ){ 
8900   q=knil(p);
8901   while ( x_coord(q)<x_coord(p) ) q=knil(q);
8902   while ( x_coord(q)==x_coord(p) ) {
8903     if ( y_coord(q)<y_coord(p) ) q=knil(q); else break;
8904   }
8905   if ( q==knil(p) ) p=link(p);
8906   else { p=link(p); mp_move_knot(mp, knil(p),q); };
8907 }
8908
8909 @ The condition involving |ab_vs_cd| tests if there is not a left turn
8910 at knot |q|.  There usually will be a left turn so we streamline the case
8911 where the |then| clause is not executed.
8912
8913 @<Do a Gramm scan and remove vertices where there...@>=
8914
8915 p=l; q=link(l);
8916 while (1) { 
8917   dx=x_coord(q)-x_coord(p);
8918   dy=y_coord(q)-y_coord(p);
8919   p=q; q=link(q);
8920   if ( p==l ) break;
8921   if ( p!=r )
8922     if ( mp_ab_vs_cd(mp, dx,y_coord(q)-y_coord(p),dy,x_coord(q)-x_coord(p))<=0 ) {
8923       @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>;
8924     }
8925   }
8926 }
8927
8928 @ @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>=
8929
8930 s=knil(p);
8931 mp_free_node(mp, p,knot_node_size);
8932 link(s)=q; knil(q)=s;
8933 if ( s==l ) p=s;
8934 else { p=knil(s); q=s; };
8935 }
8936
8937 @ The |find_offset| procedure sets global variables |(cur_x,cur_y)| to the
8938 offset associated with the given direction |(x,y)|.  If two different offsets
8939 apply, it chooses one of them.
8940
8941 @c 
8942 void mp_find_offset (MP mp,scaled x, scaled y, pointer h) {
8943   pointer p,q; /* consecutive knots */
8944   scaled wx,wy,hx,hy;
8945   /* the transformation matrix for an elliptical pen */
8946   fraction xx,yy; /* untransformed offset for an elliptical pen */
8947   fraction d; /* a temporary register */
8948   if ( pen_is_elliptical(h) ) {
8949     @<Find the offset for |(x,y)| on the elliptical pen~|h|@>
8950   } else { 
8951     q=h;
8952     do {  
8953       p=q; q=link(q);
8954     } while (!(mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)>=0));
8955     do {  
8956       p=q; q=link(q);
8957     } while (!(mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)<=0));
8958     mp->cur_x=x_coord(p);
8959     mp->cur_y=y_coord(p);
8960   }
8961 }
8962
8963 @ @<Glob...@>=
8964 scaled cur_x;
8965 scaled cur_y; /* all-purpose return value registers */
8966
8967 @ @<Find the offset for |(x,y)| on the elliptical pen~|h|@>=
8968 if ( (x==0) && (y==0) ) {
8969   mp->cur_x=x_coord(h); mp->cur_y=y_coord(h);  
8970 } else { 
8971   @<Find the non-constant part of the transformation for |h|@>;
8972   while ( (abs(x)<fraction_half) && (abs(y)<fraction_half) ){ 
8973     x+=x; y+=y;  
8974   };
8975   @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the
8976     untransformed version of |(x,y)|@>;
8977   mp->cur_x=x_coord(h)+mp_take_fraction(mp, xx,wx)+mp_take_fraction(mp, yy,hx);
8978   mp->cur_y=y_coord(h)+mp_take_fraction(mp, xx,wy)+mp_take_fraction(mp, yy,hy);
8979 }
8980
8981 @ @<Find the non-constant part of the transformation for |h|@>=
8982 wx=left_x(h)-x_coord(h);
8983 wy=left_y(h)-y_coord(h);
8984 hx=right_x(h)-x_coord(h);
8985 hy=right_y(h)-y_coord(h)
8986
8987 @ @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the...@>=
8988 yy=-(mp_take_fraction(mp, x,hy)+mp_take_fraction(mp, y,-hx));
8989 xx=mp_take_fraction(mp, x,-wy)+mp_take_fraction(mp, y,wx);
8990 d=mp_pyth_add(mp, xx,yy);
8991 if ( d>0 ) { 
8992   xx=half(mp_make_fraction(mp, xx,d));
8993   yy=half(mp_make_fraction(mp, yy,d));
8994 }
8995
8996 @ Finding the bounding box of a pen is easy except if the pen is elliptical.
8997 But we can handle that case by just calling |find_offset| twice.  The answer
8998 is stored in the global variables |minx|, |maxx|, |miny|, and |maxy|.
8999
9000 @c 
9001 void mp_pen_bbox (MP mp,pointer h) {
9002   pointer p; /* for scanning the knot list */
9003   if ( pen_is_elliptical(h) ) {
9004     @<Find the bounding box of an elliptical pen@>;
9005   } else { 
9006     minx=x_coord(h); maxx=minx;
9007     miny=y_coord(h); maxy=miny;
9008     p=link(h);
9009     while ( p!=h ) {
9010       if ( x_coord(p)<minx ) minx=x_coord(p);
9011       if ( y_coord(p)<miny ) miny=y_coord(p);
9012       if ( x_coord(p)>maxx ) maxx=x_coord(p);
9013       if ( y_coord(p)>maxy ) maxy=y_coord(p);
9014       p=link(p);
9015     }
9016   }
9017 }
9018
9019 @ @<Find the bounding box of an elliptical pen@>=
9020
9021 mp_find_offset(mp, 0,fraction_one,h);
9022 maxx=mp->cur_x;
9023 minx=2*x_coord(h)-mp->cur_x;
9024 mp_find_offset(mp, -fraction_one,0,h);
9025 maxy=mp->cur_y;
9026 miny=2*y_coord(h)-mp->cur_y;
9027 }
9028
9029 @* \[21] Edge structures.
9030 Now we come to \MP's internal scheme for representing pictures.
9031 The representation is very different from \MF's edge structures
9032 because \MP\ pictures contain \ps\ graphics objects instead of pixel
9033 images.  However, the basic idea is somewhat similar in that shapes
9034 are represented via their boundaries.
9035
9036 The main purpose of edge structures is to keep track of graphical objects
9037 until it is time to translate them into \ps.  Since \MP\ does not need to
9038 know anything about an edge structure other than how to translate it into
9039 \ps\ and how to find its bounding box, edge structures can be just linked
9040 lists of graphical objects.  \MP\ has no easy way to determine whether
9041 two such objects overlap, but it suffices to draw the first one first and
9042 let the second one overwrite it if necessary.
9043
9044 @<Types...@>=
9045 enum mp_graphical_object_code {
9046   @<Graphical object codes@>
9047 };
9048
9049 @ Let's consider the types of graphical objects one at a time.
9050 First of all, a filled contour is represented by a eight-word node.  The first
9051 word contains |type| and |link| fields, and the next six words contain a
9052 pointer to a cyclic path and the value to use for \ps' \&{currentrgbcolor}
9053 parameter.  If a pen is used for filling |pen_p|, |ljoin_val| and |miterlim_val|
9054 give the relevant information.
9055
9056 @d path_p(A) link((A)+1)
9057   /* a pointer to the path that needs filling */
9058 @d pen_p(A) info((A)+1)
9059   /* a pointer to the pen to fill or stroke with */
9060 @d color_model(A) type((A)+2) /*  the color model  */
9061 @d obj_red_loc(A) ((A)+3)  /* the first of three locations for the color */
9062 @d obj_cyan_loc obj_red_loc  /* the first of four locations for the color */
9063 @d obj_grey_loc obj_red_loc  /* the location for the color */
9064 @d red_val(A) mp->mem[(A)+3].sc
9065   /* the red component of the color in the range $0\ldots1$ */
9066 @d cyan_val red_val
9067 @d grey_val red_val
9068 @d green_val(A) mp->mem[(A)+4].sc
9069   /* the green component of the color in the range $0\ldots1$ */
9070 @d magenta_val green_val
9071 @d blue_val(A) mp->mem[(A)+5].sc
9072   /* the blue component of the color in the range $0\ldots1$ */
9073 @d yellow_val blue_val
9074 @d black_val(A) mp->mem[(A)+6].sc
9075   /* the blue component of the color in the range $0\ldots1$ */
9076 @d ljoin_val(A) name_type((A))  /* the value of \&{linejoin} */
9077 @:mp_linejoin_}{\&{linejoin} primitive@>
9078 @d miterlim_val(A) mp->mem[(A)+7].sc  /* the value of \&{miterlimit} */
9079 @:mp_miterlimit_}{\&{miterlimit} primitive@>
9080 @d obj_color_part(A) mp->mem[(A)+3-red_part].sc
9081   /* interpret an object pointer that has been offset by |red_part..blue_part| */
9082 @d pre_script(A) mp->mem[(A)+8].hh.lh
9083 @d post_script(A) mp->mem[(A)+8].hh.rh
9084 @d fill_node_size 9
9085
9086 @ @<Graphical object codes@>=
9087 mp_fill_code=1,
9088
9089 @ @c 
9090 pointer mp_new_fill_node (MP mp,pointer p) {
9091   /* make a fill node for cyclic path |p| and color black */
9092   pointer t; /* the new node */
9093   t=mp_get_node(mp, fill_node_size);
9094   type(t)=mp_fill_code;
9095   path_p(t)=p;
9096   pen_p(t)=null; /* |null| means don't use a pen */
9097   red_val(t)=0;
9098   green_val(t)=0;
9099   blue_val(t)=0;
9100   black_val(t)=0;
9101   color_model(t)=mp_uninitialized_model;
9102   pre_script(t)=null;
9103   post_script(t)=null;
9104   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9105   return t;
9106 }
9107
9108 @ @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>=
9109 if ( mp->internal[mp_linejoin]>unity ) ljoin_val(t)=2;
9110 else if ( mp->internal[mp_linejoin]>0 ) ljoin_val(t)=1;
9111 else ljoin_val(t)=0;
9112 if ( mp->internal[mp_miterlimit]<unity )
9113   miterlim_val(t)=unity;
9114 else
9115   miterlim_val(t)=mp->internal[mp_miterlimit]
9116
9117 @ A stroked path is represented by an eight-word node that is like a filled
9118 contour node except that it contains the current \&{linecap} value, a scale
9119 factor for the dash pattern, and a pointer that is non-null if the stroke
9120 is to be dashed.  The purpose of the scale factor is to allow a picture to
9121 be transformed without touching the picture that |dash_p| points to.
9122
9123 @d dash_p(A) link((A)+9)
9124   /* a pointer to the edge structure that gives the dash pattern */
9125 @d lcap_val(A) type((A)+9)
9126   /* the value of \&{linecap} */
9127 @:mp_linecap_}{\&{linecap} primitive@>
9128 @d dash_scale(A) mp->mem[(A)+10].sc /* dash lengths are scaled by this factor */
9129 @d stroked_node_size 11
9130
9131 @ @<Graphical object codes@>=
9132 mp_stroked_code=2,
9133
9134 @ @c 
9135 pointer mp_new_stroked_node (MP mp,pointer p) {
9136   /* make a stroked node for path |p| with |pen_p(p)| temporarily |null| */
9137   pointer t; /* the new node */
9138   t=mp_get_node(mp, stroked_node_size);
9139   type(t)=mp_stroked_code;
9140   path_p(t)=p; pen_p(t)=null;
9141   dash_p(t)=null;
9142   dash_scale(t)=unity;
9143   red_val(t)=0;
9144   green_val(t)=0;
9145   blue_val(t)=0;
9146   black_val(t)=0;
9147   color_model(t)=mp_uninitialized_model;
9148   pre_script(t)=null;
9149   post_script(t)=null;
9150   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9151   if ( mp->internal[mp_linecap]>unity ) lcap_val(t)=2;
9152   else if ( mp->internal[mp_linecap]>0 ) lcap_val(t)=1;
9153   else lcap_val(t)=0;
9154   return t;
9155 }
9156
9157 @ When a dashed line is computed in a transformed coordinate system, the dash
9158 lengths get scaled like the pen shape and we need to compensate for this.  Since
9159 there is no unique scale factor for an arbitrary transformation, we use the
9160 the square root of the determinant.  The properties of the determinant make it
9161 easier to maintain the |dash_scale|.  The computation is fairly straight-forward
9162 except for the initialization of the scale factor |s|.  The factor of 64 is
9163 needed because |square_rt| scales its result by $2^8$ while we need $2^{14}$
9164 to counteract the effect of |take_fraction|.
9165
9166 @<Declare subroutines needed by |print_edges|@>=
9167 scaled mp_sqrt_det (MP mp,scaled a, scaled b, scaled c, scaled d) {
9168   scaled maxabs; /* $max(|a|,|b|,|c|,|d|)$ */
9169   integer s; /* amount by which the result of |square_rt| needs to be scaled */
9170   @<Initialize |maxabs|@>;
9171   s=64;
9172   while ( (maxabs<fraction_one) && (s>1) ){ 
9173     a+=a; b+=b; c+=c; d+=d;
9174     maxabs+=maxabs; s=halfp(s);
9175   }
9176   return s*mp_square_rt(mp, abs(mp_take_fraction(mp, a,d)-mp_take_fraction(mp, b,c)));
9177 }
9178 @#
9179 scaled mp_get_pen_scale (MP mp,pointer p) { 
9180   return mp_sqrt_det(mp, 
9181     left_x(p)-x_coord(p), right_x(p)-x_coord(p),
9182     left_y(p)-y_coord(p), right_y(p)-y_coord(p));
9183 }
9184
9185 @ @<Internal library ...@>=
9186 scaled mp_sqrt_det (MP mp,scaled a, scaled b, scaled c, scaled d) ;
9187
9188
9189 @ @<Initialize |maxabs|@>=
9190 maxabs=abs(a);
9191 if ( abs(b)>maxabs ) maxabs=abs(b);
9192 if ( abs(c)>maxabs ) maxabs=abs(c);
9193 if ( abs(d)>maxabs ) maxabs=abs(d)
9194
9195 @ When a picture contains text, this is represented by a fourteen-word node
9196 where the color information and |type| and |link| fields are augmented by
9197 additional fields that describe the text and  how it is transformed.
9198 The |path_p| and |pen_p| pointers are replaced by a number that identifies
9199 the font and a string number that gives the text to be displayed.
9200 The |width|, |height|, and |depth| fields
9201 give the dimensions of the text at its design size, and the remaining six
9202 words give a transformation to be applied to the text.  The |new_text_node|
9203 function initializes everything to default values so that the text comes out
9204 black with its reference point at the origin.
9205
9206 @d text_p(A) link((A)+1)  /* a string pointer for the text to display */
9207 @d font_n(A) info((A)+1)  /* the font number */
9208 @d width_val(A) mp->mem[(A)+7].sc  /* unscaled width of the text */
9209 @d height_val(A) mp->mem[(A)+9].sc  /* unscaled height of the text */
9210 @d depth_val(A) mp->mem[(A)+10].sc  /* unscaled depth of the text */
9211 @d text_tx_loc(A) ((A)+11)
9212   /* the first of six locations for transformation parameters */
9213 @d tx_val(A) mp->mem[(A)+11].sc  /* $x$ shift amount */
9214 @d ty_val(A) mp->mem[(A)+12].sc  /* $y$ shift amount */
9215 @d txx_val(A) mp->mem[(A)+13].sc  /* |txx| transformation parameter */
9216 @d txy_val(A) mp->mem[(A)+14].sc  /* |txy| transformation parameter */
9217 @d tyx_val(A) mp->mem[(A)+15].sc  /* |tyx| transformation parameter */
9218 @d tyy_val(A) mp->mem[(A)+16].sc  /* |tyy| transformation parameter */
9219 @d text_trans_part(A) mp->mem[(A)+11-x_part].sc
9220     /* interpret a text node pointer that has been offset by |x_part..yy_part| */
9221 @d text_node_size 17
9222
9223 @ @<Graphical object codes@>=
9224 mp_text_code=3,
9225
9226 @ @c @<Declare text measuring subroutines@>;
9227 pointer mp_new_text_node (MP mp,char *f,str_number s) {
9228   /* make a text node for font |f| and text string |s| */
9229   pointer t; /* the new node */
9230   t=mp_get_node(mp, text_node_size);
9231   type(t)=mp_text_code;
9232   text_p(t)=s;
9233   font_n(t)=mp_find_font(mp, f); /* this identifies the font */
9234   red_val(t)=0;
9235   green_val(t)=0;
9236   blue_val(t)=0;
9237   black_val(t)=0;
9238   color_model(t)=mp_uninitialized_model;
9239   pre_script(t)=null;
9240   post_script(t)=null;
9241   tx_val(t)=0; ty_val(t)=0;
9242   txx_val(t)=unity; txy_val(t)=0;
9243   tyx_val(t)=0; tyy_val(t)=unity;
9244   mp_set_text_box(mp, t); /* this finds the bounding box */
9245   return t;
9246 }
9247
9248 @ The last two types of graphical objects that can occur in an edge structure
9249 are clipping paths and \&{setbounds} paths.  These are slightly more difficult
9250 @:set_bounds_}{\&{setbounds} primitive@>
9251 to implement because we must keep track of exactly what is being clipped or
9252 bounded when pictures get merged together.  For this reason, each clipping or
9253 \&{setbounds} operation is represented by a pair of nodes:  first comes a
9254 two-word node whose |path_p| gives the relevant path, then there is the list
9255 of objects to clip or bound followed by a two-word node whose second word is
9256 unused.
9257
9258 Using at least two words for each graphical object node allows them all to be
9259 allocated and deallocated similarly with a global array |gr_object_size| to
9260 give the size in words for each object type.
9261
9262 @d start_clip_size 2
9263 @d start_bounds_size 2
9264 @d stop_clip_size 2 /* the second word is not used here */
9265 @d stop_bounds_size 2 /* the second word is not used here */
9266 @#
9267 @d stop_type(A) ((A)+2)
9268   /* matching |type| for |start_clip_code| or |start_bounds_code| */
9269 @d has_color(A) (type((A))<mp_start_clip_code)
9270   /* does a graphical object have color fields? */
9271 @d has_pen(A) (type((A))<mp_text_code)
9272   /* does a graphical object have a |pen_p| field? */
9273 @d is_start_or_stop(A) (type((A))>=mp_start_clip_code)
9274 @d is_stop(A) (type((A))>=mp_stop_clip_code)
9275
9276 @ @<Graphical object codes@>=
9277 mp_start_clip_code=4, /* |type| of a node that starts clipping */
9278 mp_start_bounds_code=5, /* |type| of a node that gives a \&{setbounds} path */
9279 mp_stop_clip_code=6, /* |type| of a node that stops clipping */
9280 mp_stop_bounds_code=7, /* |type| of a node that stops \&{setbounds} */
9281
9282 @ @c 
9283 pointer mp_new_bounds_node (MP mp,pointer p, small_number  c) {
9284   /* make a node of type |c| where |p| is the clipping or \&{setbounds} path */
9285   pointer t; /* the new node */
9286   t=mp_get_node(mp, mp->gr_object_size[c]);
9287   type(t)=c;
9288   path_p(t)=p;
9289   return t;
9290 };
9291
9292 @ We need an array to keep track of the sizes of graphical objects.
9293
9294 @<Glob...@>=
9295 small_number gr_object_size[mp_stop_bounds_code+1];
9296
9297 @ @<Set init...@>=
9298 mp->gr_object_size[mp_fill_code]=fill_node_size;
9299 mp->gr_object_size[mp_stroked_code]=stroked_node_size;
9300 mp->gr_object_size[mp_text_code]=text_node_size;
9301 mp->gr_object_size[mp_start_clip_code]=start_clip_size;
9302 mp->gr_object_size[mp_stop_clip_code]=stop_clip_size;
9303 mp->gr_object_size[mp_start_bounds_code]=start_bounds_size;
9304 mp->gr_object_size[mp_stop_bounds_code]=stop_bounds_size;
9305
9306 @ All the essential information in an edge structure is encoded as a linked list
9307 of graphical objects as we have just seen, but it is helpful to add some
9308 redundant information.  A single edge structure might be used as a dash pattern
9309 many times, and it would be nice to avoid scanning the same structure
9310 repeatedly.  Thus, an edge structure known to be a suitable dash pattern
9311 has a header that gives a list of dashes in a sorted order designed for rapid
9312 translation into \ps.
9313
9314 Each dash is represented by a three-word node containing the initial and final
9315 $x$~coordinates as well as the usual |link| field.  The |link| fields points to
9316 the dash node with the next higher $x$-coordinates and the final link points
9317 to a special location called |null_dash|.  (There should be no overlap between
9318 dashes).  Since the $y$~coordinate of the dash pattern is needed to determine
9319 the period of repetition, this needs to be stored in the edge header along
9320 with a pointer to the list of dash nodes.
9321
9322 @d start_x(A) mp->mem[(A)+1].sc  /* the starting $x$~coordinate in a dash node */
9323 @d stop_x(A) mp->mem[(A)+2].sc  /* the ending $x$~coordinate in a dash node */
9324 @d dash_node_size 3
9325 @d dash_list link
9326   /* in an edge header this points to the first dash node */
9327 @d dash_y(A) mp->mem[(A)+1].sc  /* $y$ value for the dash list in an edge header */
9328
9329 @ It is also convenient for an edge header to contain the bounding
9330 box information needed by the \&{llcorner} and \&{urcorner} operators
9331 so that this does not have to be recomputed unnecessarily.  This is done by
9332 adding fields for the $x$~and $y$ extremes as well as a pointer that indicates
9333 how far the bounding box computation has gotten.  Thus if the user asks for
9334 the bounding box and then adds some more text to the picture before asking
9335 for more bounding box information, the second computation need only look at
9336 the additional text.
9337
9338 When the bounding box has not been computed, the |bblast| pointer points
9339 to a dummy link at the head of the graphical object list while the |minx_val|
9340 and |miny_val| fields contain |el_gordo| and the |maxx_val| and |maxy_val|
9341 fields contain |-el_gordo|.
9342
9343 Since the bounding box of pictures containing objects of type
9344 |mp_start_bounds_code| depends on the value of \&{truecorners}, the bounding box
9345 @:mp_true_corners_}{\&{truecorners} primitive@>
9346 data might not be valid for all values of this parameter.  Hence, the |bbtype|
9347 field is needed to keep track of this.
9348
9349 @d minx_val(A) mp->mem[(A)+2].sc
9350 @d miny_val(A) mp->mem[(A)+3].sc
9351 @d maxx_val(A) mp->mem[(A)+4].sc
9352 @d maxy_val(A) mp->mem[(A)+5].sc
9353 @d bblast(A) link((A)+6)  /* last item considered in bounding box computation */
9354 @d bbtype(A) info((A)+6)  /* tells how bounding box data depends on \&{truecorners} */
9355 @d dummy_loc(A) ((A)+7)  /* where the object list begins in an edge header */
9356 @d no_bounds 0
9357   /* |bbtype| value when bounding box data is valid for all \&{truecorners} values */
9358 @d bounds_set 1
9359   /* |bbtype| value when bounding box data is for \&{truecorners}${}\le 0$ */
9360 @d bounds_unset 2
9361   /* |bbtype| value when bounding box data is for \&{truecorners}${}>0$ */
9362
9363 @c 
9364 void mp_init_bbox (MP mp,pointer h) {
9365   /* Initialize the bounding box information in edge structure |h| */
9366   bblast(h)=dummy_loc(h);
9367   bbtype(h)=no_bounds;
9368   minx_val(h)=el_gordo;
9369   miny_val(h)=el_gordo;
9370   maxx_val(h)=-el_gordo;
9371   maxy_val(h)=-el_gordo;
9372 }
9373
9374 @ The only other entries in an edge header are a reference count in the first
9375 word and a pointer to the tail of the object list in the last word.
9376
9377 @d obj_tail(A) info((A)+7)  /* points to the last entry in the object list */
9378 @d edge_header_size 8
9379
9380 @c 
9381 void mp_init_edges (MP mp,pointer h) {
9382   /* initialize an edge header to null values */
9383   dash_list(h)=null_dash;
9384   obj_tail(h)=dummy_loc(h);
9385   link(dummy_loc(h))=null;
9386   ref_count(h)=null;
9387   mp_init_bbox(mp, h);
9388 }
9389
9390 @ Here is how edge structures are deleted.  The process can be recursive because
9391 of the need to dereference edge structures that are used as dash patterns.
9392 @^recursion@>
9393
9394 @d add_edge_ref(A) incr(ref_count(A))
9395 @d delete_edge_ref(A) { 
9396    if ( ref_count((A))==null ) 
9397      mp_toss_edges(mp, A);
9398    else 
9399      decr(ref_count(A)); 
9400    }
9401
9402 @<Declare the recycling subroutines@>=
9403 void mp_flush_dash_list (MP mp,pointer h);
9404 pointer mp_toss_gr_object (MP mp,pointer p) ;
9405 void mp_toss_edges (MP mp,pointer h) ;
9406
9407 @ @c void mp_toss_edges (MP mp,pointer h) {
9408   pointer p,q;  /* pointers that scan the list being recycled */
9409   pointer r; /* an edge structure that object |p| refers to */
9410   mp_flush_dash_list(mp, h);
9411   q=link(dummy_loc(h));
9412   while ( (q!=null) ) { 
9413     p=q; q=link(q);
9414     r=mp_toss_gr_object(mp, p);
9415     if ( r!=null ) delete_edge_ref(r);
9416   }
9417   mp_free_node(mp, h,edge_header_size);
9418 }
9419 void mp_flush_dash_list (MP mp,pointer h) {
9420   pointer p,q;  /* pointers that scan the list being recycled */
9421   q=dash_list(h);
9422   while ( q!=null_dash ) { 
9423     p=q; q=link(q);
9424     mp_free_node(mp, p,dash_node_size);
9425   }
9426   dash_list(h)=null_dash;
9427 }
9428 pointer mp_toss_gr_object (MP mp,pointer p) {
9429   /* returns an edge structure that needs to be dereferenced */
9430   pointer e; /* the edge structure to return */
9431   e=null;
9432   @<Prepare to recycle graphical object |p|@>;
9433   mp_free_node(mp, p,mp->gr_object_size[type(p)]);
9434   return e;
9435 }
9436
9437 @ @<Prepare to recycle graphical object |p|@>=
9438 switch (type(p)) {
9439 case mp_fill_code: 
9440   mp_toss_knot_list(mp, path_p(p));
9441   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9442   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9443   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9444   break;
9445 case mp_stroked_code: 
9446   mp_toss_knot_list(mp, path_p(p));
9447   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9448   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9449   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9450   e=dash_p(p);
9451   break;
9452 case mp_text_code: 
9453   delete_str_ref(text_p(p));
9454   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9455   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9456   break;
9457 case mp_start_clip_code:
9458 case mp_start_bounds_code: 
9459   mp_toss_knot_list(mp, path_p(p));
9460   break;
9461 case mp_stop_clip_code:
9462 case mp_stop_bounds_code: 
9463   break;
9464 } /* there are no other cases */
9465
9466 @ If we use |add_edge_ref| to ``copy'' edge structures, the real copying needs
9467 to be done before making a significant change to an edge structure.  Much of
9468 the work is done in a separate routine |copy_objects| that copies a list of
9469 graphical objects into a new edge header.
9470
9471 @c @<Declare a function called |copy_objects|@>;
9472 pointer mp_private_edges (MP mp,pointer h) {
9473   /* make a private copy of the edge structure headed by |h| */
9474   pointer hh;  /* the edge header for the new copy */
9475   pointer p,pp;  /* pointers for copying the dash list */
9476   if ( ref_count(h)==null ) {
9477     return h;
9478   } else { 
9479     decr(ref_count(h));
9480     hh=mp_copy_objects(mp, link(dummy_loc(h)),null);
9481     @<Copy the dash list from |h| to |hh|@>;
9482     @<Copy the bounding box information from |h| to |hh| and make |bblast(hh)|
9483       point into the new object list@>;
9484     return hh;
9485   }
9486 }
9487
9488 @ Here we use the fact that |dash_list(hh)=link(hh)|.
9489 @^data structure assumptions@>
9490
9491 @<Copy the dash list from |h| to |hh|@>=
9492 pp=hh; p=dash_list(h);
9493 while ( (p!=null_dash) ) { 
9494   link(pp)=mp_get_node(mp, dash_node_size);
9495   pp=link(pp);
9496   start_x(pp)=start_x(p);
9497   stop_x(pp)=stop_x(p);
9498   p=link(p);
9499 }
9500 link(pp)=null_dash;
9501 dash_y(hh)=dash_y(h)
9502
9503
9504 @ |h| is an edge structure
9505
9506 @d gr_start_x(A)    (A)->start_x_field
9507 @d gr_stop_x(A)     (A)->stop_x_field
9508 @d gr_dash_link(A)  (A)->next_field
9509
9510 @d gr_dash_list(A)  (A)->list_field
9511 @d gr_dash_y(A)     (A)->y_field
9512
9513 @c
9514 struct mp_dash_list *mp_export_dashes (MP mp, pointer h) {
9515   struct mp_dash_list *dl;
9516   struct mp_dash_item *dh, *di;
9517   pointer p;
9518   if (h==null ||  dash_list(h)==null_dash) 
9519         return NULL;
9520   p = dash_list(h);
9521   dl = mp_xmalloc(mp,1,sizeof(struct mp_dash_list));
9522   gr_dash_list(dl) = NULL;
9523   gr_dash_y(dl) = dash_y(h);
9524   dh = NULL;
9525   while (p != null_dash) { 
9526     di=mp_xmalloc(mp,1,sizeof(struct mp_dash_item));
9527     gr_dash_link(di) = NULL;
9528     gr_start_x(di) = start_x(p);
9529     gr_stop_x(di) = stop_x(p);
9530     if (dh==NULL) {
9531       gr_dash_list(dl) = di;
9532     } else {
9533       gr_dash_link(dh) = di;
9534     }
9535     dh = di;
9536     p=link(p);
9537   }
9538   return dl;
9539 }
9540
9541
9542 @ @<Copy the bounding box information from |h| to |hh|...@>=
9543 minx_val(hh)=minx_val(h);
9544 miny_val(hh)=miny_val(h);
9545 maxx_val(hh)=maxx_val(h);
9546 maxy_val(hh)=maxy_val(h);
9547 bbtype(hh)=bbtype(h);
9548 p=dummy_loc(h); pp=dummy_loc(hh);
9549 while ((p!=bblast(h)) ) { 
9550   if ( p==null ) mp_confusion(mp, "bblast");
9551 @:this can't happen bblast}{\quad bblast@>
9552   p=link(p); pp=link(pp);
9553 }
9554 bblast(hh)=pp
9555
9556 @ Here is the promised routine for copying graphical objects into a new edge
9557 structure.  It starts copying at object~|p| and stops just before object~|q|.
9558 If |q| is null, it copies the entire sublist headed at |p|.  The resulting edge
9559 structure requires further initialization by |init_bbox|.
9560
9561 @<Declare a function called |copy_objects|@>=
9562 pointer mp_copy_objects (MP mp, pointer p, pointer q) {
9563   pointer hh;  /* the new edge header */
9564   pointer pp;  /* the last newly copied object */
9565   small_number k;  /* temporary register */
9566   hh=mp_get_node(mp, edge_header_size);
9567   dash_list(hh)=null_dash;
9568   ref_count(hh)=null;
9569   pp=dummy_loc(hh);
9570   while ( (p!=q) ) {
9571     @<Make |link(pp)| point to a copy of object |p|, and update |p| and |pp|@>;
9572   }
9573   obj_tail(hh)=pp;
9574   link(pp)=null;
9575   return hh;
9576 }
9577
9578 @ @<Make |link(pp)| point to a copy of object |p|, and update |p| and |pp|@>=
9579 { k=mp->gr_object_size[type(p)];
9580   link(pp)=mp_get_node(mp, k);
9581   pp=link(pp);
9582   while ( (k>0) ) { decr(k); mp->mem[pp+k]=mp->mem[p+k];  };
9583   @<Fix anything in graphical object |pp| that should differ from the
9584     corresponding field in |p|@>;
9585   p=link(p);
9586 }
9587
9588 @ @<Fix anything in graphical object |pp| that should differ from the...@>=
9589 switch (type(p)) {
9590 case mp_start_clip_code:
9591 case mp_start_bounds_code: 
9592   path_p(pp)=mp_copy_path(mp, path_p(p));
9593   break;
9594 case mp_fill_code: 
9595   path_p(pp)=mp_copy_path(mp, path_p(p));
9596   if ( pen_p(p)!=null ) pen_p(pp)=copy_pen(pen_p(p));
9597   break;
9598 case mp_stroked_code: 
9599   path_p(pp)=mp_copy_path(mp, path_p(p));
9600   pen_p(pp)=copy_pen(pen_p(p));
9601   if ( dash_p(p)!=null ) add_edge_ref(dash_p(pp));
9602   break;
9603 case mp_text_code: 
9604   add_str_ref(text_p(pp));
9605   break;
9606 case mp_stop_clip_code:
9607 case mp_stop_bounds_code: 
9608   break;
9609 }  /* there are no other cases */
9610
9611 @ Here is one way to find an acceptable value for the second argument to
9612 |copy_objects|.  Given a non-null graphical object list, |skip_1component|
9613 skips past one picture component, where a ``picture component'' is a single
9614 graphical object, or a start bounds or start clip object and everything up
9615 through the matching stop bounds or stop clip object.  The macro version avoids
9616 procedure call overhead and error handling: |skip_component(p)(e)| advances |p|
9617 unless |p| points to a stop bounds or stop clip node, in which case it executes
9618 |e| instead.
9619
9620 @d skip_component(A)
9621     if ( ! is_start_or_stop((A)) ) (A)=link((A));
9622     else if ( ! is_stop((A)) ) (A)=mp_skip_1component(mp, (A));
9623     else 
9624
9625 @c 
9626 pointer mp_skip_1component (MP mp,pointer p) {
9627   integer lev; /* current nesting level */
9628   lev=0;
9629   do {  
9630    if ( is_start_or_stop(p) ) {
9631      if ( is_stop(p) ) decr(lev);  else incr(lev);
9632    }
9633    p=link(p);
9634   } while (lev!=0);
9635   return p;
9636 }
9637
9638 @ Here is a diagnostic routine for printing an edge structure in symbolic form.
9639
9640 @<Declare subroutines for printing expressions@>=
9641 @<Declare subroutines needed by |print_edges|@>;
9642 void mp_print_edges (MP mp,pointer h, char *s, boolean nuline) {
9643   pointer p;  /* a graphical object to be printed */
9644   pointer hh,pp;  /* temporary pointers */
9645   scaled scf;  /* a scale factor for the dash pattern */
9646   boolean ok_to_dash;  /* |false| for polygonal pen strokes */
9647   mp_print_diagnostic(mp, "Edge structure",s,nuline);
9648   p=dummy_loc(h);
9649   while ( link(p)!=null ) { 
9650     p=link(p);
9651     mp_print_ln(mp);
9652     switch (type(p)) {
9653       @<Cases for printing graphical object node |p|@>;
9654     default: 
9655           mp_print(mp, "[unknown object type!]");
9656           break;
9657     }
9658   }
9659   mp_print_nl(mp, "End edges");
9660   if ( p!=obj_tail(h) ) mp_print(mp, "?");
9661 @.End edges?@>
9662   mp_end_diagnostic(mp, true);
9663 }
9664
9665 @ @<Cases for printing graphical object node |p|@>=
9666 case mp_fill_code: 
9667   mp_print(mp, "Filled contour ");
9668   mp_print_obj_color(mp, p);
9669   mp_print_char(mp, ':'); mp_print_ln(mp);
9670   mp_pr_path(mp, path_p(p)); mp_print_ln(mp);
9671   if ( (pen_p(p)!=null) ) {
9672     @<Print join type for graphical object |p|@>;
9673     mp_print(mp, " with pen"); mp_print_ln(mp);
9674     mp_pr_pen(mp, pen_p(p));
9675   }
9676   break;
9677
9678 @ @<Print join type for graphical object |p|@>=
9679 switch (ljoin_val(p)) {
9680 case 0:
9681   mp_print(mp, "mitered joins limited ");
9682   mp_print_scaled(mp, miterlim_val(p));
9683   break;
9684 case 1:
9685   mp_print(mp, "round joins");
9686   break;
9687 case 2:
9688   mp_print(mp, "beveled joins");
9689   break;
9690 default: 
9691   mp_print(mp, "?? joins");
9692 @.??@>
9693   break;
9694 }
9695
9696 @ For stroked nodes, we need to print |lcap_val(p)| as well.
9697
9698 @<Print join and cap types for stroked node |p|@>=
9699 switch (lcap_val(p)) {
9700 case 0:mp_print(mp, "butt"); break;
9701 case 1:mp_print(mp, "round"); break;
9702 case 2:mp_print(mp, "square"); break;
9703 default: mp_print(mp, "??"); break;
9704 @.??@>
9705 }
9706 mp_print(mp, " ends, ");
9707 @<Print join type for graphical object |p|@>
9708
9709 @ Here is a routine that prints the color of a graphical object if it isn't
9710 black (the default color).
9711
9712 @<Declare subroutines needed by |print_edges|@>=
9713 @<Declare a procedure called |print_compact_node|@>;
9714 void mp_print_obj_color (MP mp,pointer p) { 
9715   if ( color_model(p)==mp_grey_model ) {
9716     if ( grey_val(p)>0 ) { 
9717       mp_print(mp, "greyed ");
9718       mp_print_compact_node(mp, obj_grey_loc(p),1);
9719     };
9720   } else if ( color_model(p)==mp_cmyk_model ) {
9721     if ( (cyan_val(p)>0) || (magenta_val(p)>0) || 
9722          (yellow_val(p)>0) || (black_val(p)>0) ) { 
9723       mp_print(mp, "processcolored ");
9724       mp_print_compact_node(mp, obj_cyan_loc(p),4);
9725     };
9726   } else if ( color_model(p)==mp_rgb_model ) {
9727     if ( (red_val(p)>0) || (green_val(p)>0) || (blue_val(p)>0) ) { 
9728       mp_print(mp, "colored "); 
9729       mp_print_compact_node(mp, obj_red_loc(p),3);
9730     };
9731   }
9732 }
9733
9734 @ We also need a procedure for printing consecutive scaled values as if they
9735 were a known big node.
9736
9737 @<Declare a procedure called |print_compact_node|@>=
9738 void mp_print_compact_node (MP mp,pointer p, small_number k) {
9739   pointer q;  /* last location to print */
9740   q=p+k-1;
9741   mp_print_char(mp, '(');
9742   while ( p<=q ){ 
9743     mp_print_scaled(mp, mp->mem[p].sc);
9744     if ( p<q ) mp_print_char(mp, ',');
9745     incr(p);
9746   }
9747   mp_print_char(mp, ')');
9748 }
9749
9750 @ @<Cases for printing graphical object node |p|@>=
9751 case mp_stroked_code: 
9752   mp_print(mp, "Filled pen stroke ");
9753   mp_print_obj_color(mp, p);
9754   mp_print_char(mp, ':'); mp_print_ln(mp);
9755   mp_pr_path(mp, path_p(p));
9756   if ( dash_p(p)!=null ) { 
9757     mp_print_nl(mp, "dashed (");
9758     @<Finish printing the dash pattern that |p| refers to@>;
9759   }
9760   mp_print_ln(mp);
9761   @<Print join and cap types for stroked node |p|@>;
9762   mp_print(mp, " with pen"); mp_print_ln(mp);
9763   if ( pen_p(p)==null ) mp_print(mp, "???"); /* shouldn't happen */
9764 @.???@>
9765   else mp_pr_pen(mp, pen_p(p));
9766   break;
9767
9768 @ Normally, the  |dash_list| field in an edge header is set to |null_dash|
9769 when it is not known to define a suitable dash pattern.  This is disallowed
9770 here because the |dash_p| field should never point to such an edge header.
9771 Note that memory is allocated for |start_x(null_dash)| and we are free to
9772 give it any convenient value.
9773
9774 @<Finish printing the dash pattern that |p| refers to@>=
9775 ok_to_dash=pen_is_elliptical(pen_p(p));
9776 if ( ! ok_to_dash ) scf=unity; else scf=dash_scale(p);
9777 hh=dash_p(p);
9778 pp=dash_list(hh);
9779 if ( (pp==null_dash) || (dash_y(hh)<0) ) {
9780   mp_print(mp, " ??");
9781 } else { start_x(null_dash)=start_x(pp)+dash_y(hh);
9782   while ( pp!=null_dash ) { 
9783     mp_print(mp, "on ");
9784     mp_print_scaled(mp, mp_take_scaled(mp, stop_x(pp)-start_x(pp),scf));
9785     mp_print(mp, " off ");
9786     mp_print_scaled(mp, mp_take_scaled(mp, start_x(link(pp))-stop_x(pp),scf));
9787     pp = link(pp);
9788     if ( pp!=null_dash ) mp_print_char(mp, ' ');
9789   }
9790   mp_print(mp, ") shifted ");
9791   mp_print_scaled(mp, -mp_take_scaled(mp, mp_dash_offset(mp, hh),scf));
9792   if ( ! ok_to_dash || (dash_y(hh)==0) ) mp_print(mp, " (this will be ignored)");
9793 }
9794
9795 @ @<Declare subroutines needed by |print_edges|@>=
9796 scaled mp_dash_offset (MP mp,pointer h) {
9797   scaled x;  /* the answer */
9798   if (dash_list(h)==null_dash || dash_y(h)<0) mp_confusion(mp, "dash0");
9799 @:this can't happen dash0}{\quad dash0@>
9800   if ( dash_y(h)==0 ) {
9801     x=0; 
9802   } else { 
9803     x=-(start_x(dash_list(h)) % dash_y(h));
9804     if ( x<0 ) x=x+dash_y(h);
9805   }
9806   return x;
9807 }
9808
9809 @ @<Cases for printing graphical object node |p|@>=
9810 case mp_text_code: 
9811   mp_print_char(mp, '"'); mp_print_str(mp,text_p(p));
9812   mp_print(mp, "\" infont \""); mp_print(mp, mp->font_name[font_n(p)]);
9813   mp_print_char(mp, '"'); mp_print_ln(mp);
9814   mp_print_obj_color(mp, p);
9815   mp_print(mp, "transformed ");
9816   mp_print_compact_node(mp, text_tx_loc(p),6);
9817   break;
9818
9819 @ @<Cases for printing graphical object node |p|@>=
9820 case mp_start_clip_code: 
9821   mp_print(mp, "clipping path:");
9822   mp_print_ln(mp);
9823   mp_pr_path(mp, path_p(p));
9824   break;
9825 case mp_stop_clip_code: 
9826   mp_print(mp, "stop clipping");
9827   break;
9828
9829 @ @<Cases for printing graphical object node |p|@>=
9830 case mp_start_bounds_code: 
9831   mp_print(mp, "setbounds path:");
9832   mp_print_ln(mp);
9833   mp_pr_path(mp, path_p(p));
9834   break;
9835 case mp_stop_bounds_code: 
9836   mp_print(mp, "end of setbounds");
9837   break;
9838
9839 @ To initialize the |dash_list| field in an edge header~|h|, we need a
9840 subroutine that scans an edge structure and tries to interpret it as a dash
9841 pattern.  This can only be done when there are no filled regions or clipping
9842 paths and all the pen strokes have the same color.  The first step is to let
9843 $y_0$ be the initial $y$~coordinate of the first pen stroke.  Then we implicitly
9844 project all the pen stroke paths onto the line $y=y_0$ and require that there
9845 be no retracing.  If the resulting paths cover a range of $x$~coordinates of
9846 length $\Delta x$, we set |dash_y(h)| to the length of the dash pattern by
9847 finding the maximum of $\Delta x$ and the absolute value of~$y_0$.
9848
9849 @c @<Declare a procedure called |x_retrace_error|@>;
9850 pointer mp_make_dashes (MP mp,pointer h) { /* returns |h| or |null| */
9851   pointer p;  /* this scans the stroked nodes in the object list */
9852   pointer p0;  /* if not |null| this points to the first stroked node */
9853   pointer pp,qq,rr;  /* pointers into |path_p(p)| */
9854   pointer d,dd;  /* pointers used to create the dash list */
9855   @<Other local variables in |make_dashes|@>;
9856   scaled y0=0;  /* the initial $y$ coordinate */
9857   if ( dash_list(h)!=null_dash ) 
9858         return h;
9859   p0=null;
9860   p=link(dummy_loc(h));
9861   while ( p!=null ) { 
9862     if ( type(p)!=mp_stroked_code ) {
9863       @<Compain that the edge structure contains a node of the wrong type
9864         and |goto not_found|@>;
9865     }
9866     pp=path_p(p);
9867     if ( p0==null ){ p0=p; y0=y_coord(pp);  };
9868     @<Make |d| point to a new dash node created from stroke |p| and path |pp|
9869       or |goto not_found| if there is an error@>;
9870     @<Insert |d| into the dash list and |goto not_found| if there is an error@>;
9871     p=link(p);
9872   }
9873   if ( dash_list(h)==null_dash ) 
9874     goto NOT_FOUND; /* No error message */
9875   @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>;
9876   @<Set |dash_y(h)| and merge the first and last dashes if necessary@>;
9877   return h;
9878 NOT_FOUND: 
9879   @<Flush the dash list, recycle |h| and return |null|@>;
9880 };
9881
9882 @ @<Compain that the edge structure contains a node of the wrong type...@>=
9883
9884 print_err("Picture is too complicated to use as a dash pattern");
9885 help3("When you say `dashed p', picture p should not contain any")
9886   ("text, filled regions, or clipping paths.  This time it did")
9887   ("so I'll just make it a solid line instead.");
9888 mp_put_get_error(mp);
9889 goto NOT_FOUND;
9890 }
9891
9892 @ A similar error occurs when monotonicity fails.
9893
9894 @<Declare a procedure called |x_retrace_error|@>=
9895 void mp_x_retrace_error (MP mp) { 
9896 print_err("Picture is too complicated to use as a dash pattern");
9897 help3("When you say `dashed p', every path in p should be monotone")
9898   ("in x and there must be no overlapping.  This failed")
9899   ("so I'll just make it a solid line instead.");
9900 mp_put_get_error(mp);
9901 }
9902
9903 @ We stash |p| in |info(d)| if |dash_p(p)<>0| so that subsequent processing can
9904 handle the case where the pen stroke |p| is itself dashed.
9905
9906 @<Make |d| point to a new dash node created from stroke |p| and path...@>=
9907 @<Make sure |p| and |p0| are the same color and |goto not_found| if there is
9908   an error@>;
9909 rr=pp;
9910 if ( link(pp)!=pp ) {
9911   do {  
9912     qq=rr; rr=link(rr);
9913     @<Check for retracing between knots |qq| and |rr| and |goto not_found|
9914       if there is a problem@>;
9915   } while (right_type(rr)!=mp_endpoint);
9916 }
9917 d=mp_get_node(mp, dash_node_size);
9918 if ( dash_p(p)==0 ) info(d)=0;  else info(d)=p;
9919 if ( x_coord(pp)<x_coord(rr) ) { 
9920   start_x(d)=x_coord(pp);
9921   stop_x(d)=x_coord(rr);
9922 } else { 
9923   start_x(d)=x_coord(rr);
9924   stop_x(d)=x_coord(pp);
9925 }
9926
9927 @ We also need to check for the case where the segment from |qq| to |rr| is
9928 monotone in $x$ but is reversed relative to the path from |pp| to |qq|.
9929
9930 @<Check for retracing between knots |qq| and |rr| and |goto not_found|...@>=
9931 x0=x_coord(qq);
9932 x1=right_x(qq);
9933 x2=left_x(rr);
9934 x3=x_coord(rr);
9935 if ( (x0>x1) || (x1>x2) || (x2>x3) ) {
9936   if ( (x0<x1) || (x1<x2) || (x2<x3) ) {
9937     if ( mp_ab_vs_cd(mp, x2-x1,x2-x1,x1-x0,x3-x2)>0 ) {
9938       mp_x_retrace_error(mp); goto NOT_FOUND;
9939     }
9940   }
9941 }
9942 if ( (x_coord(pp)>x0) || (x0>x3) ) {
9943   if ( (x_coord(pp)<x0) || (x0<x3) ) {
9944     mp_x_retrace_error(mp); goto NOT_FOUND;
9945   }
9946 }
9947
9948 @ @<Other local variables in |make_dashes|@>=
9949   scaled x0,x1,x2,x3;  /* $x$ coordinates of the segment from |qq| to |rr| */
9950
9951 @ @<Make sure |p| and |p0| are the same color and |goto not_found|...@>=
9952 if ( (red_val(p)!=red_val(p0)) || (black_val(p)!=black_val(p0)) ||
9953   (green_val(p)!=green_val(p0)) || (blue_val(p)!=blue_val(p0)) ) {
9954   print_err("Picture is too complicated to use as a dash pattern");
9955   help3("When you say `dashed p', everything in picture p should")
9956     ("be the same color.  I can\'t handle your color changes")
9957     ("so I'll just make it a solid line instead.");
9958   mp_put_get_error(mp);
9959   goto NOT_FOUND;
9960 }
9961
9962 @ @<Insert |d| into the dash list and |goto not_found| if there is an error@>=
9963 start_x(null_dash)=stop_x(d);
9964 dd=h; /* this makes |link(dd)=dash_list(h)| */
9965 while ( start_x(link(dd))<stop_x(d) )
9966   dd=link(dd);
9967 if ( dd!=h ) {
9968   if ( (stop_x(dd)>start_x(d)) )
9969     { mp_x_retrace_error(mp); goto NOT_FOUND;  };
9970 }
9971 link(d)=link(dd);
9972 link(dd)=d
9973
9974 @ @<Set |dash_y(h)| and merge the first and last dashes if necessary@>=
9975 d=dash_list(h);
9976 while ( (link(d)!=null_dash) )
9977   d=link(d);
9978 dd=dash_list(h);
9979 dash_y(h)=stop_x(d)-start_x(dd);
9980 if ( abs(y0)>dash_y(h) ) {
9981   dash_y(h)=abs(y0);
9982 } else if ( d!=dd ) { 
9983   dash_list(h)=link(dd);
9984   stop_x(d)=stop_x(dd)+dash_y(h);
9985   mp_free_node(mp, dd,dash_node_size);
9986 }
9987
9988 @ We get here when the argument is a null picture or when there is an error.
9989 Recovering from an error involves making |dash_list(h)| empty to indicate
9990 that |h| is not known to be a valid dash pattern.  We also dereference |h|
9991 since it is not being used for the return value.
9992
9993 @<Flush the dash list, recycle |h| and return |null|@>=
9994 mp_flush_dash_list(mp, h);
9995 delete_edge_ref(h);
9996 return null
9997
9998 @ Having carefully saved the dashed stroked nodes in the
9999 corresponding dash nodes, we must be prepared to break up these dashes into
10000 smaller dashes.
10001
10002 @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>=
10003 d=h;  /* now |link(d)=dash_list(h)| */
10004 while ( link(d)!=null_dash ) {
10005   ds=info(link(d));
10006   if ( ds==null ) { 
10007     d=link(d);
10008   } else {
10009     hh=dash_p(ds);
10010     hsf=dash_scale(ds);
10011     if ( (hh==null) ) mp_confusion(mp, "dash1");
10012 @:this can't happen dash0}{\quad dash1@>
10013     if ( dash_y(hh)==0 ) {
10014       d=link(d);
10015     } else { 
10016       if ( dash_list(hh)==null ) mp_confusion(mp, "dash1");
10017 @:this can't happen dash0}{\quad dash1@>
10018       @<Replace |link(d)| by a dashed version as determined by edge header
10019           |hh| and scale factor |ds|@>;
10020     }
10021   }
10022 }
10023
10024 @ @<Other local variables in |make_dashes|@>=
10025 pointer dln;  /* |link(d)| */
10026 pointer hh;  /* an edge header that tells how to break up |dln| */
10027 scaled hsf;  /* the dash pattern from |hh| gets scaled by this */
10028 pointer ds;  /* the stroked node from which |hh| and |hsf| are derived */
10029 scaled xoff;  /* added to $x$ values in |dash_list(hh)| to match |dln| */
10030
10031 @ @<Replace |link(d)| by a dashed version as determined by edge header...@>=
10032 dln=link(d);
10033 dd=dash_list(hh);
10034 xoff=start_x(dln)-mp_take_scaled(mp, hsf,start_x(dd))-
10035         mp_take_scaled(mp, hsf,mp_dash_offset(mp, hh));
10036 start_x(null_dash)=mp_take_scaled(mp, hsf,start_x(dd))
10037                    +mp_take_scaled(mp, hsf,dash_y(hh));
10038 stop_x(null_dash)=start_x(null_dash);
10039 @<Advance |dd| until finding the first dash that overlaps |dln| when
10040   offset by |xoff|@>;
10041 while ( start_x(dln)<=stop_x(dln) ) {
10042   @<If |dd| has `fallen off the end', back up to the beginning and fix |xoff|@>;
10043   @<Insert a dash between |d| and |dln| for the overlap with the offset version
10044     of |dd|@>;
10045   dd=link(dd);
10046   start_x(dln)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
10047 }
10048 link(d)=link(dln);
10049 mp_free_node(mp, dln,dash_node_size)
10050
10051 @ The name of this module is a bit of a lie because we just find the
10052 first |dd| where |take_scaled (hsf, stop_x(dd))| is large enough to make an
10053 overlap possible.  It could be that the unoffset version of dash |dln| falls
10054 in the gap between |dd| and its predecessor.
10055
10056 @<Advance |dd| until finding the first dash that overlaps |dln| when...@>=
10057 while ( xoff+mp_take_scaled(mp, hsf,stop_x(dd))<start_x(dln) ) {
10058   dd=link(dd);
10059 }
10060
10061 @ @<If |dd| has `fallen off the end', back up to the beginning and fix...@>=
10062 if ( dd==null_dash ) { 
10063   dd=dash_list(hh);
10064   xoff=xoff+mp_take_scaled(mp, hsf,dash_y(hh));
10065 }
10066
10067 @ At this point we already know that
10068 |start_x(dln)<=xoff+take_scaled(hsf,stop_x(dd))|.
10069
10070 @<Insert a dash between |d| and |dln| for the overlap with the offset...@>=
10071 if ( (xoff+mp_take_scaled(mp, hsf,start_x(dd)))<=stop_x(dln) ) {
10072   link(d)=mp_get_node(mp, dash_node_size);
10073   d=link(d);
10074   link(d)=dln;
10075   if ( start_x(dln)>(xoff+mp_take_scaled(mp, hsf,start_x(dd))))
10076     start_x(d)=start_x(dln);
10077   else 
10078     start_x(d)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
10079   if ( stop_x(dln)<(xoff+mp_take_scaled(mp, hsf,stop_x(dd)))) 
10080     stop_x(d)=stop_x(dln);
10081   else 
10082     stop_x(d)=xoff+mp_take_scaled(mp, hsf,stop_x(dd));
10083 }
10084
10085 @ The next major task is to update the bounding box information in an edge
10086 header~|h|. This is done via a procedure |adjust_bbox| that enlarges an edge
10087 header's bounding box to accommodate the box computed by |path_bbox| or
10088 |pen_bbox|. (This is stored in global variables |minx|, |miny|, |maxx|, and
10089 |maxy|.)
10090
10091 @c void mp_adjust_bbox (MP mp,pointer h) { 
10092   if ( minx<minx_val(h) ) minx_val(h)=minx;
10093   if ( miny<miny_val(h) ) miny_val(h)=miny;
10094   if ( maxx>maxx_val(h) ) maxx_val(h)=maxx;
10095   if ( maxy>maxy_val(h) ) maxy_val(h)=maxy;
10096 }
10097
10098 @ Here is a special routine for updating the bounding box information in
10099 edge header~|h| to account for the squared-off ends of a non-cyclic path~|p|
10100 that is to be stroked with the pen~|pp|.
10101
10102 @c void mp_box_ends (MP mp, pointer p, pointer pp, pointer h) {
10103   pointer q;  /* a knot node adjacent to knot |p| */
10104   fraction dx,dy;  /* a unit vector in the direction out of the path at~|p| */
10105   scaled d;  /* a factor for adjusting the length of |(dx,dy)| */
10106   scaled z;  /* a coordinate being tested against the bounding box */
10107   scaled xx,yy;  /* the extreme pen vertex in the |(dx,dy)| direction */
10108   integer i; /* a loop counter */
10109   if ( right_type(p)!=mp_endpoint ) { 
10110     q=link(p);
10111     while (1) { 
10112       @<Make |(dx,dy)| the final direction for the path segment from
10113         |q| to~|p|; set~|d|@>;
10114       d=mp_pyth_add(mp, dx,dy);
10115       if ( d>0 ) { 
10116          @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>;
10117          for (i=1;i<= 2;i++) { 
10118            @<Use |(dx,dy)| to generate a vertex of the square end cap and
10119              update the bounding box to accommodate it@>;
10120            dx=-dx; dy=-dy; 
10121         }
10122       }
10123       if ( right_type(p)==mp_endpoint ) {
10124          return;
10125       } else {
10126         @<Advance |p| to the end of the path and make |q| the previous knot@>;
10127       } 
10128     }
10129   }
10130 }
10131
10132 @ @<Make |(dx,dy)| the final direction for the path segment from...@>=
10133 if ( q==link(p) ) { 
10134   dx=x_coord(p)-right_x(p);
10135   dy=y_coord(p)-right_y(p);
10136   if ( (dx==0)&&(dy==0) ) {
10137     dx=x_coord(p)-left_x(q);
10138     dy=y_coord(p)-left_y(q);
10139   }
10140 } else { 
10141   dx=x_coord(p)-left_x(p);
10142   dy=y_coord(p)-left_y(p);
10143   if ( (dx==0)&&(dy==0) ) {
10144     dx=x_coord(p)-right_x(q);
10145     dy=y_coord(p)-right_y(q);
10146   }
10147 }
10148 dx=x_coord(p)-x_coord(q);
10149 dy=y_coord(p)-y_coord(q)
10150
10151 @ @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>=
10152 dx=mp_make_fraction(mp, dx,d);
10153 dy=mp_make_fraction(mp, dy,d);
10154 mp_find_offset(mp, -dy,dx,pp);
10155 xx=mp->cur_x; yy=mp->cur_y
10156
10157 @ @<Use |(dx,dy)| to generate a vertex of the square end cap and...@>=
10158 mp_find_offset(mp, dx,dy,pp);
10159 d=mp_take_fraction(mp, xx-mp->cur_x,dx)+mp_take_fraction(mp, yy-mp->cur_y,dy);
10160 if ( ((d<0)&&(i==1)) || ((d>0)&&(i==2))) 
10161   mp_confusion(mp, "box_ends");
10162 @:this can't happen box ends}{\quad\\{box\_ends}@>
10163 z=x_coord(p)+mp->cur_x+mp_take_fraction(mp, d,dx);
10164 if ( z<minx_val(h) ) minx_val(h)=z;
10165 if ( z>maxx_val(h) ) maxx_val(h)=z;
10166 z=y_coord(p)+mp->cur_y+mp_take_fraction(mp, d,dy);
10167 if ( z<miny_val(h) ) miny_val(h)=z;
10168 if ( z>maxy_val(h) ) maxy_val(h)=z
10169
10170 @ @<Advance |p| to the end of the path and make |q| the previous knot@>=
10171 do {  
10172   q=p;
10173   p=link(p);
10174 } while (right_type(p)!=mp_endpoint)
10175
10176 @ The major difficulty in finding the bounding box of an edge structure is the
10177 effect of clipping paths.  We treat them conservatively by only clipping to the
10178 clipping path's bounding box, but this still
10179 requires recursive calls to |set_bbox| in order to find the bounding box of
10180 @^recursion@>
10181 the objects to be clipped.  Such calls are distinguished by the fact that the
10182 boolean parameter |top_level| is false.
10183
10184 @c void mp_set_bbox (MP mp,pointer h, boolean top_level) {
10185   pointer p;  /* a graphical object being considered */
10186   scaled sminx,sminy,smaxx,smaxy;
10187   /* for saving the bounding box during recursive calls */
10188   scaled x0,x1,y0,y1;  /* temporary registers */
10189   integer lev;  /* nesting level for |mp_start_bounds_code| nodes */
10190   @<Wipe out any existing bounding box information if |bbtype(h)| is
10191   incompatible with |internal[mp_true_corners]|@>;
10192   while ( link(bblast(h))!=null ) { 
10193     p=link(bblast(h));
10194     bblast(h)=p;
10195     switch (type(p)) {
10196     case mp_stop_clip_code: 
10197       if ( top_level ) mp_confusion(mp, "bbox");  else return;
10198 @:this can't happen bbox}{\quad bbox@>
10199       break;
10200     @<Other cases for updating the bounding box based on the type of object |p|@>;
10201     } /* all cases are enumerated above */
10202   }
10203   if ( ! top_level ) mp_confusion(mp, "bbox");
10204 }
10205
10206 @ @<Internal library declarations@>=
10207 void mp_set_bbox (MP mp,pointer h, boolean top_level);
10208
10209 @ @<Wipe out any existing bounding box information if |bbtype(h)| is...@>=
10210 switch (bbtype(h)) {
10211 case no_bounds: 
10212   break;
10213 case bounds_set: 
10214   if ( mp->internal[mp_true_corners]>0 ) mp_init_bbox(mp, h);
10215   break;
10216 case bounds_unset: 
10217   if ( mp->internal[mp_true_corners]<=0 ) mp_init_bbox(mp, h);
10218   break;
10219 } /* there are no other cases */
10220
10221 @ @<Other cases for updating the bounding box...@>=
10222 case mp_fill_code: 
10223   mp_path_bbox(mp, path_p(p));
10224   if ( pen_p(p)!=null ) { 
10225     x0=minx; y0=miny;
10226     x1=maxx; y1=maxy;
10227     mp_pen_bbox(mp, pen_p(p));
10228     minx=minx+x0;
10229     miny=miny+y0;
10230     maxx=maxx+x1;
10231     maxy=maxy+y1;
10232   }
10233   mp_adjust_bbox(mp, h);
10234   break;
10235
10236 @ @<Other cases for updating the bounding box...@>=
10237 case mp_start_bounds_code: 
10238   if ( mp->internal[mp_true_corners]>0 ) {
10239     bbtype(h)=bounds_unset;
10240   } else { 
10241     bbtype(h)=bounds_set;
10242     mp_path_bbox(mp, path_p(p));
10243     mp_adjust_bbox(mp, h);
10244     @<Scan to the matching |mp_stop_bounds_code| node and update |p| and
10245       |bblast(h)|@>;
10246   }
10247   break;
10248 case mp_stop_bounds_code: 
10249   if ( mp->internal[mp_true_corners]<=0 ) mp_confusion(mp, "bbox2");
10250 @:this can't happen bbox2}{\quad bbox2@>
10251   break;
10252
10253 @ @<Scan to the matching |mp_stop_bounds_code| node and update |p| and...@>=
10254 lev=1;
10255 while ( lev!=0 ) { 
10256   if ( link(p)==null ) mp_confusion(mp, "bbox2");
10257 @:this can't happen bbox2}{\quad bbox2@>
10258   p=link(p);
10259   if ( type(p)==mp_start_bounds_code ) incr(lev);
10260   else if ( type(p)==mp_stop_bounds_code ) decr(lev);
10261 }
10262 bblast(h)=p
10263
10264 @ It saves a lot of grief here to be slightly conservative and not account for
10265 omitted parts of dashed lines.  We also don't worry about the material omitted
10266 when using butt end caps.  The basic computation is for round end caps and
10267 |box_ends| augments it for square end caps.
10268
10269 @<Other cases for updating the bounding box...@>=
10270 case mp_stroked_code: 
10271   mp_path_bbox(mp, path_p(p));
10272   x0=minx; y0=miny;
10273   x1=maxx; y1=maxy;
10274   mp_pen_bbox(mp, pen_p(p));
10275   minx=minx+x0;
10276   miny=miny+y0;
10277   maxx=maxx+x1;
10278   maxy=maxy+y1;
10279   mp_adjust_bbox(mp, h);
10280   if ( (left_type(path_p(p))==mp_endpoint)&&(lcap_val(p)==2) )
10281     mp_box_ends(mp, path_p(p), pen_p(p), h);
10282   break;
10283
10284 @ The height width and depth information stored in a text node determines a
10285 rectangle that needs to be transformed according to the transformation
10286 parameters stored in the text node.
10287
10288 @<Other cases for updating the bounding box...@>=
10289 case mp_text_code: 
10290   x1=mp_take_scaled(mp, txx_val(p),width_val(p));
10291   y0=mp_take_scaled(mp, txy_val(p),-depth_val(p));
10292   y1=mp_take_scaled(mp, txy_val(p),height_val(p));
10293   minx=tx_val(p);
10294   maxx=minx;
10295   if ( y0<y1 ) { minx=minx+y0; maxx=maxx+y1;  }
10296   else         { minx=minx+y1; maxx=maxx+y0;  }
10297   if ( x1<0 ) minx=minx+x1;  else maxx=maxx+x1;
10298   x1=mp_take_scaled(mp, tyx_val(p),width_val(p));
10299   y0=mp_take_scaled(mp, tyy_val(p),-depth_val(p));
10300   y1=mp_take_scaled(mp, tyy_val(p),height_val(p));
10301   miny=ty_val(p);
10302   maxy=miny;
10303   if ( y0<y1 ) { miny=miny+y0; maxy=maxy+y1;  }
10304   else         { miny=miny+y1; maxy=maxy+y0;  }
10305   if ( x1<0 ) miny=miny+x1;  else maxy=maxy+x1;
10306   mp_adjust_bbox(mp, h);
10307   break;
10308
10309 @ This case involves a recursive call that advances |bblast(h)| to the node of
10310 type |mp_stop_clip_code| that matches |p|.
10311
10312 @<Other cases for updating the bounding box...@>=
10313 case mp_start_clip_code: 
10314   mp_path_bbox(mp, path_p(p));
10315   x0=minx; y0=miny;
10316   x1=maxx; y1=maxy;
10317   sminx=minx_val(h); sminy=miny_val(h);
10318   smaxx=maxx_val(h); smaxy=maxy_val(h);
10319   @<Reinitialize the bounding box in header |h| and call |set_bbox| recursively
10320     starting at |link(p)|@>;
10321   @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,
10322     |y0|, |y1|@>;
10323   minx=sminx; miny=sminy;
10324   maxx=smaxx; maxy=smaxy;
10325   mp_adjust_bbox(mp, h);
10326   break;
10327
10328 @ @<Reinitialize the bounding box in header |h| and call |set_bbox|...@>=
10329 minx_val(h)=el_gordo;
10330 miny_val(h)=el_gordo;
10331 maxx_val(h)=-el_gordo;
10332 maxy_val(h)=-el_gordo;
10333 mp_set_bbox(mp, h,false)
10334
10335 @ @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,...@>=
10336 if ( minx_val(h)<x0 ) minx_val(h)=x0;
10337 if ( miny_val(h)<y0 ) miny_val(h)=y0;
10338 if ( maxx_val(h)>x1 ) maxx_val(h)=x1;
10339 if ( maxy_val(h)>y1 ) maxy_val(h)=y1
10340
10341 @* \[22] Finding an envelope.
10342 When \MP\ has a path and a polygonal pen, it needs to express the desired
10343 shape in terms of things \ps\ can understand.  The present task is to compute
10344 a new path that describes the region to be filled.  It is convenient to
10345 define this as a two step process where the first step is determining what
10346 offset to use for each segment of the path.
10347
10348 @ Given a pointer |c| to a cyclic path,
10349 and a pointer~|h| to the first knot of a pen polygon,
10350 the |offset_prep| routine changes the path into cubics that are
10351 associated with particular pen offsets. Thus if the cubic between |p|
10352 and~|q| is associated with the |k|th offset and the cubic between |q| and~|r|
10353 has offset |l| then |info(q)=zero_off+l-k|. (The constant |zero_off| is added
10354 to because |l-k| could be negative.)
10355
10356 After overwriting the type information with offset differences, we no longer
10357 have a true path so we refer to the knot list returned by |offset_prep| as an
10358 ``envelope spec.''
10359 @^envelope spec@>
10360 Since an envelope spec only determines relative changes in pen offsets,
10361 |offset_prep| sets a global variable |spec_offset| to the relative change from
10362 |h| to the first offset.
10363
10364 @d zero_off 16384 /* added to offset changes to make them positive */
10365
10366 @<Glob...@>=
10367 integer spec_offset; /* number of pen edges between |h| and the initial offset */
10368
10369 @ @c @<Declare subroutines needed by |offset_prep|@>;
10370 pointer mp_offset_prep (MP mp,pointer c, pointer h) {
10371   halfword n; /* the number of vertices in the pen polygon */
10372   pointer p,q,q0,r,w, ww; /* for list manipulation */
10373   integer k_needed; /* amount to be added to |info(p)| when it is computed */
10374   pointer w0; /* a pointer to pen offset to use just before |p| */
10375   scaled dxin,dyin; /* the direction into knot |p| */
10376   integer turn_amt; /* change in pen offsets for the current cubic */
10377   @<Other local variables for |offset_prep|@>;
10378   dx0=0; dy0=0;
10379   @<Initialize the pen size~|n|@>;
10380   @<Initialize the incoming direction and pen offset at |c|@>;
10381   p=c; k_needed=0;
10382   do {  
10383     q=link(p);
10384     @<Split the cubic between |p| and |q|, if necessary, into cubics
10385       associated with single offsets, after which |q| should
10386       point to the end of the final such cubic@>;
10387   NOT_FOUND:
10388     @<Advance |p| to node |q|, removing any ``dead'' cubics that
10389       might have been introduced by the splitting process@>;
10390   } while (q!=c);
10391   @<Fix the offset change in |info(c)| and set |c| to the return value of
10392     |offset_prep|@>;
10393   return c;
10394 }
10395
10396 @ We shall want to keep track of where certain knots on the cyclic path
10397 wind up in the envelope spec.  It doesn't suffice just to keep pointers to
10398 knot nodes because some nodes are deleted while removing dead cubics.  Thus
10399 |offset_prep| updates the following pointers
10400
10401 @<Glob...@>=
10402 pointer spec_p1;
10403 pointer spec_p2; /* pointers to distinguished knots */
10404
10405 @ @<Set init...@>=
10406 mp->spec_p1=null; mp->spec_p2=null;
10407
10408 @ @<Initialize the pen size~|n|@>=
10409 n=0; p=h;
10410 do {  
10411   incr(n);
10412   p=link(p);
10413 } while (p!=h)
10414
10415 @ Since the true incoming direction isn't known yet, we just pick a direction
10416 consistent with the pen offset~|h|.  If this is wrong, it can be corrected
10417 later.
10418
10419 @<Initialize the incoming direction and pen offset at |c|@>=
10420 dxin=x_coord(link(h))-x_coord(knil(h));
10421 dyin=y_coord(link(h))-y_coord(knil(h));
10422 if ( (dxin==0)&&(dyin==0) ) {
10423   dxin=y_coord(knil(h))-y_coord(h);
10424   dyin=x_coord(h)-x_coord(knil(h));
10425 }
10426 w0=h
10427
10428 @ We must be careful not to remove the only cubic in a cycle.
10429
10430 But we must also be careful for another reason. If the user-supplied
10431 path starts with a set of degenerate cubics, the target node |q| can
10432 be collapsed to the initial node |p| which might be the same as the
10433 initial node |c| of the curve. This would cause the |offset_prep| routine
10434 to bail out too early, causing distress later on. (See for example
10435 the testcase reported by Bogus\l{}aw Jackowski in tracker id 267, case 52c
10436 on Sarovar.)
10437
10438 @<Advance |p| to node |q|, removing any ``dead'' cubics...@>=
10439 q0=q;
10440 do { 
10441   r=link(p);
10442   if ( x_coord(p)==right_x(p) && y_coord(p)==right_y(p) &&
10443        x_coord(p)==left_x(r)  && y_coord(p)==left_y(r) &&
10444        x_coord(p)==x_coord(r) && y_coord(p)==y_coord(r) &&
10445        r!=p ) {
10446       @<Remove the cubic following |p| and update the data structures
10447         to merge |r| into |p|@>;
10448   }
10449   p=r;
10450 } while (p!=q);
10451 /* Check if we removed too much */
10452 if(q!=q0)
10453   q = link(q)
10454
10455 @ @<Remove the cubic following |p| and update the data structures...@>=
10456 { k_needed=info(p)-zero_off;
10457   if ( r==q ) { 
10458     q=p;
10459   } else { 
10460     info(p)=k_needed+info(r);
10461     k_needed=0;
10462   };
10463   if ( r==c ) { info(p)=info(c); c=p; };
10464   if ( r==mp->spec_p1 ) mp->spec_p1=p;
10465   if ( r==mp->spec_p2 ) mp->spec_p2=p;
10466   r=p; mp_remove_cubic(mp, p);
10467 }
10468
10469 @ Not setting the |info| field of the newly created knot allows the splitting
10470 routine to work for paths.
10471
10472 @<Declare subroutines needed by |offset_prep|@>=
10473 void mp_split_cubic (MP mp,pointer p, fraction t) { /* splits the cubic after |p| */
10474   scaled v; /* an intermediate value */
10475   pointer q,r; /* for list manipulation */
10476   q=link(p); r=mp_get_node(mp, knot_node_size); link(p)=r; link(r)=q;
10477   originator(r)=mp_program_code;
10478   left_type(r)=mp_explicit; right_type(r)=mp_explicit;
10479   v=t_of_the_way(right_x(p),left_x(q));
10480   right_x(p)=t_of_the_way(x_coord(p),right_x(p));
10481   left_x(q)=t_of_the_way(left_x(q),x_coord(q));
10482   left_x(r)=t_of_the_way(right_x(p),v);
10483   right_x(r)=t_of_the_way(v,left_x(q));
10484   x_coord(r)=t_of_the_way(left_x(r),right_x(r));
10485   v=t_of_the_way(right_y(p),left_y(q));
10486   right_y(p)=t_of_the_way(y_coord(p),right_y(p));
10487   left_y(q)=t_of_the_way(left_y(q),y_coord(q));
10488   left_y(r)=t_of_the_way(right_y(p),v);
10489   right_y(r)=t_of_the_way(v,left_y(q));
10490   y_coord(r)=t_of_the_way(left_y(r),right_y(r));
10491 }
10492
10493 @ This does not set |info(p)| or |right_type(p)|.
10494
10495 @<Declare subroutines needed by |offset_prep|@>=
10496 void mp_remove_cubic (MP mp,pointer p) { /* removes the dead cubic following~|p| */
10497   pointer q; /* the node that disappears */
10498   q=link(p); link(p)=link(q);
10499   right_x(p)=right_x(q); right_y(p)=right_y(q);
10500   mp_free_node(mp, q,knot_node_size);
10501 }
10502
10503 @ Let $d\prec d'$ mean that the counter-clockwise angle from $d$ to~$d'$ is
10504 strictly between zero and $180^\circ$.  Then we can define $d\preceq d'$ to
10505 mean that the angle could be zero or $180^\circ$. If $w_k=(u_k,v_k)$ is the
10506 $k$th pen offset, the $k$th pen edge direction is defined by the formula
10507 $$d_k=(u\k-u_k,\,v\k-v_k).$$
10508 When listed by increasing $k$, these directions occur in counter-clockwise
10509 order so that $d_k\preceq d\k$ for all~$k$.
10510 The goal of |offset_prep| is to find an offset index~|k| to associate with
10511 each cubic, such that the direction $d(t)$ of the cubic satisfies
10512 $$d_{k-1}\preceq d(t)\preceq d_k\qquad\hbox{for $0\le t\le 1$.}\eqno(*)$$
10513 We may have to split a cubic into many pieces before each
10514 piece corresponds to a unique offset.
10515
10516 @<Split the cubic between |p| and |q|, if necessary, into cubics...@>=
10517 info(p)=zero_off+k_needed;
10518 k_needed=0;
10519 @<Prepare for derivative computations;
10520   |goto not_found| if the current cubic is dead@>;
10521 @<Find the initial direction |(dx,dy)|@>;
10522 @<Update |info(p)| and find the offset $w_k$ such that
10523   $d_{k-1}\preceq(\\{dx},\\{dy})\prec d_k$; also advance |w0| for
10524   the direction change at |p|@>;
10525 @<Find the final direction |(dxin,dyin)|@>;
10526 @<Decide on the net change in pen offsets and set |turn_amt|@>;
10527 @<Complete the offset splitting process@>;
10528 w0=mp_pen_walk(mp, w0,turn_amt)
10529
10530 @ @<Declare subroutines needed by |offset_prep|@>=
10531 pointer mp_pen_walk (MP mp,pointer w, integer k) {
10532   /* walk |k| steps around a pen from |w| */
10533   while ( k>0 ) { w=link(w); decr(k);  };
10534   while ( k<0 ) { w=knil(w); incr(k);  };
10535   return w;
10536 }
10537
10538 @ The direction of a cubic $B(z_0,z_1,z_2,z_3;t)=\bigl(x(t),y(t)\bigr)$ can be
10539 calculated from the quadratic polynomials
10540 ${1\over3}x'(t)=B(x_1-x_0,x_2-x_1,x_3-x_2;t)$ and
10541 ${1\over3}y'(t)=B(y_1-y_0,y_2-y_1,y_3-y_2;t)$.
10542 Since we may be calculating directions from several cubics
10543 split from the current one, it is desirable to do these calculations
10544 without losing too much precision. ``Scaled up'' values of the
10545 derivatives, which will be less tainted by accumulated errors than
10546 derivatives found from the cubics themselves, are maintained in
10547 local variables |x0|, |x1|, and |x2|, representing $X_0=2^l(x_1-x_0)$,
10548 $X_1=2^l(x_2-x_1)$, and $X_2=2^l(x_3-x_2)$; similarly |y0|, |y1|, and~|y2|
10549 represent $Y_0=2^l(y_1-y_0)$, $Y_1=2^l(y_2-y_1)$, and $Y_2=2^l(y_3-y_2)$.
10550
10551 @<Other local variables for |offset_prep|@>=
10552 integer x0,x1,x2,y0,y1,y2; /* representatives of derivatives */
10553 integer t0,t1,t2; /* coefficients of polynomial for slope testing */
10554 integer du,dv,dx,dy; /* for directions of the pen and the curve */
10555 integer dx0,dy0; /* initial direction for the first cubic in the curve */
10556 integer max_coef; /* used while scaling */
10557 integer x0a,x1a,x2a,y0a,y1a,y2a; /* intermediate values */
10558 fraction t; /* where the derivative passes through zero */
10559 fraction s; /* a temporary value */
10560
10561 @ @<Prepare for derivative computations...@>=
10562 x0=right_x(p)-x_coord(p);
10563 x2=x_coord(q)-left_x(q);
10564 x1=left_x(q)-right_x(p);
10565 y0=right_y(p)-y_coord(p); y2=y_coord(q)-left_y(q);
10566 y1=left_y(q)-right_y(p);
10567 max_coef=abs(x0);
10568 if ( abs(x1)>max_coef ) max_coef=abs(x1);
10569 if ( abs(x2)>max_coef ) max_coef=abs(x2);
10570 if ( abs(y0)>max_coef ) max_coef=abs(y0);
10571 if ( abs(y1)>max_coef ) max_coef=abs(y1);
10572 if ( abs(y2)>max_coef ) max_coef=abs(y2);
10573 if ( max_coef==0 ) goto NOT_FOUND;
10574 while ( max_coef<fraction_half ) {
10575   double(max_coef);
10576   double(x0); double(x1); double(x2);
10577   double(y0); double(y1); double(y2);
10578 }
10579
10580 @ Let us first solve a special case of the problem: Suppose we
10581 know an index~$k$ such that either (i)~$d(t)\succeq d_{k-1}$ for all~$t$
10582 and $d(0)\prec d_k$, or (ii)~$d(t)\preceq d_k$ for all~$t$ and
10583 $d(0)\succ d_{k-1}$.
10584 Then, in a sense, we're halfway done, since one of the two relations
10585 in $(*)$ is satisfied, and the other couldn't be satisfied for
10586 any other value of~|k|.
10587
10588 Actually, the conditions can be relaxed somewhat since a relation such as
10589 $d(t)\succeq d_{k-1}$ restricts $d(t)$ to a half plane when all that really
10590 matters is whether $d(t)$ crosses the ray in the $d_{k-1}$ direction from
10591 the origin.  The condition for case~(i) becomes $d_{k-1}\preceq d(0)\prec d_k$
10592 and $d(t)$ never crosses the $d_{k-1}$ ray in the clockwise direction.
10593 Case~(ii) is similar except $d(t)$ cannot cross the $d_k$ ray in the
10594 counterclockwise direction.
10595
10596 The |fin_offset_prep| subroutine solves the stated subproblem.
10597 It has a parameter called |rise| that is |1| in
10598 case~(i), |-1| in case~(ii). Parameters |x0| through |y2| represent
10599 the derivative of the cubic following |p|.
10600 The |w| parameter should point to offset~$w_k$ and |info(p)| should already
10601 be set properly.  The |turn_amt| parameter gives the absolute value of the
10602 overall net change in pen offsets.
10603
10604 @<Declare subroutines needed by |offset_prep|@>=
10605 void mp_fin_offset_prep (MP mp,pointer p, pointer w, integer 
10606   x0,integer x1, integer x2, integer y0, integer y1, integer y2, 
10607   integer rise, integer turn_amt)  {
10608   pointer ww; /* for list manipulation */
10609   scaled du,dv; /* for slope calculation */
10610   integer t0,t1,t2; /* test coefficients */
10611   fraction t; /* place where the derivative passes a critical slope */
10612   fraction s; /* slope or reciprocal slope */
10613   integer v; /* intermediate value for updating |x0..y2| */
10614   pointer q; /* original |link(p)| */
10615   q=link(p);
10616   while (1)  { 
10617     if ( rise>0 ) ww=link(w); /* a pointer to $w\k$ */
10618     else  ww=knil(w); /* a pointer to $w_{k-1}$ */
10619     @<Compute test coefficients |(t0,t1,t2)|
10620       for $d(t)$ versus $d_k$ or $d_{k-1}$@>;
10621     t=mp_crossing_point(mp, t0,t1,t2);
10622     if ( t>=fraction_one ) {
10623       if ( turn_amt>0 ) t=fraction_one;  else return;
10624     }
10625     @<Split the cubic at $t$,
10626       and split off another cubic if the derivative crosses back@>;
10627     w=ww;
10628   }
10629 }
10630
10631 @ We want $B(\\{t0},\\{t1},\\{t2};t)$ to be the dot product of $d(t)$ with a
10632 $-90^\circ$ rotation of the vector from |w| to |ww|.  This makes the resulting
10633 function cross from positive to negative when $d_{k-1}\preceq d(t)\preceq d_k$
10634 begins to fail.
10635
10636 @<Compute test coefficients |(t0,t1,t2)| for $d(t)$ versus...@>=
10637 du=x_coord(ww)-x_coord(w); dv=y_coord(ww)-y_coord(w);
10638 if ( abs(du)>=abs(dv) ) {
10639   s=mp_make_fraction(mp, dv,du);
10640   t0=mp_take_fraction(mp, x0,s)-y0;
10641   t1=mp_take_fraction(mp, x1,s)-y1;
10642   t2=mp_take_fraction(mp, x2,s)-y2;
10643   if ( du<0 ) { negate(t0); negate(t1); negate(t2);  }
10644 } else { 
10645   s=mp_make_fraction(mp, du,dv);
10646   t0=x0-mp_take_fraction(mp, y0,s);
10647   t1=x1-mp_take_fraction(mp, y1,s);
10648   t2=x2-mp_take_fraction(mp, y2,s);
10649   if ( dv<0 ) { negate(t0); negate(t1); negate(t2);  }
10650 }
10651 if ( t0<0 ) t0=0 /* should be positive without rounding error */
10652
10653 @ The curve has crossed $d_k$ or $d_{k-1}$; its initial segment satisfies
10654 $(*)$, and it might cross again, yielding another solution of $(*)$.
10655
10656 @<Split the cubic at $t$, and split off another...@>=
10657
10658 mp_split_cubic(mp, p,t); p=link(p); info(p)=zero_off+rise;
10659 decr(turn_amt);
10660 v=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10661 x0=t_of_the_way(v,x1);
10662 v=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10663 y0=t_of_the_way(v,y1);
10664 if ( turn_amt<0 ) {
10665   t1=t_of_the_way(t1,t2);
10666   if ( t1>0 ) t1=0; /* without rounding error, |t1| would be |<=0| */
10667   t=mp_crossing_point(mp, 0,-t1,-t2);
10668   if ( t>fraction_one ) t=fraction_one;
10669   incr(turn_amt);
10670   if ( (t==fraction_one)&&(link(p)!=q) ) {
10671     info(link(p))=info(link(p))-rise;
10672   } else { 
10673     mp_split_cubic(mp, p,t); info(link(p))=zero_off-rise;
10674     v=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10675     x2=t_of_the_way(x1,v);
10676     v=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10677     y2=t_of_the_way(y1,v);
10678   }
10679 }
10680 }
10681
10682 @ Now we must consider the general problem of |offset_prep|, when
10683 nothing is known about a given cubic. We start by finding its
10684 direction in the vicinity of |t=0|.
10685
10686 If $z'(t)=0$, the given cubic is numerically unstable but |offset_prep|
10687 has not yet introduced any more numerical errors.  Thus we can compute
10688 the true initial direction for the given cubic, even if it is almost
10689 degenerate.
10690
10691 @<Find the initial direction |(dx,dy)|@>=
10692 dx=x0; dy=y0;
10693 if ( dx==0 && dy==0 ) { 
10694   dx=x1; dy=y1;
10695   if ( dx==0 && dy==0 ) { 
10696     dx=x2; dy=y2;
10697   }
10698 }
10699 if ( p==c ) { dx0=dx; dy0=dy;  }
10700
10701 @ @<Find the final direction |(dxin,dyin)|@>=
10702 dxin=x2; dyin=y2;
10703 if ( dxin==0 && dyin==0 ) {
10704   dxin=x1; dyin=y1;
10705   if ( dxin==0 && dyin==0 ) {
10706     dxin=x0; dyin=y0;
10707   }
10708 }
10709
10710 @ The next step is to bracket the initial direction between consecutive
10711 edges of the pen polygon.  We must be careful to turn clockwise only if
10712 this makes the turn less than $180^\circ$. (A $180^\circ$ turn must be
10713 counter-clockwise in order to make \&{doublepath} envelopes come out
10714 @:double_path_}{\&{doublepath} primitive@>
10715 right.) This code depends on |w0| being the offset for |(dxin,dyin)|.
10716
10717 @<Update |info(p)| and find the offset $w_k$ such that...@>=
10718 turn_amt=mp_get_turn_amt(mp,w0,dx,dy,(mp_ab_vs_cd(mp, dy,dxin,dx,dyin)>=0));
10719 w=mp_pen_walk(mp, w0, turn_amt);
10720 w0=w;
10721 info(p)=info(p)+turn_amt
10722
10723 @ Decide how many pen offsets to go away from |w| in order to find the offset
10724 for |(dx,dy)|, going counterclockwise if |ccw| is |true|.  This assumes that
10725 |w| is the offset for some direction $(x',y')$ from which the angle to |(dx,dy)|
10726 in the sense determined by |ccw| is less than or equal to $180^\circ$.
10727
10728 If the pen polygon has only two edges, they could both be parallel
10729 to |(dx,dy)|.  In this case, we must be careful to stop after crossing the first
10730 such edge in order to avoid an infinite loop.
10731
10732 @<Declare subroutines needed by |offset_prep|@>=
10733 integer mp_get_turn_amt (MP mp,pointer w, scaled  dx,
10734                          scaled dy, boolean  ccw) {
10735   pointer ww; /* a neighbor of knot~|w| */
10736   integer s; /* turn amount so far */
10737   integer t; /* |ab_vs_cd| result */
10738   s=0;
10739   if ( ccw ) { 
10740     ww=link(w);
10741     do {  
10742       t=mp_ab_vs_cd(mp, dy,(x_coord(ww)-x_coord(w)),
10743                         dx,(y_coord(ww)-y_coord(w)));
10744       if ( t<0 ) break;
10745       incr(s);
10746       w=ww; ww=link(ww);
10747     } while (t>0);
10748   } else { 
10749     ww=knil(w);
10750     while ( mp_ab_vs_cd(mp, dy,(x_coord(w)-x_coord(ww)),
10751                             dx,(y_coord(w)-y_coord(ww))) < 0) { 
10752       decr(s);
10753       w=ww; ww=knil(ww);
10754     }
10755   }
10756   return s;
10757 }
10758
10759 @ When we're all done, the final offset is |w0| and the final curve direction
10760 is |(dxin,dyin)|.  With this knowledge of the incoming direction at |c|, we
10761 can correct |info(c)| which was erroneously based on an incoming offset
10762 of~|h|.
10763
10764 @d fix_by(A) info(c)=info(c)+(A)
10765
10766 @<Fix the offset change in |info(c)| and set |c| to the return value of...@>=
10767 mp->spec_offset=info(c)-zero_off;
10768 if ( link(c)==c ) {
10769   info(c)=zero_off+n;
10770 } else { 
10771   fix_by(k_needed);
10772   while ( w0!=h ) { fix_by(1); w0=link(w0);  };
10773   while ( info(c)<=zero_off-n ) fix_by(n);
10774   while ( info(c)>zero_off ) fix_by(-n);
10775   if ( (info(c)!=zero_off)&&(mp_ab_vs_cd(mp, dy0,dxin,dx0,dyin)>=0) ) fix_by(n);
10776 }
10777 return c
10778
10779 @ Finally we want to reduce the general problem to situations that
10780 |fin_offset_prep| can handle. We split the cubic into at most three parts
10781 with respect to $d_{k-1}$, and apply |fin_offset_prep| to each part.
10782
10783 @<Complete the offset splitting process@>=
10784 ww=knil(w);
10785 @<Compute test coeff...@>;
10786 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set
10787   |t:=fraction_one+1|@>;
10788 if ( t>fraction_one ) {
10789   mp_fin_offset_prep(mp, p,w,x0,x1,x2,y0,y1,y2,1,turn_amt);
10790 } else {
10791   mp_split_cubic(mp, p,t); r=link(p);
10792   x1a=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10793   x2a=t_of_the_way(x1a,x1);
10794   y1a=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10795   y2a=t_of_the_way(y1a,y1);
10796   mp_fin_offset_prep(mp, p,w,x0,x1a,x2a,y0,y1a,y2a,1,0); x0=x2a; y0=y2a;
10797   info(r)=zero_off-1;
10798   if ( turn_amt>=0 ) {
10799     t1=t_of_the_way(t1,t2);
10800     if ( t1>0 ) t1=0;
10801     t=mp_crossing_point(mp, 0,-t1,-t2);
10802     if ( t>fraction_one ) t=fraction_one;
10803     @<Split off another rising cubic for |fin_offset_prep|@>;
10804     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,0);
10805   } else {
10806     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,(-1-turn_amt));
10807   }
10808 }
10809
10810 @ @<Split off another rising cubic for |fin_offset_prep|@>=
10811 mp_split_cubic(mp, r,t); info(link(r))=zero_off+1;
10812 x1a=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10813 x0a=t_of_the_way(x1,x1a);
10814 y1a=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10815 y0a=t_of_the_way(y1,y1a);
10816 mp_fin_offset_prep(mp, link(r),w,x0a,x1a,x2,y0a,y1a,y2,1,turn_amt);
10817 x2=x0a; y2=y0a
10818
10819 @ At this point, the direction of the incoming pen edge is |(-du,-dv)|.
10820 When the component of $d(t)$ perpendicular to |(-du,-dv)| crosses zero, we
10821 need to decide whether the directions are parallel or antiparallel.  We
10822 can test this by finding the dot product of $d(t)$ and |(-du,-dv)|, but this
10823 should be avoided when the value of |turn_amt| already determines the
10824 answer.  If |t2<0|, there is one crossing and it is antiparallel only if
10825 |turn_amt>=0|.  If |turn_amt<0|, there should always be at least one
10826 crossing and the first crossing cannot be antiparallel.
10827
10828 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set...@>=
10829 t=mp_crossing_point(mp, t0,t1,t2);
10830 if ( turn_amt>=0 ) {
10831   if ( t2<0 ) {
10832     t=fraction_one+1;
10833   } else { 
10834     u0=t_of_the_way(x0,x1);
10835     u1=t_of_the_way(x1,x2);
10836     ss=mp_take_fraction(mp, -du,t_of_the_way(u0,u1));
10837     v0=t_of_the_way(y0,y1);
10838     v1=t_of_the_way(y1,y2);
10839     ss=ss+mp_take_fraction(mp, -dv,t_of_the_way(v0,v1));
10840     if ( ss<0 ) t=fraction_one+1;
10841   }
10842 } else if ( t>fraction_one ) {
10843   t=fraction_one;
10844 }
10845
10846 @ @<Other local variables for |offset_prep|@>=
10847 integer u0,u1,v0,v1; /* intermediate values for $d(t)$ calculation */
10848 integer ss = 0; /* the part of the dot product computed so far */
10849 int d_sign; /* sign of overall change in direction for this cubic */
10850
10851 @ If the cubic almost has a cusp, it is a numerically ill-conditioned
10852 problem to decide which way it loops around but that's OK as long we're
10853 consistent.  To make \&{doublepath} envelopes work properly, reversing
10854 the path should always change the sign of |turn_amt|.
10855
10856 @<Decide on the net change in pen offsets and set |turn_amt|@>=
10857 d_sign=mp_ab_vs_cd(mp, dx,dyin, dxin,dy);
10858 if ( d_sign==0 ) {
10859   @<Check rotation direction based on node position@>
10860 }
10861 if ( d_sign==0 ) {
10862   if ( dx==0 ) {
10863     if ( dy>0 ) d_sign=1;  else d_sign=-1;
10864   } else {
10865     if ( dx>0 ) d_sign=1;  else d_sign=-1; 
10866   }
10867 }
10868 @<Make |ss| negative if and only if the total change in direction is
10869   more than $180^\circ$@>;
10870 turn_amt=mp_get_turn_amt(mp, w, dxin, dyin, (d_sign>0));
10871 if ( ss<0 ) turn_amt=turn_amt-d_sign*n
10872
10873 @ We check rotation direction by looking at the vector connecting the current
10874 node with the next. If its angle with incoming and outgoing tangents has the
10875 same sign, we pick this as |d_sign|, since it means we have a flex, not a cusp.
10876 Otherwise we proceed to the cusp code.
10877
10878 @<Check rotation direction based on node position@>=
10879 u0=x_coord(q)-x_coord(p);
10880 u1=y_coord(q)-y_coord(p);
10881 d_sign = half(mp_ab_vs_cd(mp, dx, u1, u0, dy)+
10882   mp_ab_vs_cd(mp, u0, dyin, dxin, u1));
10883
10884 @ In order to be invariant under path reversal, the result of this computation
10885 should not change when |x0|, |y0|, $\ldots$ are all negated and |(x0,y0)| is
10886 then swapped with |(x2,y2)|.  We make use of the identities
10887 |take_fraction(-a,-b)=take_fraction(a,b)| and
10888 |t_of_the_way(-a,-b)=-(t_of_the_way(a,b))|.
10889
10890 @<Make |ss| negative if and only if the total change in direction is...@>=
10891 t0=half(mp_take_fraction(mp, x0,y2))-half(mp_take_fraction(mp, x2,y0));
10892 t1=half(mp_take_fraction(mp, x1,(y0+y2)))-half(mp_take_fraction(mp, y1,(x0+x2)));
10893 if ( t0==0 ) t0=d_sign; /* path reversal always negates |d_sign| */
10894 if ( t0>0 ) {
10895   t=mp_crossing_point(mp, t0,t1,-t0);
10896   u0=t_of_the_way(x0,x1);
10897   u1=t_of_the_way(x1,x2);
10898   v0=t_of_the_way(y0,y1);
10899   v1=t_of_the_way(y1,y2);
10900 } else { 
10901   t=mp_crossing_point(mp, -t0,t1,t0);
10902   u0=t_of_the_way(x2,x1);
10903   u1=t_of_the_way(x1,x0);
10904   v0=t_of_the_way(y2,y1);
10905   v1=t_of_the_way(y1,y0);
10906 }
10907 ss=mp_take_fraction(mp, (x0+x2),t_of_the_way(u0,u1))+
10908    mp_take_fraction(mp, (y0+y2),t_of_the_way(v0,v1))
10909
10910 @ Here's a routine that prints an envelope spec in symbolic form.  It assumes
10911 that the |cur_pen| has not been walked around to the first offset.
10912
10913 @c 
10914 void mp_print_spec (MP mp,pointer cur_spec, pointer cur_pen, char *s) {
10915   pointer p,q; /* list traversal */
10916   pointer w; /* the current pen offset */
10917   mp_print_diagnostic(mp, "Envelope spec",s,true);
10918   p=cur_spec; w=mp_pen_walk(mp, cur_pen,mp->spec_offset);
10919   mp_print_ln(mp);
10920   mp_print_two(mp, x_coord(cur_spec),y_coord(cur_spec));
10921   mp_print(mp, " % beginning with offset ");
10922   mp_print_two(mp, x_coord(w),y_coord(w));
10923   do { 
10924     while (1) {  
10925       q=link(p);
10926       @<Print the cubic between |p| and |q|@>;
10927       p=q;
10928           if ((p==cur_spec) || (info(p)!=zero_off)) 
10929         break;
10930     }
10931     if ( info(p)!=zero_off ) {
10932       @<Update |w| as indicated by |info(p)| and print an explanation@>;
10933     }
10934   } while (p!=cur_spec);
10935   mp_print_nl(mp, " & cycle");
10936   mp_end_diagnostic(mp, true);
10937 }
10938
10939 @ @<Update |w| as indicated by |info(p)| and print an explanation@>=
10940
10941   w=mp_pen_walk(mp, w, (info(p)-zero_off));
10942   mp_print(mp, " % ");
10943   if ( info(p)>zero_off ) mp_print(mp, "counter");
10944   mp_print(mp, "clockwise to offset ");
10945   mp_print_two(mp, x_coord(w),y_coord(w));
10946 }
10947
10948 @ @<Print the cubic between |p| and |q|@>=
10949
10950   mp_print_nl(mp, "   ..controls ");
10951   mp_print_two(mp, right_x(p),right_y(p));
10952   mp_print(mp, " and ");
10953   mp_print_two(mp, left_x(q),left_y(q));
10954   mp_print_nl(mp, " ..");
10955   mp_print_two(mp, x_coord(q),y_coord(q));
10956 }
10957
10958 @ Once we have an envelope spec, the remaining task to construct the actual
10959 envelope by offsetting each cubic as determined by the |info| fields in
10960 the knots.  First we use |offset_prep| to convert the |c| into an envelope
10961 spec. Then we add the offsets so that |c| becomes a cyclic path that represents
10962 the envelope.
10963
10964 The |ljoin| and |miterlim| parameters control the treatment of points where the
10965 pen offset changes, and |lcap| controls the endpoints of a \&{doublepath}.
10966 The endpoints are easily located because |c| is given in undoubled form
10967 and then doubled in this procedure.  We use |spec_p1| and |spec_p2| to keep
10968 track of the endpoints and treat them like very sharp corners.
10969 Butt end caps are treated like beveled joins; round end caps are treated like
10970 round joins; and square end caps are achieved by setting |join_type:=3|.
10971
10972 None of these parameters apply to inside joins where the convolution tracing
10973 has retrograde lines.  In such cases we use a simple connect-the-endpoints
10974 approach that is achieved by setting |join_type:=2|.
10975
10976 @c @<Declare a function called |insert_knot|@>;
10977 pointer mp_make_envelope (MP mp,pointer c, pointer h, small_number ljoin,
10978   small_number lcap, scaled miterlim) {
10979   pointer p,q,r,q0; /* for manipulating the path */
10980   int join_type=0; /* codes |0..3| for mitered, round, beveled, or square */
10981   pointer w,w0; /* the pen knot for the current offset */
10982   scaled qx,qy; /* unshifted coordinates of |q| */
10983   halfword k,k0; /* controls pen edge insertion */
10984   @<Other local variables for |make_envelope|@>;
10985   dxin=0; dyin=0; dxout=0; dyout=0;
10986   mp->spec_p1=null; mp->spec_p2=null;
10987   @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>;
10988   @<Use |offset_prep| to compute the envelope spec then walk |h| around to
10989     the initial offset@>;
10990   w=h;
10991   p=c;
10992   do {  
10993     q=link(p); q0=q;
10994     qx=x_coord(q); qy=y_coord(q);
10995     k=info(q);
10996     k0=k; w0=w;
10997     if ( k!=zero_off ) {
10998       @<Set |join_type| to indicate how to handle offset changes at~|q|@>;
10999     }
11000     @<Add offset |w| to the cubic from |p| to |q|@>;
11001     while ( k!=zero_off ) { 
11002       @<Step |w| and move |k| one step closer to |zero_off|@>;
11003       if ( (join_type==1)||(k==zero_off) )
11004          q=mp_insert_knot(mp, q,qx+x_coord(w),qy+y_coord(w));
11005     };
11006     if ( q!=link(p) ) {
11007       @<Set |p=link(p)| and add knots between |p| and |q| as
11008         required by |join_type|@>;
11009     }
11010     p=q;
11011   } while (q0!=c);
11012   return c;
11013 }
11014
11015 @ @<Use |offset_prep| to compute the envelope spec then walk |h| around to...@>=
11016 c=mp_offset_prep(mp, c,h);
11017 if ( mp->internal[mp_tracing_specs]>0 ) 
11018   mp_print_spec(mp, c,h,"");
11019 h=mp_pen_walk(mp, h,mp->spec_offset)
11020
11021 @ Mitered and squared-off joins depend on path directions that are difficult to
11022 compute for degenerate cubics.  The envelope spec computed by |offset_prep| can
11023 have degenerate cubics only if the entire cycle collapses to a single
11024 degenerate cubic.  Setting |join_type:=2| in this case makes the computed
11025 envelope degenerate as well.
11026
11027 @<Set |join_type| to indicate how to handle offset changes at~|q|@>=
11028 if ( k<zero_off ) {
11029   join_type=2;
11030 } else {
11031   if ( (q!=mp->spec_p1)&&(q!=mp->spec_p2) ) join_type=ljoin;
11032   else if ( lcap==2 ) join_type=3;
11033   else join_type=2-lcap;
11034   if ( (join_type==0)||(join_type==3) ) {
11035     @<Set the incoming and outgoing directions at |q|; in case of
11036       degeneracy set |join_type:=2|@>;
11037     if ( join_type==0 ) {
11038       @<If |miterlim| is less than the secant of half the angle at |q|
11039         then set |join_type:=2|@>;
11040     }
11041   }
11042 }
11043
11044 @ @<If |miterlim| is less than the secant of half the angle at |q|...@>=
11045
11046   tmp=mp_take_fraction(mp, miterlim,fraction_half+
11047       half(mp_take_fraction(mp, dxin,dxout)+mp_take_fraction(mp, dyin,dyout)));
11048   if ( tmp<unity )
11049     if ( mp_take_scaled(mp, miterlim,tmp)<unity ) join_type=2;
11050 }
11051
11052 @ @<Other local variables for |make_envelope|@>=
11053 fraction dxin,dyin,dxout,dyout; /* directions at |q| when square or mitered */
11054 scaled tmp; /* a temporary value */
11055
11056 @ The coordinates of |p| have already been shifted unless |p| is the first
11057 knot in which case they get shifted at the very end.
11058
11059 @<Add offset |w| to the cubic from |p| to |q|@>=
11060 right_x(p)=right_x(p)+x_coord(w);
11061 right_y(p)=right_y(p)+y_coord(w);
11062 left_x(q)=left_x(q)+x_coord(w);
11063 left_y(q)=left_y(q)+y_coord(w);
11064 x_coord(q)=x_coord(q)+x_coord(w);
11065 y_coord(q)=y_coord(q)+y_coord(w);
11066 left_type(q)=mp_explicit;
11067 right_type(q)=mp_explicit
11068
11069 @ @<Step |w| and move |k| one step closer to |zero_off|@>=
11070 if ( k>zero_off ){ w=link(w); decr(k);  }
11071 else { w=knil(w); incr(k);  }
11072
11073 @ The cubic from |q| to the new knot at |(x,y)| becomes a line segment and
11074 the |right_x| and |right_y| fields of |r| are set from |q|.  This is done in
11075 case the cubic containing these control points is ``yet to be examined.''
11076
11077 @<Declare a function called |insert_knot|@>=
11078 pointer mp_insert_knot (MP mp,pointer q, scaled x, scaled y) {
11079   /* returns the inserted knot */
11080   pointer r; /* the new knot */
11081   r=mp_get_node(mp, knot_node_size);
11082   link(r)=link(q); link(q)=r;
11083   right_x(r)=right_x(q);
11084   right_y(r)=right_y(q);
11085   x_coord(r)=x;
11086   y_coord(r)=y;
11087   right_x(q)=x_coord(q);
11088   right_y(q)=y_coord(q);
11089   left_x(r)=x_coord(r);
11090   left_y(r)=y_coord(r);
11091   left_type(r)=mp_explicit;
11092   right_type(r)=mp_explicit;
11093   originator(r)=mp_program_code;
11094   return r;
11095 }
11096
11097 @ After setting |p:=link(p)|, either |join_type=1| or |q=link(p)|.
11098
11099 @<Set |p=link(p)| and add knots between |p| and |q| as...@>=
11100
11101   p=link(p);
11102   if ( (join_type==0)||(join_type==3) ) {
11103     if ( join_type==0 ) {
11104       @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>
11105     } else {
11106       @<Make |r| the last of two knots inserted between |p| and |q| to form a
11107         squared join@>;
11108     }
11109     if ( r!=null ) { 
11110       right_x(r)=x_coord(r);
11111       right_y(r)=y_coord(r);
11112     }
11113   }
11114 }
11115
11116 @ For very small angles, adding a knot is unnecessary and would cause numerical
11117 problems, so we just set |r:=null| in that case.
11118
11119 @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>=
11120
11121   det=mp_take_fraction(mp, dyout,dxin)-mp_take_fraction(mp, dxout,dyin);
11122   if ( abs(det)<26844 ) { 
11123      r=null; /* sine $<10^{-4}$ */
11124   } else { 
11125     tmp=mp_take_fraction(mp, x_coord(q)-x_coord(p),dyout)-
11126         mp_take_fraction(mp, y_coord(q)-y_coord(p),dxout);
11127     tmp=mp_make_fraction(mp, tmp,det);
11128     r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
11129       y_coord(p)+mp_take_fraction(mp, tmp,dyin));
11130   }
11131 }
11132
11133 @ @<Other local variables for |make_envelope|@>=
11134 fraction det; /* a determinant used for mitered join calculations */
11135
11136 @ @<Make |r| the last of two knots inserted between |p| and |q| to form a...@>=
11137
11138   ht_x=y_coord(w)-y_coord(w0);
11139   ht_y=x_coord(w0)-x_coord(w);
11140   while ( (abs(ht_x)<fraction_half)&&(abs(ht_y)<fraction_half) ) { 
11141     ht_x+=ht_x; ht_y+=ht_y;
11142   }
11143   @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range dot
11144     product with |(ht_x,ht_y)|@>;
11145   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxin,ht_x)+
11146                                   mp_take_fraction(mp, dyin,ht_y));
11147   r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
11148                          y_coord(p)+mp_take_fraction(mp, tmp,dyin));
11149   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxout,ht_x)+
11150                                   mp_take_fraction(mp, dyout,ht_y));
11151   r=mp_insert_knot(mp, r,x_coord(q)+mp_take_fraction(mp, tmp,dxout),
11152                          y_coord(q)+mp_take_fraction(mp, tmp,dyout));
11153 }
11154
11155 @ @<Other local variables for |make_envelope|@>=
11156 fraction ht_x,ht_y; /* perpendicular to the segment from |p| to |q| */
11157 scaled max_ht; /* maximum height of the pen polygon above the |w0|-|w| line */
11158 halfword kk; /* keeps track of the pen vertices being scanned */
11159 pointer ww; /* the pen vertex being tested */
11160
11161 @ The dot product of the vector from |w0| to |ww| with |(ht_x,ht_y)| ranges
11162 from zero to |max_ht|.
11163
11164 @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range...@>=
11165 max_ht=0;
11166 kk=zero_off;
11167 ww=w;
11168 while (1)  { 
11169   @<Step |ww| and move |kk| one step closer to |k0|@>;
11170   if ( kk==k0 ) break;
11171   tmp=mp_take_fraction(mp, (x_coord(ww)-x_coord(w0)),ht_x)+
11172       mp_take_fraction(mp, (y_coord(ww)-y_coord(w0)),ht_y);
11173   if ( tmp>max_ht ) max_ht=tmp;
11174 }
11175
11176
11177 @ @<Step |ww| and move |kk| one step closer to |k0|@>=
11178 if ( kk>k0 ) { ww=link(ww); decr(kk);  }
11179 else { ww=knil(ww); incr(kk);  }
11180
11181 @ @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>=
11182 if ( left_type(c)==mp_endpoint ) { 
11183   mp->spec_p1=mp_htap_ypoc(mp, c);
11184   mp->spec_p2=mp->path_tail;
11185   originator(mp->spec_p1)=mp_program_code;
11186   link(mp->spec_p2)=link(mp->spec_p1);
11187   link(mp->spec_p1)=c;
11188   mp_remove_cubic(mp, mp->spec_p1);
11189   c=mp->spec_p1;
11190   if ( c!=link(c) ) {
11191     originator(mp->spec_p2)=mp_program_code;
11192     mp_remove_cubic(mp, mp->spec_p2);
11193   } else {
11194     @<Make |c| look like a cycle of length one@>;
11195   }
11196 }
11197
11198 @ @<Make |c| look like a cycle of length one@>=
11199
11200   left_type(c)=mp_explicit; right_type(c)=mp_explicit;
11201   left_x(c)=x_coord(c); left_y(c)=y_coord(c);
11202   right_x(c)=x_coord(c); right_y(c)=y_coord(c);
11203 }
11204
11205 @ In degenerate situations we might have to look at the knot preceding~|q|.
11206 That knot is |p| but if |p<>c|, its coordinates have already been offset by |w|.
11207
11208 @<Set the incoming and outgoing directions at |q|; in case of...@>=
11209 dxin=x_coord(q)-left_x(q);
11210 dyin=y_coord(q)-left_y(q);
11211 if ( (dxin==0)&&(dyin==0) ) {
11212   dxin=x_coord(q)-right_x(p);
11213   dyin=y_coord(q)-right_y(p);
11214   if ( (dxin==0)&&(dyin==0) ) {
11215     dxin=x_coord(q)-x_coord(p);
11216     dyin=y_coord(q)-y_coord(p);
11217     if ( p!=c ) { /* the coordinates of |p| have been offset by |w| */
11218       dxin=dxin+x_coord(w);
11219       dyin=dyin+y_coord(w);
11220     }
11221   }
11222 }
11223 tmp=mp_pyth_add(mp, dxin,dyin);
11224 if ( tmp==0 ) {
11225   join_type=2;
11226 } else { 
11227   dxin=mp_make_fraction(mp, dxin,tmp);
11228   dyin=mp_make_fraction(mp, dyin,tmp);
11229   @<Set the outgoing direction at |q|@>;
11230 }
11231
11232 @ If |q=c| then the coordinates of |r| and the control points between |q|
11233 and~|r| have already been offset by |h|.
11234
11235 @<Set the outgoing direction at |q|@>=
11236 dxout=right_x(q)-x_coord(q);
11237 dyout=right_y(q)-y_coord(q);
11238 if ( (dxout==0)&&(dyout==0) ) {
11239   r=link(q);
11240   dxout=left_x(r)-x_coord(q);
11241   dyout=left_y(r)-y_coord(q);
11242   if ( (dxout==0)&&(dyout==0) ) {
11243     dxout=x_coord(r)-x_coord(q);
11244     dyout=y_coord(r)-y_coord(q);
11245   }
11246 }
11247 if ( q==c ) {
11248   dxout=dxout-x_coord(h);
11249   dyout=dyout-y_coord(h);
11250 }
11251 tmp=mp_pyth_add(mp, dxout,dyout);
11252 if ( tmp==0 ) mp_confusion(mp, "degenerate spec");
11253 @:this can't happen degerate spec}{\quad degenerate spec@>
11254 dxout=mp_make_fraction(mp, dxout,tmp);
11255 dyout=mp_make_fraction(mp, dyout,tmp)
11256
11257 @* \[23] Direction and intersection times.
11258 A path of length $n$ is defined parametrically by functions $x(t)$ and
11259 $y(t)$, for |0<=t<=n|; we can regard $t$ as the ``time'' at which the path
11260 reaches the point $\bigl(x(t),y(t)\bigr)$.  In this section of the program
11261 we shall consider operations that determine special times associated with
11262 given paths: the first time that a path travels in a given direction, and
11263 a pair of times at which two paths cross each other.
11264
11265 @ Let's start with the easier task. The function |find_direction_time| is
11266 given a direction |(x,y)| and a path starting at~|h|. If the path never
11267 travels in direction |(x,y)|, the direction time will be~|-1|; otherwise
11268 it will be nonnegative.
11269
11270 Certain anomalous cases can arise: If |(x,y)=(0,0)|, so that the given
11271 direction is undefined, the direction time will be~0. If $\bigl(x'(t),
11272 y'(t)\bigr)=(0,0)$, so that the path direction is undefined, it will be
11273 assumed to match any given direction at time~|t|.
11274
11275 The routine solves this problem in nondegenerate cases by rotating the path
11276 and the given direction so that |(x,y)=(1,0)|; i.e., the main task will be
11277 to find when a given path first travels ``due east.''
11278
11279 @c 
11280 scaled mp_find_direction_time (MP mp,scaled x, scaled y, pointer h) {
11281   scaled max; /* $\max\bigl(\vert x\vert,\vert y\vert\bigr)$ */
11282   pointer p,q; /* for list traversal */
11283   scaled n; /* the direction time at knot |p| */
11284   scaled tt; /* the direction time within a cubic */
11285   @<Other local variables for |find_direction_time|@>;
11286   @<Normalize the given direction for better accuracy;
11287     but |return| with zero result if it's zero@>;
11288   n=0; p=h; phi=0;
11289   while (1) { 
11290     if ( right_type(p)==mp_endpoint ) break;
11291     q=link(p);
11292     @<Rotate the cubic between |p| and |q|; then
11293       |goto found| if the rotated cubic travels due east at some time |tt|;
11294       but |break| if an entire cyclic path has been traversed@>;
11295     p=q; n=n+unity;
11296   }
11297   return (-unity);
11298 FOUND: 
11299   return (n+tt);
11300 }
11301
11302 @ @<Normalize the given direction for better accuracy...@>=
11303 if ( abs(x)<abs(y) ) { 
11304   x=mp_make_fraction(mp, x,abs(y));
11305   if ( y>0 ) y=fraction_one; else y=-fraction_one;
11306 } else if ( x==0 ) { 
11307   return 0;
11308 } else  { 
11309   y=mp_make_fraction(mp, y,abs(x));
11310   if ( x>0 ) x=fraction_one; else x=-fraction_one;
11311 }
11312
11313 @ Since we're interested in the tangent directions, we work with the
11314 derivative $${\textstyle1\over3}B'(x_0,x_1,x_2,x_3;t)=
11315 B(x_1-x_0,x_2-x_1,x_3-x_2;t)$$ instead of
11316 $B(x_0,x_1,x_2,x_3;t)$ itself. The derived coefficients are also scaled up
11317 in order to achieve better accuracy.
11318
11319 The given path may turn abruptly at a knot, and it might pass the critical
11320 tangent direction at such a time. Therefore we remember the direction |phi|
11321 in which the previous rotated cubic was traveling. (The value of |phi| will be
11322 undefined on the first cubic, i.e., when |n=0|.)
11323
11324 @<Rotate the cubic between |p| and |q|; then...@>=
11325 tt=0;
11326 @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples of the control
11327   points of the rotated derivatives@>;
11328 if ( y1==0 ) if ( x1>=0 ) goto FOUND;
11329 if ( n>0 ) { 
11330   @<Exit to |found| if an eastward direction occurs at knot |p|@>;
11331   if ( p==h ) break;
11332   };
11333 if ( (x3!=0)||(y3!=0) ) phi=mp_n_arg(mp, x3,y3);
11334 @<Exit to |found| if the curve whose derivatives are specified by
11335   |x1,x2,x3,y1,y2,y3| travels eastward at some time~|tt|@>
11336
11337 @ @<Other local variables for |find_direction_time|@>=
11338 scaled x1,x2,x3,y1,y2,y3;  /* multiples of rotated derivatives */
11339 angle theta,phi; /* angles of exit and entry at a knot */
11340 fraction t; /* temp storage */
11341
11342 @ @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples...@>=
11343 x1=right_x(p)-x_coord(p); x2=left_x(q)-right_x(p);
11344 x3=x_coord(q)-left_x(q);
11345 y1=right_y(p)-y_coord(p); y2=left_y(q)-right_y(p);
11346 y3=y_coord(q)-left_y(q);
11347 max=abs(x1);
11348 if ( abs(x2)>max ) max=abs(x2);
11349 if ( abs(x3)>max ) max=abs(x3);
11350 if ( abs(y1)>max ) max=abs(y1);
11351 if ( abs(y2)>max ) max=abs(y2);
11352 if ( abs(y3)>max ) max=abs(y3);
11353 if ( max==0 ) goto FOUND;
11354 while ( max<fraction_half ){ 
11355   max+=max; x1+=x1; x2+=x2; x3+=x3;
11356   y1+=y1; y2+=y2; y3+=y3;
11357 }
11358 t=x1; x1=mp_take_fraction(mp, x1,x)+mp_take_fraction(mp, y1,y);
11359 y1=mp_take_fraction(mp, y1,x)-mp_take_fraction(mp, t,y);
11360 t=x2; x2=mp_take_fraction(mp, x2,x)+mp_take_fraction(mp, y2,y);
11361 y2=mp_take_fraction(mp, y2,x)-mp_take_fraction(mp, t,y);
11362 t=x3; x3=mp_take_fraction(mp, x3,x)+mp_take_fraction(mp, y3,y);
11363 y3=mp_take_fraction(mp, y3,x)-mp_take_fraction(mp, t,y)
11364
11365 @ @<Exit to |found| if an eastward direction occurs at knot |p|@>=
11366 theta=mp_n_arg(mp, x1,y1);
11367 if ( theta>=0 ) if ( phi<=0 ) if ( phi>=theta-one_eighty_deg ) goto FOUND;
11368 if ( theta<=0 ) if ( phi>=0 ) if ( phi<=theta+one_eighty_deg ) goto FOUND
11369
11370 @ In this step we want to use the |crossing_point| routine to find the
11371 roots of the quadratic equation $B(y_1,y_2,y_3;t)=0$.
11372 Several complications arise: If the quadratic equation has a double root,
11373 the curve never crosses zero, and |crossing_point| will find nothing;
11374 this case occurs iff $y_1y_3=y_2^2$ and $y_1y_2<0$. If the quadratic
11375 equation has simple roots, or only one root, we may have to negate it
11376 so that $B(y_1,y_2,y_3;t)$ crosses from positive to negative at its first root.
11377 And finally, we need to do special things if $B(y_1,y_2,y_3;t)$ is
11378 identically zero.
11379
11380 @ @<Exit to |found| if the curve whose derivatives are specified by...@>=
11381 if ( x1<0 ) if ( x2<0 ) if ( x3<0 ) goto DONE;
11382 if ( mp_ab_vs_cd(mp, y1,y3,y2,y2)==0 ) {
11383   @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11384     either |goto found| or |goto done|@>;
11385 }
11386 if ( y1<=0 ) {
11387   if ( y1<0 ) { y1=-y1; y2=-y2; y3=-y3; }
11388   else if ( y2>0 ){ y2=-y2; y3=-y3; };
11389 }
11390 @<Check the places where $B(y_1,y_2,y_3;t)=0$ to see if
11391   $B(x_1,x_2,x_3;t)\ge0$@>;
11392 DONE:
11393
11394 @ The quadratic polynomial $B(y_1,y_2,y_3;t)$ begins |>=0| and has at most
11395 two roots, because we know that it isn't identically zero.
11396
11397 It must be admitted that the |crossing_point| routine is not perfectly accurate;
11398 rounding errors might cause it to find a root when $y_1y_3>y_2^2$, or to
11399 miss the roots when $y_1y_3<y_2^2$. The rotation process is itself
11400 subject to rounding errors. Yet this code optimistically tries to
11401 do the right thing.
11402
11403 @d we_found_it { tt=(t+04000) / 010000; goto FOUND; }
11404
11405 @<Check the places where $B(y_1,y_2,y_3;t)=0$...@>=
11406 t=mp_crossing_point(mp, y1,y2,y3);
11407 if ( t>fraction_one ) goto DONE;
11408 y2=t_of_the_way(y2,y3);
11409 x1=t_of_the_way(x1,x2);
11410 x2=t_of_the_way(x2,x3);
11411 x1=t_of_the_way(x1,x2);
11412 if ( x1>=0 ) we_found_it;
11413 if ( y2>0 ) y2=0;
11414 tt=t; t=mp_crossing_point(mp, 0,-y2,-y3);
11415 if ( t>fraction_one ) goto DONE;
11416 x1=t_of_the_way(x1,x2);
11417 x2=t_of_the_way(x2,x3);
11418 if ( t_of_the_way(x1,x2)>=0 ) { 
11419   t=t_of_the_way(tt,fraction_one); we_found_it;
11420 }
11421
11422 @ @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11423     either |goto found| or |goto done|@>=
11424
11425   if ( mp_ab_vs_cd(mp, y1,y2,0,0)<0 ) {
11426     t=mp_make_fraction(mp, y1,y1-y2);
11427     x1=t_of_the_way(x1,x2);
11428     x2=t_of_the_way(x2,x3);
11429     if ( t_of_the_way(x1,x2)>=0 ) we_found_it;
11430   } else if ( y3==0 ) {
11431     if ( y1==0 ) {
11432       @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|@>;
11433     } else if ( x3>=0 ) {
11434       tt=unity; goto FOUND;
11435     }
11436   }
11437   goto DONE;
11438 }
11439
11440 @ At this point we know that the derivative of |y(t)| is identically zero,
11441 and that |x1<0|; but either |x2>=0| or |x3>=0|, so there's some hope of
11442 traveling east.
11443
11444 @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|...@>=
11445
11446   t=mp_crossing_point(mp, -x1,-x2,-x3);
11447   if ( t<=fraction_one ) we_found_it;
11448   if ( mp_ab_vs_cd(mp, x1,x3,x2,x2)<=0 ) { 
11449     t=mp_make_fraction(mp, x1,x1-x2); we_found_it;
11450   }
11451 }
11452
11453 @ The intersection of two cubics can be found by an interesting variant
11454 of the general bisection scheme described in the introduction to
11455 |crossing_point|.\
11456 Given $w(t)=B(w_0,w_1,w_2,w_3;t)$ and $z(t)=B(z_0,z_1,z_2,z_3;t)$,
11457 we wish to find a pair of times $(t_1,t_2)$ such that $w(t_1)=z(t_2)$,
11458 if an intersection exists. First we find the smallest rectangle that
11459 encloses the points $\{w_0,w_1,w_2,w_3\}$ and check that it overlaps
11460 the smallest rectangle that encloses
11461 $\{z_0,z_1,z_2,z_3\}$; if not, the cubics certainly don't intersect.
11462 But if the rectangles do overlap, we bisect the intervals, getting
11463 new cubics $w'$ and~$w''$, $z'$~and~$z''$; the intersection routine first
11464 tries for an intersection between $w'$ and~$z'$, then (if unsuccessful)
11465 between $w'$ and~$z''$, then (if still unsuccessful) between $w''$ and~$z'$,
11466 finally (if thrice unsuccessful) between $w''$ and~$z''$. After $l$~successful
11467 levels of bisection we will have determined the intersection times $t_1$
11468 and~$t_2$ to $l$~bits of accuracy.
11469
11470 \def\submin{_{\rm min}} \def\submax{_{\rm max}}
11471 As before, it is better to work with the numbers $W_k=2^l(w_k-w_{k-1})$
11472 and $Z_k=2^l(z_k-z_{k-1})$ rather than the coefficients $w_k$ and $z_k$
11473 themselves. We also need one other quantity, $\Delta=2^l(w_0-z_0)$,
11474 to determine when the enclosing rectangles overlap. Here's why:
11475 The $x$~coordinates of~$w(t)$ are between $u\submin$ and $u\submax$,
11476 and the $x$~coordinates of~$z(t)$ are between $x\submin$ and $x\submax$,
11477 if we write $w_k=(u_k,v_k)$ and $z_k=(x_k,y_k)$ and $u\submin=
11478 \min(u_0,u_1,u_2,u_3)$, etc. These intervals of $x$~coordinates
11479 overlap if and only if $u\submin\L x\submax$ and
11480 $x\submin\L u\submax$. Letting
11481 $$U\submin=\min(0,U_1,U_1+U_2,U_1+U_2+U_3),\;
11482   U\submax=\max(0,U_1,U_1+U_2,U_1+U_2+U_3),$$
11483 we have $u\submin=2^lu_0+U\submin$, etc.; the condition for overlap
11484 reduces to
11485 $$X\submin-U\submax\L 2^l(u_0-x_0)\L X\submax-U\submin.$$
11486 Thus we want to maintain the quantity $2^l(u_0-x_0)$; similarly,
11487 the quantity $2^l(v_0-y_0)$ accounts for the $y$~coordinates. The
11488 coordinates of $\Delta=2^l(w_0-z_0)$ must stay bounded as $l$ increases,
11489 because of the overlap condition; i.e., we know that $X\submin$,
11490 $X\submax$, and their relatives are bounded, hence $X\submax-
11491 U\submin$ and $X\submin-U\submax$ are bounded.
11492
11493 @ Incidentally, if the given cubics intersect more than once, the process
11494 just sketched will not necessarily find the lexicographically smallest pair
11495 $(t_1,t_2)$. The solution actually obtained will be smallest in ``shuffled
11496 order''; i.e., if $t_1=(.a_1a_2\ldots a_{16})_2$ and
11497 $t_2=(.b_1b_2\ldots b_{16})_2$, then we will minimize
11498 $a_1b_1a_2b_2\ldots a_{16}b_{16}$, not
11499 $a_1a_2\ldots a_{16}b_1b_2\ldots b_{16}$.
11500 Shuffled order agrees with lexicographic order if all pairs of solutions
11501 $(t_1,t_2)$ and $(t_1',t_2')$ have the property that $t_1<t_1'$ iff
11502 $t_2<t_2'$; but in general, lexicographic order can be quite different,
11503 and the bisection algorithm would be substantially less efficient if it were
11504 constrained by lexicographic order.
11505
11506 For example, suppose that an overlap has been found for $l=3$ and
11507 $(t_1,t_2)= (.101,.011)$ in binary, but that no overlap is produced by
11508 either of the alternatives $(.1010,.0110)$, $(.1010,.0111)$ at level~4.
11509 Then there is probably an intersection in one of the subintervals
11510 $(.1011,.011x)$; but lexicographic order would require us to explore
11511 $(.1010,.1xxx)$ and $(.1011,.00xx)$ and $(.1011,.010x)$ first. We wouldn't
11512 want to store all of the subdivision data for the second path, so the
11513 subdivisions would have to be regenerated many times. Such inefficiencies
11514 would be associated with every `1' in the binary representation of~$t_1$.
11515
11516 @ The subdivision process introduces rounding errors, hence we need to
11517 make a more liberal test for overlap. It is not hard to show that the
11518 computed values of $U_i$ differ from the truth by at most~$l$, on
11519 level~$l$, hence $U\submin$ and $U\submax$ will be at most $3l$ in error.
11520 If $\beta$ is an upper bound on the absolute error in the computed
11521 components of $\Delta=(|delx|,|dely|)$ on level~$l$, we will replace
11522 the test `$X\submin-U\submax\L|delx|$' by the more liberal test
11523 `$X\submin-U\submax\L|delx|+|tol|$', where $|tol|=6l+\beta$.
11524
11525 More accuracy is obtained if we try the algorithm first with |tol=0|;
11526 the more liberal tolerance is used only if an exact approach fails.
11527 It is convenient to do this double-take by letting `3' in the preceding
11528 paragraph be a parameter, which is first 0, then 3.
11529
11530 @<Glob...@>=
11531 unsigned int tol_step; /* either 0 or 3, usually */
11532
11533 @ We shall use an explicit stack to implement the recursive bisection
11534 method described above. The |bisect_stack| array will contain numerous 5-word
11535 packets like $(U_1,U_2,U_3,U\submin,U\submax)$, as well as 20-word packets
11536 comprising the 5-word packets for $U$, $V$, $X$, and~$Y$.
11537
11538 The following macros define the allocation of stack positions to
11539 the quantities needed for bisection-intersection.
11540
11541 @d stack_1(A) mp->bisect_stack[(A)] /* $U_1$, $V_1$, $X_1$, or $Y_1$ */
11542 @d stack_2(A) mp->bisect_stack[(A)+1] /* $U_2$, $V_2$, $X_2$, or $Y_2$ */
11543 @d stack_3(A) mp->bisect_stack[(A)+2] /* $U_3$, $V_3$, $X_3$, or $Y_3$ */
11544 @d stack_min(A) mp->bisect_stack[(A)+3]
11545   /* $U\submin$, $V\submin$, $X\submin$, or $Y\submin$ */
11546 @d stack_max(A) mp->bisect_stack[(A)+4]
11547   /* $U\submax$, $V\submax$, $X\submax$, or $Y\submax$ */
11548 @d int_packets 20 /* number of words to represent $U_k$, $V_k$, $X_k$, and $Y_k$ */
11549 @#
11550 @d u_packet(A) ((A)-5)
11551 @d v_packet(A) ((A)-10)
11552 @d x_packet(A) ((A)-15)
11553 @d y_packet(A) ((A)-20)
11554 @d l_packets (mp->bisect_ptr-int_packets)
11555 @d r_packets mp->bisect_ptr
11556 @d ul_packet u_packet(l_packets) /* base of $U'_k$ variables */
11557 @d vl_packet v_packet(l_packets) /* base of $V'_k$ variables */
11558 @d xl_packet x_packet(l_packets) /* base of $X'_k$ variables */
11559 @d yl_packet y_packet(l_packets) /* base of $Y'_k$ variables */
11560 @d ur_packet u_packet(r_packets) /* base of $U''_k$ variables */
11561 @d vr_packet v_packet(r_packets) /* base of $V''_k$ variables */
11562 @d xr_packet x_packet(r_packets) /* base of $X''_k$ variables */
11563 @d yr_packet y_packet(r_packets) /* base of $Y''_k$ variables */
11564 @#
11565 @d u1l stack_1(ul_packet) /* $U'_1$ */
11566 @d u2l stack_2(ul_packet) /* $U'_2$ */
11567 @d u3l stack_3(ul_packet) /* $U'_3$ */
11568 @d v1l stack_1(vl_packet) /* $V'_1$ */
11569 @d v2l stack_2(vl_packet) /* $V'_2$ */
11570 @d v3l stack_3(vl_packet) /* $V'_3$ */
11571 @d x1l stack_1(xl_packet) /* $X'_1$ */
11572 @d x2l stack_2(xl_packet) /* $X'_2$ */
11573 @d x3l stack_3(xl_packet) /* $X'_3$ */
11574 @d y1l stack_1(yl_packet) /* $Y'_1$ */
11575 @d y2l stack_2(yl_packet) /* $Y'_2$ */
11576 @d y3l stack_3(yl_packet) /* $Y'_3$ */
11577 @d u1r stack_1(ur_packet) /* $U''_1$ */
11578 @d u2r stack_2(ur_packet) /* $U''_2$ */
11579 @d u3r stack_3(ur_packet) /* $U''_3$ */
11580 @d v1r stack_1(vr_packet) /* $V''_1$ */
11581 @d v2r stack_2(vr_packet) /* $V''_2$ */
11582 @d v3r stack_3(vr_packet) /* $V''_3$ */
11583 @d x1r stack_1(xr_packet) /* $X''_1$ */
11584 @d x2r stack_2(xr_packet) /* $X''_2$ */
11585 @d x3r stack_3(xr_packet) /* $X''_3$ */
11586 @d y1r stack_1(yr_packet) /* $Y''_1$ */
11587 @d y2r stack_2(yr_packet) /* $Y''_2$ */
11588 @d y3r stack_3(yr_packet) /* $Y''_3$ */
11589 @#
11590 @d stack_dx mp->bisect_stack[mp->bisect_ptr] /* stacked value of |delx| */
11591 @d stack_dy mp->bisect_stack[mp->bisect_ptr+1] /* stacked value of |dely| */
11592 @d stack_tol mp->bisect_stack[mp->bisect_ptr+2] /* stacked value of |tol| */
11593 @d stack_uv mp->bisect_stack[mp->bisect_ptr+3] /* stacked value of |uv| */
11594 @d stack_xy mp->bisect_stack[mp->bisect_ptr+4] /* stacked value of |xy| */
11595 @d int_increment (int_packets+int_packets+5) /* number of stack words per level */
11596
11597 @<Glob...@>=
11598 integer *bisect_stack;
11599 unsigned int bisect_ptr;
11600
11601 @ @<Allocate or initialize ...@>=
11602 mp->bisect_stack = xmalloc((bistack_size+1),sizeof(integer));
11603
11604 @ @<Dealloc variables@>=
11605 xfree(mp->bisect_stack);
11606
11607 @ @<Check the ``constant''...@>=
11608 if ( int_packets+17*int_increment>bistack_size ) mp->bad=19;
11609
11610 @ Computation of the min and max is a tedious but fairly fast sequence of
11611 instructions; exactly four comparisons are made in each branch.
11612
11613 @d set_min_max(A) 
11614   if ( stack_1((A))<0 ) {
11615     if ( stack_3((A))>=0 ) {
11616       if ( stack_2((A))<0 ) stack_min((A))=stack_1((A))+stack_2((A));
11617       else stack_min((A))=stack_1((A));
11618       stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11619       if ( stack_max((A))<0 ) stack_max((A))=0;
11620     } else { 
11621       stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11622       if ( stack_min((A))>stack_1((A)) ) stack_min((A))=stack_1((A));
11623       stack_max((A))=stack_1((A))+stack_2((A));
11624       if ( stack_max((A))<0 ) stack_max((A))=0;
11625     }
11626   } else if ( stack_3((A))<=0 ) {
11627     if ( stack_2((A))>0 ) stack_max((A))=stack_1((A))+stack_2((A));
11628     else stack_max((A))=stack_1((A));
11629     stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11630     if ( stack_min((A))>0 ) stack_min((A))=0;
11631   } else  { 
11632     stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11633     if ( stack_max((A))<stack_1((A)) ) stack_max((A))=stack_1((A));
11634     stack_min((A))=stack_1((A))+stack_2((A));
11635     if ( stack_min((A))>0 ) stack_min((A))=0;
11636   }
11637
11638 @ It's convenient to keep the current values of $l$, $t_1$, and $t_2$ in
11639 the integer form $2^l+2^lt_1$ and $2^l+2^lt_2$. The |cubic_intersection|
11640 routine uses global variables |cur_t| and |cur_tt| for this purpose;
11641 after successful completion, |cur_t| and |cur_tt| will contain |unity|
11642 plus the |scaled| values of $t_1$ and~$t_2$.
11643
11644 The values of |cur_t| and |cur_tt| will be set to zero if |cubic_intersection|
11645 finds no intersection. The routine gives up and gives an approximate answer
11646 if it has backtracked
11647 more than 5000 times (otherwise there are cases where several minutes
11648 of fruitless computation would be possible).
11649
11650 @d max_patience 5000
11651
11652 @<Glob...@>=
11653 integer cur_t;integer cur_tt; /* controls and results of |cubic_intersection| */
11654 integer time_to_go; /* this many backtracks before giving up */
11655 integer max_t; /* maximum of $2^{l+1}$ so far achieved */
11656
11657 @ The given cubics $B(w_0,w_1,w_2,w_3;t)$ and
11658 $B(z_0,z_1,z_2,z_3;t)$ are specified in adjacent knot nodes |(p,link(p))|
11659 and |(pp,link(pp))|, respectively.
11660
11661 @c void mp_cubic_intersection (MP mp,pointer p, pointer pp) {
11662   pointer q,qq; /* |link(p)|, |link(pp)| */
11663   mp->time_to_go=max_patience; mp->max_t=2;
11664   @<Initialize for intersections at level zero@>;
11665 CONTINUE:
11666   while (1) { 
11667     if ( mp->delx-mp->tol<=stack_max(x_packet(mp->xy))-stack_min(u_packet(mp->uv)))
11668     if ( mp->delx+mp->tol>=stack_min(x_packet(mp->xy))-stack_max(u_packet(mp->uv)))
11669     if ( mp->dely-mp->tol<=stack_max(y_packet(mp->xy))-stack_min(v_packet(mp->uv)))
11670     if ( mp->dely+mp->tol>=stack_min(y_packet(mp->xy))-stack_max(v_packet(mp->uv))) 
11671     { 
11672       if ( mp->cur_t>=mp->max_t ){ 
11673         if ( mp->max_t==two ) { /* we've done 17 bisections */ 
11674            mp->cur_t=halfp(mp->cur_t+1); mp->cur_tt=halfp(mp->cur_tt+1); return;
11675         }
11676         mp->max_t+=mp->max_t; mp->appr_t=mp->cur_t; mp->appr_tt=mp->cur_tt;
11677       }
11678       @<Subdivide for a new level of intersection@>;
11679       goto CONTINUE;
11680     }
11681     if ( mp->time_to_go>0 ) {
11682       decr(mp->time_to_go);
11683     } else { 
11684       while ( mp->appr_t<unity ) { 
11685         mp->appr_t+=mp->appr_t; mp->appr_tt+=mp->appr_tt;
11686       }
11687       mp->cur_t=mp->appr_t; mp->cur_tt=mp->appr_tt; return;
11688     }
11689     @<Advance to the next pair |(cur_t,cur_tt)|@>;
11690   }
11691 }
11692
11693 @ The following variables are global, although they are used only by
11694 |cubic_intersection|, because it is necessary on some machines to
11695 split |cubic_intersection| up into two procedures.
11696
11697 @<Glob...@>=
11698 integer delx;integer dely; /* the components of $\Delta=2^l(w_0-z_0)$ */
11699 integer tol; /* bound on the uncertainly in the overlap test */
11700 unsigned int uv;
11701 unsigned int xy; /* pointers to the current packets of interest */
11702 integer three_l; /* |tol_step| times the bisection level */
11703 integer appr_t;integer appr_tt; /* best approximations known to the answers */
11704
11705 @ We shall assume that the coordinates are sufficiently non-extreme that
11706 integer overflow will not occur.
11707
11708 @<Initialize for intersections at level zero@>=
11709 q=link(p); qq=link(pp); mp->bisect_ptr=int_packets;
11710 u1r=right_x(p)-x_coord(p); u2r=left_x(q)-right_x(p);
11711 u3r=x_coord(q)-left_x(q); set_min_max(ur_packet);
11712 v1r=right_y(p)-y_coord(p); v2r=left_y(q)-right_y(p);
11713 v3r=y_coord(q)-left_y(q); set_min_max(vr_packet);
11714 x1r=right_x(pp)-x_coord(pp); x2r=left_x(qq)-right_x(pp);
11715 x3r=x_coord(qq)-left_x(qq); set_min_max(xr_packet);
11716 y1r=right_y(pp)-y_coord(pp); y2r=left_y(qq)-right_y(pp);
11717 y3r=y_coord(qq)-left_y(qq); set_min_max(yr_packet);
11718 mp->delx=x_coord(p)-x_coord(pp); mp->dely=y_coord(p)-y_coord(pp);
11719 mp->tol=0; mp->uv=r_packets; mp->xy=r_packets; 
11720 mp->three_l=0; mp->cur_t=1; mp->cur_tt=1
11721
11722 @ @<Subdivide for a new level of intersection@>=
11723 stack_dx=mp->delx; stack_dy=mp->dely; stack_tol=mp->tol; 
11724 stack_uv=mp->uv; stack_xy=mp->xy;
11725 mp->bisect_ptr=mp->bisect_ptr+int_increment;
11726 mp->cur_t+=mp->cur_t; mp->cur_tt+=mp->cur_tt;
11727 u1l=stack_1(u_packet(mp->uv)); u3r=stack_3(u_packet(mp->uv));
11728 u2l=half(u1l+stack_2(u_packet(mp->uv)));
11729 u2r=half(u3r+stack_2(u_packet(mp->uv)));
11730 u3l=half(u2l+u2r); u1r=u3l;
11731 set_min_max(ul_packet); set_min_max(ur_packet);
11732 v1l=stack_1(v_packet(mp->uv)); v3r=stack_3(v_packet(mp->uv));
11733 v2l=half(v1l+stack_2(v_packet(mp->uv)));
11734 v2r=half(v3r+stack_2(v_packet(mp->uv)));
11735 v3l=half(v2l+v2r); v1r=v3l;
11736 set_min_max(vl_packet); set_min_max(vr_packet);
11737 x1l=stack_1(x_packet(mp->xy)); x3r=stack_3(x_packet(mp->xy));
11738 x2l=half(x1l+stack_2(x_packet(mp->xy)));
11739 x2r=half(x3r+stack_2(x_packet(mp->xy)));
11740 x3l=half(x2l+x2r); x1r=x3l;
11741 set_min_max(xl_packet); set_min_max(xr_packet);
11742 y1l=stack_1(y_packet(mp->xy)); y3r=stack_3(y_packet(mp->xy));
11743 y2l=half(y1l+stack_2(y_packet(mp->xy)));
11744 y2r=half(y3r+stack_2(y_packet(mp->xy)));
11745 y3l=half(y2l+y2r); y1r=y3l;
11746 set_min_max(yl_packet); set_min_max(yr_packet);
11747 mp->uv=l_packets; mp->xy=l_packets;
11748 mp->delx+=mp->delx; mp->dely+=mp->dely;
11749 mp->tol=mp->tol-mp->three_l+mp->tol_step; 
11750 mp->tol+=mp->tol; mp->three_l=mp->three_l+mp->tol_step
11751
11752 @ @<Advance to the next pair |(cur_t,cur_tt)|@>=
11753 NOT_FOUND: 
11754 if ( odd(mp->cur_tt) ) {
11755   if ( odd(mp->cur_t) ) {
11756      @<Descend to the previous level and |goto not_found|@>;
11757   } else { 
11758     incr(mp->cur_t);
11759     mp->delx=mp->delx+stack_1(u_packet(mp->uv))+stack_2(u_packet(mp->uv))
11760       +stack_3(u_packet(mp->uv));
11761     mp->dely=mp->dely+stack_1(v_packet(mp->uv))+stack_2(v_packet(mp->uv))
11762       +stack_3(v_packet(mp->uv));
11763     mp->uv=mp->uv+int_packets; /* switch from |l_packet| to |r_packet| */
11764     decr(mp->cur_tt); mp->xy=mp->xy-int_packets; 
11765          /* switch from |r_packet| to |l_packet| */
11766     mp->delx=mp->delx+stack_1(x_packet(mp->xy))+stack_2(x_packet(mp->xy))
11767       +stack_3(x_packet(mp->xy));
11768     mp->dely=mp->dely+stack_1(y_packet(mp->xy))+stack_2(y_packet(mp->xy))
11769       +stack_3(y_packet(mp->xy));
11770   }
11771 } else { 
11772   incr(mp->cur_tt); mp->tol=mp->tol+mp->three_l;
11773   mp->delx=mp->delx-stack_1(x_packet(mp->xy))-stack_2(x_packet(mp->xy))
11774     -stack_3(x_packet(mp->xy));
11775   mp->dely=mp->dely-stack_1(y_packet(mp->xy))-stack_2(y_packet(mp->xy))
11776     -stack_3(y_packet(mp->xy));
11777   mp->xy=mp->xy+int_packets; /* switch from |l_packet| to |r_packet| */
11778 }
11779
11780 @ @<Descend to the previous level...@>=
11781
11782   mp->cur_t=halfp(mp->cur_t); mp->cur_tt=halfp(mp->cur_tt);
11783   if ( mp->cur_t==0 ) return;
11784   mp->bisect_ptr=mp->bisect_ptr-int_increment; 
11785   mp->three_l=mp->three_l-mp->tol_step;
11786   mp->delx=stack_dx; mp->dely=stack_dy; mp->tol=stack_tol; 
11787   mp->uv=stack_uv; mp->xy=stack_xy;
11788   goto NOT_FOUND;
11789 }
11790
11791 @ The |path_intersection| procedure is much simpler.
11792 It invokes |cubic_intersection| in lexicographic order until finding a
11793 pair of cubics that intersect. The final intersection times are placed in
11794 |cur_t| and~|cur_tt|.
11795
11796 @c void mp_path_intersection (MP mp,pointer h, pointer hh) {
11797   pointer p,pp; /* link registers that traverse the given paths */
11798   integer n,nn; /* integer parts of intersection times, minus |unity| */
11799   @<Change one-point paths into dead cycles@>;
11800   mp->tol_step=0;
11801   do {  
11802     n=-unity; p=h;
11803     do {  
11804       if ( right_type(p)!=mp_endpoint ) { 
11805         nn=-unity; pp=hh;
11806         do {  
11807           if ( right_type(pp)!=mp_endpoint )  { 
11808             mp_cubic_intersection(mp, p,pp);
11809             if ( mp->cur_t>0 ) { 
11810               mp->cur_t=mp->cur_t+n; mp->cur_tt=mp->cur_tt+nn; 
11811               return;
11812             }
11813           }
11814           nn=nn+unity; pp=link(pp);
11815         } while (pp!=hh);
11816       }
11817       n=n+unity; p=link(p);
11818     } while (p!=h);
11819     mp->tol_step=mp->tol_step+3;
11820   } while (mp->tol_step<=3);
11821   mp->cur_t=-unity; mp->cur_tt=-unity;
11822 }
11823
11824 @ @<Change one-point paths...@>=
11825 if ( right_type(h)==mp_endpoint ) {
11826   right_x(h)=x_coord(h); left_x(h)=x_coord(h);
11827   right_y(h)=y_coord(h); left_y(h)=y_coord(h); right_type(h)=mp_explicit;
11828 }
11829 if ( right_type(hh)==mp_endpoint ) {
11830   right_x(hh)=x_coord(hh); left_x(hh)=x_coord(hh);
11831   right_y(hh)=y_coord(hh); left_y(hh)=y_coord(hh); right_type(hh)=mp_explicit;
11832 }
11833
11834 @* \[24] Dynamic linear equations.
11835 \MP\ users define variables implicitly by stating equations that should be
11836 satisfied; the computer is supposed to be smart enough to solve those equations.
11837 And indeed, the computer tries valiantly to do so, by distinguishing five
11838 different types of numeric values:
11839
11840 \smallskip\hang
11841 |type(p)=mp_known| is the nice case, when |value(p)| is the |scaled| value
11842 of the variable whose address is~|p|.
11843
11844 \smallskip\hang
11845 |type(p)=mp_dependent| means that |value(p)| is not present, but |dep_list(p)|
11846 points to a {\sl dependency list\/} that expresses the value of variable~|p|
11847 as a |scaled| number plus a sum of independent variables with |fraction|
11848 coefficients.
11849
11850 \smallskip\hang
11851 |type(p)=mp_independent| means that |value(p)=64s+m|, where |s>0| is a ``serial
11852 number'' reflecting the time this variable was first used in an equation;
11853 also |0<=m<64|, and each dependent variable
11854 that refers to this one is actually referring to the future value of
11855 this variable times~$2^m$. (Usually |m=0|, but higher degrees of
11856 scaling are sometimes needed to keep the coefficients in dependency lists
11857 from getting too large. The value of~|m| will always be even.)
11858
11859 \smallskip\hang
11860 |type(p)=mp_numeric_type| means that variable |p| hasn't appeared in an
11861 equation before, but it has been explicitly declared to be numeric.
11862
11863 \smallskip\hang
11864 |type(p)=undefined| means that variable |p| hasn't appeared before.
11865
11866 \smallskip\noindent
11867 We have actually discussed these five types in the reverse order of their
11868 history during a computation: Once |known|, a variable never again
11869 becomes |dependent|; once |dependent|, it almost never again becomes
11870 |mp_independent|; once |mp_independent|, it never again becomes |mp_numeric_type|;
11871 and once |mp_numeric_type|, it never again becomes |undefined| (except
11872 of course when the user specifically decides to scrap the old value
11873 and start again). A backward step may, however, take place: Sometimes
11874 a |dependent| variable becomes |mp_independent| again, when one of the
11875 independent variables it depends on is reverting to |undefined|.
11876
11877
11878 The next patch detects overflow of independent-variable serial
11879 numbers. Diagnosed and patched by Thorsten Dahlheimer.
11880
11881 @d s_scale 64 /* the serial numbers are multiplied by this factor */
11882 @d max_indep_vars 0177777777 /* $2^{25}-1$ */
11883 @d max_serial_no 017777777700 /* |max_indep_vars*s_scale| */
11884 @d new_indep(A)  /* create a new independent variable */
11885   { if ( mp->serial_no==max_serial_no )
11886     mp_fatal_error(mp, "variable instance identifiers exhausted");
11887   type((A))=mp_independent; mp->serial_no=mp->serial_no+s_scale;
11888   value((A))=mp->serial_no;
11889   }
11890
11891 @<Glob...@>=
11892 integer serial_no; /* the most recent serial number, times |s_scale| */
11893
11894 @ @<Make variable |q+s| newly independent@>=new_indep(q+s)
11895
11896 @ But how are dependency lists represented? It's simple: The linear combination
11897 $\alpha_1v_1+\cdots+\alpha_kv_k+\beta$ appears in |k+1| value nodes. If
11898 |q=dep_list(p)| points to this list, and if |k>0|, then |value(q)=
11899 @t$\alpha_1$@>| (which is a |fraction|); |info(q)| points to the location
11900 of $\alpha_1$; and |link(p)| points to the dependency list
11901 $\alpha_2v_2+\cdots+\alpha_kv_k+\beta$. On the other hand if |k=0|,
11902 then |value(q)=@t$\beta$@>| (which is |scaled|) and |info(q)=null|.
11903 The independent variables $v_1$, \dots,~$v_k$ have been sorted so that
11904 they appear in decreasing order of their |value| fields (i.e., of
11905 their serial numbers). \ (It is convenient to use decreasing order,
11906 since |value(null)=0|. If the independent variables were not sorted by
11907 serial number but by some other criterion, such as their location in |mem|,
11908 the equation-solving mechanism would be too system-dependent, because
11909 the ordering can affect the computed results.)
11910
11911 The |link| field in the node that contains the constant term $\beta$ is
11912 called the {\sl final link\/} of the dependency list. \MP\ maintains
11913 a doubly-linked master list of all dependency lists, in terms of a permanently
11914 allocated node
11915 in |mem| called |dep_head|. If there are no dependencies, we have
11916 |link(dep_head)=dep_head| and |prev_dep(dep_head)=dep_head|;
11917 otherwise |link(dep_head)| points to the first dependent variable, say~|p|,
11918 and |prev_dep(p)=dep_head|. We have |type(p)=mp_dependent|, and |dep_list(p)|
11919 points to its dependency list. If the final link of that dependency list
11920 occurs in location~|q|, then |link(q)| points to the next dependent
11921 variable (say~|r|); and we have |prev_dep(r)=q|, etc.
11922
11923 @d dep_list(A) link(value_loc((A)))
11924   /* half of the |value| field in a |dependent| variable */
11925 @d prev_dep(A) info(value_loc((A)))
11926   /* the other half; makes a doubly linked list */
11927 @d dep_node_size 2 /* the number of words per dependency node */
11928
11929 @<Initialize table entries...@>= mp->serial_no=0;
11930 link(dep_head)=dep_head; prev_dep(dep_head)=dep_head;
11931 info(dep_head)=null; dep_list(dep_head)=null;
11932
11933 @ Actually the description above contains a little white lie. There's
11934 another kind of variable called |mp_proto_dependent|, which is
11935 just like a |dependent| one except that the $\alpha$ coefficients
11936 in its dependency list are |scaled| instead of being fractions.
11937 Proto-dependency lists are mixed with dependency lists in the
11938 nodes reachable from |dep_head|.
11939
11940 @ Here is a procedure that prints a dependency list in symbolic form.
11941 The second parameter should be either |dependent| or |mp_proto_dependent|,
11942 to indicate the scaling of the coefficients.
11943
11944 @<Declare subroutines for printing expressions@>=
11945 void mp_print_dependency (MP mp,pointer p, small_number t) {
11946   integer v; /* a coefficient */
11947   pointer pp,q; /* for list manipulation */
11948   pp=p;
11949   while (1) { 
11950     v=abs(value(p)); q=info(p);
11951     if ( q==null ) { /* the constant term */
11952       if ( (v!=0)||(p==pp) ) {
11953          if ( value(p)>0 ) if ( p!=pp ) mp_print_char(mp, '+');
11954          mp_print_scaled(mp, value(p));
11955       }
11956       return;
11957     }
11958     @<Print the coefficient, unless it's $\pm1.0$@>;
11959     if ( type(q)!=mp_independent ) mp_confusion(mp, "dep");
11960 @:this can't happen dep}{\quad dep@>
11961     mp_print_variable_name(mp, q); v=value(q) % s_scale;
11962     while ( v>0 ) { mp_print(mp, "*4"); v=v-2; }
11963     p=link(p);
11964   }
11965 }
11966
11967 @ @<Print the coefficient, unless it's $\pm1.0$@>=
11968 if ( value(p)<0 ) mp_print_char(mp, '-');
11969 else if ( p!=pp ) mp_print_char(mp, '+');
11970 if ( t==mp_dependent ) v=mp_round_fraction(mp, v);
11971 if ( v!=unity ) mp_print_scaled(mp, v)
11972
11973 @ The maximum absolute value of a coefficient in a given dependency list
11974 is returned by the following simple function.
11975
11976 @c fraction mp_max_coef (MP mp,pointer p) {
11977   fraction x; /* the maximum so far */
11978   x=0;
11979   while ( info(p)!=null ) {
11980     if ( abs(value(p))>x ) x=abs(value(p));
11981     p=link(p);
11982   }
11983   return x;
11984 }
11985
11986 @ One of the main operations needed on dependency lists is to add a multiple
11987 of one list to the other; we call this |p_plus_fq|, where |p| and~|q| point
11988 to dependency lists and |f| is a fraction.
11989
11990 If the coefficient of any independent variable becomes |coef_bound| or
11991 more, in absolute value, this procedure changes the type of that variable
11992 to `|independent_needing_fix|', and sets the global variable |fix_needed|
11993 to~|true|. The value of $|coef_bound|=\mu$ is chosen so that
11994 $\mu^2+\mu<8$; this means that the numbers we deal with won't
11995 get too large. (Instead of the ``optimum'' $\mu=(\sqrt{33}-1)/2\approx
11996 2.3723$, the safer value 7/3 is taken as the threshold.)
11997
11998 The changes mentioned in the preceding paragraph are actually done only if
11999 the global variable |watch_coefs| is |true|. But it usually is; in fact,
12000 it is |false| only when \MP\ is making a dependency list that will soon
12001 be equated to zero.
12002
12003 Several procedures that act on dependency lists, including |p_plus_fq|,
12004 set the global variable |dep_final| to the final (constant term) node of
12005 the dependency list that they produce.
12006
12007 @d coef_bound 04525252525 /* |fraction| approximation to 7/3 */
12008 @d independent_needing_fix 0
12009
12010 @<Glob...@>=
12011 boolean fix_needed; /* does at least one |independent| variable need scaling? */
12012 boolean watch_coefs; /* should we scale coefficients that exceed |coef_bound|? */
12013 pointer dep_final; /* location of the constant term and final link */
12014
12015 @ @<Set init...@>=
12016 mp->fix_needed=false; mp->watch_coefs=true;
12017
12018 @ The |p_plus_fq| procedure has a fourth parameter, |t|, that should be
12019 set to |mp_proto_dependent| if |p| is a proto-dependency list. In this
12020 case |f| will be |scaled|, not a |fraction|. Similarly, the fifth parameter~|tt|
12021 should be |mp_proto_dependent| if |q| is a proto-dependency list.
12022
12023 List |q| is unchanged by the operation; but list |p| is totally destroyed.
12024
12025 The final link of the dependency list or proto-dependency list returned
12026 by |p_plus_fq| is the same as the original final link of~|p|. Indeed, the
12027 constant term of the result will be located in the same |mem| location
12028 as the original constant term of~|p|.
12029
12030 Coefficients of the result are assumed to be zero if they are less than
12031 a certain threshold. This compensates for inevitable rounding errors,
12032 and tends to make more variables `|known|'. The threshold is approximately
12033 $10^{-5}$ in the case of normal dependency lists, $10^{-4}$ for
12034 proto-dependencies.
12035
12036 @d fraction_threshold 2685 /* a |fraction| coefficient less than this is zeroed */
12037 @d half_fraction_threshold 1342 /* half of |fraction_threshold| */
12038 @d scaled_threshold 8 /* a |scaled| coefficient less than this is zeroed */
12039 @d half_scaled_threshold 4 /* half of |scaled_threshold| */
12040
12041 @<Declare basic dependency-list subroutines@>=
12042 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
12043                       pointer q, small_number t, small_number tt) ;
12044
12045 @ @c
12046 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
12047                       pointer q, small_number t, small_number tt) {
12048   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
12049   pointer r,s; /* for list manipulation */
12050   integer mp_threshold; /* defines a neighborhood of zero */
12051   integer v; /* temporary register */
12052   if ( t==mp_dependent ) mp_threshold=fraction_threshold;
12053   else mp_threshold=scaled_threshold;
12054   r=temp_head; pp=info(p); qq=info(q);
12055   while (1) {
12056     if ( pp==qq ) {
12057       if ( pp==null ) {
12058        break;
12059       } else {
12060         @<Contribute a term from |p|, plus |f| times the
12061           corresponding term from |q|@>
12062       }
12063     } else if ( value(pp)<value(qq) ) {
12064       @<Contribute a term from |q|, multiplied by~|f|@>
12065     } else { 
12066      link(r)=p; r=p; p=link(p); pp=info(p);
12067     }
12068   }
12069   if ( t==mp_dependent )
12070     value(p)=mp_slow_add(mp, value(p),mp_take_fraction(mp, value(q),f));
12071   else  
12072     value(p)=mp_slow_add(mp, value(p),mp_take_scaled(mp, value(q),f));
12073   link(r)=p; mp->dep_final=p; 
12074   return link(temp_head);
12075 }
12076
12077 @ @<Contribute a term from |p|, plus |f|...@>=
12078
12079   if ( tt==mp_dependent ) v=value(p)+mp_take_fraction(mp, f,value(q));
12080   else v=value(p)+mp_take_scaled(mp, f,value(q));
12081   value(p)=v; s=p; p=link(p);
12082   if ( abs(v)<mp_threshold ) {
12083     mp_free_node(mp, s,dep_node_size);
12084   } else {
12085     if ( (abs(v)>=coef_bound)  && mp->watch_coefs ) { 
12086       type(qq)=independent_needing_fix; mp->fix_needed=true;
12087     }
12088     link(r)=s; r=s;
12089   };
12090   pp=info(p); q=link(q); qq=info(q);
12091 }
12092
12093 @ @<Contribute a term from |q|, multiplied by~|f|@>=
12094
12095   if ( tt==mp_dependent ) v=mp_take_fraction(mp, f,value(q));
12096   else v=mp_take_scaled(mp, f,value(q));
12097   if ( abs(v)>halfp(mp_threshold) ) { 
12098     s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=v;
12099     if ( (abs(v)>=coef_bound) && mp->watch_coefs ) { 
12100       type(qq)=independent_needing_fix; mp->fix_needed=true;
12101     }
12102     link(r)=s; r=s;
12103   }
12104   q=link(q); qq=info(q);
12105 }
12106
12107 @ It is convenient to have another subroutine for the special case
12108 of |p_plus_fq| when |f=1.0|. In this routine lists |p| and |q| are
12109 both of the same type~|t| (either |dependent| or |mp_proto_dependent|).
12110
12111 @c pointer mp_p_plus_q (MP mp,pointer p, pointer q, small_number t) {
12112   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
12113   pointer r,s; /* for list manipulation */
12114   integer mp_threshold; /* defines a neighborhood of zero */
12115   integer v; /* temporary register */
12116   if ( t==mp_dependent ) mp_threshold=fraction_threshold;
12117   else mp_threshold=scaled_threshold;
12118   r=temp_head; pp=info(p); qq=info(q);
12119   while (1) {
12120     if ( pp==qq ) {
12121       if ( pp==null ) {
12122         break;
12123       } else {
12124         @<Contribute a term from |p|, plus the
12125           corresponding term from |q|@>
12126       }
12127     } else if ( value(pp)<value(qq) ) {
12128       s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=value(q);
12129       q=link(q); qq=info(q); link(r)=s; r=s;
12130     } else { 
12131       link(r)=p; r=p; p=link(p); pp=info(p);
12132     }
12133   }
12134   value(p)=mp_slow_add(mp, value(p),value(q));
12135   link(r)=p; mp->dep_final=p; 
12136   return link(temp_head);
12137 }
12138
12139 @ @<Contribute a term from |p|, plus the...@>=
12140
12141   v=value(p)+value(q);
12142   value(p)=v; s=p; p=link(p); pp=info(p);
12143   if ( abs(v)<mp_threshold ) {
12144     mp_free_node(mp, s,dep_node_size);
12145   } else { 
12146     if ( (abs(v)>=coef_bound ) && mp->watch_coefs ) {
12147       type(qq)=independent_needing_fix; mp->fix_needed=true;
12148     }
12149     link(r)=s; r=s;
12150   }
12151   q=link(q); qq=info(q);
12152 }
12153
12154 @ A somewhat simpler routine will multiply a dependency list
12155 by a given constant~|v|. The constant is either a |fraction| less than
12156 |fraction_one|, or it is |scaled|. In the latter case we might be forced to
12157 convert a dependency list to a proto-dependency list.
12158 Parameters |t0| and |t1| are the list types before and after;
12159 they should agree unless |t0=mp_dependent| and |t1=mp_proto_dependent|
12160 and |v_is_scaled=true|.
12161
12162 @c pointer mp_p_times_v (MP mp,pointer p, integer v, small_number t0,
12163                          small_number t1, boolean v_is_scaled) {
12164   pointer r,s; /* for list manipulation */
12165   integer w; /* tentative coefficient */
12166   integer mp_threshold;
12167   boolean scaling_down;
12168   if ( t0!=t1 ) scaling_down=true; else scaling_down=! v_is_scaled;
12169   if ( t1==mp_dependent ) mp_threshold=half_fraction_threshold;
12170   else mp_threshold=half_scaled_threshold;
12171   r=temp_head;
12172   while ( info(p)!=null ) {    
12173     if ( scaling_down ) w=mp_take_fraction(mp, v,value(p));
12174     else w=mp_take_scaled(mp, v,value(p));
12175     if ( abs(w)<=mp_threshold ) { 
12176       s=link(p); mp_free_node(mp, p,dep_node_size); p=s;
12177     } else {
12178       if ( abs(w)>=coef_bound ) { 
12179         mp->fix_needed=true; type(info(p))=independent_needing_fix;
12180       }
12181       link(r)=p; r=p; value(p)=w; p=link(p);
12182     }
12183   }
12184   link(r)=p;
12185   if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
12186   else value(p)=mp_take_fraction(mp, value(p),v);
12187   return link(temp_head);
12188 };
12189
12190 @ Similarly, we sometimes need to divide a dependency list
12191 by a given |scaled| constant.
12192
12193 @<Declare basic dependency-list subroutines@>=
12194 pointer mp_p_over_v (MP mp,pointer p, scaled v, small_number 
12195   t0, small_number t1) ;
12196
12197 @ @c
12198 pointer mp_p_over_v (MP mp,pointer p, scaled v, small_number 
12199   t0, small_number t1) {
12200   pointer r,s; /* for list manipulation */
12201   integer w; /* tentative coefficient */
12202   integer mp_threshold;
12203   boolean scaling_down;
12204   if ( t0!=t1 ) scaling_down=true; else scaling_down=false;
12205   if ( t1==mp_dependent ) mp_threshold=half_fraction_threshold;
12206   else mp_threshold=half_scaled_threshold;
12207   r=temp_head;
12208   while ( info( p)!=null ) {
12209     if ( scaling_down ) {
12210       if ( abs(v)<02000000 ) w=mp_make_scaled(mp, value(p),v*010000);
12211       else w=mp_make_scaled(mp, mp_round_fraction(mp, value(p)),v);
12212     } else {
12213       w=mp_make_scaled(mp, value(p),v);
12214     }
12215     if ( abs(w)<=mp_threshold ) {
12216       s=link(p); mp_free_node(mp, p,dep_node_size); p=s;
12217     } else { 
12218       if ( abs(w)>=coef_bound ) {
12219          mp->fix_needed=true; type(info(p))=independent_needing_fix;
12220       }
12221       link(r)=p; r=p; value(p)=w; p=link(p);
12222     }
12223   }
12224   link(r)=p; value(p)=mp_make_scaled(mp, value(p),v);
12225   return link(temp_head);
12226 };
12227
12228 @ Here's another utility routine for dependency lists. When an independent
12229 variable becomes dependent, we want to remove it from all existing
12230 dependencies. The |p_with_x_becoming_q| function computes the
12231 dependency list of~|p| after variable~|x| has been replaced by~|q|.
12232
12233 This procedure has basically the same calling conventions as |p_plus_fq|:
12234 List~|q| is unchanged; list~|p| is destroyed; the constant node and the
12235 final link are inherited from~|p|; and the fourth parameter tells whether
12236 or not |p| is |mp_proto_dependent|. However, the global variable |dep_final|
12237 is not altered if |x| does not occur in list~|p|.
12238
12239 @c pointer mp_p_with_x_becoming_q (MP mp,pointer p,
12240            pointer x, pointer q, small_number t) {
12241   pointer r,s; /* for list manipulation */
12242   integer v; /* coefficient of |x| */
12243   integer sx; /* serial number of |x| */
12244   s=p; r=temp_head; sx=value(x);
12245   while ( value(info(s))>sx ) { r=s; s=link(s); };
12246   if ( info(s)!=x ) { 
12247     return p;
12248   } else { 
12249     link(temp_head)=p; link(r)=link(s); v=value(s);
12250     mp_free_node(mp, s,dep_node_size);
12251     return mp_p_plus_fq(mp, link(temp_head),v,q,t,mp_dependent);
12252   }
12253 }
12254
12255 @ Here's a simple procedure that reports an error when a variable
12256 has just received a known value that's out of the required range.
12257
12258 @<Declare basic dependency-list subroutines@>=
12259 void mp_val_too_big (MP mp,scaled x) ;
12260
12261 @ @c void mp_val_too_big (MP mp,scaled x) { 
12262   if ( mp->internal[mp_warning_check]>0 ) { 
12263     print_err("Value is too large ("); mp_print_scaled(mp, x); mp_print_char(mp, ')');
12264 @.Value is too large@>
12265     help4("The equation I just processed has given some variable")
12266       ("a value of 4096 or more. Continue and I'll try to cope")
12267       ("with that big value; but it might be dangerous.")
12268       ("(Set warningcheck:=0 to suppress this message.)");
12269     mp_error(mp);
12270   }
12271 }
12272
12273 @ When a dependent variable becomes known, the following routine
12274 removes its dependency list. Here |p| points to the variable, and
12275 |q| points to the dependency list (which is one node long).
12276
12277 @<Declare basic dependency-list subroutines@>=
12278 void mp_make_known (MP mp,pointer p, pointer q) ;
12279
12280 @ @c void mp_make_known (MP mp,pointer p, pointer q) {
12281   int t; /* the previous type */
12282   prev_dep(link(q))=prev_dep(p);
12283   link(prev_dep(p))=link(q); t=type(p);
12284   type(p)=mp_known; value(p)=value(q); mp_free_node(mp, q,dep_node_size);
12285   if ( abs(value(p))>=fraction_one ) mp_val_too_big(mp, value(p));
12286   if (( mp->internal[mp_tracing_equations]>0) && mp_interesting(mp, p) ) {
12287     mp_begin_diagnostic(mp); mp_print_nl(mp, "#### ");
12288 @:]]]\#\#\#\#_}{\.{\#\#\#\#}@>
12289     mp_print_variable_name(mp, p); 
12290     mp_print_char(mp, '='); mp_print_scaled(mp, value(p));
12291     mp_end_diagnostic(mp, false);
12292   }
12293   if (( mp->cur_exp==p ) && mp->cur_type==t ) {
12294     mp->cur_type=mp_known; mp->cur_exp=value(p);
12295     mp_free_node(mp, p,value_node_size);
12296   }
12297 }
12298
12299 @ The |fix_dependencies| routine is called into action when |fix_needed|
12300 has been triggered. The program keeps a list~|s| of independent variables
12301 whose coefficients must be divided by~4.
12302
12303 In unusual cases, this fixup process might reduce one or more coefficients
12304 to zero, so that a variable will become known more or less by default.
12305
12306 @<Declare basic dependency-list subroutines@>=
12307 void mp_fix_dependencies (MP mp);
12308
12309 @ @c void mp_fix_dependencies (MP mp) {
12310   pointer p,q,r,s,t; /* list manipulation registers */
12311   pointer x; /* an independent variable */
12312   r=link(dep_head); s=null;
12313   while ( r!=dep_head ){ 
12314     t=r;
12315     @<Run through the dependency list for variable |t|, fixing
12316       all nodes, and ending with final link~|q|@>;
12317     r=link(q);
12318     if ( q==dep_list(t) ) mp_make_known(mp, t,q);
12319   }
12320   while ( s!=null ) { 
12321     p=link(s); x=info(s); free_avail(s); s=p;
12322     type(x)=mp_independent; value(x)=value(x)+2;
12323   }
12324   mp->fix_needed=false;
12325 }
12326
12327 @ @d independent_being_fixed 1 /* this variable already appears in |s| */
12328
12329 @<Run through the dependency list for variable |t|...@>=
12330 r=value_loc(t); /* |link(r)=dep_list(t)| */
12331 while (1) { 
12332   q=link(r); x=info(q);
12333   if ( x==null ) break;
12334   if ( type(x)<=independent_being_fixed ) {
12335     if ( type(x)<independent_being_fixed ) {
12336       p=mp_get_avail(mp); link(p)=s; s=p;
12337       info(s)=x; type(x)=independent_being_fixed;
12338     }
12339     value(q)=value(q) / 4;
12340     if ( value(q)==0 ) {
12341       link(r)=link(q); mp_free_node(mp, q,dep_node_size); q=r;
12342     }
12343   }
12344   r=q;
12345 }
12346
12347
12348 @ The |new_dep| routine installs a dependency list~|p| into the value node~|q|,
12349 linking it into the list of all known dependencies. We assume that
12350 |dep_final| points to the final node of list~|p|.
12351
12352 @c void mp_new_dep (MP mp,pointer q, pointer p) {
12353   pointer r; /* what used to be the first dependency */
12354   dep_list(q)=p; prev_dep(q)=dep_head;
12355   r=link(dep_head); link(mp->dep_final)=r; prev_dep(r)=mp->dep_final;
12356   link(dep_head)=q;
12357 }
12358
12359 @ Here is one of the ways a dependency list gets started.
12360 The |const_dependency| routine produces a list that has nothing but
12361 a constant term.
12362
12363 @c pointer mp_const_dependency (MP mp, scaled v) {
12364   mp->dep_final=mp_get_node(mp, dep_node_size);
12365   value(mp->dep_final)=v; info(mp->dep_final)=null;
12366   return mp->dep_final;
12367 }
12368
12369 @ And here's a more interesting way to start a dependency list from scratch:
12370 The parameter to |single_dependency| is the location of an
12371 independent variable~|x|, and the result is the simple dependency list
12372 `|x+0|'.
12373
12374 In the unlikely event that the given independent variable has been doubled so
12375 often that we can't refer to it with a nonzero coefficient,
12376 |single_dependency| returns the simple list `0'.  This case can be
12377 recognized by testing that the returned list pointer is equal to
12378 |dep_final|.
12379
12380 @c pointer mp_single_dependency (MP mp,pointer p) {
12381   pointer q; /* the new dependency list */
12382   integer m; /* the number of doublings */
12383   m=value(p) % s_scale;
12384   if ( m>28 ) {
12385     return mp_const_dependency(mp, 0);
12386   } else { 
12387     q=mp_get_node(mp, dep_node_size);
12388     value(q)=two_to_the(28-m); info(q)=p;
12389     link(q)=mp_const_dependency(mp, 0);
12390     return q;
12391   }
12392 }
12393
12394 @ We sometimes need to make an exact copy of a dependency list.
12395
12396 @c pointer mp_copy_dep_list (MP mp,pointer p) {
12397   pointer q; /* the new dependency list */
12398   q=mp_get_node(mp, dep_node_size); mp->dep_final=q;
12399   while (1) { 
12400     info(mp->dep_final)=info(p); value(mp->dep_final)=value(p);
12401     if ( info(mp->dep_final)==null ) break;
12402     link(mp->dep_final)=mp_get_node(mp, dep_node_size);
12403     mp->dep_final=link(mp->dep_final); p=link(p);
12404   }
12405   return q;
12406 }
12407
12408 @ But how do variables normally become known? Ah, now we get to the heart of the
12409 equation-solving mechanism. The |linear_eq| procedure is given a |dependent|
12410 or |mp_proto_dependent| list,~|p|, in which at least one independent variable
12411 appears. It equates this list to zero, by choosing an independent variable
12412 with the largest coefficient and making it dependent on the others. The
12413 newly dependent variable is eliminated from all current dependencies,
12414 thereby possibly making other dependent variables known.
12415
12416 The given list |p| is, of course, totally destroyed by all this processing.
12417
12418 @c void mp_linear_eq (MP mp, pointer p, small_number t) {
12419   pointer q,r,s; /* for link manipulation */
12420   pointer x; /* the variable that loses its independence */
12421   integer n; /* the number of times |x| had been halved */
12422   integer v; /* the coefficient of |x| in list |p| */
12423   pointer prev_r; /* lags one step behind |r| */
12424   pointer final_node; /* the constant term of the new dependency list */
12425   integer w; /* a tentative coefficient */
12426    @<Find a node |q| in list |p| whose coefficient |v| is largest@>;
12427   x=info(q); n=value(x) % s_scale;
12428   @<Divide list |p| by |-v|, removing node |q|@>;
12429   if ( mp->internal[mp_tracing_equations]>0 ) {
12430     @<Display the new dependency@>;
12431   }
12432   @<Simplify all existing dependencies by substituting for |x|@>;
12433   @<Change variable |x| from |independent| to |dependent| or |known|@>;
12434   if ( mp->fix_needed ) mp_fix_dependencies(mp);
12435 }
12436
12437 @ @<Find a node |q| in list |p| whose coefficient |v| is largest@>=
12438 q=p; r=link(p); v=value(q);
12439 while ( info(r)!=null ) { 
12440   if ( abs(value(r))>abs(v) ) { q=r; v=value(r); };
12441   r=link(r);
12442 }
12443
12444 @ Here we want to change the coefficients from |scaled| to |fraction|,
12445 except in the constant term. In the common case of a trivial equation
12446 like `\.{x=3.14}', we will have |v=-fraction_one|, |q=p|, and |t=mp_dependent|.
12447
12448 @<Divide list |p| by |-v|, removing node |q|@>=
12449 s=temp_head; link(s)=p; r=p;
12450 do { 
12451   if ( r==q ) {
12452     link(s)=link(r); mp_free_node(mp, r,dep_node_size);
12453   } else  { 
12454     w=mp_make_fraction(mp, value(r),v);
12455     if ( abs(w)<=half_fraction_threshold ) {
12456       link(s)=link(r); mp_free_node(mp, r,dep_node_size);
12457     } else { 
12458       value(r)=-w; s=r;
12459     }
12460   }
12461   r=link(s);
12462 } while (info(r)!=null);
12463 if ( t==mp_proto_dependent ) {
12464   value(r)=-mp_make_scaled(mp, value(r),v);
12465 } else if ( v!=-fraction_one ) {
12466   value(r)=-mp_make_fraction(mp, value(r),v);
12467 }
12468 final_node=r; p=link(temp_head)
12469
12470 @ @<Display the new dependency@>=
12471 if ( mp_interesting(mp, x) ) {
12472   mp_begin_diagnostic(mp); mp_print_nl(mp, "## "); 
12473   mp_print_variable_name(mp, x);
12474 @:]]]\#\#_}{\.{\#\#}@>
12475   w=n;
12476   while ( w>0 ) { mp_print(mp, "*4"); w=w-2;  };
12477   mp_print_char(mp, '='); mp_print_dependency(mp, p,mp_dependent); 
12478   mp_end_diagnostic(mp, false);
12479 }
12480
12481 @ @<Simplify all existing dependencies by substituting for |x|@>=
12482 prev_r=dep_head; r=link(dep_head);
12483 while ( r!=dep_head ) {
12484   s=dep_list(r); q=mp_p_with_x_becoming_q(mp, s,x,p,type(r));
12485   if ( info(q)==null ) {
12486     mp_make_known(mp, r,q);
12487   } else { 
12488     dep_list(r)=q;
12489     do {  q=link(q); } while (info(q)!=null);
12490     prev_r=q;
12491   }
12492   r=link(prev_r);
12493 }
12494
12495 @ @<Change variable |x| from |independent| to |dependent| or |known|@>=
12496 if ( n>0 ) @<Divide list |p| by $2^n$@>;
12497 if ( info(p)==null ) {
12498   type(x)=mp_known;
12499   value(x)=value(p);
12500   if ( abs(value(x))>=fraction_one ) mp_val_too_big(mp, value(x));
12501   mp_free_node(mp, p,dep_node_size);
12502   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) {
12503     mp->cur_exp=value(x); mp->cur_type=mp_known;
12504     mp_free_node(mp, x,value_node_size);
12505   }
12506 } else { 
12507   type(x)=mp_dependent; mp->dep_final=final_node; mp_new_dep(mp, x,p);
12508   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) mp->cur_type=mp_dependent;
12509 }
12510
12511 @ @<Divide list |p| by $2^n$@>=
12512
12513   s=temp_head; link(temp_head)=p; r=p;
12514   do {  
12515     if ( n>30 ) w=0;
12516     else w=value(r) / two_to_the(n);
12517     if ( (abs(w)<=half_fraction_threshold)&&(info(r)!=null) ) {
12518       link(s)=link(r);
12519       mp_free_node(mp, r,dep_node_size);
12520     } else { 
12521       value(r)=w; s=r;
12522     }
12523     r=link(s);
12524   } while (info(s)!=null);
12525   p=link(temp_head);
12526 }
12527
12528 @ The |check_mem| procedure, which is used only when \MP\ is being
12529 debugged, makes sure that the current dependency lists are well formed.
12530
12531 @<Check the list of linear dependencies@>=
12532 q=dep_head; p=link(q);
12533 while ( p!=dep_head ) {
12534   if ( prev_dep(p)!=q ) {
12535     mp_print_nl(mp, "Bad PREVDEP at "); mp_print_int(mp, p);
12536 @.Bad PREVDEP...@>
12537   }
12538   p=dep_list(p);
12539   while (1) {
12540     r=info(p); q=p; p=link(q);
12541     if ( r==null ) break;
12542     if ( value(info(p))>=value(r) ) {
12543       mp_print_nl(mp, "Out of order at "); mp_print_int(mp, p);
12544 @.Out of order...@>
12545     }
12546   }
12547 }
12548
12549 @* \[25] Dynamic nonlinear equations.
12550 Variables of numeric type are maintained by the general scheme of
12551 independent, dependent, and known values that we have just studied;
12552 and the components of pair and transform variables are handled in the
12553 same way. But \MP\ also has five other types of values: \&{boolean},
12554 \&{string}, \&{pen}, \&{path}, and \&{picture}; what about them?
12555
12556 Equations are allowed between nonlinear quantities, but only in a
12557 simple form. Two variables that haven't yet been assigned values are
12558 either equal to each other, or they're not.
12559
12560 Before a boolean variable has received a value, its type is |mp_unknown_boolean|;
12561 similarly, there are variables whose type is |mp_unknown_string|, |mp_unknown_pen|,
12562 |mp_unknown_path|, and |mp_unknown_picture|. In such cases the value is either
12563 |null| (which means that no other variables are equivalent to this one), or
12564 it points to another variable of the same undefined type. The pointers in the
12565 latter case form a cycle of nodes, which we shall call a ``ring.''
12566 Rings of undefined variables may include capsules, which arise as
12567 intermediate results within expressions or as \&{expr} parameters to macros.
12568
12569 When one member of a ring receives a value, the same value is given to
12570 all the other members. In the case of paths and pictures, this implies
12571 making separate copies of a potentially large data structure; users should
12572 restrain their enthusiasm for such generality, unless they have lots and
12573 lots of memory space.
12574
12575 @ The following procedure is called when a capsule node is being
12576 added to a ring (e.g., when an unknown variable is mentioned in an expression).
12577
12578 @c pointer mp_new_ring_entry (MP mp,pointer p) {
12579   pointer q; /* the new capsule node */
12580   q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
12581   type(q)=type(p);
12582   if ( value(p)==null ) value(q)=p; else value(q)=value(p);
12583   value(p)=q;
12584   return q;
12585 }
12586
12587 @ Conversely, we might delete a capsule or a variable before it becomes known.
12588 The following procedure simply detaches a quantity from its ring,
12589 without recycling the storage.
12590
12591 @<Declare the recycling subroutines@>=
12592 void mp_ring_delete (MP mp,pointer p) {
12593   pointer q; 
12594   q=value(p);
12595   if ( q!=null ) if ( q!=p ){ 
12596     while ( value(q)!=p ) q=value(q);
12597     value(q)=value(p);
12598   }
12599 }
12600
12601 @ Eventually there might be an equation that assigns values to all of the
12602 variables in a ring. The |nonlinear_eq| subroutine does the necessary
12603 propagation of values.
12604
12605 If the parameter |flush_p| is |true|, node |p| itself needn't receive a
12606 value, it will soon be recycled.
12607
12608 @c void mp_nonlinear_eq (MP mp,integer v, pointer p, boolean flush_p) {
12609   small_number t; /* the type of ring |p| */
12610   pointer q,r; /* link manipulation registers */
12611   t=type(p)-unknown_tag; q=value(p);
12612   if ( flush_p ) type(p)=mp_vacuous; else p=q;
12613   do {  
12614     r=value(q); type(q)=t;
12615     switch (t) {
12616     case mp_boolean_type: value(q)=v; break;
12617     case mp_string_type: value(q)=v; add_str_ref(v); break;
12618     case mp_pen_type: value(q)=copy_pen(v); break;
12619     case mp_path_type: value(q)=mp_copy_path(mp, v); break;
12620     case mp_picture_type: value(q)=v; add_edge_ref(v); break;
12621     } /* there ain't no more cases */
12622     q=r;
12623   } while (q!=p);
12624 }
12625
12626 @ If two members of rings are equated, and if they have the same type,
12627 the |ring_merge| procedure is called on to make them equivalent.
12628
12629 @c void mp_ring_merge (MP mp,pointer p, pointer q) {
12630   pointer r; /* traverses one list */
12631   r=value(p);
12632   while ( r!=p ) {
12633     if ( r==q ) {
12634       @<Exclaim about a redundant equation@>;
12635       return;
12636     };
12637     r=value(r);
12638   }
12639   r=value(p); value(p)=value(q); value(q)=r;
12640 }
12641
12642 @ @<Exclaim about a redundant equation@>=
12643
12644   print_err("Redundant equation");
12645 @.Redundant equation@>
12646   help2("I already knew that this equation was true.")
12647    ("But perhaps no harm has been done; let's continue.");
12648   mp_put_get_error(mp);
12649 }
12650
12651 @* \[26] Introduction to the syntactic routines.
12652 Let's pause a moment now and try to look at the Big Picture.
12653 The \MP\ program consists of three main parts: syntactic routines,
12654 semantic routines, and output routines. The chief purpose of the
12655 syntactic routines is to deliver the user's input to the semantic routines,
12656 while parsing expressions and locating operators and operands. The
12657 semantic routines act as an interpreter responding to these operators,
12658 which may be regarded as commands. And the output routines are
12659 periodically called on to produce compact font descriptions that can be
12660 used for typesetting or for making interim proof drawings. We have
12661 discussed the basic data structures and many of the details of semantic
12662 operations, so we are good and ready to plunge into the part of \MP\ that
12663 actually controls the activities.
12664
12665 Our current goal is to come to grips with the |get_next| procedure,
12666 which is the keystone of \MP's input mechanism. Each call of |get_next|
12667 sets the value of three variables |cur_cmd|, |cur_mod|, and |cur_sym|,
12668 representing the next input token.
12669 $$\vbox{\halign{#\hfil\cr
12670   \hbox{|cur_cmd| denotes a command code from the long list of codes
12671    given earlier;}\cr
12672   \hbox{|cur_mod| denotes a modifier of the command code;}\cr
12673   \hbox{|cur_sym| is the hash address of the symbolic token that was
12674    just scanned,}\cr
12675   \hbox{\qquad or zero in the case of a numeric or string
12676    or capsule token.}\cr}}$$
12677 Underlying this external behavior of |get_next| is all the machinery
12678 necessary to convert from character files to tokens. At a given time we
12679 may be only partially finished with the reading of several files (for
12680 which \&{input} was specified), and partially finished with the expansion
12681 of some user-defined macros and/or some macro parameters, and partially
12682 finished reading some text that the user has inserted online,
12683 and so on. When reading a character file, the characters must be
12684 converted to tokens; comments and blank spaces must
12685 be removed, numeric and string tokens must be evaluated.
12686
12687 To handle these situations, which might all be present simultaneously,
12688 \MP\ uses various stacks that hold information about the incomplete
12689 activities, and there is a finite state control for each level of the
12690 input mechanism. These stacks record the current state of an implicitly
12691 recursive process, but the |get_next| procedure is not recursive.
12692
12693 @<Glob...@>=
12694 eight_bits cur_cmd; /* current command set by |get_next| */
12695 integer cur_mod; /* operand of current command */
12696 halfword cur_sym; /* hash address of current symbol */
12697
12698 @ The |print_cmd_mod| routine prints a symbolic interpretation of a
12699 command code and its modifier.
12700 It consists of a rather tedious sequence of print
12701 commands, and most of it is essentially an inverse to the |primitive|
12702 routine that enters a \MP\ primitive into |hash| and |eqtb|. Therefore almost
12703 all of this procedure appears elsewhere in the program, together with the
12704 corresponding |primitive| calls.
12705
12706 @<Declare the procedure called |print_cmd_mod|@>=
12707 void mp_print_cmd_mod (MP mp,integer c, integer m) { 
12708  switch (c) {
12709   @<Cases of |print_cmd_mod| for symbolic printing of primitives@>
12710   default: mp_print(mp, "[unknown command code!]"); break;
12711   }
12712 }
12713
12714 @ Here is a procedure that displays a given command in braces, in the
12715 user's transcript file.
12716
12717 @d show_cur_cmd_mod mp_show_cmd_mod(mp, mp->cur_cmd,mp->cur_mod)
12718
12719 @c 
12720 void mp_show_cmd_mod (MP mp,integer c, integer m) { 
12721   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
12722   mp_print_cmd_mod(mp, c,m); mp_print_char(mp, '}');
12723   mp_end_diagnostic(mp, false);
12724 }
12725
12726 @* \[27] Input stacks and states.
12727 The state of \MP's input mechanism appears in the input stack, whose
12728 entries are records with five fields, called |index|, |start|, |loc|,
12729 |limit|, and |name|. The top element of this stack is maintained in a
12730 global variable for which no subscripting needs to be done; the other
12731 elements of the stack appear in an array. Hence the stack is declared thus:
12732
12733 @<Types...@>=
12734 typedef struct {
12735   quarterword index_field;
12736   halfword start_field, loc_field, limit_field, name_field;
12737 } in_state_record;
12738
12739 @ @<Glob...@>=
12740 in_state_record *input_stack;
12741 integer input_ptr; /* first unused location of |input_stack| */
12742 integer max_in_stack; /* largest value of |input_ptr| when pushing */
12743 in_state_record cur_input; /* the ``top'' input state */
12744 int stack_size; /* maximum number of simultaneous input sources */
12745
12746 @ @<Allocate or initialize ...@>=
12747 mp->stack_size = 300;
12748 mp->input_stack = xmalloc((mp->stack_size+1),sizeof(in_state_record));
12749
12750 @ @<Dealloc variables@>=
12751 xfree(mp->input_stack);
12752
12753 @ We've already defined the special variable |loc==cur_input.loc_field|
12754 in our discussion of basic input-output routines. The other components of
12755 |cur_input| are defined in the same way:
12756
12757 @d index mp->cur_input.index_field /* reference for buffer information */
12758 @d start mp->cur_input.start_field /* starting position in |buffer| */
12759 @d limit mp->cur_input.limit_field /* end of current line in |buffer| */
12760 @d name mp->cur_input.name_field /* name of the current file */
12761
12762 @ Let's look more closely now at the five control variables
12763 (|index|,~|start|,~|loc|,~|limit|,~|name|),
12764 assuming that \MP\ is reading a line of characters that have been input
12765 from some file or from the user's terminal. There is an array called
12766 |buffer| that acts as a stack of all lines of characters that are
12767 currently being read from files, including all lines on subsidiary
12768 levels of the input stack that are not yet completed. \MP\ will return to
12769 the other lines when it is finished with the present input file.
12770
12771 (Incidentally, on a machine with byte-oriented addressing, it would be
12772 appropriate to combine |buffer| with the |str_pool| array,
12773 letting the buffer entries grow downward from the top of the string pool
12774 and checking that these two tables don't bump into each other.)
12775
12776 The line we are currently working on begins in position |start| of the
12777 buffer; the next character we are about to read is |buffer[loc]|; and
12778 |limit| is the location of the last character present. We always have
12779 |loc<=limit|. For convenience, |buffer[limit]| has been set to |"%"|, so
12780 that the end of a line is easily sensed.
12781
12782 The |name| variable is a string number that designates the name of
12783 the current file, if we are reading an ordinary text file.  Special codes
12784 |is_term..max_spec_src| indicate other sources of input text.
12785
12786 @d is_term 0 /* |name| value when reading from the terminal for normal input */
12787 @d is_read 1 /* |name| value when executing a \&{readstring} or \&{readfrom} */
12788 @d is_scantok 2 /* |name| value when reading text generated by \&{scantokens} */
12789 @d max_spec_src is_scantok
12790
12791 @ Additional information about the current line is available via the
12792 |index| variable, which counts how many lines of characters are present
12793 in the buffer below the current level. We have |index=0| when reading
12794 from the terminal and prompting the user for each line; then if the user types,
12795 e.g., `\.{input figs}', we will have |index=1| while reading
12796 the file \.{figs.mp}. However, it does not follow that |index| is the
12797 same as the input stack pointer, since many of the levels on the input
12798 stack may come from token lists and some |index| values may correspond
12799 to \.{MPX} files that are not currently on the stack.
12800
12801 The global variable |in_open| is equal to the highest |index| value counting
12802 \.{MPX} files but excluding token-list input levels.  Thus, the number of
12803 partially read lines in the buffer is |in_open+1| and we have |in_open>=index|
12804 when we are not reading a token list.
12805
12806 If we are not currently reading from the terminal,
12807 we are reading from the file variable |input_file[index]|. We use
12808 the notation |terminal_input| as a convenient abbreviation for |name=is_term|,
12809 and |cur_file| as an abbreviation for |input_file[index]|.
12810
12811 When \MP\ is not reading from the terminal, the global variable |line| contains
12812 the line number in the current file, for use in error messages. More precisely,
12813 |line| is a macro for |line_stack[index]| and the |line_stack| array gives
12814 the line number for each file in the |input_file| array.
12815
12816 When an \.{MPX} file is opened the file name is stored in the |mpx_name|
12817 array so that the name doesn't get lost when the file is temporarily removed
12818 from the input stack.
12819 Thus when |input_file[k]| is an \.{MPX} file, its name is |mpx_name[k]|
12820 and it contains translated \TeX\ pictures for |input_file[k-1]|.
12821 Since this is not an \.{MPX} file, we have
12822 $$ \hbox{|mpx_name[k-1]<=absent|}. $$
12823 This |name| field is set to |finished| when |input_file[k]| is completely
12824 read.
12825
12826 If more information about the input state is needed, it can be
12827 included in small arrays like those shown here. For example,
12828 the current page or segment number in the input file might be put
12829 into a variable |page|, that is really a macro for the current entry
12830 in `\ignorespaces|page_stack:array[0..max_in_open] of integer|\unskip'
12831 by analogy with |line_stack|.
12832 @^system dependencies@>
12833
12834 @d terminal_input (name==is_term) /* are we reading from the terminal? */
12835 @d cur_file mp->input_file[index] /* the current |void *| variable */
12836 @d line mp->line_stack[index] /* current line number in the current source file */
12837 @d in_name mp->iname_stack[index] /* a string used to construct \.{MPX} file names */
12838 @d in_area mp->iarea_stack[index] /* another string for naming \.{MPX} files */
12839 @d absent 1 /* |name_field| value for unused |mpx_in_stack| entries */
12840 @d mpx_reading (mp->mpx_name[index]>absent)
12841   /* when reading a file, is it an \.{MPX} file? */
12842 @d finished 0
12843   /* |name_field| value when the corresponding \.{MPX} file is finished */
12844
12845 @<Glob...@>=
12846 integer in_open; /* the number of lines in the buffer, less one */
12847 unsigned int open_parens; /* the number of open text files */
12848 void  * *input_file ;
12849 integer *line_stack ; /* the line number for each file */
12850 char *  *iname_stack; /* used for naming \.{MPX} files */
12851 char *  *iarea_stack; /* used for naming \.{MPX} files */
12852 halfword*mpx_name  ;
12853
12854 @ @<Allocate or ...@>=
12855 mp->input_file  = xmalloc((mp->max_in_open+1),sizeof(void *));
12856 mp->line_stack  = xmalloc((mp->max_in_open+1),sizeof(integer));
12857 mp->iname_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
12858 mp->iarea_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
12859 mp->mpx_name    = xmalloc((mp->max_in_open+1),sizeof(halfword));
12860 {
12861   int k;
12862   for (k=0;k<=mp->max_in_open;k++) {
12863     mp->iname_stack[k] =NULL;
12864     mp->iarea_stack[k] =NULL;
12865   }
12866 }
12867
12868 @ @<Dealloc variables@>=
12869 {
12870   int l;
12871   for (l=0;l<=mp->max_in_open;l++) {
12872     xfree(mp->iname_stack[l]);
12873     xfree(mp->iarea_stack[l]);
12874   }
12875 }
12876 xfree(mp->input_file);
12877 xfree(mp->line_stack);
12878 xfree(mp->iname_stack);
12879 xfree(mp->iarea_stack);
12880 xfree(mp->mpx_name);
12881
12882
12883 @ However, all this discussion about input state really applies only to the
12884 case that we are inputting from a file. There is another important case,
12885 namely when we are currently getting input from a token list. In this case
12886 |index>max_in_open|, and the conventions about the other state variables
12887 are different:
12888
12889 \yskip\hang|loc| is a pointer to the current node in the token list, i.e.,
12890 the node that will be read next. If |loc=null|, the token list has been
12891 fully read.
12892
12893 \yskip\hang|start| points to the first node of the token list; this node
12894 may or may not contain a reference count, depending on the type of token
12895 list involved.
12896
12897 \yskip\hang|token_type|, which takes the place of |index| in the
12898 discussion above, is a code number that explains what kind of token list
12899 is being scanned.
12900
12901 \yskip\hang|name| points to the |eqtb| address of the control sequence
12902 being expanded, if the current token list is a macro not defined by
12903 \&{vardef}. Macros defined by \&{vardef} have |name=null|; their name
12904 can be deduced by looking at their first two parameters.
12905
12906 \yskip\hang|param_start|, which takes the place of |limit|, tells where
12907 the parameters of the current macro or loop text begin in the |param_stack|.
12908
12909 \yskip\noindent The |token_type| can take several values, depending on
12910 where the current token list came from:
12911
12912 \yskip
12913 \indent|forever_text|, if the token list being scanned is the body of
12914 a \&{forever} loop;
12915
12916 \indent|loop_text|, if the token list being scanned is the body of
12917 a \&{for} or \&{forsuffixes} loop;
12918
12919 \indent|parameter|, if a \&{text} or \&{suffix} parameter is being scanned;
12920
12921 \indent|backed_up|, if the token list being scanned has been inserted as
12922 `to be read again'.
12923
12924 \indent|inserted|, if the token list being scanned has been inserted as
12925 part of error recovery;
12926
12927 \indent|macro|, if the expansion of a user-defined symbolic token is being
12928 scanned.
12929
12930 \yskip\noindent
12931 The token list begins with a reference count if and only if |token_type=
12932 macro|.
12933 @^reference counts@>
12934
12935 @d token_type index /* type of current token list */
12936 @d token_state (index>(int)mp->max_in_open) /* are we scanning a token list? */
12937 @d file_state (index<=(int)mp->max_in_open) /* are we scanning a file line? */
12938 @d param_start limit /* base of macro parameters in |param_stack| */
12939 @d forever_text (mp->max_in_open+1) /* |token_type| code for loop texts */
12940 @d loop_text (mp->max_in_open+2) /* |token_type| code for loop texts */
12941 @d parameter (mp->max_in_open+3) /* |token_type| code for parameter texts */
12942 @d backed_up (mp->max_in_open+4) /* |token_type| code for texts to be reread */
12943 @d inserted (mp->max_in_open+5) /* |token_type| code for inserted texts */
12944 @d macro (mp->max_in_open+6) /* |token_type| code for macro replacement texts */
12945
12946 @ The |param_stack| is an auxiliary array used to hold pointers to the token
12947 lists for parameters at the current level and subsidiary levels of input.
12948 This stack grows at a different rate from the others.
12949
12950 @<Glob...@>=
12951 pointer *param_stack;  /* token list pointers for parameters */
12952 integer param_ptr; /* first unused entry in |param_stack| */
12953 integer max_param_stack;  /* largest value of |param_ptr| */
12954
12955 @ @<Allocate or initialize ...@>=
12956 mp->param_stack = xmalloc((mp->param_size+1),sizeof(pointer));
12957
12958 @ @<Dealloc variables@>=
12959 xfree(mp->param_stack);
12960
12961 @ Notice that the |line| isn't valid when |token_state| is true because it
12962 depends on |index|.  If we really need to know the line number for the
12963 topmost file in the index stack we use the following function.  If a page
12964 number or other information is needed, this routine should be modified to
12965 compute it as well.
12966 @^system dependencies@>
12967
12968 @<Declare a function called |true_line|@>=
12969 integer mp_true_line (MP mp) {
12970   int k; /* an index into the input stack */
12971   if ( file_state && (name>max_spec_src) ) {
12972      return line;
12973   } else { 
12974     k=mp->input_ptr;
12975     while ((k>0) &&
12976            ((mp->input_stack[(k-1)].index_field>mp->max_in_open)||
12977             (mp->input_stack[(k-1)].name_field<=max_spec_src))) {
12978       decr(k);
12979     }
12980     return (k>0 ? mp->line_stack[(k-1)] : 0 );
12981   }
12982   return 0; 
12983 }
12984
12985 @ Thus, the ``current input state'' can be very complicated indeed; there
12986 can be many levels and each level can arise in a variety of ways. The
12987 |show_context| procedure, which is used by \MP's error-reporting routine to
12988 print out the current input state on all levels down to the most recent
12989 line of characters from an input file, illustrates most of these conventions.
12990 The global variable |file_ptr| contains the lowest level that was
12991 displayed by this procedure.
12992
12993 @<Glob...@>=
12994 integer file_ptr; /* shallowest level shown by |show_context| */
12995
12996 @ The status at each level is indicated by printing two lines, where the first
12997 line indicates what was read so far and the second line shows what remains
12998 to be read. The context is cropped, if necessary, so that the first line
12999 contains at most |half_error_line| characters, and the second contains
13000 at most |error_line|. Non-current input levels whose |token_type| is
13001 `|backed_up|' are shown only if they have not been fully read.
13002
13003 @c void mp_show_context (MP mp) { /* prints where the scanner is */
13004   int old_setting; /* saved |selector| setting */
13005   @<Local variables for formatting calculations@>
13006   mp->file_ptr=mp->input_ptr; mp->input_stack[mp->file_ptr]=mp->cur_input;
13007   /* store current state */
13008   while (1) { 
13009     mp->cur_input=mp->input_stack[mp->file_ptr]; /* enter into the context */
13010     @<Display the current context@>;
13011     if ( file_state )
13012       if ( (name>max_spec_src) || (mp->file_ptr==0) ) break;
13013     decr(mp->file_ptr);
13014   }
13015   mp->cur_input=mp->input_stack[mp->input_ptr]; /* restore original state */
13016 }
13017
13018 @ @<Display the current context@>=
13019 if ( (mp->file_ptr==mp->input_ptr) || file_state ||
13020    (token_type!=backed_up) || (loc!=null) ) {
13021     /* we omit backed-up token lists that have already been read */
13022   mp->tally=0; /* get ready to count characters */
13023   old_setting=mp->selector;
13024   if ( file_state ) {
13025     @<Print location of current line@>;
13026     @<Pseudoprint the line@>;
13027   } else { 
13028     @<Print type of token list@>;
13029     @<Pseudoprint the token list@>;
13030   }
13031   mp->selector=old_setting; /* stop pseudoprinting */
13032   @<Print two lines using the tricky pseudoprinted information@>;
13033 }
13034
13035 @ This routine should be changed, if necessary, to give the best possible
13036 indication of where the current line resides in the input file.
13037 For example, on some systems it is best to print both a page and line number.
13038 @^system dependencies@>
13039
13040 @<Print location of current line@>=
13041 if ( name>max_spec_src ) {
13042   mp_print_nl(mp, "l."); mp_print_int(mp, mp_true_line(mp));
13043 } else if ( terminal_input ) {
13044   if ( mp->file_ptr==0 ) mp_print_nl(mp, "<*>");
13045   else mp_print_nl(mp, "<insert>");
13046 } else if ( name==is_scantok ) {
13047   mp_print_nl(mp, "<scantokens>");
13048 } else {
13049   mp_print_nl(mp, "<read>");
13050 }
13051 mp_print_char(mp, ' ')
13052
13053 @ Can't use case statement here because the |token_type| is not
13054 a constant expression.
13055
13056 @<Print type of token list@>=
13057 {
13058   if(token_type==forever_text) {
13059     mp_print_nl(mp, "<forever> ");
13060   } else if (token_type==loop_text) {
13061     @<Print the current loop value@>;
13062   } else if (token_type==parameter) {
13063     mp_print_nl(mp, "<argument> "); 
13064   } else if (token_type==backed_up) { 
13065     if ( loc==null ) mp_print_nl(mp, "<recently read> ");
13066     else mp_print_nl(mp, "<to be read again> ");
13067   } else if (token_type==inserted) {
13068     mp_print_nl(mp, "<inserted text> ");
13069   } else if (token_type==macro) {
13070     mp_print_ln(mp);
13071     if ( name!=null ) mp_print_text(name);
13072     else @<Print the name of a \&{vardef}'d macro@>;
13073     mp_print(mp, "->");
13074   } else {
13075     mp_print_nl(mp, "?");/* this should never happen */
13076 @.?\relax@>
13077   }
13078 }
13079
13080 @ The parameter that corresponds to a loop text is either a token list
13081 (in the case of \&{forsuffixes}) or a ``capsule'' (in the case of \&{for}).
13082 We'll discuss capsules later; for now, all we need to know is that
13083 the |link| field in a capsule parameter is |void| and that
13084 |print_exp(p,0)| displays the value of capsule~|p| in abbreviated form.
13085
13086 @<Print the current loop value@>=
13087 { mp_print_nl(mp, "<for("); p=mp->param_stack[param_start];
13088   if ( p!=null ) {
13089     if ( link(p)==mp_void ) mp_print_exp(mp, p,0); /* we're in a \&{for} loop */
13090     else mp_show_token_list(mp, p,null,20,mp->tally);
13091   }
13092   mp_print(mp, ")> ");
13093 }
13094
13095 @ The first two parameters of a macro defined by \&{vardef} will be token
13096 lists representing the macro's prefix and ``at point.'' By putting these
13097 together, we get the macro's full name.
13098
13099 @<Print the name of a \&{vardef}'d macro@>=
13100 { p=mp->param_stack[param_start];
13101   if ( p==null ) {
13102     mp_show_token_list(mp, mp->param_stack[param_start+1],null,20,mp->tally);
13103   } else { 
13104     q=p;
13105     while ( link(q)!=null ) q=link(q);
13106     link(q)=mp->param_stack[param_start+1];
13107     mp_show_token_list(mp, p,null,20,mp->tally);
13108     link(q)=null;
13109   }
13110 }
13111
13112 @ Now it is necessary to explain a little trick. We don't want to store a long
13113 string that corresponds to a token list, because that string might take up
13114 lots of memory; and we are printing during a time when an error message is
13115 being given, so we dare not do anything that might overflow one of \MP's
13116 tables. So `pseudoprinting' is the answer: We enter a mode of printing
13117 that stores characters into a buffer of length |error_line|, where character
13118 $k+1$ is placed into \hbox{|trick_buf[k mod error_line]|} if
13119 |k<trick_count|, otherwise character |k| is dropped. Initially we set
13120 |tally:=0| and |trick_count:=1000000|; then when we reach the
13121 point where transition from line 1 to line 2 should occur, we
13122 set |first_count:=tally| and |trick_count:=@tmax@>(error_line,
13123 tally+1+error_line-half_error_line)|. At the end of the
13124 pseudoprinting, the values of |first_count|, |tally|, and
13125 |trick_count| give us all the information we need to print the two lines,
13126 and all of the necessary text is in |trick_buf|.
13127
13128 Namely, let |l| be the length of the descriptive information that appears
13129 on the first line. The length of the context information gathered for that
13130 line is |k=first_count|, and the length of the context information
13131 gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|,
13132 where |h=half_error_line|, we print |trick_buf[0..k-1]| after the
13133 descriptive information on line~1, and set |n:=l+k|; here |n| is the
13134 length of line~1. If $l+k>h$, some cropping is necessary, so we set |n:=h|
13135 and print `\.{...}' followed by
13136 $$\hbox{|trick_buf[(l+k-h+3)..k-1]|,}$$
13137 where subscripts of |trick_buf| are circular modulo |error_line|. The
13138 second line consists of |n|~spaces followed by |trick_buf[k..(k+m-1)]|,
13139 unless |n+m>error_line|; in the latter case, further cropping is done.
13140 This is easier to program than to explain.
13141
13142 @<Local variables for formatting...@>=
13143 int i; /* index into |buffer| */
13144 integer l; /* length of descriptive information on line 1 */
13145 integer m; /* context information gathered for line 2 */
13146 int n; /* length of line 1 */
13147 integer p; /* starting or ending place in |trick_buf| */
13148 integer q; /* temporary index */
13149
13150 @ The following code tells the print routines to gather
13151 the desired information.
13152
13153 @d begin_pseudoprint { 
13154   l=mp->tally; mp->tally=0; mp->selector=pseudo;
13155   mp->trick_count=1000000;
13156 }
13157 @d set_trick_count {
13158   mp->first_count=mp->tally;
13159   mp->trick_count=mp->tally+1+mp->error_line-mp->half_error_line;
13160   if ( mp->trick_count<mp->error_line ) mp->trick_count=mp->error_line;
13161 }
13162
13163 @ And the following code uses the information after it has been gathered.
13164
13165 @<Print two lines using the tricky pseudoprinted information@>=
13166 if ( mp->trick_count==1000000 ) set_trick_count;
13167   /* |set_trick_count| must be performed */
13168 if ( mp->tally<mp->trick_count ) m=mp->tally-mp->first_count;
13169 else m=mp->trick_count-mp->first_count; /* context on line 2 */
13170 if ( l+mp->first_count<=mp->half_error_line ) {
13171   p=0; n=l+mp->first_count;
13172 } else  { 
13173   mp_print(mp, "..."); p=l+mp->first_count-mp->half_error_line+3;
13174   n=mp->half_error_line;
13175 }
13176 for (q=p;q<=mp->first_count-1;q++) {
13177   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13178 }
13179 mp_print_ln(mp);
13180 for (q=1;q<=n;q++) {
13181   mp_print_char(mp, ' '); /* print |n| spaces to begin line~2 */
13182 }
13183 if ( m+n<=mp->error_line ) p=mp->first_count+m; 
13184 else p=mp->first_count+(mp->error_line-n-3);
13185 for (q=mp->first_count;q<=p-1;q++) {
13186   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13187 }
13188 if ( m+n>mp->error_line ) mp_print(mp, "...")
13189
13190 @ But the trick is distracting us from our current goal, which is to
13191 understand the input state. So let's concentrate on the data structures that
13192 are being pseudoprinted as we finish up the |show_context| procedure.
13193
13194 @<Pseudoprint the line@>=
13195 begin_pseudoprint;
13196 if ( limit>0 ) {
13197   for (i=start;i<=limit-1;i++) {
13198     if ( i==loc ) set_trick_count;
13199     mp_print_str(mp, mp->buffer[i]);
13200   }
13201 }
13202
13203 @ @<Pseudoprint the token list@>=
13204 begin_pseudoprint;
13205 if ( token_type!=macro ) mp_show_token_list(mp, start,loc,100000,0);
13206 else mp_show_macro(mp, start,loc,100000)
13207
13208 @ Here is the missing piece of |show_token_list| that is activated when the
13209 token beginning line~2 is about to be shown:
13210
13211 @<Do magic computation@>=set_trick_count
13212
13213 @* \[28] Maintaining the input stacks.
13214 The following subroutines change the input status in commonly needed ways.
13215
13216 First comes |push_input|, which stores the current state and creates a
13217 new level (having, initially, the same properties as the old).
13218
13219 @d push_input  { /* enter a new input level, save the old */
13220   if ( mp->input_ptr>mp->max_in_stack ) {
13221     mp->max_in_stack=mp->input_ptr;
13222     if ( mp->input_ptr==mp->stack_size ) {
13223       int l = (mp->stack_size+(mp->stack_size>>2));
13224       XREALLOC(mp->input_stack, l, in_state_record);
13225       mp->stack_size = l;
13226     }         
13227   }
13228   mp->input_stack[mp->input_ptr]=mp->cur_input; /* stack the record */
13229   incr(mp->input_ptr);
13230 }
13231
13232 @ And of course what goes up must come down.
13233
13234 @d pop_input { /* leave an input level, re-enter the old */
13235     decr(mp->input_ptr); mp->cur_input=mp->input_stack[mp->input_ptr];
13236   }
13237
13238 @ Here is a procedure that starts a new level of token-list input, given
13239 a token list |p| and its type |t|. If |t=macro|, the calling routine should
13240 set |name|, reset~|loc|, and increase the macro's reference count.
13241
13242 @d back_list(A) mp_begin_token_list(mp, (A),backed_up) /* backs up a simple token list */
13243
13244 @c void mp_begin_token_list (MP mp,pointer p, quarterword t)  { 
13245   push_input; start=p; token_type=t;
13246   param_start=mp->param_ptr; loc=p;
13247 }
13248
13249 @ When a token list has been fully scanned, the following computations
13250 should be done as we leave that level of input.
13251 @^inner loop@>
13252
13253 @c void mp_end_token_list (MP mp) { /* leave a token-list input level */
13254   pointer p; /* temporary register */
13255   if ( token_type>=backed_up ) { /* token list to be deleted */
13256     if ( token_type<=inserted ) { 
13257       mp_flush_token_list(mp, start); goto DONE;
13258     } else {
13259       mp_delete_mac_ref(mp, start); /* update reference count */
13260     }
13261   }
13262   while ( mp->param_ptr>param_start ) { /* parameters must be flushed */
13263     decr(mp->param_ptr);
13264     p=mp->param_stack[mp->param_ptr];
13265     if ( p!=null ) {
13266       if ( link(p)==mp_void ) { /* it's an \&{expr} parameter */
13267         mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
13268       } else {
13269         mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
13270       }
13271     }
13272   }
13273 DONE: 
13274   pop_input; check_interrupt;
13275 }
13276
13277 @ The contents of |cur_cmd,cur_mod,cur_sym| are placed into an equivalent
13278 token by the |cur_tok| routine.
13279 @^inner loop@>
13280
13281 @c @<Declare the procedure called |make_exp_copy|@>;
13282 pointer mp_cur_tok (MP mp) {
13283   pointer p; /* a new token node */
13284   small_number save_type; /* |cur_type| to be restored */
13285   integer save_exp; /* |cur_exp| to be restored */
13286   if ( mp->cur_sym==0 ) {
13287     if ( mp->cur_cmd==capsule_token ) {
13288       save_type=mp->cur_type; save_exp=mp->cur_exp;
13289       mp_make_exp_copy(mp, mp->cur_mod); p=mp_stash_cur_exp(mp); link(p)=null;
13290       mp->cur_type=save_type; mp->cur_exp=save_exp;
13291     } else { 
13292       p=mp_get_node(mp, token_node_size);
13293       value(p)=mp->cur_mod; name_type(p)=mp_token;
13294       if ( mp->cur_cmd==numeric_token ) type(p)=mp_known;
13295       else type(p)=mp_string_type;
13296     }
13297   } else { 
13298     fast_get_avail(p); info(p)=mp->cur_sym;
13299   }
13300   return p;
13301 }
13302
13303 @ Sometimes \MP\ has read too far and wants to ``unscan'' what it has
13304 seen. The |back_input| procedure takes care of this by putting the token
13305 just scanned back into the input stream, ready to be read again.
13306 If |cur_sym<>0|, the values of |cur_cmd| and |cur_mod| are irrelevant.
13307
13308 @<Declarations@>= 
13309 void mp_back_input (MP mp);
13310
13311 @ @c void mp_back_input (MP mp) {/* undoes one token of input */
13312   pointer p; /* a token list of length one */
13313   p=mp_cur_tok(mp);
13314   while ( token_state &&(loc==null) ) 
13315     mp_end_token_list(mp); /* conserve stack space */
13316   back_list(p);
13317 }
13318
13319 @ The |back_error| routine is used when we want to restore or replace an
13320 offending token just before issuing an error message.  We disable interrupts
13321 during the call of |back_input| so that the help message won't be lost.
13322
13323 @<Declarations@>=
13324 void mp_error (MP mp);
13325 void mp_back_error (MP mp);
13326
13327 @ @c void mp_back_error (MP mp) { /* back up one token and call |error| */
13328   mp->OK_to_interrupt=false; 
13329   mp_back_input(mp); 
13330   mp->OK_to_interrupt=true; mp_error(mp);
13331 }
13332 void mp_ins_error (MP mp) { /* back up one inserted token and call |error| */
13333   mp->OK_to_interrupt=false; 
13334   mp_back_input(mp); token_type=inserted;
13335   mp->OK_to_interrupt=true; mp_error(mp);
13336 }
13337
13338 @ The |begin_file_reading| procedure starts a new level of input for lines
13339 of characters to be read from a file, or as an insertion from the
13340 terminal. It does not take care of opening the file, nor does it set |loc|
13341 or |limit| or |line|.
13342 @^system dependencies@>
13343
13344 @c void mp_begin_file_reading (MP mp) { 
13345   if ( mp->in_open==mp->max_in_open ) 
13346     mp_overflow(mp, "text input levels",mp->max_in_open);
13347 @:MetaPost capacity exceeded text input levels}{\quad text input levels@>
13348   if ( mp->first==mp->buf_size ) 
13349     mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
13350   incr(mp->in_open); push_input; index=mp->in_open;
13351   mp->mpx_name[index]=absent;
13352   start=mp->first;
13353   name=is_term; /* |terminal_input| is now |true| */
13354 }
13355
13356 @ Conversely, the variables must be downdated when such a level of input
13357 is finished.  Any associated \.{MPX} file must also be closed and popped
13358 off the file stack.
13359
13360 @c void mp_end_file_reading (MP mp) { 
13361   if ( mp->in_open>index ) {
13362     if ( (mp->mpx_name[mp->in_open]==absent)||(name<=max_spec_src) ) {
13363       mp_confusion(mp, "endinput");
13364 @:this can't happen endinput}{\quad endinput@>
13365     } else { 
13366       (mp->close_file)(mp,mp->input_file[mp->in_open]); /* close an \.{MPX} file */
13367       delete_str_ref(mp->mpx_name[mp->in_open]);
13368       decr(mp->in_open);
13369     }
13370   }
13371   mp->first=start;
13372   if ( index!=mp->in_open ) mp_confusion(mp, "endinput");
13373   if ( name>max_spec_src ) {
13374     (mp->close_file)(mp,cur_file);
13375     delete_str_ref(name);
13376     xfree(in_name); 
13377     xfree(in_area);
13378   }
13379   pop_input; decr(mp->in_open);
13380 }
13381
13382 @ Here is a function that tries to resume input from an \.{MPX} file already
13383 associated with the current input file.  It returns |false| if this doesn't
13384 work.
13385
13386 @c boolean mp_begin_mpx_reading (MP mp) { 
13387   if ( mp->in_open!=index+1 ) {
13388      return false;
13389   } else { 
13390     if ( mp->mpx_name[mp->in_open]<=absent ) mp_confusion(mp, "mpx");
13391 @:this can't happen mpx}{\quad mpx@>
13392     if ( mp->first==mp->buf_size ) 
13393       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
13394     push_input; index=mp->in_open;
13395     start=mp->first;
13396     name=mp->mpx_name[mp->in_open]; add_str_ref(name);
13397     @<Put an empty line in the input buffer@>;
13398     return true;
13399   }
13400 }
13401
13402 @ This procedure temporarily stops reading an \.{MPX} file.
13403
13404 @c void mp_end_mpx_reading (MP mp) { 
13405   if ( mp->in_open!=index ) mp_confusion(mp, "mpx");
13406 @:this can't happen mpx}{\quad mpx@>
13407   if ( loc<limit ) {
13408     @<Complain that we are not at the end of a line in the \.{MPX} file@>;
13409   }
13410   mp->first=start;
13411   pop_input;
13412 }
13413
13414 @ Here we enforce a restriction that simplifies the input stacks considerably.
13415 This should not inconvenience the user because \.{MPX} files are generated
13416 by an auxiliary program called \.{DVItoMP}.
13417
13418 @ @<Complain that we are not at the end of a line in the \.{MPX} file@>=
13419
13420 print_err("`mpxbreak' must be at the end of a line");
13421 help4("This file contains picture expressions for btex...etex")
13422   ("blocks.  Such files are normally generated automatically")
13423   ("but this one seems to be messed up.  I'm going to ignore")
13424   ("the rest of this line.");
13425 mp_error(mp);
13426 }
13427
13428 @ In order to keep the stack from overflowing during a long sequence of
13429 inserted `\.{show}' commands, the following routine removes completed
13430 error-inserted lines from memory.
13431
13432 @c void mp_clear_for_error_prompt (MP mp) { 
13433   while ( file_state && terminal_input &&
13434     (mp->input_ptr>0)&&(loc==limit) ) mp_end_file_reading(mp);
13435   mp_print_ln(mp); clear_terminal;
13436 }
13437
13438 @ To get \MP's whole input mechanism going, we perform the following
13439 actions.
13440
13441 @<Initialize the input routines@>=
13442 { mp->input_ptr=0; mp->max_in_stack=0;
13443   mp->in_open=0; mp->open_parens=0; mp->max_buf_stack=0;
13444   mp->param_ptr=0; mp->max_param_stack=0;
13445   mp->first=1;
13446   start=1; index=0; line=0; name=is_term;
13447   mp->mpx_name[0]=absent;
13448   mp->force_eof=false;
13449   if ( ! mp_init_terminal(mp) ) mp_jump_out(mp);
13450   limit=mp->last; mp->first=mp->last+1; 
13451   /* |init_terminal| has set |loc| and |last| */
13452 }
13453
13454 @* \[29] Getting the next token.
13455 The heart of \MP's input mechanism is the |get_next| procedure, which
13456 we shall develop in the next few sections of the program. Perhaps we
13457 shouldn't actually call it the ``heart,'' however; it really acts as \MP's
13458 eyes and mouth, reading the source files and gobbling them up. And it also
13459 helps \MP\ to regurgitate stored token lists that are to be processed again.
13460
13461 The main duty of |get_next| is to input one token and to set |cur_cmd|
13462 and |cur_mod| to that token's command code and modifier. Furthermore, if
13463 the input token is a symbolic token, that token's |hash| address
13464 is stored in |cur_sym|; otherwise |cur_sym| is set to zero.
13465
13466 Underlying this simple description is a certain amount of complexity
13467 because of all the cases that need to be handled.
13468 However, the inner loop of |get_next| is reasonably short and fast.
13469
13470 @ Before getting into |get_next|, we need to consider a mechanism by which
13471 \MP\ helps keep errors from propagating too far. Whenever the program goes
13472 into a mode where it keeps calling |get_next| repeatedly until a certain
13473 condition is met, it sets |scanner_status| to some value other than |normal|.
13474 Then if an input file ends, or if an `\&{outer}' symbol appears,
13475 an appropriate error recovery will be possible.
13476
13477 The global variable |warning_info| helps in this error recovery by providing
13478 additional information. For example, |warning_info| might indicate the
13479 name of a macro whose replacement text is being scanned.
13480
13481 @d normal 0 /* |scanner_status| at ``quiet times'' */
13482 @d skipping 1 /* |scanner_status| when false conditional text is being skipped */
13483 @d flushing 2 /* |scanner_status| when junk after a statement is being ignored */
13484 @d absorbing 3 /* |scanner_status| when a \&{text} parameter is being scanned */
13485 @d var_defining 4 /* |scanner_status| when a \&{vardef} is being scanned */
13486 @d op_defining 5 /* |scanner_status| when a macro \&{def} is being scanned */
13487 @d loop_defining 6 /* |scanner_status| when a \&{for} loop is being scanned */
13488 @d tex_flushing 7 /* |scanner_status| when skipping \TeX\ material */
13489
13490 @<Glob...@>=
13491 integer scanner_status; /* are we scanning at high speed? */
13492 integer warning_info; /* if so, what else do we need to know,
13493     in case an error occurs? */
13494
13495 @ @<Initialize the input routines@>=
13496 mp->scanner_status=normal;
13497
13498 @ The following subroutine
13499 is called when an `\&{outer}' symbolic token has been scanned or
13500 when the end of a file has been reached. These two cases are distinguished
13501 by |cur_sym|, which is zero at the end of a file.
13502
13503 @c boolean mp_check_outer_validity (MP mp) {
13504   pointer p; /* points to inserted token list */
13505   if ( mp->scanner_status==normal ) {
13506     return true;
13507   } else if ( mp->scanner_status==tex_flushing ) {
13508     @<Check if the file has ended while flushing \TeX\ material and set the
13509       result value for |check_outer_validity|@>;
13510   } else { 
13511     mp->deletions_allowed=false;
13512     @<Back up an outer symbolic token so that it can be reread@>;
13513     if ( mp->scanner_status>skipping ) {
13514       @<Tell the user what has run away and try to recover@>;
13515     } else { 
13516       print_err("Incomplete if; all text was ignored after line ");
13517 @.Incomplete if...@>
13518       mp_print_int(mp, mp->warning_info);
13519       help3("A forbidden `outer' token occurred in skipped text.")
13520         ("This kind of error happens when you say `if...' and forget")
13521         ("the matching `fi'. I've inserted a `fi'; this might work.");
13522       if ( mp->cur_sym==0 ) 
13523         mp->help_line[2]="The file ended while I was skipping conditional text.";
13524       mp->cur_sym=frozen_fi; mp_ins_error(mp);
13525     }
13526     mp->deletions_allowed=true; 
13527         return false;
13528   }
13529 }
13530
13531 @ @<Check if the file has ended while flushing \TeX\ material and set...@>=
13532 if ( mp->cur_sym!=0 ) { 
13533    return true;
13534 } else { 
13535   mp->deletions_allowed=false;
13536   print_err("TeX mode didn't end; all text was ignored after line ");
13537   mp_print_int(mp, mp->warning_info);
13538   help2("The file ended while I was looking for the `etex' to")
13539     ("finish this TeX material.  I've inserted `etex' now.");
13540   mp->cur_sym = frozen_etex;
13541   mp_ins_error(mp);
13542   mp->deletions_allowed=true;
13543   return false;
13544 }
13545
13546 @ @<Back up an outer symbolic token so that it can be reread@>=
13547 if ( mp->cur_sym!=0 ) {
13548   p=mp_get_avail(mp); info(p)=mp->cur_sym;
13549   back_list(p); /* prepare to read the symbolic token again */
13550 }
13551
13552 @ @<Tell the user what has run away...@>=
13553
13554   mp_runaway(mp); /* print the definition-so-far */
13555   if ( mp->cur_sym==0 ) {
13556     print_err("File ended");
13557 @.File ended while scanning...@>
13558   } else { 
13559     print_err("Forbidden token found");
13560 @.Forbidden token found...@>
13561   }
13562   mp_print(mp, " while scanning ");
13563   help4("I suspect you have forgotten an `enddef',")
13564     ("causing me to read past where you wanted me to stop.")
13565     ("I'll try to recover; but if the error is serious,")
13566     ("you'd better type `E' or `X' now and fix your file.");
13567   switch (mp->scanner_status) {
13568     @<Complete the error message,
13569       and set |cur_sym| to a token that might help recover from the error@>
13570   } /* there are no other cases */
13571   mp_ins_error(mp);
13572 }
13573
13574 @ As we consider various kinds of errors, it is also appropriate to
13575 change the first line of the help message just given; |help_line[3]|
13576 points to the string that might be changed.
13577
13578 @<Complete the error message,...@>=
13579 case flushing: 
13580   mp_print(mp, "to the end of the statement");
13581   mp->help_line[3]="A previous error seems to have propagated,";
13582   mp->cur_sym=frozen_semicolon;
13583   break;
13584 case absorbing: 
13585   mp_print(mp, "a text argument");
13586   mp->help_line[3]="It seems that a right delimiter was left out,";
13587   if ( mp->warning_info==0 ) {
13588     mp->cur_sym=frozen_end_group;
13589   } else { 
13590     mp->cur_sym=frozen_right_delimiter;
13591     equiv(frozen_right_delimiter)=mp->warning_info;
13592   }
13593   break;
13594 case var_defining:
13595 case op_defining: 
13596   mp_print(mp, "the definition of ");
13597   if ( mp->scanner_status==op_defining ) 
13598      mp_print_text(mp->warning_info);
13599   else 
13600      mp_print_variable_name(mp, mp->warning_info);
13601   mp->cur_sym=frozen_end_def;
13602   break;
13603 case loop_defining: 
13604   mp_print(mp, "the text of a "); 
13605   mp_print_text(mp->warning_info);
13606   mp_print(mp, " loop");
13607   mp->help_line[3]="I suspect you have forgotten an `endfor',";
13608   mp->cur_sym=frozen_end_for;
13609   break;
13610
13611 @ The |runaway| procedure displays the first part of the text that occurred
13612 when \MP\ began its special |scanner_status|, if that text has been saved.
13613
13614 @<Declare the procedure called |runaway|@>=
13615 void mp_runaway (MP mp) { 
13616   if ( mp->scanner_status>flushing ) { 
13617      mp_print_nl(mp, "Runaway ");
13618          switch (mp->scanner_status) { 
13619          case absorbing: mp_print(mp, "text?"); break;
13620          case var_defining: 
13621      case op_defining: mp_print(mp,"definition?"); break;
13622      case loop_defining: mp_print(mp, "loop?"); break;
13623      } /* there are no other cases */
13624      mp_print_ln(mp); 
13625      mp_show_token_list(mp, link(hold_head),null,mp->error_line-10,0);
13626   }
13627 }
13628
13629 @ We need to mention a procedure that may be called by |get_next|.
13630
13631 @<Declarations@>= 
13632 void mp_firm_up_the_line (MP mp);
13633
13634 @ And now we're ready to take the plunge into |get_next| itself.
13635 Note that the behavior depends on the |scanner_status| because percent signs
13636 and double quotes need to be passed over when skipping TeX material.
13637
13638 @c 
13639 void mp_get_next (MP mp) {
13640   /* sets |cur_cmd|, |cur_mod|, |cur_sym| to next token */
13641 @^inner loop@>
13642   /*restart*/ /* go here to get the next input token */
13643   /*exit*/ /* go here when the next input token has been got */
13644   /*|common_ending|*/ /* go here to finish getting a symbolic token */
13645   /*found*/ /* go here when the end of a symbolic token has been found */
13646   /*switch*/ /* go here to branch on the class of an input character */
13647   /*|start_numeric_token|,|start_decimal_token|,|fin_numeric_token|,|done|*/
13648     /* go here at crucial stages when scanning a number */
13649   int k; /* an index into |buffer| */
13650   ASCII_code c; /* the current character in the buffer */
13651   ASCII_code class; /* its class number */
13652   integer n,f; /* registers for decimal-to-binary conversion */
13653 RESTART: 
13654   mp->cur_sym=0;
13655   if ( file_state ) {
13656     @<Input from external file; |goto restart| if no input found,
13657     or |return| if a non-symbolic token is found@>;
13658   } else {
13659     @<Input from token list; |goto restart| if end of list or
13660       if a parameter needs to be expanded,
13661       or |return| if a non-symbolic token is found@>;
13662   }
13663 COMMON_ENDING: 
13664   @<Finish getting the symbolic token in |cur_sym|;
13665    |goto restart| if it is illegal@>;
13666 }
13667
13668 @ When a symbolic token is declared to be `\&{outer}', its command code
13669 is increased by |outer_tag|.
13670 @^inner loop@>
13671
13672 @<Finish getting the symbolic token in |cur_sym|...@>=
13673 mp->cur_cmd=eq_type(mp->cur_sym); mp->cur_mod=equiv(mp->cur_sym);
13674 if ( mp->cur_cmd>=outer_tag ) {
13675   if ( mp_check_outer_validity(mp) ) 
13676     mp->cur_cmd=mp->cur_cmd-outer_tag;
13677   else 
13678     goto RESTART;
13679 }
13680
13681 @ A percent sign appears in |buffer[limit]|; this makes it unnecessary
13682 to have a special test for end-of-line.
13683 @^inner loop@>
13684
13685 @<Input from external file;...@>=
13686
13687 SWITCH: 
13688   c=mp->buffer[loc]; incr(loc); class=mp->char_class[c];
13689   switch (class) {
13690   case digit_class: goto START_NUMERIC_TOKEN; break;
13691   case period_class: 
13692     class=mp->char_class[mp->buffer[loc]];
13693     if ( class>period_class ) {
13694       goto SWITCH;
13695     } else if ( class<period_class ) { /* |class=digit_class| */
13696       n=0; goto START_DECIMAL_TOKEN;
13697     }
13698 @:. }{\..\ token@>
13699     break;
13700   case space_class: goto SWITCH; break;
13701   case percent_class: 
13702     if ( mp->scanner_status==tex_flushing ) {
13703       if ( loc<limit ) goto SWITCH;
13704     }
13705     @<Move to next line of file, or |goto restart| if there is no next line@>;
13706     check_interrupt;
13707     goto SWITCH;
13708     break;
13709   case string_class: 
13710     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13711     else @<Get a string token and |return|@>;
13712     break;
13713   case isolated_classes: 
13714     k=loc-1; goto FOUND; break;
13715   case invalid_class: 
13716     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13717     else @<Decry the invalid character and |goto restart|@>;
13718     break;
13719   default: break; /* letters, etc. */
13720   }
13721   k=loc-1;
13722   while ( mp->char_class[mp->buffer[loc]]==class ) incr(loc);
13723   goto FOUND;
13724 START_NUMERIC_TOKEN:
13725   @<Get the integer part |n| of a numeric token;
13726     set |f:=0| and |goto fin_numeric_token| if there is no decimal point@>;
13727 START_DECIMAL_TOKEN:
13728   @<Get the fraction part |f| of a numeric token@>;
13729 FIN_NUMERIC_TOKEN:
13730   @<Pack the numeric and fraction parts of a numeric token
13731     and |return|@>;
13732 FOUND: 
13733   mp->cur_sym=mp_id_lookup(mp, k,loc-k);
13734 }
13735
13736 @ We go to |restart| instead of to |SWITCH|, because |state| might equal
13737 |token_list| after the error has been dealt with
13738 (cf.\ |clear_for_error_prompt|).
13739
13740 @<Decry the invalid...@>=
13741
13742   print_err("Text line contains an invalid character");
13743 @.Text line contains...@>
13744   help2("A funny symbol that I can\'t read has just been input.")
13745     ("Continue, and I'll forget that it ever happened.");
13746   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13747   goto RESTART;
13748 }
13749
13750 @ @<Get a string token and |return|@>=
13751
13752   if ( mp->buffer[loc]=='"' ) {
13753     mp->cur_mod=rts("");
13754   } else { 
13755     k=loc; mp->buffer[limit+1]='"';
13756     do {  
13757      incr(loc);
13758     } while (mp->buffer[loc]!='"');
13759     if ( loc>limit ) {
13760       @<Decry the missing string delimiter and |goto restart|@>;
13761     }
13762     if ( loc==k+1 ) {
13763       mp->cur_mod=mp->buffer[k];
13764     } else { 
13765       str_room(loc-k);
13766       do {  
13767         append_char(mp->buffer[k]); incr(k);
13768       } while (k!=loc);
13769       mp->cur_mod=mp_make_string(mp);
13770     }
13771   }
13772   incr(loc); mp->cur_cmd=string_token; 
13773   return;
13774 }
13775
13776 @ We go to |restart| after this error message, not to |SWITCH|,
13777 because the |clear_for_error_prompt| routine might have reinstated
13778 |token_state| after |error| has finished.
13779
13780 @<Decry the missing string delimiter and |goto restart|@>=
13781
13782   loc=limit; /* the next character to be read on this line will be |"%"| */
13783   print_err("Incomplete string token has been flushed");
13784 @.Incomplete string token...@>
13785   help3("Strings should finish on the same line as they began.")
13786     ("I've deleted the partial string; you might want to")
13787     ("insert another by typing, e.g., `I\"new string\"'.");
13788   mp->deletions_allowed=false; mp_error(mp);
13789   mp->deletions_allowed=true; 
13790   goto RESTART;
13791 }
13792
13793 @ @<Get the integer part |n| of a numeric token...@>=
13794 n=c-'0';
13795 while ( mp->char_class[mp->buffer[loc]]==digit_class ) {
13796   if ( n<32768 ) n=10*n+mp->buffer[loc]-'0';
13797   incr(loc);
13798 }
13799 if ( mp->buffer[loc]=='.' ) 
13800   if ( mp->char_class[mp->buffer[loc+1]]==digit_class ) 
13801     goto DONE;
13802 f=0; 
13803 goto FIN_NUMERIC_TOKEN;
13804 DONE: incr(loc)
13805
13806 @ @<Get the fraction part |f| of a numeric token@>=
13807 k=0;
13808 do { 
13809   if ( k<17 ) { /* digits for |k>=17| cannot affect the result */
13810     mp->dig[k]=mp->buffer[loc]-'0'; incr(k);
13811   }
13812   incr(loc);
13813 } while (mp->char_class[mp->buffer[loc]]==digit_class);
13814 f=mp_round_decimals(mp, k);
13815 if ( f==unity ) {
13816   incr(n); f=0;
13817 }
13818
13819 @ @<Pack the numeric and fraction parts of a numeric token and |return|@>=
13820 if ( n<32768 ) {
13821   @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>;
13822 } else if ( mp->scanner_status!=tex_flushing ) {
13823   print_err("Enormous number has been reduced");
13824 @.Enormous number...@>
13825   help2("I can\'t handle numbers bigger than 32767.99998;")
13826     ("so I've changed your constant to that maximum amount.");
13827   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13828   mp->cur_mod=el_gordo;
13829 }
13830 mp->cur_cmd=numeric_token; return
13831
13832 @ @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>=
13833
13834   mp->cur_mod=n*unity+f;
13835   if ( mp->cur_mod>=fraction_one ) {
13836     if ( (mp->internal[mp_warning_check]>0) &&
13837          (mp->scanner_status!=tex_flushing) ) {
13838       print_err("Number is too large (");
13839       mp_print_scaled(mp, mp->cur_mod);
13840       mp_print_char(mp, ')');
13841       help3("It is at least 4096. Continue and I'll try to cope")
13842       ("with that big value; but it might be dangerous.")
13843       ("(Set warningcheck:=0 to suppress this message.)");
13844       mp_error(mp);
13845     }
13846   }
13847 }
13848
13849 @ Let's consider now what happens when |get_next| is looking at a token list.
13850 @^inner loop@>
13851
13852 @<Input from token list;...@>=
13853 if ( loc>=mp->hi_mem_min ) { /* one-word token */
13854   mp->cur_sym=info(loc); loc=link(loc); /* move to next */
13855   if ( mp->cur_sym>=expr_base ) {
13856     if ( mp->cur_sym>=suffix_base ) {
13857       @<Insert a suffix or text parameter and |goto restart|@>;
13858     } else { 
13859       mp->cur_cmd=capsule_token;
13860       mp->cur_mod=mp->param_stack[param_start+mp->cur_sym-(expr_base)];
13861       mp->cur_sym=0; return;
13862     }
13863   }
13864 } else if ( loc>null ) {
13865   @<Get a stored numeric or string or capsule token and |return|@>
13866 } else { /* we are done with this token list */
13867   mp_end_token_list(mp); goto RESTART; /* resume previous level */
13868 }
13869
13870 @ @<Insert a suffix or text parameter...@>=
13871
13872   if ( mp->cur_sym>=text_base ) mp->cur_sym=mp->cur_sym-mp->param_size;
13873   /* |param_size=text_base-suffix_base| */
13874   mp_begin_token_list(mp,
13875                       mp->param_stack[param_start+mp->cur_sym-(suffix_base)],
13876                       parameter);
13877   goto RESTART;
13878 }
13879
13880 @ @<Get a stored numeric or string or capsule token...@>=
13881
13882   if ( name_type(loc)==mp_token ) {
13883     mp->cur_mod=value(loc);
13884     if ( type(loc)==mp_known ) {
13885       mp->cur_cmd=numeric_token;
13886     } else { 
13887       mp->cur_cmd=string_token; add_str_ref(mp->cur_mod);
13888     }
13889   } else { 
13890     mp->cur_mod=loc; mp->cur_cmd=capsule_token;
13891   };
13892   loc=link(loc); return;
13893 }
13894
13895 @ All of the easy branches of |get_next| have now been taken care of.
13896 There is one more branch.
13897
13898 @<Move to next line of file, or |goto restart|...@>=
13899 if ( name>max_spec_src ) {
13900   @<Read next line of file into |buffer|, or
13901     |goto restart| if the file has ended@>;
13902 } else { 
13903   if ( mp->input_ptr>0 ) {
13904      /* text was inserted during error recovery or by \&{scantokens} */
13905     mp_end_file_reading(mp); goto RESTART; /* resume previous level */
13906   }
13907   if ( mp->selector<log_only || mp->selector>=write_file) mp_open_log_file(mp);
13908   if ( mp->interaction>mp_nonstop_mode ) {
13909     if ( limit==start ) /* previous line was empty */
13910       mp_print_nl(mp, "(Please type a command or say `end')");
13911 @.Please type...@>
13912     mp_print_ln(mp); mp->first=start;
13913     prompt_input("*"); /* input on-line into |buffer| */
13914 @.*\relax@>
13915     limit=mp->last; mp->buffer[limit]='%';
13916     mp->first=limit+1; loc=start;
13917   } else {
13918     mp_fatal_error(mp, "*** (job aborted, no legal end found)");
13919 @.job aborted@>
13920     /* nonstop mode, which is intended for overnight batch processing,
13921     never waits for on-line input */
13922   }
13923 }
13924
13925 @ The global variable |force_eof| is normally |false|; it is set |true|
13926 by an \&{endinput} command.
13927
13928 @<Glob...@>=
13929 boolean force_eof; /* should the next \&{input} be aborted early? */
13930
13931 @ We must decrement |loc| in order to leave the buffer in a valid state
13932 when an error condition causes us to |goto restart| without calling
13933 |end_file_reading|.
13934
13935 @<Read next line of file into |buffer|, or
13936   |goto restart| if the file has ended@>=
13937
13938   incr(line); mp->first=start;
13939   if ( ! mp->force_eof ) {
13940     if ( mp_input_ln(mp, cur_file ) ) /* not end of file */
13941       mp_firm_up_the_line(mp); /* this sets |limit| */
13942     else 
13943       mp->force_eof=true;
13944   };
13945   if ( mp->force_eof ) {
13946     mp->force_eof=false;
13947     decr(loc);
13948     if ( mpx_reading ) {
13949       @<Complain that the \.{MPX} file ended unexpectly; then set
13950         |cur_sym:=frozen_mpx_break| and |goto comon_ending|@>;
13951     } else { 
13952       mp_print_char(mp, ')'); decr(mp->open_parens);
13953       update_terminal; /* show user that file has been read */
13954       mp_end_file_reading(mp); /* resume previous level */
13955       if ( mp_check_outer_validity(mp) ) goto  RESTART;  
13956       else goto RESTART;
13957     }
13958   }
13959   mp->buffer[limit]='%'; mp->first=limit+1; loc=start; /* ready to read */
13960 }
13961
13962 @ We should never actually come to the end of an \.{MPX} file because such
13963 files should have an \&{mpxbreak} after the translation of the last
13964 \&{btex}$\,\ldots\,$\&{etex} block.
13965
13966 @<Complain that the \.{MPX} file ended unexpectly; then set...@>=
13967
13968   mp->mpx_name[index]=finished;
13969   print_err("mpx file ended unexpectedly");
13970   help4("The file had too few picture expressions for btex...etex")
13971     ("blocks.  Such files are normally generated automatically")
13972     ("but this one got messed up.  You might want to insert a")
13973     ("picture expression now.");
13974   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13975   mp->cur_sym=frozen_mpx_break; goto COMMON_ENDING;
13976 }
13977
13978 @ Sometimes we want to make it look as though we have just read a blank line
13979 without really doing so.
13980
13981 @<Put an empty line in the input buffer@>=
13982 mp->last=mp->first; limit=mp->last; /* simulate |input_ln| and |firm_up_the_line| */
13983 mp->buffer[limit]='%'; mp->first=limit+1; loc=start
13984
13985 @ If the user has set the |mp_pausing| parameter to some positive value,
13986 and if nonstop mode has not been selected, each line of input is displayed
13987 on the terminal and the transcript file, followed by `\.{=>}'.
13988 \MP\ waits for a response. If the response is null (i.e., if nothing is
13989 typed except perhaps a few blank spaces), the original
13990 line is accepted as it stands; otherwise the line typed is
13991 used instead of the line in the file.
13992
13993 @c void mp_firm_up_the_line (MP mp) {
13994   size_t k; /* an index into |buffer| */
13995   limit=mp->last;
13996   if ( mp->internal[mp_pausing]>0) if ( mp->interaction>mp_nonstop_mode ) {
13997     wake_up_terminal; mp_print_ln(mp);
13998     if ( start<limit ) {
13999       for (k=(size_t)start;k<=(size_t)(limit-1);k++) {
14000         mp_print_str(mp, mp->buffer[k]);
14001       } 
14002     }
14003     mp->first=limit; prompt_input("=>"); /* wait for user response */
14004 @.=>@>
14005     if ( mp->last>mp->first ) {
14006       for (k=mp->first;k<=mp->last-1;k++) { /* move line down in buffer */
14007         mp->buffer[k+start-mp->first]=mp->buffer[k];
14008       }
14009       limit=start+mp->last-mp->first;
14010     }
14011   }
14012 }
14013
14014 @* \[30] Dealing with \TeX\ material.
14015 The \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}$\,\ldots\,$\&{etex}
14016 features need to be implemented at a low level in the scanning process
14017 so that \MP\ can stay in synch with the a preprocessor that treats
14018 blocks of \TeX\ material as they occur in the input file without trying
14019 to expand \MP\ macros.  Thus we need a special version of |get_next|
14020 that does not expand macros and such but does handle \&{btex},
14021 \&{verbatimtex}, etc.
14022
14023 The special version of |get_next| is called |get_t_next|.  It works by flushing
14024 \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}\allowbreak
14025 $\,\ldots\,$\&{etex} blocks, switching to the \.{MPX} file when it sees
14026 \&{btex}, and switching back when it sees \&{mpxbreak}.
14027
14028 @d btex_code 0
14029 @d verbatim_code 1
14030
14031 @ @<Put each...@>=
14032 mp_primitive(mp, "btex",start_tex,btex_code);
14033 @:btex_}{\&{btex} primitive@>
14034 mp_primitive(mp, "verbatimtex",start_tex,verbatim_code);
14035 @:verbatimtex_}{\&{verbatimtex} primitive@>
14036 mp_primitive(mp, "etex",etex_marker,0); mp->eqtb[frozen_etex]=mp->eqtb[mp->cur_sym];
14037 @:etex_}{\&{etex} primitive@>
14038 mp_primitive(mp, "mpxbreak",mpx_break,0); mp->eqtb[frozen_mpx_break]=mp->eqtb[mp->cur_sym];
14039 @:mpx_break_}{\&{mpxbreak} primitive@>
14040
14041 @ @<Cases of |print_cmd...@>=
14042 case start_tex: if ( m==btex_code ) mp_print(mp, "btex");
14043   else mp_print(mp, "verbatimtex"); break;
14044 case etex_marker: mp_print(mp, "etex"); break;
14045 case mpx_break: mp_print(mp, "mpxbreak"); break;
14046
14047 @ Actually, |get_t_next| is a macro that avoids procedure overhead except
14048 in the unusual case where \&{btex}, \&{verbatimtex}, \&{etex}, or \&{mpxbreak}
14049 is encountered.
14050
14051 @d get_t_next {mp_get_next(mp); if ( mp->cur_cmd<=max_pre_command ) mp_t_next(mp); }
14052
14053 @<Declarations@>=
14054 void mp_start_mpx_input (MP mp);
14055
14056 @ @c 
14057 void mp_t_next (MP mp) {
14058   int old_status; /* saves the |scanner_status| */
14059   integer old_info; /* saves the |warning_info| */
14060   while ( mp->cur_cmd<=max_pre_command ) {
14061     if ( mp->cur_cmd==mpx_break ) {
14062       if ( ! file_state || (mp->mpx_name[index]==absent) ) {
14063         @<Complain about a misplaced \&{mpxbreak}@>;
14064       } else { 
14065         mp_end_mpx_reading(mp); 
14066         goto TEX_FLUSH;
14067       }
14068     } else if ( mp->cur_cmd==start_tex ) {
14069       if ( token_state || (name<=max_spec_src) ) {
14070         @<Complain that we are not reading a file@>;
14071       } else if ( mpx_reading ) {
14072         @<Complain that \.{MPX} files cannot contain \TeX\ material@>;
14073       } else if ( (mp->cur_mod!=verbatim_code)&&
14074                   (mp->mpx_name[index]!=finished) ) {
14075         if ( ! mp_begin_mpx_reading(mp) ) mp_start_mpx_input(mp);
14076       } else {
14077         goto TEX_FLUSH;
14078       }
14079     } else {
14080        @<Complain about a misplaced \&{etex}@>;
14081     }
14082     goto COMMON_ENDING;
14083   TEX_FLUSH: 
14084     @<Flush the \TeX\ material@>;
14085   COMMON_ENDING: 
14086     mp_get_next(mp);
14087   }
14088 }
14089
14090 @ We could be in the middle of an operation such as skipping false conditional
14091 text when \TeX\ material is encountered, so we must be careful to save the
14092 |scanner_status|.
14093
14094 @<Flush the \TeX\ material@>=
14095 old_status=mp->scanner_status;
14096 old_info=mp->warning_info;
14097 mp->scanner_status=tex_flushing;
14098 mp->warning_info=line;
14099 do {  mp_get_next(mp); } while (mp->cur_cmd!=etex_marker);
14100 mp->scanner_status=old_status;
14101 mp->warning_info=old_info
14102
14103 @ @<Complain that \.{MPX} files cannot contain \TeX\ material@>=
14104 { print_err("An mpx file cannot contain btex or verbatimtex blocks");
14105 help4("This file contains picture expressions for btex...etex")
14106   ("blocks.  Such files are normally generated automatically")
14107   ("but this one seems to be messed up.  I'll just keep going")
14108   ("and hope for the best.");
14109 mp_error(mp);
14110 }
14111
14112 @ @<Complain that we are not reading a file@>=
14113 { print_err("You can only use `btex' or `verbatimtex' in a file");
14114 help3("I'll have to ignore this preprocessor command because it")
14115   ("only works when there is a file to preprocess.  You might")
14116   ("want to delete everything up to the next `etex`.");
14117 mp_error(mp);
14118 }
14119
14120 @ @<Complain about a misplaced \&{mpxbreak}@>=
14121 { print_err("Misplaced mpxbreak");
14122 help2("I'll ignore this preprocessor command because it")
14123   ("doesn't belong here");
14124 mp_error(mp);
14125 }
14126
14127 @ @<Complain about a misplaced \&{etex}@>=
14128 { print_err("Extra etex will be ignored");
14129 help1("There is no btex or verbatimtex for this to match");
14130 mp_error(mp);
14131 }
14132
14133 @* \[31] Scanning macro definitions.
14134 \MP\ has a variety of ways to tuck tokens away into token lists for later
14135 use: Macros can be defined with \&{def}, \&{vardef}, \&{primarydef}, etc.;
14136 repeatable code can be defined with \&{for}, \&{forever}, \&{forsuffixes}.
14137 All such operations are handled by the routines in this part of the program.
14138
14139 The modifier part of each command code is zero for the ``ending delimiters''
14140 like \&{enddef} and \&{endfor}.
14141
14142 @d start_def 1 /* command modifier for \&{def} */
14143 @d var_def 2 /* command modifier for \&{vardef} */
14144 @d end_def 0 /* command modifier for \&{enddef} */
14145 @d start_forever 1 /* command modifier for \&{forever} */
14146 @d end_for 0 /* command modifier for \&{endfor} */
14147
14148 @<Put each...@>=
14149 mp_primitive(mp, "def",macro_def,start_def);
14150 @:def_}{\&{def} primitive@>
14151 mp_primitive(mp, "vardef",macro_def,var_def);
14152 @:var_def_}{\&{vardef} primitive@>
14153 mp_primitive(mp, "primarydef",macro_def,secondary_primary_macro);
14154 @:primary_def_}{\&{primarydef} primitive@>
14155 mp_primitive(mp, "secondarydef",macro_def,tertiary_secondary_macro);
14156 @:secondary_def_}{\&{secondarydef} primitive@>
14157 mp_primitive(mp, "tertiarydef",macro_def,expression_tertiary_macro);
14158 @:tertiary_def_}{\&{tertiarydef} primitive@>
14159 mp_primitive(mp, "enddef",macro_def,end_def); mp->eqtb[frozen_end_def]=mp->eqtb[mp->cur_sym];
14160 @:end_def_}{\&{enddef} primitive@>
14161 @#
14162 mp_primitive(mp, "for",iteration,expr_base);
14163 @:for_}{\&{for} primitive@>
14164 mp_primitive(mp, "forsuffixes",iteration,suffix_base);
14165 @:for_suffixes_}{\&{forsuffixes} primitive@>
14166 mp_primitive(mp, "forever",iteration,start_forever);
14167 @:forever_}{\&{forever} primitive@>
14168 mp_primitive(mp, "endfor",iteration,end_for); mp->eqtb[frozen_end_for]=mp->eqtb[mp->cur_sym];
14169 @:end_for_}{\&{endfor} primitive@>
14170
14171 @ @<Cases of |print_cmd...@>=
14172 case macro_def:
14173   if ( m<=var_def ) {
14174     if ( m==start_def ) mp_print(mp, "def");
14175     else if ( m<start_def ) mp_print(mp, "enddef");
14176     else mp_print(mp, "vardef");
14177   } else if ( m==secondary_primary_macro ) { 
14178     mp_print(mp, "primarydef");
14179   } else if ( m==tertiary_secondary_macro ) { 
14180     mp_print(mp, "secondarydef");
14181   } else { 
14182     mp_print(mp, "tertiarydef");
14183   }
14184   break;
14185 case iteration: 
14186   if ( m<=start_forever ) {
14187     if ( m==start_forever ) mp_print(mp, "forever"); 
14188     else mp_print(mp, "endfor");
14189   } else if ( m==expr_base ) {
14190     mp_print(mp, "for"); 
14191   } else { 
14192     mp_print(mp, "forsuffixes");
14193   }
14194   break;
14195
14196 @ Different macro-absorbing operations have different syntaxes, but they
14197 also have a lot in common. There is a list of special symbols that are to
14198 be replaced by parameter tokens; there is a special command code that
14199 ends the definition; the quotation conventions are identical.  Therefore
14200 it makes sense to have most of the work done by a single subroutine. That
14201 subroutine is called |scan_toks|.
14202
14203 The first parameter to |scan_toks| is the command code that will
14204 terminate scanning (either |macro_def|, |loop_repeat|, or |iteration|).
14205
14206 The second parameter, |subst_list|, points to a (possibly empty) list
14207 of two-word nodes whose |info| and |value| fields specify symbol tokens
14208 before and after replacement. The list will be returned to free storage
14209 by |scan_toks|.
14210
14211 The third parameter is simply appended to the token list that is built.
14212 And the final parameter tells how many of the special operations
14213 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#} are to be replaced by suffix parameters.
14214 When such parameters are present, they are called \.{(SUFFIX0)},
14215 \.{(SUFFIX1)}, and \.{(SUFFIX2)}.
14216
14217 @c pointer mp_scan_toks (MP mp,command_code terminator, pointer 
14218   subst_list, pointer tail_end, small_number suffix_count) {
14219   pointer p; /* tail of the token list being built */
14220   pointer q; /* temporary for link management */
14221   integer balance; /* left delimiters minus right delimiters */
14222   p=hold_head; balance=1; link(hold_head)=null;
14223   while (1) { 
14224     get_t_next;
14225     if ( mp->cur_sym>0 ) {
14226       @<Substitute for |cur_sym|, if it's on the |subst_list|@>;
14227       if ( mp->cur_cmd==terminator ) {
14228         @<Adjust the balance; |break| if it's zero@>;
14229       } else if ( mp->cur_cmd==macro_special ) {
14230         @<Handle quoted symbols, \.{\#\AT!}, \.{\AT!}, or \.{\AT!\#}@>;
14231       }
14232     }
14233     link(p)=mp_cur_tok(mp); p=link(p);
14234   }
14235   link(p)=tail_end; mp_flush_node_list(mp, subst_list);
14236   return link(hold_head);
14237 }
14238
14239 @ @<Substitute for |cur_sym|...@>=
14240
14241   q=subst_list;
14242   while ( q!=null ) {
14243     if ( info(q)==mp->cur_sym ) {
14244       mp->cur_sym=value(q); mp->cur_cmd=relax; break;
14245     }
14246     q=link(q);
14247   }
14248 }
14249
14250 @ @<Adjust the balance; |break| if it's zero@>=
14251 if ( mp->cur_mod>0 ) {
14252   incr(balance);
14253 } else { 
14254   decr(balance);
14255   if ( balance==0 )
14256     break;
14257 }
14258
14259 @ Four commands are intended to be used only within macro texts: \&{quote},
14260 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#}. They are variants of a single command
14261 code called |macro_special|.
14262
14263 @d quote 0 /* |macro_special| modifier for \&{quote} */
14264 @d macro_prefix 1 /* |macro_special| modifier for \.{\#\AT!} */
14265 @d macro_at 2 /* |macro_special| modifier for \.{\AT!} */
14266 @d macro_suffix 3 /* |macro_special| modifier for \.{\AT!\#} */
14267
14268 @<Put each...@>=
14269 mp_primitive(mp, "quote",macro_special,quote);
14270 @:quote_}{\&{quote} primitive@>
14271 mp_primitive(mp, "#@@",macro_special,macro_prefix);
14272 @:]]]\#\AT!_}{\.{\#\AT!} primitive@>
14273 mp_primitive(mp, "@@",macro_special,macro_at);
14274 @:]]]\AT!_}{\.{\AT!} primitive@>
14275 mp_primitive(mp, "@@#",macro_special,macro_suffix);
14276 @:]]]\AT!\#_}{\.{\AT!\#} primitive@>
14277
14278 @ @<Cases of |print_cmd...@>=
14279 case macro_special: 
14280   switch (m) {
14281   case macro_prefix: mp_print(mp, "#@@"); break;
14282   case macro_at: mp_print_char(mp, '@@'); break;
14283   case macro_suffix: mp_print(mp, "@@#"); break;
14284   default: mp_print(mp, "quote"); break;
14285   }
14286   break;
14287
14288 @ @<Handle quoted...@>=
14289
14290   if ( mp->cur_mod==quote ) { get_t_next; } 
14291   else if ( mp->cur_mod<=suffix_count ) 
14292     mp->cur_sym=suffix_base-1+mp->cur_mod;
14293 }
14294
14295 @ Here is a routine that's used whenever a token will be redefined. If
14296 the user's token is unredefinable, the `|frozen_inaccessible|' token is
14297 substituted; the latter is redefinable but essentially impossible to use,
14298 hence \MP's tables won't get fouled up.
14299
14300 @c void mp_get_symbol (MP mp) { /* sets |cur_sym| to a safe symbol */
14301 RESTART: 
14302   get_t_next;
14303   if ( (mp->cur_sym==0)||(mp->cur_sym>frozen_inaccessible) ) {
14304     print_err("Missing symbolic token inserted");
14305 @.Missing symbolic token...@>
14306     help3("Sorry: You can\'t redefine a number, string, or expr.")
14307       ("I've inserted an inaccessible symbol so that your")
14308       ("definition will be completed without mixing me up too badly.");
14309     if ( mp->cur_sym>0 )
14310       mp->help_line[2]="Sorry: You can\'t redefine my error-recovery tokens.";
14311     else if ( mp->cur_cmd==string_token ) 
14312       delete_str_ref(mp->cur_mod);
14313     mp->cur_sym=frozen_inaccessible; mp_ins_error(mp); goto RESTART;
14314   }
14315 }
14316
14317 @ Before we actually redefine a symbolic token, we need to clear away its
14318 former value, if it was a variable. The following stronger version of
14319 |get_symbol| does that.
14320
14321 @c void mp_get_clear_symbol (MP mp) { 
14322   mp_get_symbol(mp); mp_clear_symbol(mp, mp->cur_sym,false);
14323 }
14324
14325 @ Here's another little subroutine; it checks that an equals sign
14326 or assignment sign comes along at the proper place in a macro definition.
14327
14328 @c void mp_check_equals (MP mp) { 
14329   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
14330      mp_missing_err(mp, "=");
14331 @.Missing `='@>
14332     help5("The next thing in this `def' should have been `=',")
14333       ("because I've already looked at the definition heading.")
14334       ("But don't worry; I'll pretend that an equals sign")
14335       ("was present. Everything from here to `enddef'")
14336       ("will be the replacement text of this macro.");
14337     mp_back_error(mp);
14338   }
14339 }
14340
14341 @ A \&{primarydef}, \&{secondarydef}, or \&{tertiarydef} is rather easily
14342 handled now that we have |scan_toks|.  In this case there are
14343 two parameters, which will be \.{EXPR0} and \.{EXPR1} (i.e.,
14344 |expr_base| and |expr_base+1|).
14345
14346 @c void mp_make_op_def (MP mp) {
14347   command_code m; /* the type of definition */
14348   pointer p,q,r; /* for list manipulation */
14349   m=mp->cur_mod;
14350   mp_get_symbol(mp); q=mp_get_node(mp, token_node_size);
14351   info(q)=mp->cur_sym; value(q)=expr_base;
14352   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym;
14353   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
14354   info(p)=mp->cur_sym; value(p)=expr_base+1; link(p)=q;
14355   get_t_next; mp_check_equals(mp);
14356   mp->scanner_status=op_defining; q=mp_get_avail(mp); ref_count(q)=null;
14357   r=mp_get_avail(mp); link(q)=r; info(r)=general_macro;
14358   link(r)=mp_scan_toks(mp, macro_def,p,null,0);
14359   mp->scanner_status=normal; eq_type(mp->warning_info)=m;
14360   equiv(mp->warning_info)=q; mp_get_x_next(mp);
14361 }
14362
14363 @ Parameters to macros are introduced by the keywords \&{expr},
14364 \&{suffix}, \&{text}, \&{primary}, \&{secondary}, and \&{tertiary}.
14365
14366 @<Put each...@>=
14367 mp_primitive(mp, "expr",param_type,expr_base);
14368 @:expr_}{\&{expr} primitive@>
14369 mp_primitive(mp, "suffix",param_type,suffix_base);
14370 @:suffix_}{\&{suffix} primitive@>
14371 mp_primitive(mp, "text",param_type,text_base);
14372 @:text_}{\&{text} primitive@>
14373 mp_primitive(mp, "primary",param_type,primary_macro);
14374 @:primary_}{\&{primary} primitive@>
14375 mp_primitive(mp, "secondary",param_type,secondary_macro);
14376 @:secondary_}{\&{secondary} primitive@>
14377 mp_primitive(mp, "tertiary",param_type,tertiary_macro);
14378 @:tertiary_}{\&{tertiary} primitive@>
14379
14380 @ @<Cases of |print_cmd...@>=
14381 case param_type:
14382   if ( m>=expr_base ) {
14383     if ( m==expr_base ) mp_print(mp, "expr");
14384     else if ( m==suffix_base ) mp_print(mp, "suffix");
14385     else mp_print(mp, "text");
14386   } else if ( m<secondary_macro ) {
14387     mp_print(mp, "primary");
14388   } else if ( m==secondary_macro ) {
14389     mp_print(mp, "secondary");
14390   } else {
14391     mp_print(mp, "tertiary");
14392   }
14393   break;
14394
14395 @ Let's turn next to the more complex processing associated with \&{def}
14396 and \&{vardef}. When the following procedure is called, |cur_mod|
14397 should be either |start_def| or |var_def|.
14398
14399 @c @<Declare the procedure called |check_delimiter|@>;
14400 @<Declare the function called |scan_declared_variable|@>;
14401 void mp_scan_def (MP mp) {
14402   int m; /* the type of definition */
14403   int n; /* the number of special suffix parameters */
14404   int k; /* the total number of parameters */
14405   int c; /* the kind of macro we're defining */
14406   pointer r; /* parameter-substitution list */
14407   pointer q; /* tail of the macro token list */
14408   pointer p; /* temporary storage */
14409   halfword base; /* |expr_base|, |suffix_base|, or |text_base| */
14410   pointer l_delim,r_delim; /* matching delimiters */
14411   m=mp->cur_mod; c=general_macro; link(hold_head)=null;
14412   q=mp_get_avail(mp); ref_count(q)=null; r=null;
14413   @<Scan the token or variable to be defined;
14414     set |n|, |scanner_status|, and |warning_info|@>;
14415   k=n;
14416   if ( mp->cur_cmd==left_delimiter ) {
14417     @<Absorb delimited parameters, putting them into lists |q| and |r|@>;
14418   }
14419   if ( mp->cur_cmd==param_type ) {
14420     @<Absorb undelimited parameters, putting them into list |r|@>;
14421   }
14422   mp_check_equals(mp);
14423   p=mp_get_avail(mp); info(p)=c; link(q)=p;
14424   @<Attach the replacement text to the tail of node |p|@>;
14425   mp->scanner_status=normal; mp_get_x_next(mp);
14426 }
14427
14428 @ We don't put `|frozen_end_group|' into the replacement text of
14429 a \&{vardef}, because the user may want to redefine `\.{endgroup}'.
14430
14431 @<Attach the replacement text to the tail of node |p|@>=
14432 if ( m==start_def ) {
14433   link(p)=mp_scan_toks(mp, macro_def,r,null,n);
14434 } else { 
14435   q=mp_get_avail(mp); info(q)=mp->bg_loc; link(p)=q;
14436   p=mp_get_avail(mp); info(p)=mp->eg_loc;
14437   link(q)=mp_scan_toks(mp, macro_def,r,p,n);
14438 }
14439 if ( mp->warning_info==bad_vardef ) 
14440   mp_flush_token_list(mp, value(bad_vardef))
14441
14442 @ @<Glob...@>=
14443 int bg_loc;
14444 int eg_loc; /* hash addresses of `\.{begingroup}' and `\.{endgroup}' */
14445
14446 @ @<Scan the token or variable to be defined;...@>=
14447 if ( m==start_def ) {
14448   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym; get_t_next;
14449   mp->scanner_status=op_defining; n=0;
14450   eq_type(mp->warning_info)=defined_macro; equiv(mp->warning_info)=q;
14451 } else { 
14452   p=mp_scan_declared_variable(mp);
14453   mp_flush_variable(mp, equiv(info(p)),link(p),true);
14454   mp->warning_info=mp_find_variable(mp, p); mp_flush_list(mp, p);
14455   if ( mp->warning_info==null ) @<Change to `\.{a bad variable}'@>;
14456   mp->scanner_status=var_defining; n=2;
14457   if ( mp->cur_cmd==macro_special ) if ( mp->cur_mod==macro_suffix ) {/* \.{\AT!\#} */
14458     n=3; get_t_next;
14459   }
14460   type(mp->warning_info)=mp_unsuffixed_macro-2+n; value(mp->warning_info)=q;
14461 } /* |mp_suffixed_macro=mp_unsuffixed_macro+1| */
14462
14463 @ @<Change to `\.{a bad variable}'@>=
14464
14465   print_err("This variable already starts with a macro");
14466 @.This variable already...@>
14467   help2("After `vardef a' you can\'t say `vardef a.b'.")
14468     ("So I'll have to discard this definition.");
14469   mp_error(mp); mp->warning_info=bad_vardef;
14470 }
14471
14472 @ @<Initialize table entries...@>=
14473 name_type(bad_vardef)=mp_root; link(bad_vardef)=frozen_bad_vardef;
14474 equiv(frozen_bad_vardef)=bad_vardef; eq_type(frozen_bad_vardef)=tag_token;
14475
14476 @ @<Absorb delimited parameters, putting them into lists |q| and |r|@>=
14477 do {  
14478   l_delim=mp->cur_sym; r_delim=mp->cur_mod; get_t_next;
14479   if ( (mp->cur_cmd==param_type)&&(mp->cur_mod>=expr_base) ) {
14480    base=mp->cur_mod;
14481   } else { 
14482     print_err("Missing parameter type; `expr' will be assumed");
14483 @.Missing parameter type@>
14484     help1("You should've had `expr' or `suffix' or `text' here.");
14485     mp_back_error(mp); base=expr_base;
14486   }
14487   @<Absorb parameter tokens for type |base|@>;
14488   mp_check_delimiter(mp, l_delim,r_delim);
14489   get_t_next;
14490 } while (mp->cur_cmd==left_delimiter)
14491
14492 @ @<Absorb parameter tokens for type |base|@>=
14493 do { 
14494   link(q)=mp_get_avail(mp); q=link(q); info(q)=base+k;
14495   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size); 
14496   value(p)=base+k; info(p)=mp->cur_sym;
14497   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14498 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14499   incr(k); link(p)=r; r=p; get_t_next;
14500 } while (mp->cur_cmd==comma)
14501
14502 @ @<Absorb undelimited parameters, putting them into list |r|@>=
14503
14504   p=mp_get_node(mp, token_node_size);
14505   if ( mp->cur_mod<expr_base ) {
14506     c=mp->cur_mod; value(p)=expr_base+k;
14507   } else { 
14508     value(p)=mp->cur_mod+k;
14509     if ( mp->cur_mod==expr_base ) c=expr_macro;
14510     else if ( mp->cur_mod==suffix_base ) c=suffix_macro;
14511     else c=text_macro;
14512   }
14513   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14514   incr(k); mp_get_symbol(mp); info(p)=mp->cur_sym; link(p)=r; r=p; get_t_next;
14515   if ( c==expr_macro ) if ( mp->cur_cmd==of_token ) {
14516     c=of_macro; p=mp_get_node(mp, token_node_size);
14517     if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14518     value(p)=expr_base+k; mp_get_symbol(mp); info(p)=mp->cur_sym;
14519     link(p)=r; r=p; get_t_next;
14520   }
14521 }
14522
14523 @* \[32] Expanding the next token.
14524 Only a few command codes |<min_command| can possibly be returned by
14525 |get_t_next|; in increasing order, they are
14526 |if_test|, |fi_or_else|, |input|, |iteration|, |repeat_loop|,
14527 |exit_test|, |relax|, |scan_tokens|, |expand_after|, and |defined_macro|.
14528
14529 \MP\ usually gets the next token of input by saying |get_x_next|. This is
14530 like |get_t_next| except that it keeps getting more tokens until
14531 finding |cur_cmd>=min_command|. In other words, |get_x_next| expands
14532 macros and removes conditionals or iterations or input instructions that
14533 might be present.
14534
14535 It follows that |get_x_next| might invoke itself recursively. In fact,
14536 there is massive recursion, since macro expansion can involve the
14537 scanning of arbitrarily complex expressions, which in turn involve
14538 macro expansion and conditionals, etc.
14539 @^recursion@>
14540
14541 Therefore it's necessary to declare a whole bunch of |forward|
14542 procedures at this point, and to insert some other procedures
14543 that will be invoked by |get_x_next|.
14544
14545 @<Declarations@>= 
14546 void mp_scan_primary (MP mp);
14547 void mp_scan_secondary (MP mp);
14548 void mp_scan_tertiary (MP mp);
14549 void mp_scan_expression (MP mp);
14550 void mp_scan_suffix (MP mp);
14551 @<Declare the procedure called |macro_call|@>;
14552 void mp_get_boolean (MP mp);
14553 void mp_pass_text (MP mp);
14554 void mp_conditional (MP mp);
14555 void mp_start_input (MP mp);
14556 void mp_begin_iteration (MP mp);
14557 void mp_resume_iteration (MP mp);
14558 void mp_stop_iteration (MP mp);
14559
14560 @ An auxiliary subroutine called |expand| is used by |get_x_next|
14561 when it has to do exotic expansion commands.
14562
14563 @c void mp_expand (MP mp) {
14564   pointer p; /* for list manipulation */
14565   size_t k; /* something that we hope is |<=buf_size| */
14566   pool_pointer j; /* index into |str_pool| */
14567   if ( mp->internal[mp_tracing_commands]>unity ) 
14568     if ( mp->cur_cmd!=defined_macro )
14569       show_cur_cmd_mod;
14570   switch (mp->cur_cmd)  {
14571   case if_test:
14572     mp_conditional(mp); /* this procedure is discussed in Part 36 below */
14573     break;
14574   case fi_or_else:
14575     @<Terminate the current conditional and skip to \&{fi}@>;
14576     break;
14577   case input:
14578     @<Initiate or terminate input from a file@>;
14579     break;
14580   case iteration:
14581     if ( mp->cur_mod==end_for ) {
14582       @<Scold the user for having an extra \&{endfor}@>;
14583     } else {
14584       mp_begin_iteration(mp); /* this procedure is discussed in Part 37 below */
14585     }
14586     break;
14587   case repeat_loop: 
14588     @<Repeat a loop@>;
14589     break;
14590   case exit_test: 
14591     @<Exit a loop if the proper time has come@>;
14592     break;
14593   case relax: 
14594     break;
14595   case expand_after: 
14596     @<Expand the token after the next token@>;
14597     break;
14598   case scan_tokens: 
14599     @<Put a string into the input buffer@>;
14600     break;
14601   case defined_macro:
14602    mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14603    break;
14604   }; /* there are no other cases */
14605 };
14606
14607 @ @<Scold the user...@>=
14608
14609   print_err("Extra `endfor'");
14610 @.Extra `endfor'@>
14611   help2("I'm not currently working on a for loop,")
14612     ("so I had better not try to end anything.");
14613   mp_error(mp);
14614 }
14615
14616 @ The processing of \&{input} involves the |start_input| subroutine,
14617 which will be declared later; the processing of \&{endinput} is trivial.
14618
14619 @<Put each...@>=
14620 mp_primitive(mp, "input",input,0);
14621 @:input_}{\&{input} primitive@>
14622 mp_primitive(mp, "endinput",input,1);
14623 @:end_input_}{\&{endinput} primitive@>
14624
14625 @ @<Cases of |print_cmd_mod|...@>=
14626 case input: 
14627   if ( m==0 ) mp_print(mp, "input");
14628   else mp_print(mp, "endinput");
14629   break;
14630
14631 @ @<Initiate or terminate input...@>=
14632 if ( mp->cur_mod>0 ) mp->force_eof=true;
14633 else mp_start_input(mp)
14634
14635 @ We'll discuss the complicated parts of loop operations later. For now
14636 it suffices to know that there's a global variable called |loop_ptr|
14637 that will be |null| if no loop is in progress.
14638
14639 @<Repeat a loop@>=
14640 { while ( token_state &&(loc==null) ) 
14641     mp_end_token_list(mp); /* conserve stack space */
14642   if ( mp->loop_ptr==null ) {
14643     print_err("Lost loop");
14644 @.Lost loop@>
14645     help2("I'm confused; after exiting from a loop, I still seem")
14646       ("to want to repeat it. I'll try to forget the problem.");
14647     mp_error(mp);
14648   } else {
14649     mp_resume_iteration(mp); /* this procedure is in Part 37 below */
14650   }
14651 }
14652
14653 @ @<Exit a loop if the proper time has come@>=
14654 { mp_get_boolean(mp);
14655   if ( mp->internal[mp_tracing_commands]>unity ) 
14656     mp_show_cmd_mod(mp, nullary,mp->cur_exp);
14657   if ( mp->cur_exp==true_code ) {
14658     if ( mp->loop_ptr==null ) {
14659       print_err("No loop is in progress");
14660 @.No loop is in progress@>
14661       help1("Why say `exitif' when there's nothing to exit from?");
14662       if ( mp->cur_cmd==semicolon ) mp_error(mp); else mp_back_error(mp);
14663     } else {
14664      @<Exit prematurely from an iteration@>;
14665     }
14666   } else if ( mp->cur_cmd!=semicolon ) {
14667     mp_missing_err(mp, ";");
14668 @.Missing `;'@>
14669     help2("After `exitif <boolean exp>' I expect to see a semicolon.")
14670     ("I shall pretend that one was there."); mp_back_error(mp);
14671   }
14672 }
14673
14674 @ Here we use the fact that |forever_text| is the only |token_type| that
14675 is less than |loop_text|.
14676
14677 @<Exit prematurely...@>=
14678 { p=null;
14679   do {  
14680     if ( file_state ) {
14681       mp_end_file_reading(mp);
14682     } else { 
14683       if ( token_type<=loop_text ) p=start;
14684       mp_end_token_list(mp);
14685     }
14686   } while (p==null);
14687   if ( p!=info(mp->loop_ptr) ) mp_fatal_error(mp, "*** (loop confusion)");
14688 @.loop confusion@>
14689   mp_stop_iteration(mp); /* this procedure is in Part 34 below */
14690 }
14691
14692 @ @<Expand the token after the next token@>=
14693 { get_t_next;
14694   p=mp_cur_tok(mp); get_t_next;
14695   if ( mp->cur_cmd<min_command ) mp_expand(mp); 
14696   else mp_back_input(mp);
14697   back_list(p);
14698 }
14699
14700 @ @<Put a string into the input buffer@>=
14701 { mp_get_x_next(mp); mp_scan_primary(mp);
14702   if ( mp->cur_type!=mp_string_type ) {
14703     mp_disp_err(mp, null,"Not a string");
14704 @.Not a string@>
14705     help2("I'm going to flush this expression, since")
14706        ("scantokens should be followed by a known string.");
14707     mp_put_get_flush_error(mp, 0);
14708   } else { 
14709     mp_back_input(mp);
14710     if ( length(mp->cur_exp)>0 )
14711        @<Pretend we're reading a new one-line file@>;
14712   }
14713 }
14714
14715 @ @<Pretend we're reading a new one-line file@>=
14716 { mp_begin_file_reading(mp); name=is_scantok;
14717   k=mp->first+length(mp->cur_exp);
14718   if ( k>=mp->max_buf_stack ) {
14719     while ( k>=mp->buf_size ) {
14720       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
14721     }
14722     mp->max_buf_stack=k+1;
14723   }
14724   j=mp->str_start[mp->cur_exp]; limit=k;
14725   while ( mp->first<(size_t)limit ) {
14726     mp->buffer[mp->first]=mp->str_pool[j]; incr(j); incr(mp->first);
14727   }
14728   mp->buffer[limit]='%'; mp->first=limit+1; loc=start; 
14729   mp_flush_cur_exp(mp, 0);
14730 }
14731
14732 @ Here finally is |get_x_next|.
14733
14734 The expression scanning routines to be considered later
14735 communicate via the global quantities |cur_type| and |cur_exp|;
14736 we must be very careful to save and restore these quantities while
14737 macros are being expanded.
14738 @^inner loop@>
14739
14740 @<Declarations@>=
14741 void mp_get_x_next (MP mp);
14742
14743 @ @c void mp_get_x_next (MP mp) {
14744   pointer save_exp; /* a capsule to save |cur_type| and |cur_exp| */
14745   get_t_next;
14746   if ( mp->cur_cmd<min_command ) {
14747     save_exp=mp_stash_cur_exp(mp);
14748     do {  
14749       if ( mp->cur_cmd==defined_macro ) 
14750         mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14751       else 
14752         mp_expand(mp);
14753       get_t_next;
14754      } while (mp->cur_cmd<min_command);
14755      mp_unstash_cur_exp(mp, save_exp); /* that restores |cur_type| and |cur_exp| */
14756   }
14757 }
14758
14759 @ Now let's consider the |macro_call| procedure, which is used to start up
14760 all user-defined macros. Since the arguments to a macro might be expressions,
14761 |macro_call| is recursive.
14762 @^recursion@>
14763
14764 The first parameter to |macro_call| points to the reference count of the
14765 token list that defines the macro. The second parameter contains any
14766 arguments that have already been parsed (see below).  The third parameter
14767 points to the symbolic token that names the macro. If the third parameter
14768 is |null|, the macro was defined by \&{vardef}, so its name can be
14769 reconstructed from the prefix and ``at'' arguments found within the
14770 second parameter.
14771
14772 What is this second parameter? It's simply a linked list of one-word items,
14773 whose |info| fields point to the arguments. In other words, if |arg_list=null|,
14774 no arguments have been scanned yet; otherwise |info(arg_list)| points to
14775 the first scanned argument, and |link(arg_list)| points to the list of
14776 further arguments (if any).
14777
14778 Arguments of type \&{expr} are so-called capsules, which we will
14779 discuss later when we concentrate on expressions; they can be
14780 recognized easily because their |link| field is |void|. Arguments of type
14781 \&{suffix} and \&{text} are token lists without reference counts.
14782
14783 @ After argument scanning is complete, the arguments are moved to the
14784 |param_stack|. (They can't be put on that stack any sooner, because
14785 the stack is growing and shrinking in unpredictable ways as more arguments
14786 are being acquired.)  Then the macro body is fed to the scanner; i.e.,
14787 the replacement text of the macro is placed at the top of the \MP's
14788 input stack, so that |get_t_next| will proceed to read it next.
14789
14790 @<Declare the procedure called |macro_call|@>=
14791 @<Declare the procedure called |print_macro_name|@>;
14792 @<Declare the procedure called |print_arg|@>;
14793 @<Declare the procedure called |scan_text_arg|@>;
14794 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14795                     pointer macro_name) ;
14796
14797 @ @c
14798 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14799                     pointer macro_name) {
14800   /* invokes a user-defined control sequence */
14801   pointer r; /* current node in the macro's token list */
14802   pointer p,q; /* for list manipulation */
14803   integer n; /* the number of arguments */
14804   pointer tail = 0; /* tail of the argument list */
14805   pointer l_delim=0,r_delim=0; /* a delimiter pair */
14806   r=link(def_ref); add_mac_ref(def_ref);
14807   if ( arg_list==null ) {
14808     n=0;
14809   } else {
14810    @<Determine the number |n| of arguments already supplied,
14811     and set |tail| to the tail of |arg_list|@>;
14812   }
14813   if ( mp->internal[mp_tracing_macros]>0 ) {
14814     @<Show the text of the macro being expanded, and the existing arguments@>;
14815   }
14816   @<Scan the remaining arguments, if any; set |r| to the first token
14817     of the replacement text@>;
14818   @<Feed the arguments and replacement text to the scanner@>;
14819 }
14820
14821 @ @<Show the text of the macro...@>=
14822 mp_begin_diagnostic(mp); mp_print_ln(mp); 
14823 mp_print_macro_name(mp, arg_list,macro_name);
14824 if ( n==3 ) mp_print(mp, "@@#"); /* indicate a suffixed macro */
14825 mp_show_macro(mp, def_ref,null,100000);
14826 if ( arg_list!=null ) {
14827   n=0; p=arg_list;
14828   do {  
14829     q=info(p);
14830     mp_print_arg(mp, q,n,0);
14831     incr(n); p=link(p);
14832   } while (p!=null);
14833 }
14834 mp_end_diagnostic(mp, false)
14835
14836
14837 @ @<Declare the procedure called |print_macro_name|@>=
14838 void mp_print_macro_name (MP mp,pointer a, pointer n);
14839
14840 @ @c
14841 void mp_print_macro_name (MP mp,pointer a, pointer n) {
14842   pointer p,q; /* they traverse the first part of |a| */
14843   if ( n!=null ) {
14844     mp_print_text(n);
14845   } else  { 
14846     p=info(a);
14847     if ( p==null ) {
14848       mp_print_text(info(info(link(a))));
14849     } else { 
14850       q=p;
14851       while ( link(q)!=null ) q=link(q);
14852       link(q)=info(link(a));
14853       mp_show_token_list(mp, p,null,1000,0);
14854       link(q)=null;
14855     }
14856   }
14857 }
14858
14859 @ @<Declare the procedure called |print_arg|@>=
14860 void mp_print_arg (MP mp,pointer q, integer n, pointer b) ;
14861
14862 @ @c
14863 void mp_print_arg (MP mp,pointer q, integer n, pointer b) {
14864   if ( link(q)==mp_void ) mp_print_nl(mp, "(EXPR");
14865   else if ( (b<text_base)&&(b!=text_macro) ) mp_print_nl(mp, "(SUFFIX");
14866   else mp_print_nl(mp, "(TEXT");
14867   mp_print_int(mp, n); mp_print(mp, ")<-");
14868   if ( link(q)==mp_void ) mp_print_exp(mp, q,1);
14869   else mp_show_token_list(mp, q,null,1000,0);
14870 }
14871
14872 @ @<Determine the number |n| of arguments already supplied...@>=
14873 {  
14874   n=1; tail=arg_list;
14875   while ( link(tail)!=null ) { 
14876     incr(n); tail=link(tail);
14877   }
14878 }
14879
14880 @ @<Scan the remaining arguments, if any; set |r|...@>=
14881 mp->cur_cmd=comma+1; /* anything |<>comma| will do */
14882 while ( info(r)>=expr_base ) { 
14883   @<Scan the delimited argument represented by |info(r)|@>;
14884   r=link(r);
14885 };
14886 if ( mp->cur_cmd==comma ) {
14887   print_err("Too many arguments to ");
14888 @.Too many arguments...@>
14889   mp_print_macro_name(mp, arg_list,macro_name); mp_print_char(mp, ';');
14890   mp_print_nl(mp, "  Missing `"); mp_print_text(r_delim);
14891 @.Missing `)'...@>
14892   mp_print(mp, "' has been inserted");
14893   help3("I'm going to assume that the comma I just read was a")
14894    ("right delimiter, and then I'll begin expanding the macro.")
14895    ("You might want to delete some tokens before continuing.");
14896   mp_error(mp);
14897 }
14898 if ( info(r)!=general_macro ) {
14899   @<Scan undelimited argument(s)@>;
14900 }
14901 r=link(r)
14902
14903 @ At this point, the reader will find it advisable to review the explanation
14904 of token list format that was presented earlier, paying special attention to
14905 the conventions that apply only at the beginning of a macro's token list.
14906
14907 On the other hand, the reader will have to take the expression-parsing
14908 aspects of the following program on faith; we will explain |cur_type|
14909 and |cur_exp| later. (Several things in this program depend on each other,
14910 and it's necessary to jump into the circle somewhere.)
14911
14912 @<Scan the delimited argument represented by |info(r)|@>=
14913 if ( mp->cur_cmd!=comma ) {
14914   mp_get_x_next(mp);
14915   if ( mp->cur_cmd!=left_delimiter ) {
14916     print_err("Missing argument to ");
14917 @.Missing argument...@>
14918     mp_print_macro_name(mp, arg_list,macro_name);
14919     help3("That macro has more parameters than you thought.")
14920      ("I'll continue by pretending that each missing argument")
14921      ("is either zero or null.");
14922     if ( info(r)>=suffix_base ) {
14923       mp->cur_exp=null; mp->cur_type=mp_token_list;
14924     } else { 
14925       mp->cur_exp=0; mp->cur_type=mp_known;
14926     }
14927     mp_back_error(mp); mp->cur_cmd=right_delimiter; 
14928     goto FOUND;
14929   }
14930   l_delim=mp->cur_sym; r_delim=mp->cur_mod;
14931 }
14932 @<Scan the argument represented by |info(r)|@>;
14933 if ( mp->cur_cmd!=comma ) 
14934   @<Check that the proper right delimiter was present@>;
14935 FOUND:  
14936 @<Append the current expression to |arg_list|@>
14937
14938 @ @<Check that the proper right delim...@>=
14939 if ( (mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
14940   if ( info(link(r))>=expr_base ) {
14941     mp_missing_err(mp, ",");
14942 @.Missing `,'@>
14943     help3("I've finished reading a macro argument and am about to")
14944       ("read another; the arguments weren't delimited correctly.")
14945        ("You might want to delete some tokens before continuing.");
14946     mp_back_error(mp); mp->cur_cmd=comma;
14947   } else { 
14948     mp_missing_err(mp, str(text(r_delim)));
14949 @.Missing `)'@>
14950     help2("I've gotten to the end of the macro parameter list.")
14951        ("You might want to delete some tokens before continuing.");
14952     mp_back_error(mp);
14953   }
14954 }
14955
14956 @ A \&{suffix} or \&{text} parameter will be have been scanned as
14957 a token list pointed to by |cur_exp|, in which case we will have
14958 |cur_type=token_list|.
14959
14960 @<Append the current expression to |arg_list|@>=
14961
14962   p=mp_get_avail(mp);
14963   if ( mp->cur_type==mp_token_list ) info(p)=mp->cur_exp;
14964   else info(p)=mp_stash_cur_exp(mp);
14965   if ( mp->internal[mp_tracing_macros]>0 ) {
14966     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,info(r)); 
14967     mp_end_diagnostic(mp, false);
14968   }
14969   if ( arg_list==null ) arg_list=p;
14970   else link(tail)=p;
14971   tail=p; incr(n);
14972 }
14973
14974 @ @<Scan the argument represented by |info(r)|@>=
14975 if ( info(r)>=text_base ) {
14976   mp_scan_text_arg(mp, l_delim,r_delim);
14977 } else { 
14978   mp_get_x_next(mp);
14979   if ( info(r)>=suffix_base ) mp_scan_suffix(mp);
14980   else mp_scan_expression(mp);
14981 }
14982
14983 @ The parameters to |scan_text_arg| are either a pair of delimiters
14984 or zero; the latter case is for undelimited text arguments, which
14985 end with the first semicolon or \&{endgroup} or \&{end} that is not
14986 contained in a group.
14987
14988 @<Declare the procedure called |scan_text_arg|@>=
14989 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) ;
14990
14991 @ @c
14992 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) {
14993   integer balance; /* excess of |l_delim| over |r_delim| */
14994   pointer p; /* list tail */
14995   mp->warning_info=l_delim; mp->scanner_status=absorbing;
14996   p=hold_head; balance=1; link(hold_head)=null;
14997   while (1)  { 
14998     get_t_next;
14999     if ( l_delim==0 ) {
15000       @<Adjust the balance for an undelimited argument; |break| if done@>;
15001     } else {
15002           @<Adjust the balance for a delimited argument; |break| if done@>;
15003     }
15004     link(p)=mp_cur_tok(mp); p=link(p);
15005   }
15006   mp->cur_exp=link(hold_head); mp->cur_type=mp_token_list;
15007   mp->scanner_status=normal;
15008 };
15009
15010 @ @<Adjust the balance for a delimited argument...@>=
15011 if ( mp->cur_cmd==right_delimiter ) { 
15012   if ( mp->cur_mod==l_delim ) { 
15013     decr(balance);
15014     if ( balance==0 ) break;
15015   }
15016 } else if ( mp->cur_cmd==left_delimiter ) {
15017   if ( mp->cur_mod==r_delim ) incr(balance);
15018 }
15019
15020 @ @<Adjust the balance for an undelimited...@>=
15021 if ( end_of_statement ) { /* |cur_cmd=semicolon|, |end_group|, or |stop| */
15022   if ( balance==1 ) { break; }
15023   else  { if ( mp->cur_cmd==end_group ) decr(balance); }
15024 } else if ( mp->cur_cmd==begin_group ) { 
15025   incr(balance); 
15026 }
15027
15028 @ @<Scan undelimited argument(s)@>=
15029
15030   if ( info(r)<text_macro ) {
15031     mp_get_x_next(mp);
15032     if ( info(r)!=suffix_macro ) {
15033       if ( (mp->cur_cmd==equals)||(mp->cur_cmd==assignment) ) mp_get_x_next(mp);
15034     }
15035   }
15036   switch (info(r)) {
15037   case primary_macro:mp_scan_primary(mp); break;
15038   case secondary_macro:mp_scan_secondary(mp); break;
15039   case tertiary_macro:mp_scan_tertiary(mp); break;
15040   case expr_macro:mp_scan_expression(mp); break;
15041   case of_macro:
15042     @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>;
15043     break;
15044   case suffix_macro:
15045     @<Scan a suffix with optional delimiters@>;
15046     break;
15047   case text_macro:mp_scan_text_arg(mp, 0,0); break;
15048   } /* there are no other cases */
15049   mp_back_input(mp); 
15050   @<Append the current expression to |arg_list|@>;
15051 }
15052
15053 @ @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>=
15054
15055   mp_scan_expression(mp); p=mp_get_avail(mp); info(p)=mp_stash_cur_exp(mp);
15056   if ( mp->internal[mp_tracing_macros]>0 ) { 
15057     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,0); 
15058     mp_end_diagnostic(mp, false);
15059   }
15060   if ( arg_list==null ) arg_list=p; else link(tail)=p;
15061   tail=p;incr(n);
15062   if ( mp->cur_cmd!=of_token ) {
15063     mp_missing_err(mp, "of"); mp_print(mp, " for ");
15064 @.Missing `of'@>
15065     mp_print_macro_name(mp, arg_list,macro_name);
15066     help1("I've got the first argument; will look now for the other.");
15067     mp_back_error(mp);
15068   }
15069   mp_get_x_next(mp); mp_scan_primary(mp);
15070 }
15071
15072 @ @<Scan a suffix with optional delimiters@>=
15073
15074   if ( mp->cur_cmd!=left_delimiter ) {
15075     l_delim=null;
15076   } else { 
15077     l_delim=mp->cur_sym; r_delim=mp->cur_mod; mp_get_x_next(mp);
15078   };
15079   mp_scan_suffix(mp);
15080   if ( l_delim!=null ) {
15081     if ((mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
15082       mp_missing_err(mp, str(text(r_delim)));
15083 @.Missing `)'@>
15084       help2("I've gotten to the end of the macro parameter list.")
15085          ("You might want to delete some tokens before continuing.");
15086       mp_back_error(mp);
15087     }
15088     mp_get_x_next(mp);
15089   }
15090 }
15091
15092 @ Before we put a new token list on the input stack, it is wise to clean off
15093 all token lists that have recently been depleted. Then a user macro that ends
15094 with a call to itself will not require unbounded stack space.
15095
15096 @<Feed the arguments and replacement text to the scanner@>=
15097 while ( token_state &&(loc==null) ) mp_end_token_list(mp); /* conserve stack space */
15098 if ( mp->param_ptr+n>mp->max_param_stack ) {
15099   mp->max_param_stack=mp->param_ptr+n;
15100   if ( mp->max_param_stack>mp->param_size )
15101     mp_overflow(mp, "parameter stack size",mp->param_size);
15102 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
15103 }
15104 mp_begin_token_list(mp, def_ref,macro); name=macro_name; loc=r;
15105 if ( n>0 ) {
15106   p=arg_list;
15107   do {  
15108    mp->param_stack[mp->param_ptr]=info(p); incr(mp->param_ptr); p=link(p);
15109   } while (p!=null);
15110   mp_flush_list(mp, arg_list);
15111 }
15112
15113 @ It's sometimes necessary to put a single argument onto |param_stack|.
15114 The |stack_argument| subroutine does this.
15115
15116 @c void mp_stack_argument (MP mp,pointer p) { 
15117   if ( mp->param_ptr==mp->max_param_stack ) {
15118     incr(mp->max_param_stack);
15119     if ( mp->max_param_stack>mp->param_size )
15120       mp_overflow(mp, "parameter stack size",mp->param_size);
15121 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
15122   }
15123   mp->param_stack[mp->param_ptr]=p; incr(mp->param_ptr);
15124 }
15125
15126 @* \[33] Conditional processing.
15127 Let's consider now the way \&{if} commands are handled.
15128
15129 Conditions can be inside conditions, and this nesting has a stack
15130 that is independent of other stacks.
15131 Four global variables represent the top of the condition stack:
15132 |cond_ptr| points to pushed-down entries, if~any; |cur_if| tells whether
15133 we are processing \&{if} or \&{elseif}; |if_limit| specifies
15134 the largest code of a |fi_or_else| command that is syntactically legal;
15135 and |if_line| is the line number at which the current conditional began.
15136
15137 If no conditions are currently in progress, the condition stack has the
15138 special state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|.
15139 Otherwise |cond_ptr| points to a two-word node; the |type|, |name_type|, and
15140 |link| fields of the first word contain |if_limit|, |cur_if|, and
15141 |cond_ptr| at the next level, and the second word contains the
15142 corresponding |if_line|.
15143
15144 @d if_node_size 2 /* number of words in stack entry for conditionals */
15145 @d if_line_field(A) mp->mem[(A)+1].cint
15146 @d if_code 1 /* code for \&{if} being evaluated */
15147 @d fi_code 2 /* code for \&{fi} */
15148 @d else_code 3 /* code for \&{else} */
15149 @d else_if_code 4 /* code for \&{elseif} */
15150
15151 @<Glob...@>=
15152 pointer cond_ptr; /* top of the condition stack */
15153 integer if_limit; /* upper bound on |fi_or_else| codes */
15154 small_number cur_if; /* type of conditional being worked on */
15155 integer if_line; /* line where that conditional began */
15156
15157 @ @<Set init...@>=
15158 mp->cond_ptr=null; mp->if_limit=normal; mp->cur_if=0; mp->if_line=0;
15159
15160 @ @<Put each...@>=
15161 mp_primitive(mp, "if",if_test,if_code);
15162 @:if_}{\&{if} primitive@>
15163 mp_primitive(mp, "fi",fi_or_else,fi_code); mp->eqtb[frozen_fi]=mp->eqtb[mp->cur_sym];
15164 @:fi_}{\&{fi} primitive@>
15165 mp_primitive(mp, "else",fi_or_else,else_code);
15166 @:else_}{\&{else} primitive@>
15167 mp_primitive(mp, "elseif",fi_or_else,else_if_code);
15168 @:else_if_}{\&{elseif} primitive@>
15169
15170 @ @<Cases of |print_cmd_mod|...@>=
15171 case if_test:
15172 case fi_or_else: 
15173   switch (m) {
15174   case if_code:mp_print(mp, "if"); break;
15175   case fi_code:mp_print(mp, "fi");  break;
15176   case else_code:mp_print(mp, "else"); break;
15177   default: mp_print(mp, "elseif"); break;
15178   }
15179   break;
15180
15181 @ Here is a procedure that ignores text until coming to an \&{elseif},
15182 \&{else}, or \&{fi} at level zero of $\&{if}\ldots\&{fi}$
15183 nesting. After it has acted, |cur_mod| will indicate the token that
15184 was found.
15185
15186 \MP's smallest two command codes are |if_test| and |fi_or_else|; this
15187 makes the skipping process a bit simpler.
15188
15189 @c 
15190 void mp_pass_text (MP mp) {
15191   integer l = 0;
15192   mp->scanner_status=skipping;
15193   mp->warning_info=mp_true_line(mp);
15194   while (1)  { 
15195     get_t_next;
15196     if ( mp->cur_cmd<=fi_or_else ) {
15197       if ( mp->cur_cmd<fi_or_else ) {
15198         incr(l);
15199       } else { 
15200         if ( l==0 ) break;
15201         if ( mp->cur_mod==fi_code ) decr(l);
15202       }
15203     } else {
15204       @<Decrease the string reference count,
15205        if the current token is a string@>;
15206     }
15207   }
15208   mp->scanner_status=normal;
15209 }
15210
15211 @ @<Decrease the string reference count...@>=
15212 if ( mp->cur_cmd==string_token ) { delete_str_ref(mp->cur_mod); }
15213
15214 @ When we begin to process a new \&{if}, we set |if_limit:=if_code|; then
15215 if \&{elseif} or \&{else} or \&{fi} occurs before the current \&{if}
15216 condition has been evaluated, a colon will be inserted.
15217 A construction like `\.{if fi}' would otherwise get \MP\ confused.
15218
15219 @<Push the condition stack@>=
15220 { p=mp_get_node(mp, if_node_size); link(p)=mp->cond_ptr; type(p)=mp->if_limit;
15221   name_type(p)=mp->cur_if; if_line_field(p)=mp->if_line;
15222   mp->cond_ptr=p; mp->if_limit=if_code; mp->if_line=mp_true_line(mp); 
15223   mp->cur_if=if_code;
15224 }
15225
15226 @ @<Pop the condition stack@>=
15227 { p=mp->cond_ptr; mp->if_line=if_line_field(p);
15228   mp->cur_if=name_type(p); mp->if_limit=type(p); mp->cond_ptr=link(p);
15229   mp_free_node(mp, p,if_node_size);
15230 }
15231
15232 @ Here's a procedure that changes the |if_limit| code corresponding to
15233 a given value of |cond_ptr|.
15234
15235 @c void mp_change_if_limit (MP mp,small_number l, pointer p) {
15236   pointer q;
15237   if ( p==mp->cond_ptr ) {
15238     mp->if_limit=l; /* that's the easy case */
15239   } else  { 
15240     q=mp->cond_ptr;
15241     while (1) { 
15242       if ( q==null ) mp_confusion(mp, "if");
15243 @:this can't happen if}{\quad if@>
15244       if ( link(q)==p ) { 
15245         type(q)=l; return;
15246       }
15247       q=link(q);
15248     }
15249   }
15250 }
15251
15252 @ The user is supposed to put colons into the proper parts of conditional
15253 statements. Therefore, \MP\ has to check for their presence.
15254
15255 @c 
15256 void mp_check_colon (MP mp) { 
15257   if ( mp->cur_cmd!=colon ) { 
15258     mp_missing_err(mp, ":");
15259 @.Missing `:'@>
15260     help2("There should've been a colon after the condition.")
15261          ("I shall pretend that one was there.");;
15262     mp_back_error(mp);
15263   }
15264 }
15265
15266 @ A condition is started when the |get_x_next| procedure encounters
15267 an |if_test| command; in that case |get_x_next| calls |conditional|,
15268 which is a recursive procedure.
15269 @^recursion@>
15270
15271 @c void mp_conditional (MP mp) {
15272   pointer save_cond_ptr; /* |cond_ptr| corresponding to this conditional */
15273   int new_if_limit; /* future value of |if_limit| */
15274   pointer p; /* temporary register */
15275   @<Push the condition stack@>; 
15276   save_cond_ptr=mp->cond_ptr;
15277 RESWITCH: 
15278   mp_get_boolean(mp); new_if_limit=else_if_code;
15279   if ( mp->internal[mp_tracing_commands]>unity ) {
15280     @<Display the boolean value of |cur_exp|@>;
15281   }
15282 FOUND: 
15283   mp_check_colon(mp);
15284   if ( mp->cur_exp==true_code ) {
15285     mp_change_if_limit(mp, new_if_limit,save_cond_ptr);
15286     return; /* wait for \&{elseif}, \&{else}, or \&{fi} */
15287   };
15288   @<Skip to \&{elseif} or \&{else} or \&{fi}, then |goto done|@>;
15289 DONE: 
15290   mp->cur_if=mp->cur_mod; mp->if_line=mp_true_line(mp);
15291   if ( mp->cur_mod==fi_code ) {
15292     @<Pop the condition stack@>
15293   } else if ( mp->cur_mod==else_if_code ) {
15294     goto RESWITCH;
15295   } else  { 
15296     mp->cur_exp=true_code; new_if_limit=fi_code; mp_get_x_next(mp); 
15297     goto FOUND;
15298   }
15299 }
15300
15301 @ In a construction like `\&{if} \&{if} \&{true}: $0=1$: \\{foo}
15302 \&{else}: \\{bar} \&{fi}', the first \&{else}
15303 that we come to after learning that the \&{if} is false is not the
15304 \&{else} we're looking for. Hence the following curious logic is needed.
15305
15306 @<Skip to \&{elseif}...@>=
15307 while (1) { 
15308   mp_pass_text(mp);
15309   if ( mp->cond_ptr==save_cond_ptr ) goto DONE;
15310   else if ( mp->cur_mod==fi_code ) @<Pop the condition stack@>;
15311 }
15312
15313
15314 @ @<Display the boolean value...@>=
15315 { mp_begin_diagnostic(mp);
15316   if ( mp->cur_exp==true_code ) mp_print(mp, "{true}");
15317   else mp_print(mp, "{false}");
15318   mp_end_diagnostic(mp, false);
15319 }
15320
15321 @ The processing of conditionals is complete except for the following
15322 code, which is actually part of |get_x_next|. It comes into play when
15323 \&{elseif}, \&{else}, or \&{fi} is scanned.
15324
15325 @<Terminate the current conditional and skip to \&{fi}@>=
15326 if ( mp->cur_mod>mp->if_limit ) {
15327   if ( mp->if_limit==if_code ) { /* condition not yet evaluated */
15328     mp_missing_err(mp, ":");
15329 @.Missing `:'@>
15330     mp_back_input(mp); mp->cur_sym=frozen_colon; mp_ins_error(mp);
15331   } else  { 
15332     print_err("Extra "); mp_print_cmd_mod(mp, fi_or_else,mp->cur_mod);
15333 @.Extra else@>
15334 @.Extra elseif@>
15335 @.Extra fi@>
15336     help1("I'm ignoring this; it doesn't match any if.");
15337     mp_error(mp);
15338   }
15339 } else  { 
15340   while ( mp->cur_mod!=fi_code ) mp_pass_text(mp); /* skip to \&{fi} */
15341   @<Pop the condition stack@>;
15342 }
15343
15344 @* \[34] Iterations.
15345 To bring our treatment of |get_x_next| to a close, we need to consider what
15346 \MP\ does when it sees \&{for}, \&{forsuffixes}, and \&{forever}.
15347
15348 There's a global variable |loop_ptr| that keeps track of the \&{for} loops
15349 that are currently active. If |loop_ptr=null|, no loops are in progress;
15350 otherwise |info(loop_ptr)| points to the iterative text of the current
15351 (innermost) loop, and |link(loop_ptr)| points to the data for any other
15352 loops that enclose the current one.
15353
15354 A loop-control node also has two other fields, called |loop_type| and
15355 |loop_list|, whose contents depend on the type of loop:
15356
15357 \yskip\indent|loop_type(loop_ptr)=null| means that |loop_list(loop_ptr)|
15358 points to a list of one-word nodes whose |info| fields point to the
15359 remaining argument values of a suffix list and expression list.
15360
15361 \yskip\indent|loop_type(loop_ptr)=mp_void| means that the current loop is
15362 `\&{forever}'.
15363
15364 \yskip\indent|loop_type(loop_ptr)=progression_flag| means that
15365 |p=loop_list(loop_ptr)| points to a ``progression node'' and |value(p)|,
15366 |step_size(p)|, and |final_value(p)| contain the data for an arithmetic
15367 progression.
15368
15369 \yskip\indent|loop_type(loop_ptr)=p>mp_void| means that |p| points to an edge
15370 header and |loop_list(loop_ptr)| points into the graphical object list for
15371 that edge header.
15372
15373 \yskip\noindent In the case of a progression node, the first word is not used
15374 because the link field of words in the dynamic memory area cannot be arbitrary.
15375
15376 @d loop_list_loc(A) ((A)+1) /* where the |loop_list| field resides */
15377 @d loop_type(A) info(loop_list_loc((A))) /* the type of \&{for} loop */
15378 @d loop_list(A) link(loop_list_loc((A))) /* the remaining list elements */
15379 @d loop_node_size 2 /* the number of words in a loop control node */
15380 @d progression_node_size 4 /* the number of words in a progression node */
15381 @d step_size(A) mp->mem[(A)+2].sc /* the step size in an arithmetic progression */
15382 @d final_value(A) mp->mem[(A)+3].sc /* the final value in an arithmetic progression */
15383 @d progression_flag (null+2)
15384   /* |loop_type| value when |loop_list| points to a progression node */
15385
15386 @<Glob...@>=
15387 pointer loop_ptr; /* top of the loop-control-node stack */
15388
15389 @ @<Set init...@>=
15390 mp->loop_ptr=null;
15391
15392 @ If the expressions that define an arithmetic progression in
15393 a \&{for} loop don't have known numeric values, the |bad_for|
15394 subroutine screams at the user.
15395
15396 @c void mp_bad_for (MP mp, char * s) {
15397   mp_disp_err(mp, null,"Improper "); /* show the bad expression above the message */
15398 @.Improper...replaced by 0@>
15399   mp_print(mp, s); mp_print(mp, " has been replaced by 0");
15400   help4("When you say `for x=a step b until c',")
15401     ("the initial value `a' and the step size `b'")
15402     ("and the final value `c' must have known numeric values.")
15403     ("I'm zeroing this one. Proceed, with fingers crossed.");
15404   mp_put_get_flush_error(mp, 0);
15405 };
15406
15407 @ Here's what \MP\ does when \&{for}, \&{forsuffixes}, or \&{forever}
15408 has just been scanned. (This code requires slight familiarity with
15409 expression-parsing routines that we have not yet discussed; but it seems
15410 to belong in the present part of the program, even though the original author
15411 didn't write it until later. The reader may wish to come back to it.)
15412
15413 @c void mp_begin_iteration (MP mp) {
15414   halfword m; /* |expr_base| (\&{for}) or |suffix_base| (\&{forsuffixes}) */
15415   halfword n; /* hash address of the current symbol */
15416   pointer s; /* the new loop-control node */
15417   pointer p; /* substitution list for |scan_toks| */
15418   pointer q;  /* link manipulation register */
15419   pointer pp; /* a new progression node */
15420   m=mp->cur_mod; n=mp->cur_sym; s=mp_get_node(mp, loop_node_size);
15421   if ( m==start_forever ){ 
15422     loop_type(s)=mp_void; p=null; mp_get_x_next(mp);
15423   } else { 
15424     mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
15425     info(p)=mp->cur_sym; value(p)=m;
15426     mp_get_x_next(mp);
15427     if ( mp->cur_cmd==within_token ) {
15428       @<Set up a picture iteration@>;
15429     } else { 
15430       @<Check for the |"="| or |":="| in a loop header@>;
15431       @<Scan the values to be used in the loop@>;
15432     }
15433   }
15434   @<Check for the presence of a colon@>;
15435   @<Scan the loop text and put it on the loop control stack@>;
15436   mp_resume_iteration(mp);
15437 }
15438
15439 @ @<Check for the |"="| or |":="| in a loop header@>=
15440 if ( (mp->cur_cmd!=equals)&&(mp->cur_cmd!=assignment) ) { 
15441   mp_missing_err(mp, "=");
15442 @.Missing `='@>
15443   help3("The next thing in this loop should have been `=' or `:='.")
15444     ("But don't worry; I'll pretend that an equals sign")
15445     ("was present, and I'll look for the values next.");
15446   mp_back_error(mp);
15447 }
15448
15449 @ @<Check for the presence of a colon@>=
15450 if ( mp->cur_cmd!=colon ) { 
15451   mp_missing_err(mp, ":");
15452 @.Missing `:'@>
15453   help3("The next thing in this loop should have been a `:'.")
15454     ("So I'll pretend that a colon was present;")
15455     ("everything from here to `endfor' will be iterated.");
15456   mp_back_error(mp);
15457 }
15458
15459 @ We append a special |frozen_repeat_loop| token in place of the
15460 `\&{endfor}' at the end of the loop. This will come through \MP's scanner
15461 at the proper time to cause the loop to be repeated.
15462
15463 (If the user tries some shenanigan like `\&{for} $\ldots$ \&{let} \&{endfor}',
15464 he will be foiled by the |get_symbol| routine, which keeps frozen
15465 tokens unchanged. Furthermore the |frozen_repeat_loop| is an \&{outer}
15466 token, so it won't be lost accidentally.)
15467
15468 @ @<Scan the loop text...@>=
15469 q=mp_get_avail(mp); info(q)=frozen_repeat_loop;
15470 mp->scanner_status=loop_defining; mp->warning_info=n;
15471 info(s)=mp_scan_toks(mp, iteration,p,q,0); mp->scanner_status=normal;
15472 link(s)=mp->loop_ptr; mp->loop_ptr=s
15473
15474 @ @<Initialize table...@>=
15475 eq_type(frozen_repeat_loop)=repeat_loop+outer_tag;
15476 text(frozen_repeat_loop)=intern(" ENDFOR");
15477
15478 @ The loop text is inserted into \MP's scanning apparatus by the
15479 |resume_iteration| routine.
15480
15481 @c void mp_resume_iteration (MP mp) {
15482   pointer p,q; /* link registers */
15483   p=loop_type(mp->loop_ptr);
15484   if ( p==progression_flag ) { 
15485     p=loop_list(mp->loop_ptr); /* now |p| points to a progression node */
15486     mp->cur_exp=value(p);
15487     if ( @<The arithmetic progression has ended@> ) {
15488       mp_stop_iteration(mp);
15489       return;
15490     }
15491     mp->cur_type=mp_known; q=mp_stash_cur_exp(mp); /* make |q| an \&{expr} argument */
15492     value(p)=mp->cur_exp+step_size(p); /* set |value(p)| for the next iteration */
15493   } else if ( p==null ) { 
15494     p=loop_list(mp->loop_ptr);
15495     if ( p==null ) {
15496       mp_stop_iteration(mp);
15497       return;
15498     }
15499     loop_list(mp->loop_ptr)=link(p); q=info(p); free_avail(p);
15500   } else if ( p==mp_void ) { 
15501     mp_begin_token_list(mp, info(mp->loop_ptr),forever_text); return;
15502   } else {
15503     @<Make |q| a capsule containing the next picture component from
15504       |loop_list(loop_ptr)| or |goto not_found|@>;
15505   }
15506   mp_begin_token_list(mp, info(mp->loop_ptr),loop_text);
15507   mp_stack_argument(mp, q);
15508   if ( mp->internal[mp_tracing_commands]>unity ) {
15509      @<Trace the start of a loop@>;
15510   }
15511   return;
15512 NOT_FOUND:
15513   mp_stop_iteration(mp);
15514 }
15515
15516 @ @<The arithmetic progression has ended@>=
15517 ((step_size(p)>0)&&(mp->cur_exp>final_value(p)))||
15518  ((step_size(p)<0)&&(mp->cur_exp<final_value(p)))
15519
15520 @ @<Trace the start of a loop@>=
15521
15522   mp_begin_diagnostic(mp); mp_print_nl(mp, "{loop value=");
15523 @.loop value=n@>
15524   if ( (q!=null)&&(link(q)==mp_void) ) mp_print_exp(mp, q,1);
15525   else mp_show_token_list(mp, q,null,50,0);
15526   mp_print_char(mp, '}'); mp_end_diagnostic(mp, false);
15527 }
15528
15529 @ @<Make |q| a capsule containing the next picture component from...@>=
15530 { q=loop_list(mp->loop_ptr);
15531   if ( q==null ) goto NOT_FOUND;
15532   skip_component(q) goto NOT_FOUND;
15533   mp->cur_exp=mp_copy_objects(mp, loop_list(mp->loop_ptr),q);
15534   mp_init_bbox(mp, mp->cur_exp);
15535   mp->cur_type=mp_picture_type;
15536   loop_list(mp->loop_ptr)=q;
15537   q=mp_stash_cur_exp(mp);
15538 }
15539
15540 @ A level of loop control disappears when |resume_iteration| has decided
15541 not to resume, or when an \&{exitif} construction has removed the loop text
15542 from the input stack.
15543
15544 @c void mp_stop_iteration (MP mp) {
15545   pointer p,q; /* the usual */
15546   p=loop_type(mp->loop_ptr);
15547   if ( p==progression_flag )  {
15548     mp_free_node(mp, loop_list(mp->loop_ptr),progression_node_size);
15549   } else if ( p==null ){ 
15550     q=loop_list(mp->loop_ptr);
15551     while ( q!=null ) {
15552       p=info(q);
15553       if ( p!=null ) {
15554         if ( link(p)==mp_void ) { /* it's an \&{expr} parameter */
15555           mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
15556         } else {
15557           mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
15558         }
15559       }
15560       p=q; q=link(q); free_avail(p);
15561     }
15562   } else if ( p>progression_flag ) {
15563     delete_edge_ref(p);
15564   }
15565   p=mp->loop_ptr; mp->loop_ptr=link(p); mp_flush_token_list(mp, info(p));
15566   mp_free_node(mp, p,loop_node_size);
15567 }
15568
15569 @ Now that we know all about loop control, we can finish up
15570 the missing portion of |begin_iteration| and we'll be done.
15571
15572 The following code is performed after the `\.=' has been scanned in
15573 a \&{for} construction (if |m=expr_base|) or a \&{forsuffixes} construction
15574 (if |m=suffix_base|).
15575
15576 @<Scan the values to be used in the loop@>=
15577 loop_type(s)=null; q=loop_list_loc(s); link(q)=null; /* |link(q)=loop_list(s)| */
15578 do {  
15579   mp_get_x_next(mp);
15580   if ( m!=expr_base ) {
15581     mp_scan_suffix(mp);
15582   } else { 
15583     if ( mp->cur_cmd>=colon ) if ( mp->cur_cmd<=comma ) 
15584           goto CONTINUE;
15585     mp_scan_expression(mp);
15586     if ( mp->cur_cmd==step_token ) if ( q==loop_list_loc(s) ) {
15587       @<Prepare for step-until construction and |break|@>;
15588     }
15589     mp->cur_exp=mp_stash_cur_exp(mp);
15590   }
15591   link(q)=mp_get_avail(mp); q=link(q); 
15592   info(q)=mp->cur_exp; mp->cur_type=mp_vacuous;
15593 CONTINUE:
15594   ;
15595 } while (mp->cur_cmd==comma)
15596
15597 @ @<Prepare for step-until construction and |break|@>=
15598
15599   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "initial value");
15600   pp=mp_get_node(mp, progression_node_size); value(pp)=mp->cur_exp;
15601   mp_get_x_next(mp); mp_scan_expression(mp);
15602   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "step size");
15603   step_size(pp)=mp->cur_exp;
15604   if ( mp->cur_cmd!=until_token ) { 
15605     mp_missing_err(mp, "until");
15606 @.Missing `until'@>
15607     help2("I assume you meant to say `until' after `step'.")
15608       ("So I'll look for the final value and colon next.");
15609     mp_back_error(mp);
15610   }
15611   mp_get_x_next(mp); mp_scan_expression(mp);
15612   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "final value");
15613   final_value(pp)=mp->cur_exp; loop_list(s)=pp;
15614   loop_type(s)=progression_flag; 
15615   break;
15616 }
15617
15618 @ The last case is when we have just seen ``\&{within}'', and we need to
15619 parse a picture expression and prepare to iterate over it.
15620
15621 @<Set up a picture iteration@>=
15622 { mp_get_x_next(mp);
15623   mp_scan_expression(mp);
15624   @<Make sure the current expression is a known picture@>;
15625   loop_type(s)=mp->cur_exp; mp->cur_type=mp_vacuous;
15626   q=link(dummy_loc(mp->cur_exp));
15627   if ( q!= null ) 
15628     if ( is_start_or_stop(q) )
15629       if ( mp_skip_1component(mp, q)==null ) q=link(q);
15630   loop_list(s)=q;
15631 }
15632
15633 @ @<Make sure the current expression is a known picture@>=
15634 if ( mp->cur_type!=mp_picture_type ) {
15635   mp_disp_err(mp, null,"Improper iteration spec has been replaced by nullpicture");
15636   help1("When you say `for x in p', p must be a known picture.");
15637   mp_put_get_flush_error(mp, mp_get_node(mp, edge_header_size));
15638   mp_init_edges(mp, mp->cur_exp); mp->cur_type=mp_picture_type;
15639 }
15640
15641 @* \[35] File names.
15642 It's time now to fret about file names.  Besides the fact that different
15643 operating systems treat files in different ways, we must cope with the
15644 fact that completely different naming conventions are used by different
15645 groups of people. The following programs show what is required for one
15646 particular operating system; similar routines for other systems are not
15647 difficult to devise.
15648 @^system dependencies@>
15649
15650 \MP\ assumes that a file name has three parts: the name proper; its
15651 ``extension''; and a ``file area'' where it is found in an external file
15652 system.  The extension of an input file is assumed to be
15653 `\.{.mp}' unless otherwise specified; it is `\.{.log}' on the
15654 transcript file that records each run of \MP; it is `\.{.tfm}' on the font
15655 metric files that describe characters in any fonts created by \MP; it is
15656 `\.{.ps}' or `.{\it nnn}' for some number {\it nnn} on the \ps\ output files;
15657 and it is `\.{.mem}' on the mem files written by \.{INIMP} to initialize \MP.
15658 The file area can be arbitrary on input files, but files are usually
15659 output to the user's current area.  If an input file cannot be
15660 found on the specified area, \MP\ will look for it on a special system
15661 area; this special area is intended for commonly used input files.
15662
15663 Simple uses of \MP\ refer only to file names that have no explicit
15664 extension or area. For example, a person usually says `\.{input} \.{cmr10}'
15665 instead of `\.{input} \.{cmr10.new}'. Simple file
15666 names are best, because they make the \MP\ source files portable;
15667 whenever a file name consists entirely of letters and digits, it should be
15668 treated in the same way by all implementations of \MP. However, users
15669 need the ability to refer to other files in their environment, especially
15670 when responding to error messages concerning unopenable files; therefore
15671 we want to let them use the syntax that appears in their favorite
15672 operating system.
15673
15674 @ \MP\ uses the same conventions that have proved to be satisfactory for
15675 \TeX\ and \MF. In order to isolate the system-dependent aspects of file names,
15676 @^system dependencies@>
15677 the system-independent parts of \MP\ are expressed in terms
15678 of three system-dependent
15679 procedures called |begin_name|, |more_name|, and |end_name|. In
15680 essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
15681 the system-independent driver program does the operations
15682 $$|begin_name|;\,|more_name|(c_1);\,\ldots\,;|more_name|(c_n);
15683 \,|end_name|.$$
15684 These three procedures communicate with each other via global variables.
15685 Afterwards the file name will appear in the string pool as three strings
15686 called |cur_name|\penalty10000\hskip-.05em,
15687 |cur_area|, and |cur_ext|; the latter two are null (i.e.,
15688 |""|), unless they were explicitly specified by the user.
15689
15690 Actually the situation is slightly more complicated, because \MP\ needs
15691 to know when the file name ends. The |more_name| routine is a function
15692 (with side effects) that returns |true| on the calls |more_name|$(c_1)$,
15693 \dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$
15694 returns |false|; or, it returns |true| and $c_n$ is the last character
15695 on the current input line. In other words,
15696 |more_name| is supposed to return |true| unless it is sure that the
15697 file name has been completely scanned; and |end_name| is supposed to be able
15698 to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of
15699 whether $|more_name|(c_n)$ returned |true| or |false|.
15700
15701 @<Glob...@>=
15702 char * cur_name; /* name of file just scanned */
15703 char * cur_area; /* file area just scanned, or \.{""} */
15704 char * cur_ext; /* file extension just scanned, or \.{""} */
15705
15706 @ It is easier to maintain reference counts if we assign initial values.
15707
15708 @<Set init...@>=
15709 mp->cur_name=xstrdup(""); 
15710 mp->cur_area=xstrdup(""); 
15711 mp->cur_ext=xstrdup("");
15712
15713 @ @<Dealloc variables@>=
15714 xfree(mp->cur_area);
15715 xfree(mp->cur_name);
15716 xfree(mp->cur_ext);
15717
15718 @ The file names we shall deal with for illustrative purposes have the
15719 following structure:  If the name contains `\.>' or `\.:', the file area
15720 consists of all characters up to and including the final such character;
15721 otherwise the file area is null.  If the remaining file name contains
15722 `\..', the file extension consists of all such characters from the first
15723 remaining `\..' to the end, otherwise the file extension is null.
15724 @^system dependencies@>
15725
15726 We can scan such file names easily by using two global variables that keep track
15727 of the occurrences of area and extension delimiters.  Note that these variables
15728 cannot be of type |pool_pointer| because a string pool compaction could occur
15729 while scanning a file name.
15730
15731 @<Glob...@>=
15732 integer area_delimiter;
15733   /* most recent `\.>' or `\.:' relative to |str_start[str_ptr]| */
15734 integer ext_delimiter; /* the relevant `\..', if any */
15735
15736 @ Here now is the first of the system-dependent routines for file name scanning.
15737 @^system dependencies@>
15738
15739 @<Declare subroutines for parsing file names@>=
15740 void mp_begin_name (MP mp) { 
15741   xfree(mp->cur_name); 
15742   xfree(mp->cur_area); 
15743   xfree(mp->cur_ext);
15744   mp->area_delimiter=-1; 
15745   mp->ext_delimiter=-1;
15746 }
15747
15748 @ And here's the second.
15749 @^system dependencies@>
15750
15751 @<Declare subroutines for parsing file names@>=
15752 boolean mp_more_name (MP mp, ASCII_code c) { 
15753   if (c==' ') {
15754     return false;
15755   } else { 
15756     if ( (c=='>')||(c==':') ) { 
15757       mp->area_delimiter=mp->pool_ptr; 
15758       mp->ext_delimiter=-1;
15759     } else if ( (c=='.')&&(mp->ext_delimiter<0) ) {
15760       mp->ext_delimiter=mp->pool_ptr;
15761     }
15762     str_room(1); append_char(c); /* contribute |c| to the current string */
15763     return true;
15764   }
15765 }
15766
15767 @ The third.
15768 @^system dependencies@>
15769
15770 @d copy_pool_segment(A,B,C) { 
15771       A = xmalloc(C+1,sizeof(char)); 
15772       strncpy(A,(char *)(mp->str_pool+B),C);  
15773       A[C] = 0;}
15774
15775 @<Declare subroutines for parsing file names@>=
15776 void mp_end_name (MP mp) {
15777   pool_pointer s; /* length of area, name, and extension */
15778   unsigned int len;
15779   /* "my/w.mp" */
15780   s = mp->str_start[mp->str_ptr];
15781   if ( mp->area_delimiter<0 ) {    
15782     mp->cur_area=xstrdup("");
15783   } else {
15784     len = mp->area_delimiter-s; 
15785     copy_pool_segment(mp->cur_area,s,len);
15786     s += len+1;
15787   }
15788   if ( mp->ext_delimiter<0 ) {
15789     mp->cur_ext=xstrdup("");
15790     len = mp->pool_ptr-s; 
15791   } else {
15792     copy_pool_segment(mp->cur_ext,mp->ext_delimiter,(mp->pool_ptr-mp->ext_delimiter));
15793     len = mp->ext_delimiter-s;
15794   }
15795   copy_pool_segment(mp->cur_name,s,len);
15796   mp->pool_ptr=s; /* don't need this partial string */
15797 }
15798
15799 @ Conversely, here is a routine that takes three strings and prints a file
15800 name that might have produced them. (The routine is system dependent, because
15801 some operating systems put the file area last instead of first.)
15802 @^system dependencies@>
15803
15804 @<Basic printing...@>=
15805 void mp_print_file_name (MP mp, char * n, char * a, char * e) { 
15806   mp_print(mp, a); mp_print(mp, n); mp_print(mp, e);
15807 };
15808
15809 @ Another system-dependent routine is needed to convert three internal
15810 \MP\ strings
15811 to the |name_of_file| value that is used to open files. The present code
15812 allows both lowercase and uppercase letters in the file name.
15813 @^system dependencies@>
15814
15815 @d append_to_name(A) { c=(A); 
15816   if ( k<file_name_size ) {
15817     mp->name_of_file[k]=xchr(c);
15818     incr(k);
15819   }
15820 }
15821
15822 @<Declare subroutines for parsing file names@>=
15823 void mp_pack_file_name (MP mp, char *n, char *a, char *e) {
15824   integer k; /* number of positions filled in |name_of_file| */
15825   ASCII_code c; /* character being packed */
15826   char *j; /* a character  index */
15827   k=0;
15828   assert(n);
15829   if (a!=NULL) {
15830     for (j=a;*j;j++) { append_to_name(*j); }
15831   }
15832   for (j=n;*j;j++) { append_to_name(*j); }
15833   if (e!=NULL) {
15834     for (j=e;*j;j++) { append_to_name(*j); }
15835   }
15836   mp->name_of_file[k]=0;
15837   mp->name_length=k; 
15838 }
15839
15840 @ @<Internal library declarations@>=
15841 void mp_pack_file_name (MP mp, char *n, char *a, char *e) ;
15842
15843 @ A messier routine is also needed, since mem file names must be scanned
15844 before \MP's string mechanism has been initialized. We shall use the
15845 global variable |MP_mem_default| to supply the text for default system areas
15846 and extensions related to mem files.
15847 @^system dependencies@>
15848
15849 @d mem_default_length 9 /* length of the |MP_mem_default| string */
15850 @d mem_ext_length 4 /* length of its `\.{.mem}' part */
15851 @d mem_extension ".mem" /* the extension, as a \.{WEB} constant */
15852
15853 @<Glob...@>=
15854 char *MP_mem_default;
15855
15856 @ @<Option variables@>=
15857 char *mem_name; /* for commandline */
15858
15859 @ @<Allocate or initialize ...@>=
15860 mp->MP_mem_default = xstrdup("plain.mem");
15861 mp->mem_name = xstrdup(opt->mem_name);
15862 @.plain@>
15863 @^system dependencies@>
15864
15865 @ @<Dealloc variables@>=
15866 xfree(mp->MP_mem_default);
15867 xfree(mp->mem_name);
15868
15869 @ @<Check the ``constant'' values for consistency@>=
15870 if ( mem_default_length>file_name_size ) mp->bad=20;
15871
15872 @ Here is the messy routine that was just mentioned. It sets |name_of_file|
15873 from the first |n| characters of |MP_mem_default|, followed by
15874 |buffer[a..b-1]|, followed by the last |mem_ext_length| characters of
15875 |MP_mem_default|.
15876
15877 We dare not give error messages here, since \MP\ calls this routine before
15878 the |error| routine is ready to roll. Instead, we simply drop excess characters,
15879 since the error will be detected in another way when a strange file name
15880 isn't found.
15881 @^system dependencies@>
15882
15883 @c void mp_pack_buffered_name (MP mp,small_number n, integer a,
15884                                integer b) {
15885   integer k; /* number of positions filled in |name_of_file| */
15886   ASCII_code c; /* character being packed */
15887   integer j; /* index into |buffer| or |MP_mem_default| */
15888   if ( n+b-a+1+mem_ext_length>file_name_size )
15889     b=a+file_name_size-n-1-mem_ext_length;
15890   k=0;
15891   for (j=0;j<n;j++) {
15892     append_to_name(xord((int)mp->MP_mem_default[j]));
15893   }
15894   for (j=a;j<b;j++) {
15895     append_to_name(mp->buffer[j]);
15896   }
15897   for (j=mem_default_length-mem_ext_length;
15898       j<mem_default_length;j++) {
15899     append_to_name(xord((int)mp->MP_mem_default[j]));
15900   } 
15901   mp->name_of_file[k]=0;
15902   mp->name_length=k; 
15903 }
15904
15905 @ Here is the only place we use |pack_buffered_name|. This part of the program
15906 becomes active when a ``virgin'' \MP\ is trying to get going, just after
15907 the preliminary initialization, or when the user is substituting another
15908 mem file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
15909 contains the first line of input in |buffer[loc..(last-1)]|, where
15910 |loc<last| and |buffer[loc]<>" "|.
15911
15912 @<Declarations@>=
15913 boolean mp_open_mem_file (MP mp) ;
15914
15915 @ @c
15916 boolean mp_open_mem_file (MP mp) {
15917   int j; /* the first space after the file name */
15918   if (mp->mem_name!=NULL) {
15919     mp->mem_file = (mp->open_file)(mp,mp->mem_name, "rb", mp_filetype_memfile);
15920     if ( mp->mem_file ) return true;
15921   }
15922   j=loc;
15923   if ( mp->buffer[loc]=='&' ) {
15924     incr(loc); j=loc; mp->buffer[mp->last]=' ';
15925     while ( mp->buffer[j]!=' ' ) incr(j);
15926     mp_pack_buffered_name(mp, 0,loc,j); /* try first without the system file area */
15927     if ( mp_w_open_in(mp, &mp->mem_file) ) goto FOUND;
15928     wake_up_terminal;
15929     wterm_ln("Sorry, I can\'t find that mem file; will try PLAIN.");
15930 @.Sorry, I can't find...@>
15931     update_terminal;
15932   }
15933   /* now pull out all the stops: try for the system \.{plain} file */
15934   mp_pack_buffered_name(mp, mem_default_length-mem_ext_length,0,0);
15935   if ( ! mp_w_open_in(mp, &mp->mem_file) ) {
15936     wake_up_terminal;
15937     wterm_ln("I can\'t find the PLAIN mem file!\n");
15938 @.I can't find PLAIN...@>
15939 @.plain@>
15940     return false;
15941   }
15942 FOUND:
15943   loc=j; return true;
15944 }
15945
15946 @ Operating systems often make it possible to determine the exact name (and
15947 possible version number) of a file that has been opened. The following routine,
15948 which simply makes a \MP\ string from the value of |name_of_file|, should
15949 ideally be changed to deduce the full name of file~|f|, which is the file
15950 most recently opened, if it is possible to do this.
15951 @^system dependencies@>
15952
15953 @<Declarations@>=
15954 #define mp_a_make_name_string(A,B)  mp_make_name_string(A)
15955 #define mp_b_make_name_string(A,B)  mp_make_name_string(A)
15956 #define mp_w_make_name_string(A,B)  mp_make_name_string(A)
15957
15958 @ @c 
15959 str_number mp_make_name_string (MP mp) {
15960   int k; /* index into |name_of_file| */
15961   str_room(mp->name_length);
15962   for (k=0;k<mp->name_length;k++) {
15963     append_char(xord((int)mp->name_of_file[k]));
15964   }
15965   return mp_make_string(mp);
15966 }
15967
15968 @ Now let's consider the ``driver''
15969 routines by which \MP\ deals with file names
15970 in a system-independent manner.  First comes a procedure that looks for a
15971 file name in the input by taking the information from the input buffer.
15972 (We can't use |get_next|, because the conversion to tokens would
15973 destroy necessary information.)
15974
15975 This procedure doesn't allow semicolons or percent signs to be part of
15976 file names, because of other conventions of \MP.
15977 {\sl The {\logos METAFONT\/}book} doesn't
15978 use semicolons or percents immediately after file names, but some users
15979 no doubt will find it natural to do so; therefore system-dependent
15980 changes to allow such characters in file names should probably
15981 be made with reluctance, and only when an entire file name that
15982 includes special characters is ``quoted'' somehow.
15983 @^system dependencies@>
15984
15985 @c void mp_scan_file_name (MP mp) { 
15986   mp_begin_name(mp);
15987   while ( mp->buffer[loc]==' ' ) incr(loc);
15988   while (1) { 
15989     if ( (mp->buffer[loc]==';')||(mp->buffer[loc]=='%') ) break;
15990     if ( ! mp_more_name(mp, mp->buffer[loc]) ) break;
15991     incr(loc);
15992   }
15993   mp_end_name(mp);
15994 }
15995
15996 @ Here is another version that takes its input from a string.
15997
15998 @<Declare subroutines for parsing file names@>=
15999 void mp_str_scan_file (MP mp,  str_number s) {
16000   pool_pointer p,q; /* current position and stopping point */
16001   mp_begin_name(mp);
16002   p=mp->str_start[s]; q=str_stop(s);
16003   while ( p<q ){ 
16004     if ( ! mp_more_name(mp, mp->str_pool[p]) ) break;
16005     incr(p);
16006   }
16007   mp_end_name(mp);
16008 }
16009
16010 @ And one that reads from a |char*|.
16011
16012 @<Declare subroutines for parsing file names@>=
16013 void mp_ptr_scan_file (MP mp,  char *s) {
16014   char *p, *q; /* current position and stopping point */
16015   mp_begin_name(mp);
16016   p=s; q=p+strlen(s);
16017   while ( p<q ){ 
16018     if ( ! mp_more_name(mp, *p)) break;
16019     p++;
16020   }
16021   mp_end_name(mp);
16022 }
16023
16024
16025 @ The global variable |job_name| contains the file name that was first
16026 \&{input} by the user. This name is extended by `\.{.log}' and `\.{ps}' and
16027 `\.{.mem}' and `\.{.tfm}' in order to make the names of \MP's output files.
16028
16029 @<Glob...@>=
16030 boolean log_opened; /* has the transcript file been opened? */
16031 char *log_name; /* full name of the log file */
16032
16033 @ @<Option variables@>=
16034 char *job_name; /* principal file name */
16035
16036 @ Initially |job_name=NULL|; it becomes nonzero as soon as the true name is known.
16037 We have |job_name=NULL| if and only if the `\.{log}' file has not been opened,
16038 except of course for a short time just after |job_name| has become nonzero.
16039
16040 @<Allocate or ...@>=
16041 mp->job_name=opt->job_name; 
16042 mp->log_opened=false;
16043
16044 @ @<Dealloc variables@>=
16045 xfree(mp->job_name);
16046
16047 @ Here is a routine that manufactures the output file names, assuming that
16048 |job_name<>0|. It ignores and changes the current settings of |cur_area|
16049 and |cur_ext|.
16050
16051 @d pack_cur_name mp_pack_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext)
16052
16053 @<Declarations@>=
16054 void mp_pack_job_name (MP mp, char *s) ;
16055
16056 @ @c void mp_pack_job_name (MP mp, char  *s) { /* |s = ".log"|, |".mem"|, |".ps"|, or .\\{nnn} */
16057   xfree(mp->cur_name); mp->cur_name=xstrdup(mp->job_name);
16058   xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
16059   xfree(mp->cur_ext);  mp->cur_ext=xstrdup(s);
16060   pack_cur_name;
16061 }
16062
16063 @ If some trouble arises when \MP\ tries to open a file, the following
16064 routine calls upon the user to supply another file name. Parameter~|s|
16065 is used in the error message to identify the type of file; parameter~|e|
16066 is the default extension if none is given. Upon exit from the routine,
16067 variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
16068 ready for another attempt at file opening.
16069
16070 @<Declarations@>=
16071 void mp_prompt_file_name (MP mp,char * s, char * e) ;
16072
16073 @ @c void mp_prompt_file_name (MP mp,char * s, char * e) {
16074   size_t k; /* index into |buffer| */
16075   char * saved_cur_name;
16076   if ( mp->interaction==mp_scroll_mode ) 
16077         wake_up_terminal;
16078   if (strcmp(s,"input file name")==0) {
16079         print_err("I can\'t find file `");
16080 @.I can't find file x@>
16081   } else {
16082         print_err("I can\'t write on file `");
16083   }
16084 @.I can't write on file x@>
16085   mp_print_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext); 
16086   mp_print(mp, "'.");
16087   if (strcmp(e,"")==0) 
16088         mp_show_context(mp);
16089   mp_print_nl(mp, "Please type another "); mp_print(mp, s);
16090 @.Please type...@>
16091   if ( mp->interaction<mp_scroll_mode )
16092     mp_fatal_error(mp, "*** (job aborted, file error in nonstop mode)");
16093 @.job aborted, file error...@>
16094   saved_cur_name = xstrdup(mp->cur_name);
16095   clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
16096   if (strcmp(mp->cur_ext,"")==0) 
16097         mp->cur_ext=e;
16098   if (strlen(mp->cur_name)==0) {
16099     mp->cur_name=saved_cur_name;
16100   } else {
16101     xfree(saved_cur_name);
16102   }
16103   pack_cur_name;
16104 }
16105
16106 @ @<Scan file name in the buffer@>=
16107
16108   mp_begin_name(mp); k=mp->first;
16109   while ( (mp->buffer[k]==' ')&&(k<mp->last) ) incr(k);
16110   while (1) { 
16111     if ( k==mp->last ) break;
16112     if ( ! mp_more_name(mp, mp->buffer[k]) ) break;
16113     incr(k);
16114   }
16115   mp_end_name(mp);
16116 }
16117
16118 @ The |open_log_file| routine is used to open the transcript file and to help
16119 it catch up to what has previously been printed on the terminal.
16120
16121 @c void mp_open_log_file (MP mp) {
16122   int old_setting; /* previous |selector| setting */
16123   int k; /* index into |months| and |buffer| */
16124   int l; /* end of first input line */
16125   integer m; /* the current month */
16126   char *months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; 
16127     /* abbreviations of month names */
16128   old_setting=mp->selector;
16129   if ( mp->job_name==NULL ) {
16130      mp->job_name=xstrdup("mpout");
16131   }
16132   mp_pack_job_name(mp,".log");
16133   while ( ! mp_a_open_out(mp, &mp->log_file, mp_filetype_log) ) {
16134     @<Try to get a different log file name@>;
16135   }
16136   mp->log_name=xstrdup(mp->name_of_file);
16137   mp->selector=log_only; mp->log_opened=true;
16138   @<Print the banner line, including the date and time@>;
16139   mp->input_stack[mp->input_ptr]=mp->cur_input; 
16140     /* make sure bottom level is in memory */
16141 @.**@>
16142   if (!mp->noninteractive) {
16143     mp_print_nl(mp, "**");
16144     l=mp->input_stack[0].limit_field-1; /* last position of first line */
16145     for (k=0;k<=l;k++) mp_print_str(mp, mp->buffer[k]);
16146     mp_print_ln(mp); /* now the transcript file contains the first line of input */
16147   }
16148   mp->selector=old_setting+2; /* |log_only| or |term_and_log| */
16149 }
16150
16151 @ @<Dealloc variables@>=
16152 xfree(mp->log_name);
16153
16154 @ Sometimes |open_log_file| is called at awkward moments when \MP\ is
16155 unable to print error messages or even to |show_context|.
16156 The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
16157 routine will not be invoked because |log_opened| will be false.
16158
16159 The normal idea of |mp_batch_mode| is that nothing at all should be written
16160 on the terminal. However, in the unusual case that
16161 no log file could be opened, we make an exception and allow
16162 an explanatory message to be seen.
16163
16164 Incidentally, the program always refers to the log file as a `\.{transcript
16165 file}', because some systems cannot use the extension `\.{.log}' for
16166 this file.
16167
16168 @<Try to get a different log file name@>=
16169 {  
16170   mp->selector=term_only;
16171   mp_prompt_file_name(mp, "transcript file name",".log");
16172 }
16173
16174 @ @<Print the banner...@>=
16175
16176   wlog(banner);
16177   mp_print(mp, mp->mem_ident); mp_print(mp, "  ");
16178   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_day])); 
16179   mp_print_char(mp, ' ');
16180   m=mp_round_unscaled(mp, mp->internal[mp_month]);
16181   for (k=3*m-3;k<3*m;k++) { wlog_chr(months[k]); }
16182   mp_print_char(mp, ' '); 
16183   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_year])); 
16184   mp_print_char(mp, ' ');
16185   m=mp_round_unscaled(mp, mp->internal[mp_time]);
16186   mp_print_dd(mp, m / 60); mp_print_char(mp, ':'); mp_print_dd(mp, m % 60);
16187 }
16188
16189 @ The |try_extension| function tries to open an input file determined by
16190 |cur_name|, |cur_area|, and the argument |ext|.  It returns |false| if it
16191 can't find the file in |cur_area| or the appropriate system area.
16192
16193 @c boolean mp_try_extension (MP mp,char *ext) { 
16194   mp_pack_file_name(mp, mp->cur_name,mp->cur_area, ext);
16195   in_name=xstrdup(mp->cur_name); 
16196   in_area=xstrdup(mp->cur_area);
16197   if ( mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16198     return true;
16199   } else { 
16200     mp_pack_file_name(mp, mp->cur_name,NULL,ext);
16201     return mp_a_open_in(mp, &cur_file, mp_filetype_program);
16202   }
16203   return false;
16204 }
16205
16206 @ Let's turn now to the procedure that is used to initiate file reading
16207 when an `\.{input}' command is being processed.
16208
16209 @c void mp_start_input (MP mp) { /* \MP\ will \.{input} something */
16210   char *fname = NULL;
16211   @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>;
16212   while (1) { 
16213     mp_begin_file_reading(mp); /* set up |cur_file| and new level of input */
16214     if ( strlen(mp->cur_ext)==0 ) {
16215       if ( mp_try_extension(mp, ".mp") ) break;
16216       else if ( mp_try_extension(mp, "") ) break;
16217       else if ( mp_try_extension(mp, ".mf") ) break;
16218       /* |else do_nothing; | */
16219     } else if ( mp_try_extension(mp, mp->cur_ext) ) {
16220       break;
16221     }
16222     mp_end_file_reading(mp); /* remove the level that didn't work */
16223     mp_prompt_file_name(mp, "input file name","");
16224   }
16225   name=mp_a_make_name_string(mp, cur_file);
16226   fname = xstrdup(mp->name_of_file);
16227   if ( mp->job_name==NULL ) {
16228     mp->job_name=xstrdup(mp->cur_name); 
16229     mp_open_log_file(mp);
16230   } /* |open_log_file| doesn't |show_context|, so |limit|
16231         and |loc| needn't be set to meaningful values yet */
16232   if ( ((int)mp->term_offset+(int)strlen(fname)) > (mp->max_print_line-2)) mp_print_ln(mp);
16233   else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, ' ');
16234   mp_print_char(mp, '('); incr(mp->open_parens); mp_print(mp, fname); 
16235   xfree(fname);
16236   update_terminal;
16237   @<Flush |name| and replace it with |cur_name| if it won't be needed@>;
16238   @<Read the first line of the new file@>;
16239 }
16240
16241 @ This code should be omitted if |a_make_name_string| returns something other
16242 than just a copy of its argument and the full file name is needed for opening
16243 \.{MPX} files or implementing the switch-to-editor option.
16244 @^system dependencies@>
16245
16246 @<Flush |name| and replace it with |cur_name| if it won't be needed@>=
16247 mp_flush_string(mp, name); name=rts(mp->cur_name); xfree(mp->cur_name)
16248
16249 @ If the file is empty, it is considered to contain a single blank line,
16250 so there is no need to test the return value.
16251
16252 @<Read the first line...@>=
16253
16254   line=1;
16255   (void)mp_input_ln(mp, cur_file ); 
16256   mp_firm_up_the_line(mp);
16257   mp->buffer[limit]='%'; mp->first=limit+1; loc=start;
16258 }
16259
16260 @ @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>=
16261 while ( token_state &&(loc==null) ) mp_end_token_list(mp);
16262 if ( token_state ) { 
16263   print_err("File names can't appear within macros");
16264 @.File names can't...@>
16265   help3("Sorry...I've converted what follows to tokens,")
16266     ("possibly garbaging the name you gave.")
16267     ("Please delete the tokens and insert the name again.");
16268   mp_error(mp);
16269 }
16270 if ( file_state ) {
16271   mp_scan_file_name(mp);
16272 } else { 
16273    xfree(mp->cur_name); mp->cur_name=xstrdup(""); 
16274    xfree(mp->cur_ext);  mp->cur_ext =xstrdup(""); 
16275    xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
16276 }
16277
16278 @ The following simple routine starts reading the \.{MPX} file associated
16279 with the current input file.
16280
16281 @c void mp_start_mpx_input (MP mp) {
16282   char *origname = NULL; /* a copy of nameoffile */
16283   mp_pack_file_name(mp, in_name, in_area, ".mpx");
16284   @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16285     |goto not_found| if there is a problem@>;
16286   mp_begin_file_reading(mp);
16287   if ( ! mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16288     mp_end_file_reading(mp);
16289     goto NOT_FOUND;
16290   }
16291   name=mp_a_make_name_string(mp, cur_file);
16292   mp->mpx_name[index]=name; add_str_ref(name);
16293   @<Read the first line of the new file@>;
16294   return;
16295 NOT_FOUND: 
16296     @<Explain that the \.{MPX} file can't be read and |succumb|@>;
16297   xfree(origname);
16298 }
16299
16300 @ This should ideally be changed to do whatever is necessary to create the
16301 \.{MPX} file given by |name_of_file| if it does not exist or if it is out
16302 of date.  This requires invoking \.{MPtoTeX} on the |origname| and passing
16303 the results through \TeX\ and \.{DVItoMP}.  (It is possible to use a
16304 completely different typesetting program if suitable postprocessor is
16305 available to perform the function of \.{DVItoMP}.)
16306 @^system dependencies@>
16307
16308 @ @<Exported types@>=
16309 typedef int (*mp_run_make_mpx_command)(MP mp, char *origname, char *mtxname);
16310
16311 @ @<Option variables@>=
16312 mp_run_make_mpx_command run_make_mpx;
16313
16314 @ @<Allocate or initialize ...@>=
16315 set_callback_option(run_make_mpx);
16316
16317 @ @<Internal library declarations@>=
16318 int mp_run_make_mpx (MP mp, char *origname, char *mtxname);
16319
16320 @ The default does nothing.
16321 @c 
16322 int mp_run_make_mpx (MP mp, char *origname, char *mtxname) {
16323   if (mp && origname && mtxname) /* for -W */
16324     return false;
16325   return false;
16326 }
16327
16328 @ @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16329   |goto not_found| if there is a problem@>=
16330 origname = mp_xstrdup(mp,mp->name_of_file);
16331 *(origname+strlen(origname)-1)=0; /* drop the x */
16332 if (!(mp->run_make_mpx)(mp, origname, mp->name_of_file))
16333   goto NOT_FOUND 
16334
16335 @ @<Explain that the \.{MPX} file can't be read and |succumb|@>=
16336 if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16337 mp_print_nl(mp, ">> ");
16338 mp_print(mp, origname);
16339 mp_print_nl(mp, ">> ");
16340 mp_print(mp, mp->name_of_file);
16341 mp_print_nl(mp, "! Unable to make mpx file");
16342 help4("The two files given above are one of your source files")
16343   ("and an auxiliary file I need to read to find out what your")
16344   ("btex..etex blocks mean. If you don't know why I had trouble,")
16345   ("try running it manually through MPtoTeX, TeX, and DVItoMP");
16346 succumb;
16347
16348 @ The last file-opening commands are for files accessed via the \&{readfrom}
16349 @:read_from_}{\&{readfrom} primitive@>
16350 operator and the \&{write} command.  Such files are stored in separate arrays.
16351 @:write_}{\&{write} primitive@>
16352
16353 @<Types in the outer block@>=
16354 typedef unsigned int readf_index; /* |0..max_read_files| */
16355 typedef unsigned int write_index;  /* |0..max_write_files| */
16356
16357 @ @<Glob...@>=
16358 readf_index max_read_files; /* maximum number of simultaneously open \&{readfrom} files */
16359 void ** rd_file; /* \&{readfrom} files */
16360 char ** rd_fname; /* corresponding file name or 0 if file not open */
16361 readf_index read_files; /* number of valid entries in the above arrays */
16362 write_index max_write_files; /* maximum number of simultaneously open \&{write} */
16363 void ** wr_file; /* \&{write} files */
16364 char ** wr_fname; /* corresponding file name or 0 if file not open */
16365 write_index write_files; /* number of valid entries in the above arrays */
16366
16367 @ @<Allocate or initialize ...@>=
16368 mp->max_read_files=8;
16369 mp->rd_file = xmalloc((mp->max_read_files+1),sizeof(void *));
16370 mp->rd_fname = xmalloc((mp->max_read_files+1),sizeof(char *));
16371 memset(mp->rd_fname, 0, sizeof(char *)*(mp->max_read_files+1));
16372 mp->read_files=0;
16373 mp->max_write_files=8;
16374 mp->wr_file = xmalloc((mp->max_write_files+1),sizeof(void *));
16375 mp->wr_fname = xmalloc((mp->max_write_files+1),sizeof(char *));
16376 memset(mp->wr_fname, 0, sizeof(char *)*(mp->max_write_files+1));
16377 mp->write_files=0;
16378
16379
16380 @ This routine starts reading the file named by string~|s| without setting
16381 |loc|, |limit|, or |name|.  It returns |false| if the file is empty or cannot
16382 be opened.  Otherwise it updates |rd_file[n]| and |rd_fname[n]|.
16383
16384 @c boolean mp_start_read_input (MP mp,char *s, readf_index  n) {
16385   mp_ptr_scan_file(mp, s);
16386   pack_cur_name;
16387   mp_begin_file_reading(mp);
16388   if ( ! mp_a_open_in(mp, &mp->rd_file[n], (mp_filetype_text+n)) ) 
16389         goto NOT_FOUND;
16390   if ( ! mp_input_ln(mp, mp->rd_file[n] ) ) {
16391     (mp->close_file)(mp,mp->rd_file[n]); 
16392         goto NOT_FOUND; 
16393   }
16394   mp->rd_fname[n]=xstrdup(mp->name_of_file);
16395   return true;
16396 NOT_FOUND: 
16397   mp_end_file_reading(mp);
16398   return false;
16399 }
16400
16401 @ Open |wr_file[n]| using file name~|s| and update |wr_fname[n]|.
16402
16403 @<Declarations@>=
16404 void mp_open_write_file (MP mp, char *s, readf_index  n) ;
16405
16406 @ @c void mp_open_write_file (MP mp,char *s, readf_index  n) {
16407   mp_ptr_scan_file(mp, s);
16408   pack_cur_name;
16409   while ( ! mp_a_open_out(mp, &mp->wr_file[n], (mp_filetype_text+n)) )
16410     mp_prompt_file_name(mp, "file name for write output","");
16411   mp->wr_fname[n]=xstrdup(mp->name_of_file);
16412 }
16413
16414
16415 @* \[36] Introduction to the parsing routines.
16416 We come now to the central nervous system that sparks many of \MP's activities.
16417 By evaluating expressions, from their primary constituents to ever larger
16418 subexpressions, \MP\ builds the structures that ultimately define complete
16419 pictures or fonts of type.
16420
16421 Four mutually recursive subroutines are involved in this process: We call them
16422 $$\hbox{|scan_primary|, |scan_secondary|, |scan_tertiary|,
16423 and |scan_expression|.}$$
16424 @^recursion@>
16425 Each of them is parameterless and begins with the first token to be scanned
16426 already represented in |cur_cmd|, |cur_mod|, and |cur_sym|. After execution,
16427 the value of the primary or secondary or tertiary or expression that was
16428 found will appear in the global variables |cur_type| and |cur_exp|. The
16429 token following the expression will be represented in |cur_cmd|, |cur_mod|,
16430 and |cur_sym|.
16431
16432 Technically speaking, the parsing algorithms are ``LL(1),'' more or less;
16433 backup mechanisms have been added in order to provide reasonable error
16434 recovery.
16435
16436 @<Glob...@>=
16437 small_number cur_type; /* the type of the expression just found */
16438 integer cur_exp; /* the value of the expression just found */
16439
16440 @ @<Set init...@>=
16441 mp->cur_exp=0;
16442
16443 @ Many different kinds of expressions are possible, so it is wise to have
16444 precise descriptions of what |cur_type| and |cur_exp| mean in all cases:
16445
16446 \smallskip\hang
16447 |cur_type=mp_vacuous| means that this expression didn't turn out to have a
16448 value at all, because it arose from a \&{begingroup}$\,\ldots\,$\&{endgroup}
16449 construction in which there was no expression before the \&{endgroup}.
16450 In this case |cur_exp| has some irrelevant value.
16451
16452 \smallskip\hang
16453 |cur_type=mp_boolean_type| means that |cur_exp| is either |true_code|
16454 or |false_code|.
16455
16456 \smallskip\hang
16457 |cur_type=mp_unknown_boolean| means that |cur_exp| points to a capsule
16458 node that is in the ring of variables equivalent
16459 to at least one undefined boolean variable.
16460
16461 \smallskip\hang
16462 |cur_type=mp_string_type| means that |cur_exp| is a string number (i.e., an
16463 integer in the range |0<=cur_exp<str_ptr|). That string's reference count
16464 includes this particular reference.
16465
16466 \smallskip\hang
16467 |cur_type=mp_unknown_string| means that |cur_exp| points to a capsule
16468 node that is in the ring of variables equivalent
16469 to at least one undefined string variable.
16470
16471 \smallskip\hang
16472 |cur_type=mp_pen_type| means that |cur_exp| points to a node in a pen.  Nobody
16473 else points to any of the nodes in this pen.  The pen may be polygonal or
16474 elliptical.
16475
16476 \smallskip\hang
16477 |cur_type=mp_unknown_pen| means that |cur_exp| points to a capsule
16478 node that is in the ring of variables equivalent
16479 to at least one undefined pen variable.
16480
16481 \smallskip\hang
16482 |cur_type=mp_path_type| means that |cur_exp| points to a the first node of
16483 a path; nobody else points to this particular path. The control points of
16484 the path will have been chosen.
16485
16486 \smallskip\hang
16487 |cur_type=mp_unknown_path| means that |cur_exp| points to a capsule
16488 node that is in the ring of variables equivalent
16489 to at least one undefined path variable.
16490
16491 \smallskip\hang
16492 |cur_type=mp_picture_type| means that |cur_exp| points to an edge header node.
16493 There may be other pointers to this particular set of edges.  The header node
16494 contains a reference count that includes this particular reference.
16495
16496 \smallskip\hang
16497 |cur_type=mp_unknown_picture| means that |cur_exp| points to a capsule
16498 node that is in the ring of variables equivalent
16499 to at least one undefined picture variable.
16500
16501 \smallskip\hang
16502 |cur_type=mp_transform_type| means that |cur_exp| points to a |mp_transform_type|
16503 capsule node. The |value| part of this capsule
16504 points to a transform node that contains six numeric values,
16505 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16506
16507 \smallskip\hang
16508 |cur_type=mp_color_type| means that |cur_exp| points to a |color_type|
16509 capsule node. The |value| part of this capsule
16510 points to a color node that contains three numeric values,
16511 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16512
16513 \smallskip\hang
16514 |cur_type=mp_cmykcolor_type| means that |cur_exp| points to a |mp_cmykcolor_type|
16515 capsule node. The |value| part of this capsule
16516 points to a color node that contains four numeric values,
16517 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16518
16519 \smallskip\hang
16520 |cur_type=mp_pair_type| means that |cur_exp| points to a capsule
16521 node whose type is |mp_pair_type|. The |value| part of this capsule
16522 points to a pair node that contains two numeric values,
16523 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16524
16525 \smallskip\hang
16526 |cur_type=mp_known| means that |cur_exp| is a |scaled| value.
16527
16528 \smallskip\hang
16529 |cur_type=mp_dependent| means that |cur_exp| points to a capsule node whose type
16530 is |dependent|. The |dep_list| field in this capsule points to the associated
16531 dependency list.
16532
16533 \smallskip\hang
16534 |cur_type=mp_proto_dependent| means that |cur_exp| points to a |mp_proto_dependent|
16535 capsule node. The |dep_list| field in this capsule
16536 points to the associated dependency list.
16537
16538 \smallskip\hang
16539 |cur_type=independent| means that |cur_exp| points to a capsule node
16540 whose type is |independent|. This somewhat unusual case can arise, for
16541 example, in the expression
16542 `$x+\&{begingroup}\penalty0\,\&{string}\,x; 0\,\&{endgroup}$'.
16543
16544 \smallskip\hang
16545 |cur_type=mp_token_list| means that |cur_exp| points to a linked list of
16546 tokens. This case arises only on the left-hand side of an assignment
16547 (`\.{:=}') operation, under very special circumstances.
16548
16549 \smallskip\noindent
16550 The possible settings of |cur_type| have been listed here in increasing
16551 numerical order. Notice that |cur_type| will never be |mp_numeric_type| or
16552 |suffixed_macro| or |mp_unsuffixed_macro|, although variables of those types
16553 are allowed.  Conversely, \MP\ has no variables of type |mp_vacuous| or
16554 |token_list|.
16555
16556 @ Capsules are two-word nodes that have a similar meaning
16557 to |cur_type| and |cur_exp|. Such nodes have |name_type=capsule|
16558 and |link<=mp_void|; and their |type| field is one of the possibilities for
16559 |cur_type| listed above.
16560
16561 The |value| field of a capsule is, in most cases, the value that
16562 corresponds to its |type|, as |cur_exp| corresponds to |cur_type|.
16563 However, when |cur_exp| would point to a capsule,
16564 no extra layer of indirection is present; the |value|
16565 field is what would have been called |value(cur_exp)| if it had not been
16566 encapsulated.  Furthermore, if the type is |dependent| or
16567 |mp_proto_dependent|, the |value| field of a capsule is replaced by
16568 |dep_list| and |prev_dep| fields, since dependency lists in capsules are
16569 always part of the general |dep_list| structure.
16570
16571 The |get_x_next| routine is careful not to change the values of |cur_type|
16572 and |cur_exp| when it gets an expanded token. However, |get_x_next| might
16573 call a macro, which might parse an expression, which might execute lots of
16574 commands in a group; hence it's possible that |cur_type| might change
16575 from, say, |mp_unknown_boolean| to |mp_boolean_type|, or from |dependent| to
16576 |known| or |independent|, during the time |get_x_next| is called. The
16577 programs below are careful to stash sensitive intermediate results in
16578 capsules, so that \MP's generality doesn't cause trouble.
16579
16580 Here's a procedure that illustrates these conventions. It takes
16581 the contents of $(|cur_type|\kern-.3pt,|cur_exp|\kern-.3pt)$
16582 and stashes them away in a
16583 capsule. It is not used when |cur_type=mp_token_list|.
16584 After the operation, |cur_type=mp_vacuous|; hence there is no need to
16585 copy path lists or to update reference counts, etc.
16586
16587 The special link |mp_void| is put on the capsule returned by
16588 |stash_cur_exp|, because this procedure is used to store macro parameters
16589 that must be easily distinguishable from token lists.
16590
16591 @<Declare the stashing/unstashing routines@>=
16592 pointer mp_stash_cur_exp (MP mp) {
16593   pointer p; /* the capsule that will be returned */
16594   switch (mp->cur_type) {
16595   case unknown_types:
16596   case mp_transform_type:
16597   case mp_color_type:
16598   case mp_pair_type:
16599   case mp_dependent:
16600   case mp_proto_dependent:
16601   case mp_independent: 
16602   case mp_cmykcolor_type:
16603     p=mp->cur_exp;
16604     break;
16605   default: 
16606     p=mp_get_node(mp, value_node_size); name_type(p)=mp_capsule;
16607     type(p)=mp->cur_type; value(p)=mp->cur_exp;
16608     break;
16609   }
16610   mp->cur_type=mp_vacuous; link(p)=mp_void; 
16611   return p;
16612 }
16613
16614 @ The inverse of |stash_cur_exp| is the following procedure, which
16615 deletes an unnecessary capsule and puts its contents into |cur_type|
16616 and |cur_exp|.
16617
16618 The program steps of \MP\ can be divided into two categories: those in
16619 which |cur_type| and |cur_exp| are ``alive'' and those in which they are
16620 ``dead,'' in the sense that |cur_type| and |cur_exp| contain relevant
16621 information or not. It's important not to ignore them when they're alive,
16622 and it's important not to pay attention to them when they're dead.
16623
16624 There's also an intermediate category: If |cur_type=mp_vacuous|, then
16625 |cur_exp| is irrelevant, hence we can proceed without caring if |cur_type|
16626 and |cur_exp| are alive or dead. In such cases we say that |cur_type|
16627 and |cur_exp| are {\sl dormant}. It is permissible to call |get_x_next|
16628 only when they are alive or dormant.
16629
16630 The \\{stash} procedure above assumes that |cur_type| and |cur_exp|
16631 are alive or dormant. The \\{unstash} procedure assumes that they are
16632 dead or dormant; it resuscitates them.
16633
16634 @<Declare the stashing/unstashing...@>=
16635 void mp_unstash_cur_exp (MP mp,pointer p) ;
16636
16637 @ @c
16638 void mp_unstash_cur_exp (MP mp,pointer p) { 
16639   mp->cur_type=type(p);
16640   switch (mp->cur_type) {
16641   case unknown_types:
16642   case mp_transform_type:
16643   case mp_color_type:
16644   case mp_pair_type:
16645   case mp_dependent: 
16646   case mp_proto_dependent:
16647   case mp_independent:
16648   case mp_cmykcolor_type: 
16649     mp->cur_exp=p;
16650     break;
16651   default:
16652     mp->cur_exp=value(p);
16653     mp_free_node(mp, p,value_node_size);
16654     break;
16655   }
16656 }
16657
16658 @ The following procedure prints the values of expressions in an
16659 abbreviated format. If its first parameter |p| is null, the value of
16660 |(cur_type,cur_exp)| is displayed; otherwise |p| should be a capsule
16661 containing the desired value. The second parameter controls the amount of
16662 output. If it is~0, dependency lists will be abbreviated to
16663 `\.{linearform}' unless they consist of a single term.  If it is greater
16664 than~1, complicated structures (pens, pictures, and paths) will be displayed
16665 in full.
16666
16667 @<Declare subroutines for printing expressions@>=
16668 @<Declare the procedure called |print_dp|@>;
16669 @<Declare the stashing/unstashing routines@>;
16670 void mp_print_exp (MP mp,pointer p, small_number verbosity) {
16671   boolean restore_cur_exp; /* should |cur_exp| be restored? */
16672   small_number t; /* the type of the expression */
16673   pointer q; /* a big node being displayed */
16674   integer v=0; /* the value of the expression */
16675   if ( p!=null ) {
16676     restore_cur_exp=false;
16677   } else { 
16678     p=mp_stash_cur_exp(mp); restore_cur_exp=true;
16679   }
16680   t=type(p);
16681   if ( t<mp_dependent ) v=value(p); else if ( t<mp_independent ) v=dep_list(p);
16682   @<Print an abbreviated value of |v| with format depending on |t|@>;
16683   if ( restore_cur_exp ) mp_unstash_cur_exp(mp, p);
16684 }
16685
16686 @ @<Print an abbreviated value of |v| with format depending on |t|@>=
16687 switch (t) {
16688 case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
16689 case mp_boolean_type:
16690   if ( v==true_code ) mp_print(mp, "true"); else mp_print(mp, "false");
16691   break;
16692 case unknown_types: case mp_numeric_type:
16693   @<Display a variable that's been declared but not defined@>;
16694   break;
16695 case mp_string_type:
16696   mp_print_char(mp, '"'); mp_print_str(mp, v); mp_print_char(mp, '"');
16697   break;
16698 case mp_pen_type: case mp_path_type: case mp_picture_type:
16699   @<Display a complex type@>;
16700   break;
16701 case mp_transform_type: case mp_color_type: case mp_pair_type: case mp_cmykcolor_type:
16702   if ( v==null ) mp_print_type(mp, t);
16703   else @<Display a big node@>;
16704   break;
16705 case mp_known:mp_print_scaled(mp, v); break;
16706 case mp_dependent: case mp_proto_dependent:
16707   mp_print_dp(mp, t,v,verbosity);
16708   break;
16709 case mp_independent:mp_print_variable_name(mp, p); break;
16710 default: mp_confusion(mp, "exp"); break;
16711 @:this can't happen exp}{\quad exp@>
16712 }
16713
16714 @ @<Display a big node@>=
16715
16716   mp_print_char(mp, '('); q=v+mp->big_node_size[t];
16717   do {  
16718     if ( type(v)==mp_known ) mp_print_scaled(mp, value(v));
16719     else if ( type(v)==mp_independent ) mp_print_variable_name(mp, v);
16720     else mp_print_dp(mp, type(v),dep_list(v),verbosity);
16721     v=v+2;
16722     if ( v!=q ) mp_print_char(mp, ',');
16723   } while (v!=q);
16724   mp_print_char(mp, ')');
16725 }
16726
16727 @ Values of type \&{picture}, \&{path}, and \&{pen} are displayed verbosely
16728 in the log file only, unless the user has given a positive value to
16729 \\{tracingonline}.
16730
16731 @<Display a complex type@>=
16732 if ( verbosity<=1 ) {
16733   mp_print_type(mp, t);
16734 } else { 
16735   if ( mp->selector==term_and_log )
16736    if ( mp->internal[mp_tracing_online]<=0 ) {
16737     mp->selector=term_only;
16738     mp_print_type(mp, t); mp_print(mp, " (see the transcript file)");
16739     mp->selector=term_and_log;
16740   };
16741   switch (t) {
16742   case mp_pen_type:mp_print_pen(mp, v,"",false); break;
16743   case mp_path_type:mp_print_path(mp, v,"",false); break;
16744   case mp_picture_type:mp_print_edges(mp, v,"",false); break;
16745   } /* there are no other cases */
16746 }
16747
16748 @ @<Declare the procedure called |print_dp|@>=
16749 void mp_print_dp (MP mp,small_number t, pointer p, 
16750                   small_number verbosity)  {
16751   pointer q; /* the node following |p| */
16752   q=link(p);
16753   if ( (info(q)==null) || (verbosity>0) ) mp_print_dependency(mp, p,t);
16754   else mp_print(mp, "linearform");
16755 }
16756
16757 @ The displayed name of a variable in a ring will not be a capsule unless
16758 the ring consists entirely of capsules.
16759
16760 @<Display a variable that's been declared but not defined@>=
16761 { mp_print_type(mp, t);
16762 if ( v!=null )
16763   { mp_print_char(mp, ' ');
16764   while ( (name_type(v)==mp_capsule) && (v!=p) ) v=value(v);
16765   mp_print_variable_name(mp, v);
16766   };
16767 }
16768
16769 @ When errors are detected during parsing, it is often helpful to
16770 display an expression just above the error message, using |exp_err|
16771 or |disp_err| instead of |print_err|.
16772
16773 @d exp_err(A) mp_disp_err(mp, null,(A)) /* displays the current expression */
16774
16775 @<Declare subroutines for printing expressions@>=
16776 void mp_disp_err (MP mp,pointer p, char *s) { 
16777   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16778   mp_print_nl(mp, ">> ");
16779 @.>>@>
16780   mp_print_exp(mp, p,1); /* ``medium verbose'' printing of the expression */
16781   if (strlen(s)) { 
16782     mp_print_nl(mp, "! "); mp_print(mp, s);
16783 @.!\relax@>
16784   }
16785 }
16786
16787 @ If |cur_type| and |cur_exp| contain relevant information that should
16788 be recycled, we will use the following procedure, which changes |cur_type|
16789 to |known| and stores a given value in |cur_exp|. We can think of |cur_type|
16790 and |cur_exp| as either alive or dormant after this has been done,
16791 because |cur_exp| will not contain a pointer value.
16792
16793 @ @c void mp_flush_cur_exp (MP mp,scaled v) { 
16794   switch (mp->cur_type) {
16795   case unknown_types: case mp_transform_type: case mp_color_type: case mp_pair_type:
16796   case mp_dependent: case mp_proto_dependent: case mp_independent: case mp_cmykcolor_type:
16797     mp_recycle_value(mp, mp->cur_exp); 
16798     mp_free_node(mp, mp->cur_exp,value_node_size);
16799     break;
16800   case mp_string_type:
16801     delete_str_ref(mp->cur_exp); break;
16802   case mp_pen_type: case mp_path_type: 
16803     mp_toss_knot_list(mp, mp->cur_exp); break;
16804   case mp_picture_type:
16805     delete_edge_ref(mp->cur_exp); break;
16806   default: 
16807     break;
16808   }
16809   mp->cur_type=mp_known; mp->cur_exp=v;
16810 }
16811
16812 @ There's a much more general procedure that is capable of releasing
16813 the storage associated with any two-word value packet.
16814
16815 @<Declare the recycling subroutines@>=
16816 void mp_recycle_value (MP mp,pointer p) ;
16817
16818 @ @c void mp_recycle_value (MP mp,pointer p) {
16819   small_number t; /* a type code */
16820   integer vv; /* another value */
16821   pointer q,r,s,pp; /* link manipulation registers */
16822   integer v=0; /* a value */
16823   t=type(p);
16824   if ( t<mp_dependent ) v=value(p);
16825   switch (t) {
16826   case undefined: case mp_vacuous: case mp_boolean_type: case mp_known:
16827   case mp_numeric_type:
16828     break;
16829   case unknown_types:
16830     mp_ring_delete(mp, p); break;
16831   case mp_string_type:
16832     delete_str_ref(v); break;
16833   case mp_path_type: case mp_pen_type:
16834     mp_toss_knot_list(mp, v); break;
16835   case mp_picture_type:
16836     delete_edge_ref(v); break;
16837   case mp_cmykcolor_type: case mp_pair_type: case mp_color_type:
16838   case mp_transform_type:
16839     @<Recycle a big node@>; break; 
16840   case mp_dependent: case mp_proto_dependent:
16841     @<Recycle a dependency list@>; break;
16842   case mp_independent:
16843     @<Recycle an independent variable@>; break;
16844   case mp_token_list: case mp_structured:
16845     mp_confusion(mp, "recycle"); break;
16846 @:this can't happen recycle}{\quad recycle@>
16847   case mp_unsuffixed_macro: case mp_suffixed_macro:
16848     mp_delete_mac_ref(mp, value(p)); break;
16849   } /* there are no other cases */
16850   type(p)=undefined;
16851 }
16852
16853 @ @<Recycle a big node@>=
16854 if ( v!=null ){ 
16855   q=v+mp->big_node_size[t];
16856   do {  
16857     q=q-2; mp_recycle_value(mp, q);
16858   } while (q!=v);
16859   mp_free_node(mp, v,mp->big_node_size[t]);
16860 }
16861
16862 @ @<Recycle a dependency list@>=
16863
16864   q=dep_list(p);
16865   while ( info(q)!=null ) q=link(q);
16866   link(prev_dep(p))=link(q);
16867   prev_dep(link(q))=prev_dep(p);
16868   link(q)=null; mp_flush_node_list(mp, dep_list(p));
16869 }
16870
16871 @ When an independent variable disappears, it simply fades away, unless
16872 something depends on it. In the latter case, a dependent variable whose
16873 coefficient of dependence is maximal will take its place.
16874 The relevant algorithm is due to Ignacio~A. Zabala, who implemented it
16875 as part of his Ph.D. thesis (Stanford University, December 1982).
16876 @^Zabala Salelles, Ignacio Andres@>
16877
16878 For example, suppose that variable $x$ is being recycled, and that the
16879 only variables depending on~$x$ are $y=2x+a$ and $z=x+b$. In this case
16880 we want to make $y$ independent and $z=.5y-.5a+b$; no other variables
16881 will depend on~$y$. If $\\{tracingequations}>0$ in this situation,
16882 we will print `\.{\#\#\# -2x=-y+a}'.
16883
16884 There's a slight complication, however: An independent variable $x$
16885 can occur both in dependency lists and in proto-dependency lists.
16886 This makes it necessary to be careful when deciding which coefficient
16887 is maximal.
16888
16889 Furthermore, this complication is not so slight when
16890 a proto-dependent variable is chosen to become independent. For example,
16891 suppose that $y=2x+100a$ is proto-dependent while $z=x+b$ is dependent;
16892 then we must change $z=.5y-50a+b$ to a proto-dependency, because of the
16893 large coefficient `50'.
16894
16895 In order to deal with these complications without wasting too much time,
16896 we shall link together the occurrences of~$x$ among all the linear
16897 dependencies, maintaining separate lists for the dependent and
16898 proto-dependent cases.
16899
16900 @<Recycle an independent variable@>=
16901
16902   mp->max_c[mp_dependent]=0; mp->max_c[mp_proto_dependent]=0;
16903   mp->max_link[mp_dependent]=null; mp->max_link[mp_proto_dependent]=null;
16904   q=link(dep_head);
16905   while ( q!=dep_head ) { 
16906     s=value_loc(q); /* now |link(s)=dep_list(q)| */
16907     while (1) { 
16908       r=link(s);
16909       if ( info(r)==null ) break;;
16910       if ( info(r)!=p ) { 
16911        s=r;
16912       } else  { 
16913         t=type(q); link(s)=link(r); info(r)=q;
16914         if ( abs(value(r))>mp->max_c[t] ) {
16915           @<Record a new maximum coefficient of type |t|@>;
16916         } else { 
16917           link(r)=mp->max_link[t]; mp->max_link[t]=r;
16918         }
16919       }
16920     }   
16921     q=link(r);
16922   }
16923   if ( (mp->max_c[mp_dependent]>0)||(mp->max_c[mp_proto_dependent]>0) ) {
16924     @<Choose a dependent variable to take the place of the disappearing
16925     independent variable, and change all remaining dependencies
16926     accordingly@>;
16927   }
16928 }
16929
16930 @ The code for independency removal makes use of three two-word arrays.
16931
16932 @<Glob...@>=
16933 integer max_c[mp_proto_dependent+1];  /* max coefficient magnitude */
16934 pointer max_ptr[mp_proto_dependent+1]; /* where |p| occurs with |max_c| */
16935 pointer max_link[mp_proto_dependent+1]; /* other occurrences of |p| */
16936
16937 @ @<Record a new maximum coefficient...@>=
16938
16939   if ( mp->max_c[t]>0 ) {
16940     link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
16941   }
16942   mp->max_c[t]=abs(value(r)); mp->max_ptr[t]=r;
16943 }
16944
16945 @ @<Choose a dependent...@>=
16946
16947   if ( (mp->max_c[mp_dependent] / 010000 >= mp->max_c[mp_proto_dependent]) )
16948     t=mp_dependent;
16949   else 
16950     t=mp_proto_dependent;
16951   @<Determine the dependency list |s| to substitute for the independent
16952     variable~|p|@>;
16953   t=mp_dependent+mp_proto_dependent-t; /* complement |t| */
16954   if ( mp->max_c[t]>0 ) { /* we need to pick up an unchosen dependency */ 
16955     link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
16956   }
16957   if ( t!=mp_dependent ) { @<Substitute new dependencies in place of |p|@>; }
16958   else { @<Substitute new proto-dependencies in place of |p|@>;}
16959   mp_flush_node_list(mp, s);
16960   if ( mp->fix_needed ) mp_fix_dependencies(mp);
16961   check_arith;
16962 }
16963
16964 @ Let |s=max_ptr[t]|. At this point we have $|value|(s)=\pm|max_c|[t]$,
16965 and |info(s)| points to the dependent variable~|pp| of type~|t| from
16966 whose dependency list we have removed node~|s|. We must reinsert
16967 node~|s| into the dependency list, with coefficient $-1.0$, and with
16968 |pp| as the new independent variable. Since |pp| will have a larger serial
16969 number than any other variable, we can put node |s| at the head of the
16970 list.
16971
16972 @<Determine the dep...@>=
16973 s=mp->max_ptr[t]; pp=info(s); v=value(s);
16974 if ( t==mp_dependent ) value(s)=-fraction_one; else value(s)=-unity;
16975 r=dep_list(pp); link(s)=r;
16976 while ( info(r)!=null ) r=link(r);
16977 q=link(r); link(r)=null;
16978 prev_dep(q)=prev_dep(pp); link(prev_dep(pp))=q;
16979 new_indep(pp);
16980 if ( mp->cur_exp==pp ) if ( mp->cur_type==t ) mp->cur_type=mp_independent;
16981 if ( mp->internal[mp_tracing_equations]>0 ) { 
16982   @<Show the transformed dependency@>; 
16983 }
16984
16985 @ Now $(-v)$ times the formerly independent variable~|p| is being replaced
16986 by the dependency list~|s|.
16987
16988 @<Show the transformed...@>=
16989 if ( mp_interesting(mp, p) ) {
16990   mp_begin_diagnostic(mp); mp_print_nl(mp, "### ");
16991 @:]]]\#\#\#_}{\.{\#\#\#}@>
16992   if ( v>0 ) mp_print_char(mp, '-');
16993   if ( t==mp_dependent ) vv=mp_round_fraction(mp, mp->max_c[mp_dependent]);
16994   else vv=mp->max_c[mp_proto_dependent];
16995   if ( vv!=unity ) mp_print_scaled(mp, vv);
16996   mp_print_variable_name(mp, p);
16997   while ( value(p) % s_scale>0 ) {
16998     mp_print(mp, "*4"); value(p)=value(p)-2;
16999   }
17000   if ( t==mp_dependent ) mp_print_char(mp, '='); else mp_print(mp, " = ");
17001   mp_print_dependency(mp, s,t);
17002   mp_end_diagnostic(mp, false);
17003 }
17004
17005 @ Finally, there are dependent and proto-dependent variables whose
17006 dependency lists must be brought up to date.
17007
17008 @<Substitute new dependencies...@>=
17009 for (t=mp_dependent;t<=mp_proto_dependent;t++){ 
17010   r=mp->max_link[t];
17011   while ( r!=null ) {
17012     q=info(r);
17013     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
17014      mp_make_fraction(mp, value(r),-v),s,t,mp_dependent);
17015     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
17016     q=r; r=link(r); mp_free_node(mp, q,dep_node_size);
17017   }
17018 }
17019
17020 @ @<Substitute new proto...@>=
17021 for (t=mp_dependent;t<=mp_proto_dependent;t++) {
17022   r=mp->max_link[t];
17023   while ( r!=null ) {
17024     q=info(r);
17025     if ( t==mp_dependent ) { /* for safety's sake, we change |q| to |mp_proto_dependent| */
17026       if ( mp->cur_exp==q ) if ( mp->cur_type==mp_dependent )
17027         mp->cur_type=mp_proto_dependent;
17028       dep_list(q)=mp_p_over_v(mp, dep_list(q),unity,mp_dependent,mp_proto_dependent);
17029       type(q)=mp_proto_dependent; value(r)=mp_round_fraction(mp, value(r));
17030     }
17031     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
17032       mp_make_scaled(mp, value(r),-v),s,mp_proto_dependent,mp_proto_dependent);
17033     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
17034     q=r; r=link(r); mp_free_node(mp, q,dep_node_size);
17035   }
17036 }
17037
17038 @ Here are some routines that provide handy combinations of actions
17039 that are often needed during error recovery. For example,
17040 `|flush_error|' flushes the current expression, replaces it by
17041 a given value, and calls |error|.
17042
17043 Errors often are detected after an extra token has already been scanned.
17044 The `\\{put\_get}' routines put that token back before calling |error|;
17045 then they get it back again. (Or perhaps they get another token, if
17046 the user has changed things.)
17047
17048 @<Declarations@>=
17049 void mp_flush_error (MP mp,scaled v);
17050 void mp_put_get_error (MP mp);
17051 void mp_put_get_flush_error (MP mp,scaled v) ;
17052
17053 @ @c
17054 void mp_flush_error (MP mp,scaled v) { 
17055   mp_error(mp); mp_flush_cur_exp(mp, v); 
17056 }
17057 void mp_put_get_error (MP mp) { 
17058   mp_back_error(mp); mp_get_x_next(mp); 
17059 }
17060 void mp_put_get_flush_error (MP mp,scaled v) { 
17061   mp_put_get_error(mp);
17062   mp_flush_cur_exp(mp, v); 
17063 }
17064
17065 @ A global variable |var_flag| is set to a special command code
17066 just before \MP\ calls |scan_expression|, if the expression should be
17067 treated as a variable when this command code immediately follows. For
17068 example, |var_flag| is set to |assignment| at the beginning of a
17069 statement, because we want to know the {\sl location\/} of a variable at
17070 the left of `\.{:=}', not the {\sl value\/} of that variable.
17071
17072 The |scan_expression| subroutine calls |scan_tertiary|,
17073 which calls |scan_secondary|, which calls |scan_primary|, which sets
17074 |var_flag:=0|. In this way each of the scanning routines ``knows''
17075 when it has been called with a special |var_flag|, but |var_flag| is
17076 usually zero.
17077
17078 A variable preceding a command that equals |var_flag| is converted to a
17079 token list rather than a value. Furthermore, an `\.{=}' sign following an
17080 expression with |var_flag=assignment| is not considered to be a relation
17081 that produces boolean expressions.
17082
17083
17084 @<Glob...@>=
17085 int var_flag; /* command that wants a variable */
17086
17087 @ @<Set init...@>=
17088 mp->var_flag=0;
17089
17090 @* \[37] Parsing primary expressions.
17091 The first parsing routine, |scan_primary|, is also the most complicated one,
17092 since it involves so many different cases. But each case---with one
17093 exception---is fairly simple by itself.
17094
17095 When |scan_primary| begins, the first token of the primary to be scanned
17096 should already appear in |cur_cmd|, |cur_mod|, and |cur_sym|. The values
17097 of |cur_type| and |cur_exp| should be either dead or dormant, as explained
17098 earlier. If |cur_cmd| is not between |min_primary_command| and
17099 |max_primary_command|, inclusive, a syntax error will be signaled.
17100
17101 @<Declare the basic parsing subroutines@>=
17102 void mp_scan_primary (MP mp) {
17103   pointer p,q,r; /* for list manipulation */
17104   quarterword c; /* a primitive operation code */
17105   int my_var_flag; /* initial value of |my_var_flag| */
17106   pointer l_delim,r_delim; /* hash addresses of a delimiter pair */
17107   @<Other local variables for |scan_primary|@>;
17108   my_var_flag=mp->var_flag; mp->var_flag=0;
17109 RESTART:
17110   check_arith;
17111   @<Supply diagnostic information, if requested@>;
17112   switch (mp->cur_cmd) {
17113   case left_delimiter:
17114     @<Scan a delimited primary@>; break;
17115   case begin_group:
17116     @<Scan a grouped primary@>; break;
17117   case string_token:
17118     @<Scan a string constant@>; break;
17119   case numeric_token:
17120     @<Scan a primary that starts with a numeric token@>; break;
17121   case nullary:
17122     @<Scan a nullary operation@>; break;
17123   case unary: case type_name: case cycle: case plus_or_minus:
17124     @<Scan a unary operation@>; break;
17125   case primary_binary:
17126     @<Scan a binary operation with `\&{of}' between its operands@>; break;
17127   case str_op:
17128     @<Convert a suffix to a string@>; break;
17129   case internal_quantity:
17130     @<Scan an internal numeric quantity@>; break;
17131   case capsule_token:
17132     mp_make_exp_copy(mp, mp->cur_mod); break;
17133   case tag_token:
17134     @<Scan a variable primary; |goto restart| if it turns out to be a macro@>; break;
17135   default: 
17136     mp_bad_exp(mp, "A primary"); goto RESTART; break;
17137 @.A primary expression...@>
17138   }
17139   mp_get_x_next(mp); /* the routines |goto done| if they don't want this */
17140 DONE: 
17141   if ( mp->cur_cmd==left_bracket ) {
17142     if ( mp->cur_type>=mp_known ) {
17143       @<Scan a mediation construction@>;
17144     }
17145   }
17146 }
17147
17148
17149
17150 @ Errors at the beginning of expressions are flagged by |bad_exp|.
17151
17152 @c void mp_bad_exp (MP mp,char * s) {
17153   int save_flag;
17154   print_err(s); mp_print(mp, " expression can't begin with `");
17155   mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); 
17156   mp_print_char(mp, '\'');
17157   help4("I'm afraid I need some sort of value in order to continue,")
17158     ("so I've tentatively inserted `0'. You may want to")
17159     ("delete this zero and insert something else;")
17160     ("see Chapter 27 of The METAFONTbook for an example.");
17161 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17162   mp_back_input(mp); mp->cur_sym=0; mp->cur_cmd=numeric_token; 
17163   mp->cur_mod=0; mp_ins_error(mp);
17164   save_flag=mp->var_flag; mp->var_flag=0; mp_get_x_next(mp);
17165   mp->var_flag=save_flag;
17166 }
17167
17168 @ @<Supply diagnostic information, if requested@>=
17169 #ifdef DEBUG
17170 if ( mp->panicking ) mp_check_mem(mp, false);
17171 #endif
17172 if ( mp->interrupt!=0 ) if ( mp->OK_to_interrupt ) {
17173   mp_back_input(mp); check_interrupt; mp_get_x_next(mp);
17174 }
17175
17176 @ @<Scan a delimited primary@>=
17177
17178   l_delim=mp->cur_sym; r_delim=mp->cur_mod; 
17179   mp_get_x_next(mp); mp_scan_expression(mp);
17180   if ( (mp->cur_cmd==comma) && (mp->cur_type>=mp_known) ) {
17181     @<Scan the rest of a delimited set of numerics@>;
17182   } else {
17183     mp_check_delimiter(mp, l_delim,r_delim);
17184   }
17185 }
17186
17187 @ The |stash_in| subroutine puts the current (numeric) expression into a field
17188 within a ``big node.''
17189
17190 @c void mp_stash_in (MP mp,pointer p) {
17191   pointer q; /* temporary register */
17192   type(p)=mp->cur_type;
17193   if ( mp->cur_type==mp_known ) {
17194     value(p)=mp->cur_exp;
17195   } else { 
17196     if ( mp->cur_type==mp_independent ) {
17197       @<Stash an independent |cur_exp| into a big node@>;
17198     } else { 
17199       mp->mem[value_loc(p)]=mp->mem[value_loc(mp->cur_exp)];
17200       /* |dep_list(p):=dep_list(cur_exp)| and |prev_dep(p):=prev_dep(cur_exp)| */
17201       link(prev_dep(p))=p;
17202     }
17203     mp_free_node(mp, mp->cur_exp,value_node_size);
17204   }
17205   mp->cur_type=mp_vacuous;
17206 }
17207
17208 @ In rare cases the current expression can become |independent|. There
17209 may be many dependency lists pointing to such an independent capsule,
17210 so we can't simply move it into place within a big node. Instead,
17211 we copy it, then recycle it.
17212
17213 @ @<Stash an independent |cur_exp|...@>=
17214
17215   q=mp_single_dependency(mp, mp->cur_exp);
17216   if ( q==mp->dep_final ){ 
17217     type(p)=mp_known; value(p)=0; mp_free_node(mp, q,dep_node_size);
17218   } else { 
17219     type(p)=mp_dependent; mp_new_dep(mp, p,q);
17220   }
17221   mp_recycle_value(mp, mp->cur_exp);
17222 }
17223
17224 @ This code uses the fact that |red_part_loc| and |green_part_loc|
17225 are synonymous with |x_part_loc| and |y_part_loc|.
17226
17227 @<Scan the rest of a delimited set of numerics@>=
17228
17229 p=mp_stash_cur_exp(mp);
17230 mp_get_x_next(mp); mp_scan_expression(mp);
17231 @<Make sure the second part of a pair or color has a numeric type@>;
17232 q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
17233 if ( mp->cur_cmd==comma ) type(q)=mp_color_type;
17234 else type(q)=mp_pair_type;
17235 mp_init_big_node(mp, q); r=value(q);
17236 mp_stash_in(mp, y_part_loc(r));
17237 mp_unstash_cur_exp(mp, p);
17238 mp_stash_in(mp, x_part_loc(r));
17239 if ( mp->cur_cmd==comma ) {
17240   @<Scan the last of a triplet of numerics@>;
17241 }
17242 if ( mp->cur_cmd==comma ) {
17243   type(q)=mp_cmykcolor_type;
17244   mp_init_big_node(mp, q); t=value(q);
17245   mp->mem[cyan_part_loc(t)]=mp->mem[red_part_loc(r)];
17246   value(cyan_part_loc(t))=value(red_part_loc(r));
17247   mp->mem[magenta_part_loc(t)]=mp->mem[green_part_loc(r)];
17248   value(magenta_part_loc(t))=value(green_part_loc(r));
17249   mp->mem[yellow_part_loc(t)]=mp->mem[blue_part_loc(r)];
17250   value(yellow_part_loc(t))=value(blue_part_loc(r));
17251   mp_recycle_value(mp, r);
17252   r=t;
17253   @<Scan the last of a quartet of numerics@>;
17254 }
17255 mp_check_delimiter(mp, l_delim,r_delim);
17256 mp->cur_type=type(q);
17257 mp->cur_exp=q;
17258 }
17259
17260 @ @<Make sure the second part of a pair or color has a numeric type@>=
17261 if ( mp->cur_type<mp_known ) {
17262   exp_err("Nonnumeric ypart has been replaced by 0");
17263 @.Nonnumeric...replaced by 0@>
17264   help4("I've started to scan a pair `(a,b)' or a color `(a,b,c)';")
17265     ("but after finding a nice `a' I found a `b' that isn't")
17266     ("of numeric type. So I've changed that part to zero.")
17267     ("(The b that I didn't like appears above the error message.)");
17268   mp_put_get_flush_error(mp, 0);
17269 }
17270
17271 @ @<Scan the last of a triplet of numerics@>=
17272
17273   mp_get_x_next(mp); mp_scan_expression(mp);
17274   if ( mp->cur_type<mp_known ) {
17275     exp_err("Nonnumeric third part has been replaced by 0");
17276 @.Nonnumeric...replaced by 0@>
17277     help3("I've just scanned a color `(a,b,c)' or cmykcolor(a,b,c,d); but the `c'")
17278       ("isn't of numeric type. So I've changed that part to zero.")
17279       ("(The c that I didn't like appears above the error message.)");
17280     mp_put_get_flush_error(mp, 0);
17281   }
17282   mp_stash_in(mp, blue_part_loc(r));
17283 }
17284
17285 @ @<Scan the last of a quartet of numerics@>=
17286
17287   mp_get_x_next(mp); mp_scan_expression(mp);
17288   if ( mp->cur_type<mp_known ) {
17289     exp_err("Nonnumeric blackpart has been replaced by 0");
17290 @.Nonnumeric...replaced by 0@>
17291     help3("I've just scanned a cmykcolor `(c,m,y,k)'; but the `k' isn't")
17292       ("of numeric type. So I've changed that part to zero.")
17293       ("(The k that I didn't like appears above the error message.)");
17294     mp_put_get_flush_error(mp, 0);
17295   }
17296   mp_stash_in(mp, black_part_loc(r));
17297 }
17298
17299 @ The local variable |group_line| keeps track of the line
17300 where a \&{begingroup} command occurred; this will be useful
17301 in an error message if the group doesn't actually end.
17302
17303 @<Other local variables for |scan_primary|@>=
17304 integer group_line; /* where a group began */
17305
17306 @ @<Scan a grouped primary@>=
17307
17308   group_line=mp_true_line(mp);
17309   if ( mp->internal[mp_tracing_commands]>0 ) show_cur_cmd_mod;
17310   save_boundary_item(p);
17311   do {  
17312     mp_do_statement(mp); /* ends with |cur_cmd>=semicolon| */
17313   } while (! (mp->cur_cmd!=semicolon));
17314   if ( mp->cur_cmd!=end_group ) {
17315     print_err("A group begun on line ");
17316 @.A group...never ended@>
17317     mp_print_int(mp, group_line);
17318     mp_print(mp, " never ended");
17319     help2("I saw a `begingroup' back there that hasn't been matched")
17320          ("by `endgroup'. So I've inserted `endgroup' now.");
17321     mp_back_error(mp); mp->cur_cmd=end_group;
17322   }
17323   mp_unsave(mp); 
17324     /* this might change |cur_type|, if independent variables are recycled */
17325   if ( mp->internal[mp_tracing_commands]>0 ) show_cur_cmd_mod;
17326 }
17327
17328 @ @<Scan a string constant@>=
17329
17330   mp->cur_type=mp_string_type; mp->cur_exp=mp->cur_mod;
17331 }
17332
17333 @ Later we'll come to procedures that perform actual operations like
17334 addition, square root, and so on; our purpose now is to do the parsing.
17335 But we might as well mention those future procedures now, so that the
17336 suspense won't be too bad:
17337
17338 \smallskip
17339 |do_nullary(c)| does primitive operations that have no operands (e.g.,
17340 `\&{true}' or `\&{pencircle}');
17341
17342 \smallskip
17343 |do_unary(c)| applies a primitive operation to the current expression;
17344
17345 \smallskip
17346 |do_binary(p,c)| applies a primitive operation to the capsule~|p|
17347 and the current expression.
17348
17349 @<Scan a nullary operation@>=mp_do_nullary(mp, mp->cur_mod)
17350
17351 @ @<Scan a unary operation@>=
17352
17353   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_primary(mp); 
17354   mp_do_unary(mp, c); goto DONE;
17355 }
17356
17357 @ A numeric token might be a primary by itself, or it might be the
17358 numerator of a fraction composed solely of numeric tokens, or it might
17359 multiply the primary that follows (provided that the primary doesn't begin
17360 with a plus sign or a minus sign). The code here uses the facts that
17361 |max_primary_command=plus_or_minus| and
17362 |max_primary_command-1=numeric_token|. If a fraction is found that is less
17363 than unity, we try to retain higher precision when we use it in scalar
17364 multiplication.
17365
17366 @<Other local variables for |scan_primary|@>=
17367 scaled num,denom; /* for primaries that are fractions, like `1/2' */
17368
17369 @ @<Scan a primary that starts with a numeric token@>=
17370
17371   mp->cur_exp=mp->cur_mod; mp->cur_type=mp_known; mp_get_x_next(mp);
17372   if ( mp->cur_cmd!=slash ) { 
17373     num=0; denom=0;
17374   } else { 
17375     mp_get_x_next(mp);
17376     if ( mp->cur_cmd!=numeric_token ) { 
17377       mp_back_input(mp);
17378       mp->cur_cmd=slash; mp->cur_mod=over; mp->cur_sym=frozen_slash;
17379       goto DONE;
17380     }
17381     num=mp->cur_exp; denom=mp->cur_mod;
17382     if ( denom==0 ) { @<Protest division by zero@>; }
17383     else { mp->cur_exp=mp_make_scaled(mp, num,denom); }
17384     check_arith; mp_get_x_next(mp);
17385   }
17386   if ( mp->cur_cmd>=min_primary_command ) {
17387    if ( mp->cur_cmd<numeric_token ) { /* in particular, |cur_cmd<>plus_or_minus| */
17388      p=mp_stash_cur_exp(mp); mp_scan_primary(mp);
17389      if ( (abs(num)>=abs(denom))||(mp->cur_type<mp_color_type) ) {
17390        mp_do_binary(mp, p,times);
17391      } else {
17392        mp_frac_mult(mp, num,denom);
17393        mp_free_node(mp, p,value_node_size);
17394      }
17395     }
17396   }
17397   goto DONE;
17398 }
17399
17400 @ @<Protest division...@>=
17401
17402   print_err("Division by zero");
17403 @.Division by zero@>
17404   help1("I'll pretend that you meant to divide by 1."); mp_error(mp);
17405 }
17406
17407 @ @<Scan a binary operation with `\&{of}' between its operands@>=
17408
17409   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
17410   if ( mp->cur_cmd!=of_token ) {
17411     mp_missing_err(mp, "of"); mp_print(mp, " for "); 
17412     mp_print_cmd_mod(mp, primary_binary,c);
17413 @.Missing `of'@>
17414     help1("I've got the first argument; will look now for the other.");
17415     mp_back_error(mp);
17416   }
17417   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_primary(mp); 
17418   mp_do_binary(mp, p,c); goto DONE;
17419 }
17420
17421 @ @<Convert a suffix to a string@>=
17422
17423   mp_get_x_next(mp); mp_scan_suffix(mp); 
17424   mp->old_setting=mp->selector; mp->selector=new_string;
17425   mp_show_token_list(mp, mp->cur_exp,null,100000,0); 
17426   mp_flush_token_list(mp, mp->cur_exp);
17427   mp->cur_exp=mp_make_string(mp); mp->selector=mp->old_setting; 
17428   mp->cur_type=mp_string_type;
17429   goto DONE;
17430 }
17431
17432 @ If an internal quantity appears all by itself on the left of an
17433 assignment, we return a token list of length one, containing the address
17434 of the internal quantity plus |hash_end|. (This accords with the conventions
17435 of the save stack, as described earlier.)
17436
17437 @<Scan an internal...@>=
17438
17439   q=mp->cur_mod;
17440   if ( my_var_flag==assignment ) {
17441     mp_get_x_next(mp);
17442     if ( mp->cur_cmd==assignment ) {
17443       mp->cur_exp=mp_get_avail(mp);
17444       info(mp->cur_exp)=q+hash_end; mp->cur_type=mp_token_list; 
17445       goto DONE;
17446     }
17447     mp_back_input(mp);
17448   }
17449   mp->cur_type=mp_known; mp->cur_exp=mp->internal[q];
17450 }
17451
17452 @ The most difficult part of |scan_primary| has been saved for last, since
17453 it was necessary to build up some confidence first. We can now face the task
17454 of scanning a variable.
17455
17456 As we scan a variable, we build a token list containing the relevant
17457 names and subscript values, simultaneously following along in the
17458 ``collective'' structure to see if we are actually dealing with a macro
17459 instead of a value.
17460
17461 The local variables |pre_head| and |post_head| will point to the beginning
17462 of the prefix and suffix lists; |tail| will point to the end of the list
17463 that is currently growing.
17464
17465 Another local variable, |tt|, contains partial information about the
17466 declared type of the variable-so-far. If |tt>=mp_unsuffixed_macro|, the
17467 relation |tt=type(q)| will always hold. If |tt=undefined|, the routine
17468 doesn't bother to update its information about type. And if
17469 |undefined<tt<mp_unsuffixed_macro|, the precise value of |tt| isn't critical.
17470
17471 @ @<Other local variables for |scan_primary|@>=
17472 pointer pre_head,post_head,tail;
17473   /* prefix and suffix list variables */
17474 small_number tt; /* approximation to the type of the variable-so-far */
17475 pointer t; /* a token */
17476 pointer macro_ref = 0; /* reference count for a suffixed macro */
17477
17478 @ @<Scan a variable primary...@>=
17479
17480   fast_get_avail(pre_head); tail=pre_head; post_head=null; tt=mp_vacuous;
17481   while (1) { 
17482     t=mp_cur_tok(mp); link(tail)=t;
17483     if ( tt!=undefined ) {
17484        @<Find the approximate type |tt| and corresponding~|q|@>;
17485       if ( tt>=mp_unsuffixed_macro ) {
17486         @<Either begin an unsuffixed macro call or
17487           prepare for a suffixed one@>;
17488       }
17489     }
17490     mp_get_x_next(mp); tail=t;
17491     if ( mp->cur_cmd==left_bracket ) {
17492       @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>;
17493     }
17494     if ( mp->cur_cmd>max_suffix_token ) break;
17495     if ( mp->cur_cmd<min_suffix_token ) break;
17496   } /* now |cur_cmd| is |internal_quantity|, |tag_token|, or |numeric_token| */
17497   @<Handle unusual cases that masquerade as variables, and |goto restart|
17498     or |goto done| if appropriate;
17499     otherwise make a copy of the variable and |goto done|@>;
17500 }
17501
17502 @ @<Either begin an unsuffixed macro call or...@>=
17503
17504   link(tail)=null;
17505   if ( tt>mp_unsuffixed_macro ) { /* |tt=mp_suffixed_macro| */
17506     post_head=mp_get_avail(mp); tail=post_head; link(tail)=t;
17507     tt=undefined; macro_ref=value(q); add_mac_ref(macro_ref);
17508   } else {
17509     @<Set up unsuffixed macro call and |goto restart|@>;
17510   }
17511 }
17512
17513 @ @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>=
17514
17515   mp_get_x_next(mp); mp_scan_expression(mp);
17516   if ( mp->cur_cmd!=right_bracket ) {
17517     @<Put the left bracket and the expression back to be rescanned@>;
17518   } else { 
17519     if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17520     mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp; mp->cur_sym=0;
17521   }
17522 }
17523
17524 @ The left bracket that we thought was introducing a subscript might have
17525 actually been the left bracket in a mediation construction like `\.{x[a,b]}'.
17526 So we don't issue an error message at this point; but we do want to back up
17527 so as to avoid any embarrassment about our incorrect assumption.
17528
17529 @<Put the left bracket and the expression back to be rescanned@>=
17530
17531   mp_back_input(mp); /* that was the token following the current expression */
17532   mp_back_expr(mp); mp->cur_cmd=left_bracket; 
17533   mp->cur_mod=0; mp->cur_sym=frozen_left_bracket;
17534 }
17535
17536 @ Here's a routine that puts the current expression back to be read again.
17537
17538 @c void mp_back_expr (MP mp) {
17539   pointer p; /* capsule token */
17540   p=mp_stash_cur_exp(mp); link(p)=null; back_list(p);
17541 }
17542
17543 @ Unknown subscripts lead to the following error message.
17544
17545 @c void mp_bad_subscript (MP mp) { 
17546   exp_err("Improper subscript has been replaced by zero");
17547 @.Improper subscript...@>
17548   help3("A bracketed subscript must have a known numeric value;")
17549     ("unfortunately, what I found was the value that appears just")
17550     ("above this error message. So I'll try a zero subscript.");
17551   mp_flush_error(mp, 0);
17552 }
17553
17554 @ Every time we call |get_x_next|, there's a chance that the variable we've
17555 been looking at will disappear. Thus, we cannot safely keep |q| pointing
17556 into the variable structure; we need to start searching from the root each time.
17557
17558 @<Find the approximate type |tt| and corresponding~|q|@>=
17559 @^inner loop@>
17560
17561   p=link(pre_head); q=info(p); tt=undefined;
17562   if ( eq_type(q) % outer_tag==tag_token ) {
17563     q=equiv(q);
17564     if ( q==null ) goto DONE2;
17565     while (1) { 
17566       p=link(p);
17567       if ( p==null ) {
17568         tt=type(q); goto DONE2;
17569       };
17570       if ( type(q)!=mp_structured ) goto DONE2;
17571       q=link(attr_head(q)); /* the |collective_subscript| attribute */
17572       if ( p>=mp->hi_mem_min ) { /* it's not a subscript */
17573         do {  q=link(q); } while (! (attr_loc(q)>=info(p)));
17574         if ( attr_loc(q)>info(p) ) goto DONE2;
17575       }
17576     }
17577   }
17578 DONE2:
17579   ;
17580 }
17581
17582 @ How do things stand now? Well, we have scanned an entire variable name,
17583 including possible subscripts and/or attributes; |cur_cmd|, |cur_mod|, and
17584 |cur_sym| represent the token that follows. If |post_head=null|, a
17585 token list for this variable name starts at |link(pre_head)|, with all
17586 subscripts evaluated. But if |post_head<>null|, the variable turned out
17587 to be a suffixed macro; |pre_head| is the head of the prefix list, while
17588 |post_head| is the head of a token list containing both `\.{\AT!}' and
17589 the suffix.
17590
17591 Our immediate problem is to see if this variable still exists. (Variable
17592 structures can change drastically whenever we call |get_x_next|; users
17593 aren't supposed to do this, but the fact that it is possible means that
17594 we must be cautious.)
17595
17596 The following procedure prints an error message when a variable
17597 unexpectedly disappears. Its help message isn't quite right for
17598 our present purposes, but we'll be able to fix that up.
17599
17600 @c 
17601 void mp_obliterated (MP mp,pointer q) { 
17602   print_err("Variable "); mp_show_token_list(mp, q,null,1000,0);
17603   mp_print(mp, " has been obliterated");
17604 @.Variable...obliterated@>
17605   help5("It seems you did a nasty thing---probably by accident,")
17606     ("but nevertheless you nearly hornswoggled me...")
17607     ("While I was evaluating the right-hand side of this")
17608     ("command, something happened, and the left-hand side")
17609     ("is no longer a variable! So I won't change anything.");
17610 }
17611
17612 @ If the variable does exist, we also need to check
17613 for a few other special cases before deciding that a plain old ordinary
17614 variable has, indeed, been scanned.
17615
17616 @<Handle unusual cases that masquerade as variables...@>=
17617 if ( post_head!=null ) {
17618   @<Set up suffixed macro call and |goto restart|@>;
17619 }
17620 q=link(pre_head); free_avail(pre_head);
17621 if ( mp->cur_cmd==my_var_flag ) { 
17622   mp->cur_type=mp_token_list; mp->cur_exp=q; goto DONE;
17623 }
17624 p=mp_find_variable(mp, q);
17625 if ( p!=null ) {
17626   mp_make_exp_copy(mp, p);
17627 } else { 
17628   mp_obliterated(mp, q);
17629   mp->help_line[2]="While I was evaluating the suffix of this variable,";
17630   mp->help_line[1]="something was redefined, and it's no longer a variable!";
17631   mp->help_line[0]="In order to get back on my feet, I've inserted `0' instead.";
17632   mp_put_get_flush_error(mp, 0);
17633 }
17634 mp_flush_node_list(mp, q); 
17635 goto DONE
17636
17637 @ The only complication associated with macro calling is that the prefix
17638 and ``at'' parameters must be packaged in an appropriate list of lists.
17639
17640 @<Set up unsuffixed macro call and |goto restart|@>=
17641
17642   p=mp_get_avail(mp); info(pre_head)=link(pre_head); link(pre_head)=p;
17643   info(p)=t; mp_macro_call(mp, value(q),pre_head,null);
17644   mp_get_x_next(mp); 
17645   goto RESTART;
17646 }
17647
17648 @ If the ``variable'' that turned out to be a suffixed macro no longer exists,
17649 we don't care, because we have reserved a pointer (|macro_ref|) to its
17650 token list.
17651
17652 @<Set up suffixed macro call and |goto restart|@>=
17653
17654   mp_back_input(mp); p=mp_get_avail(mp); q=link(post_head);
17655   info(pre_head)=link(pre_head); link(pre_head)=post_head;
17656   info(post_head)=q; link(post_head)=p; info(p)=link(q); link(q)=null;
17657   mp_macro_call(mp, macro_ref,pre_head,null); decr(ref_count(macro_ref));
17658   mp_get_x_next(mp); goto RESTART;
17659 }
17660
17661 @ Our remaining job is simply to make a copy of the value that has been
17662 found. Some cases are harder than others, but complexity arises solely
17663 because of the multiplicity of possible cases.
17664
17665 @<Declare the procedure called |make_exp_copy|@>=
17666 @<Declare subroutines needed by |make_exp_copy|@>;
17667 void mp_make_exp_copy (MP mp,pointer p) {
17668   pointer q,r,t; /* registers for list manipulation */
17669 RESTART: 
17670   mp->cur_type=type(p);
17671   switch (mp->cur_type) {
17672   case mp_vacuous: case mp_boolean_type: case mp_known:
17673     mp->cur_exp=value(p); break;
17674   case unknown_types:
17675     mp->cur_exp=mp_new_ring_entry(mp, p);
17676     break;
17677   case mp_string_type: 
17678     mp->cur_exp=value(p); add_str_ref(mp->cur_exp);
17679     break;
17680   case mp_picture_type:
17681     mp->cur_exp=value(p);add_edge_ref(mp->cur_exp);
17682     break;
17683   case mp_pen_type:
17684     mp->cur_exp=copy_pen(value(p));
17685     break; 
17686   case mp_path_type:
17687     mp->cur_exp=mp_copy_path(mp, value(p));
17688     break;
17689   case mp_transform_type: case mp_color_type: 
17690   case mp_cmykcolor_type: case mp_pair_type:
17691     @<Copy the big node |p|@>;
17692     break;
17693   case mp_dependent: case mp_proto_dependent:
17694     mp_encapsulate(mp, mp_copy_dep_list(mp, dep_list(p)));
17695     break;
17696   case mp_numeric_type: 
17697     new_indep(p); goto RESTART;
17698     break;
17699   case mp_independent: 
17700     q=mp_single_dependency(mp, p);
17701     if ( q==mp->dep_final ){ 
17702       mp->cur_type=mp_known; mp->cur_exp=0; mp_free_node(mp, q,value_node_size);
17703     } else { 
17704       mp->cur_type=mp_dependent; mp_encapsulate(mp, q);
17705     }
17706     break;
17707   default: 
17708     mp_confusion(mp, "copy");
17709 @:this can't happen copy}{\quad copy@>
17710     break;
17711   }
17712 }
17713
17714 @ The |encapsulate| subroutine assumes that |dep_final| is the
17715 tail of dependency list~|p|.
17716
17717 @<Declare subroutines needed by |make_exp_copy|@>=
17718 void mp_encapsulate (MP mp,pointer p) { 
17719   mp->cur_exp=mp_get_node(mp, value_node_size); type(mp->cur_exp)=mp->cur_type;
17720   name_type(mp->cur_exp)=mp_capsule; mp_new_dep(mp, mp->cur_exp,p);
17721 }
17722
17723 @ The most tedious case arises when the user refers to a
17724 \&{pair}, \&{color}, or \&{transform} variable; we must copy several fields,
17725 each of which can be |independent|, |dependent|, |mp_proto_dependent|,
17726 or |known|.
17727
17728 @<Copy the big node |p|@>=
17729
17730   if ( value(p)==null ) 
17731     mp_init_big_node(mp, p);
17732   t=mp_get_node(mp, value_node_size); name_type(t)=mp_capsule; type(t)=mp->cur_type;
17733   mp_init_big_node(mp, t);
17734   q=value(p)+mp->big_node_size[mp->cur_type]; 
17735   r=value(t)+mp->big_node_size[mp->cur_type];
17736   do {  
17737     q=q-2; r=r-2; mp_install(mp, r,q);
17738   } while (q!=value(p));
17739   mp->cur_exp=t;
17740 }
17741
17742 @ The |install| procedure copies a numeric field~|q| into field~|r| of
17743 a big node that will be part of a capsule.
17744
17745 @<Declare subroutines needed by |make_exp_copy|@>=
17746 void mp_install (MP mp,pointer r, pointer q) {
17747   pointer p; /* temporary register */
17748   if ( type(q)==mp_known ){ 
17749     value(r)=value(q); type(r)=mp_known;
17750   } else  if ( type(q)==mp_independent ) {
17751     p=mp_single_dependency(mp, q);
17752     if ( p==mp->dep_final ) {
17753       type(r)=mp_known; value(r)=0; mp_free_node(mp, p,value_node_size);
17754     } else  { 
17755       type(r)=mp_dependent; mp_new_dep(mp, r,p);
17756     }
17757   } else {
17758     type(r)=type(q); mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(q)));
17759   }
17760 }
17761
17762 @ Expressions of the form `\.{a[b,c]}' are converted into
17763 `\.{b+a*(c-b)}', without checking the types of \.b~or~\.c,
17764 provided that \.a is numeric.
17765
17766 @<Scan a mediation...@>=
17767
17768   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17769   if ( mp->cur_cmd!=comma ) {
17770     @<Put the left bracket and the expression back...@>;
17771     mp_unstash_cur_exp(mp, p);
17772   } else { 
17773     q=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17774     if ( mp->cur_cmd!=right_bracket ) {
17775       mp_missing_err(mp, "]");
17776 @.Missing `]'@>
17777       help3("I've scanned an expression of the form `a[b,c',")
17778       ("so a right bracket should have come next.")
17779       ("I shall pretend that one was there.");
17780       mp_back_error(mp);
17781     }
17782     r=mp_stash_cur_exp(mp); mp_make_exp_copy(mp, q);
17783     mp_do_binary(mp, r,minus); mp_do_binary(mp, p,times); 
17784     mp_do_binary(mp, q,plus); mp_get_x_next(mp);
17785   }
17786 }
17787
17788 @ Here is a comparatively simple routine that is used to scan the
17789 \&{suffix} parameters of a macro.
17790
17791 @<Declare the basic parsing subroutines@>=
17792 void mp_scan_suffix (MP mp) {
17793   pointer h,t; /* head and tail of the list being built */
17794   pointer p; /* temporary register */
17795   h=mp_get_avail(mp); t=h;
17796   while (1) { 
17797     if ( mp->cur_cmd==left_bracket ) {
17798       @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>;
17799     }
17800     if ( mp->cur_cmd==numeric_token ) {
17801       p=mp_new_num_tok(mp, mp->cur_mod);
17802     } else if ((mp->cur_cmd==tag_token)||(mp->cur_cmd==internal_quantity) ) {
17803        p=mp_get_avail(mp); info(p)=mp->cur_sym;
17804     } else {
17805       break;
17806     }
17807     link(t)=p; t=p; mp_get_x_next(mp);
17808   }
17809   mp->cur_exp=link(h); free_avail(h); mp->cur_type=mp_token_list;
17810 }
17811
17812 @ @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>=
17813
17814   mp_get_x_next(mp); mp_scan_expression(mp);
17815   if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17816   if ( mp->cur_cmd!=right_bracket ) {
17817      mp_missing_err(mp, "]");
17818 @.Missing `]'@>
17819     help3("I've seen a `[' and a subscript value, in a suffix,")
17820       ("so a right bracket should have come next.")
17821       ("I shall pretend that one was there.");
17822     mp_back_error(mp);
17823   }
17824   mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp;
17825 }
17826
17827 @* \[38] Parsing secondary and higher expressions.
17828
17829 After the intricacies of |scan_primary|\kern-1pt,
17830 the |scan_secondary| routine is
17831 refreshingly simple. It's not trivial, but the operations are relatively
17832 straightforward; the main difficulty is, again, that expressions and data
17833 structures might change drastically every time we call |get_x_next|, so a
17834 cautious approach is mandatory. For example, a macro defined by
17835 \&{primarydef} might have disappeared by the time its second argument has
17836 been scanned; we solve this by increasing the reference count of its token
17837 list, so that the macro can be called even after it has been clobbered.
17838
17839 @<Declare the basic parsing subroutines@>=
17840 void mp_scan_secondary (MP mp) {
17841   pointer p; /* for list manipulation */
17842   halfword c,d; /* operation codes or modifiers */
17843   pointer mac_name; /* token defined with \&{primarydef} */
17844 RESTART:
17845   if ((mp->cur_cmd<min_primary_command)||
17846       (mp->cur_cmd>max_primary_command) )
17847     mp_bad_exp(mp, "A secondary");
17848 @.A secondary expression...@>
17849   mp_scan_primary(mp);
17850 CONTINUE: 
17851   if ( mp->cur_cmd<=max_secondary_command )
17852     if ( mp->cur_cmd>=min_secondary_command ) {
17853       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17854       if ( d==secondary_primary_macro ) { 
17855         mac_name=mp->cur_sym; add_mac_ref(c);
17856      }
17857      mp_get_x_next(mp); mp_scan_primary(mp);
17858      if ( d!=secondary_primary_macro ) {
17859        mp_do_binary(mp, p,c);
17860      } else  { 
17861        mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17862        decr(ref_count(c)); mp_get_x_next(mp); 
17863        goto RESTART;
17864     }
17865     goto CONTINUE;
17866   }
17867 }
17868
17869 @ The following procedure calls a macro that has two parameters,
17870 |p| and |cur_exp|.
17871
17872 @c void mp_binary_mac (MP mp,pointer p, pointer c, pointer n) {
17873   pointer q,r; /* nodes in the parameter list */
17874   q=mp_get_avail(mp); r=mp_get_avail(mp); link(q)=r;
17875   info(q)=p; info(r)=mp_stash_cur_exp(mp);
17876   mp_macro_call(mp, c,q,n);
17877 }
17878
17879 @ The next procedure, |scan_tertiary|, is pretty much the same deal.
17880
17881 @<Declare the basic parsing subroutines@>=
17882 void mp_scan_tertiary (MP mp) {
17883   pointer p; /* for list manipulation */
17884   halfword c,d; /* operation codes or modifiers */
17885   pointer mac_name; /* token defined with \&{secondarydef} */
17886 RESTART:
17887   if ((mp->cur_cmd<min_primary_command)||
17888       (mp->cur_cmd>max_primary_command) )
17889     mp_bad_exp(mp, "A tertiary");
17890 @.A tertiary expression...@>
17891   mp_scan_secondary(mp);
17892 CONTINUE: 
17893   if ( mp->cur_cmd<=max_tertiary_command ) {
17894     if ( mp->cur_cmd>=min_tertiary_command ) {
17895       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17896       if ( d==tertiary_secondary_macro ) { 
17897         mac_name=mp->cur_sym; add_mac_ref(c);
17898       };
17899       mp_get_x_next(mp); mp_scan_secondary(mp);
17900       if ( d!=tertiary_secondary_macro ) {
17901         mp_do_binary(mp, p,c);
17902       } else { 
17903         mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17904         decr(ref_count(c)); mp_get_x_next(mp); 
17905         goto RESTART;
17906       }
17907       goto CONTINUE;
17908     }
17909   }
17910 }
17911
17912 @ Finally we reach the deepest level in our quartet of parsing routines.
17913 This one is much like the others; but it has an extra complication from
17914 paths, which materialize here.
17915
17916 @d continue_path 25 /* a label inside of |scan_expression| */
17917 @d finish_path 26 /* another */
17918
17919 @<Declare the basic parsing subroutines@>=
17920 void mp_scan_expression (MP mp) {
17921   pointer p,q,r,pp,qq; /* for list manipulation */
17922   halfword c,d; /* operation codes or modifiers */
17923   int my_var_flag; /* initial value of |var_flag| */
17924   pointer mac_name; /* token defined with \&{tertiarydef} */
17925   boolean cycle_hit; /* did a path expression just end with `\&{cycle}'? */
17926   scaled x,y; /* explicit coordinates or tension at a path join */
17927   int t; /* knot type following a path join */
17928   t=0; y=0; x=0;
17929   my_var_flag=mp->var_flag; mac_name=null;
17930 RESTART:
17931   if ((mp->cur_cmd<min_primary_command)||
17932       (mp->cur_cmd>max_primary_command) )
17933     mp_bad_exp(mp, "An");
17934 @.An expression...@>
17935   mp_scan_tertiary(mp);
17936 CONTINUE: 
17937   if ( mp->cur_cmd<=max_expression_command )
17938     if ( mp->cur_cmd>=min_expression_command ) {
17939       if ( (mp->cur_cmd!=equals)||(my_var_flag!=assignment) ) {
17940         p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17941         if ( d==expression_tertiary_macro ) {
17942           mac_name=mp->cur_sym; add_mac_ref(c);
17943         }
17944         if ( (d<ampersand)||((d==ampersand)&&
17945              ((type(p)==mp_pair_type)||(type(p)==mp_path_type))) ) {
17946           @<Scan a path construction operation;
17947             but |return| if |p| has the wrong type@>;
17948         } else { 
17949           mp_get_x_next(mp); mp_scan_tertiary(mp);
17950           if ( d!=expression_tertiary_macro ) {
17951             mp_do_binary(mp, p,c);
17952           } else  { 
17953             mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17954             decr(ref_count(c)); mp_get_x_next(mp); 
17955             goto RESTART;
17956           }
17957         }
17958         goto CONTINUE;
17959      }
17960   }
17961 }
17962
17963 @ The reader should review the data structure conventions for paths before
17964 hoping to understand the next part of this code.
17965
17966 @<Scan a path construction operation...@>=
17967
17968   cycle_hit=false;
17969   @<Convert the left operand, |p|, into a partial path ending at~|q|;
17970     but |return| if |p| doesn't have a suitable type@>;
17971 CONTINUE_PATH: 
17972   @<Determine the path join parameters;
17973     but |goto finish_path| if there's only a direction specifier@>;
17974   if ( mp->cur_cmd==cycle ) {
17975     @<Get ready to close a cycle@>;
17976   } else { 
17977     mp_scan_tertiary(mp);
17978     @<Convert the right operand, |cur_exp|,
17979       into a partial path from |pp| to~|qq|@>;
17980   }
17981   @<Join the partial paths and reset |p| and |q| to the head and tail
17982     of the result@>;
17983   if ( mp->cur_cmd>=min_expression_command )
17984     if ( mp->cur_cmd<=ampersand ) if ( ! cycle_hit ) goto CONTINUE_PATH;
17985 FINISH_PATH:
17986   @<Choose control points for the path and put the result into |cur_exp|@>;
17987 }
17988
17989 @ @<Convert the left operand, |p|, into a partial path ending at~|q|...@>=
17990
17991   mp_unstash_cur_exp(mp, p);
17992   if ( mp->cur_type==mp_pair_type ) p=mp_new_knot(mp);
17993   else if ( mp->cur_type==mp_path_type ) p=mp->cur_exp;
17994   else return;
17995   q=p;
17996   while ( link(q)!=p ) q=link(q);
17997   if ( left_type(p)!=mp_endpoint ) { /* open up a cycle */
17998     r=mp_copy_knot(mp, p); link(q)=r; q=r;
17999   }
18000   left_type(p)=mp_open; right_type(q)=mp_open;
18001 }
18002
18003 @ A pair of numeric values is changed into a knot node for a one-point path
18004 when \MP\ discovers that the pair is part of a path.
18005
18006 @c@<Declare the procedure called |known_pair|@>;
18007 pointer mp_new_knot (MP mp) { /* convert a pair to a knot with two endpoints */
18008   pointer q; /* the new node */
18009   q=mp_get_node(mp, knot_node_size); left_type(q)=mp_endpoint;
18010   right_type(q)=mp_endpoint; originator(q)=mp_metapost_user; link(q)=q;
18011   mp_known_pair(mp); x_coord(q)=mp->cur_x; y_coord(q)=mp->cur_y;
18012   return q;
18013 }
18014
18015 @ The |known_pair| subroutine sets |cur_x| and |cur_y| to the components
18016 of the current expression, assuming that the current expression is a
18017 pair of known numerics. Unknown components are zeroed, and the
18018 current expression is flushed.
18019
18020 @<Declare the procedure called |known_pair|@>=
18021 void mp_known_pair (MP mp) {
18022   pointer p; /* the pair node */
18023   if ( mp->cur_type!=mp_pair_type ) {
18024     exp_err("Undefined coordinates have been replaced by (0,0)");
18025 @.Undefined coordinates...@>
18026     help5("I need x and y numbers for this part of the path.")
18027       ("The value I found (see above) was no good;")
18028       ("so I'll try to keep going by using zero instead.")
18029       ("(Chapter 27 of The METAFONTbook explains that")
18030 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18031       ("you might want to type `I ??" "?' now.)");
18032     mp_put_get_flush_error(mp, 0); mp->cur_x=0; mp->cur_y=0;
18033   } else { 
18034     p=value(mp->cur_exp);
18035      @<Make sure that both |x| and |y| parts of |p| are known;
18036        copy them into |cur_x| and |cur_y|@>;
18037     mp_flush_cur_exp(mp, 0);
18038   }
18039 }
18040
18041 @ @<Make sure that both |x| and |y| parts of |p| are known...@>=
18042 if ( type(x_part_loc(p))==mp_known ) {
18043   mp->cur_x=value(x_part_loc(p));
18044 } else { 
18045   mp_disp_err(mp, x_part_loc(p),
18046     "Undefined x coordinate has been replaced by 0");
18047 @.Undefined coordinates...@>
18048   help5("I need a `known' x value for this part of the path.")
18049     ("The value I found (see above) was no good;")
18050     ("so I'll try to keep going by using zero instead.")
18051     ("(Chapter 27 of The METAFONTbook explains that")
18052 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18053     ("you might want to type `I ??" "?' now.)");
18054   mp_put_get_error(mp); mp_recycle_value(mp, x_part_loc(p)); mp->cur_x=0;
18055 }
18056 if ( type(y_part_loc(p))==mp_known ) {
18057   mp->cur_y=value(y_part_loc(p));
18058 } else { 
18059   mp_disp_err(mp, y_part_loc(p),
18060     "Undefined y coordinate has been replaced by 0");
18061   help5("I need a `known' y value for this part of the path.")
18062     ("The value I found (see above) was no good;")
18063     ("so I'll try to keep going by using zero instead.")
18064     ("(Chapter 27 of The METAFONTbook explains that")
18065     ("you might want to type `I ??" "?' now.)");
18066   mp_put_get_error(mp); mp_recycle_value(mp, y_part_loc(p)); mp->cur_y=0;
18067 }
18068
18069 @ At this point |cur_cmd| is either |ampersand|, |left_brace|, or |path_join|.
18070
18071 @<Determine the path join parameters...@>=
18072 if ( mp->cur_cmd==left_brace ) {
18073   @<Put the pre-join direction information into node |q|@>;
18074 }
18075 d=mp->cur_cmd;
18076 if ( d==path_join ) {
18077   @<Determine the tension and/or control points@>;
18078 } else if ( d!=ampersand ) {
18079   goto FINISH_PATH;
18080 }
18081 mp_get_x_next(mp);
18082 if ( mp->cur_cmd==left_brace ) {
18083   @<Put the post-join direction information into |x| and |t|@>;
18084 } else if ( right_type(q)!=mp_explicit ) {
18085   t=mp_open; x=0;
18086 }
18087
18088 @ The |scan_direction| subroutine looks at the directional information
18089 that is enclosed in braces, and also scans ahead to the following character.
18090 A type code is returned, either |open| (if the direction was $(0,0)$),
18091 or |curl| (if the direction was a curl of known value |cur_exp|), or
18092 |given| (if the direction is given by the |angle| value that now
18093 appears in |cur_exp|).
18094
18095 There's nothing difficult about this subroutine, but the program is rather
18096 lengthy because a variety of potential errors need to be nipped in the bud.
18097
18098 @c small_number mp_scan_direction (MP mp) {
18099   int t; /* the type of information found */
18100   scaled x; /* an |x| coordinate */
18101   mp_get_x_next(mp);
18102   if ( mp->cur_cmd==curl_command ) {
18103      @<Scan a curl specification@>;
18104   } else {
18105     @<Scan a given direction@>;
18106   }
18107   if ( mp->cur_cmd!=right_brace ) {
18108     mp_missing_err(mp, "}");
18109 @.Missing `\char`\}'@>
18110     help3("I've scanned a direction spec for part of a path,")
18111       ("so a right brace should have come next.")
18112       ("I shall pretend that one was there.");
18113     mp_back_error(mp);
18114   }
18115   mp_get_x_next(mp); 
18116   return t;
18117 }
18118
18119 @ @<Scan a curl specification@>=
18120 { mp_get_x_next(mp); mp_scan_expression(mp);
18121 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<0) ){ 
18122   exp_err("Improper curl has been replaced by 1");
18123 @.Improper curl@>
18124   help1("A curl must be a known, nonnegative number.");
18125   mp_put_get_flush_error(mp, unity);
18126 }
18127 t=mp_curl;
18128 }
18129
18130 @ @<Scan a given direction@>=
18131 { mp_scan_expression(mp);
18132   if ( mp->cur_type>mp_pair_type ) {
18133     @<Get given directions separated by commas@>;
18134   } else {
18135     mp_known_pair(mp);
18136   }
18137   if ( (mp->cur_x==0)&&(mp->cur_y==0) )  t=mp_open;
18138   else  { t=mp_given; mp->cur_exp=mp_n_arg(mp, mp->cur_x,mp->cur_y);}
18139 }
18140
18141 @ @<Get given directions separated by commas@>=
18142
18143   if ( mp->cur_type!=mp_known ) {
18144     exp_err("Undefined x coordinate has been replaced by 0");
18145 @.Undefined coordinates...@>
18146     help5("I need a `known' x value for this part of the path.")
18147       ("The value I found (see above) was no good;")
18148       ("so I'll try to keep going by using zero instead.")
18149       ("(Chapter 27 of The METAFONTbook explains that")
18150 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18151       ("you might want to type `I ??" "?' now.)");
18152     mp_put_get_flush_error(mp, 0);
18153   }
18154   x=mp->cur_exp;
18155   if ( mp->cur_cmd!=comma ) {
18156     mp_missing_err(mp, ",");
18157 @.Missing `,'@>
18158     help2("I've got the x coordinate of a path direction;")
18159       ("will look for the y coordinate next.");
18160     mp_back_error(mp);
18161   }
18162   mp_get_x_next(mp); mp_scan_expression(mp);
18163   if ( mp->cur_type!=mp_known ) {
18164      exp_err("Undefined y coordinate has been replaced by 0");
18165     help5("I need a `known' y value for this part of the path.")
18166       ("The value I found (see above) was no good;")
18167       ("so I'll try to keep going by using zero instead.")
18168       ("(Chapter 27 of The METAFONTbook explains that")
18169       ("you might want to type `I ??" "?' now.)");
18170     mp_put_get_flush_error(mp, 0);
18171   }
18172   mp->cur_y=mp->cur_exp; mp->cur_x=x;
18173 }
18174
18175 @ At this point |right_type(q)| is usually |open|, but it may have been
18176 set to some other value by a previous splicing operation. We must maintain
18177 the value of |right_type(q)| in unusual cases such as
18178 `\.{..z1\{z2\}\&\{z3\}z1\{0,0\}..}'.
18179
18180 @<Put the pre-join...@>=
18181
18182   t=mp_scan_direction(mp);
18183   if ( t!=mp_open ) {
18184     right_type(q)=t; right_given(q)=mp->cur_exp;
18185     if ( left_type(q)==mp_open ) {
18186       left_type(q)=t; left_given(q)=mp->cur_exp;
18187     } /* note that |left_given(q)=left_curl(q)| */
18188   }
18189 }
18190
18191 @ Since |left_tension| and |left_y| share the same position in knot nodes,
18192 and since |left_given| is similarly equivalent to |left_x|, we use
18193 |x| and |y| to hold the given direction and tension information when
18194 there are no explicit control points.
18195
18196 @<Put the post-join...@>=
18197
18198   t=mp_scan_direction(mp);
18199   if ( right_type(q)!=mp_explicit ) x=mp->cur_exp;
18200   else t=mp_explicit; /* the direction information is superfluous */
18201 }
18202
18203 @ @<Determine the tension and/or...@>=
18204
18205   mp_get_x_next(mp);
18206   if ( mp->cur_cmd==tension ) {
18207     @<Set explicit tensions@>;
18208   } else if ( mp->cur_cmd==controls ) {
18209     @<Set explicit control points@>;
18210   } else  { 
18211     right_tension(q)=unity; y=unity; mp_back_input(mp); /* default tension */
18212     goto DONE;
18213   };
18214   if ( mp->cur_cmd!=path_join ) {
18215      mp_missing_err(mp, "..");
18216 @.Missing `..'@>
18217     help1("A path join command should end with two dots.");
18218     mp_back_error(mp);
18219   }
18220 DONE:
18221   ;
18222 }
18223
18224 @ @<Set explicit tensions@>=
18225
18226   mp_get_x_next(mp); y=mp->cur_cmd;
18227   if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18228   mp_scan_primary(mp);
18229   @<Make sure that the current expression is a valid tension setting@>;
18230   if ( y==at_least ) negate(mp->cur_exp);
18231   right_tension(q)=mp->cur_exp;
18232   if ( mp->cur_cmd==and_command ) {
18233     mp_get_x_next(mp); y=mp->cur_cmd;
18234     if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18235     mp_scan_primary(mp);
18236     @<Make sure that the current expression is a valid tension setting@>;
18237     if ( y==at_least ) negate(mp->cur_exp);
18238   }
18239   y=mp->cur_exp;
18240 }
18241
18242 @ @d min_tension three_quarter_unit
18243
18244 @<Make sure that the current expression is a valid tension setting@>=
18245 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<min_tension) ) {
18246   exp_err("Improper tension has been set to 1");
18247 @.Improper tension@>
18248   help1("The expression above should have been a number >=3/4.");
18249   mp_put_get_flush_error(mp, unity);
18250 }
18251
18252 @ @<Set explicit control points@>=
18253
18254   right_type(q)=mp_explicit; t=mp_explicit; mp_get_x_next(mp); mp_scan_primary(mp);
18255   mp_known_pair(mp); right_x(q)=mp->cur_x; right_y(q)=mp->cur_y;
18256   if ( mp->cur_cmd!=and_command ) {
18257     x=right_x(q); y=right_y(q);
18258   } else { 
18259     mp_get_x_next(mp); mp_scan_primary(mp);
18260     mp_known_pair(mp); x=mp->cur_x; y=mp->cur_y;
18261   }
18262 }
18263
18264 @ @<Convert the right operand, |cur_exp|, into a partial path...@>=
18265
18266   if ( mp->cur_type!=mp_path_type ) pp=mp_new_knot(mp);
18267   else pp=mp->cur_exp;
18268   qq=pp;
18269   while ( link(qq)!=pp ) qq=link(qq);
18270   if ( left_type(pp)!=mp_endpoint ) { /* open up a cycle */
18271     r=mp_copy_knot(mp, pp); link(qq)=r; qq=r;
18272   }
18273   left_type(pp)=mp_open; right_type(qq)=mp_open;
18274 }
18275
18276 @ If a person tries to define an entire path by saying `\.{(x,y)\&cycle}',
18277 we silently change the specification to `\.{(x,y)..cycle}', since a cycle
18278 shouldn't have length zero.
18279
18280 @<Get ready to close a cycle@>=
18281
18282   cycle_hit=true; mp_get_x_next(mp); pp=p; qq=p;
18283   if ( d==ampersand ) if ( p==q ) {
18284     d=path_join; right_tension(q)=unity; y=unity;
18285   }
18286 }
18287
18288 @ @<Join the partial paths and reset |p| and |q|...@>=
18289
18290 if ( d==ampersand ) {
18291   if ( (x_coord(q)!=x_coord(pp))||(y_coord(q)!=y_coord(pp)) ) {
18292     print_err("Paths don't touch; `&' will be changed to `..'");
18293 @.Paths don't touch@>
18294     help3("When you join paths `p&q', the ending point of p")
18295       ("must be exactly equal to the starting point of q.")
18296       ("So I'm going to pretend that you said `p..q' instead.");
18297     mp_put_get_error(mp); d=path_join; right_tension(q)=unity; y=unity;
18298   }
18299 }
18300 @<Plug an opening in |right_type(pp)|, if possible@>;
18301 if ( d==ampersand ) {
18302   @<Splice independent paths together@>;
18303 } else  { 
18304   @<Plug an opening in |right_type(q)|, if possible@>;
18305   link(q)=pp; left_y(pp)=y;
18306   if ( t!=mp_open ) { left_x(pp)=x; left_type(pp)=t;  };
18307 }
18308 q=qq;
18309 }
18310
18311 @ @<Plug an opening in |right_type(q)|...@>=
18312 if ( right_type(q)==mp_open ) {
18313   if ( (left_type(q)==mp_curl)||(left_type(q)==mp_given) ) {
18314     right_type(q)=left_type(q); right_given(q)=left_given(q);
18315   }
18316 }
18317
18318 @ @<Plug an opening in |right_type(pp)|...@>=
18319 if ( right_type(pp)==mp_open ) {
18320   if ( (t==mp_curl)||(t==mp_given) ) {
18321     right_type(pp)=t; right_given(pp)=x;
18322   }
18323 }
18324
18325 @ @<Splice independent paths together@>=
18326
18327   if ( left_type(q)==mp_open ) if ( right_type(q)==mp_open ) {
18328     left_type(q)=mp_curl; left_curl(q)=unity;
18329   }
18330   if ( right_type(pp)==mp_open ) if ( t==mp_open ) {
18331     right_type(pp)=mp_curl; right_curl(pp)=unity;
18332   }
18333   right_type(q)=right_type(pp); link(q)=link(pp);
18334   right_x(q)=right_x(pp); right_y(q)=right_y(pp);
18335   mp_free_node(mp, pp,knot_node_size);
18336   if ( qq==pp ) qq=q;
18337 }
18338
18339 @ @<Choose control points for the path...@>=
18340 if ( cycle_hit ) { 
18341   if ( d==ampersand ) p=q;
18342 } else  { 
18343   left_type(p)=mp_endpoint;
18344   if ( right_type(p)==mp_open ) { 
18345     right_type(p)=mp_curl; right_curl(p)=unity;
18346   }
18347   right_type(q)=mp_endpoint;
18348   if ( left_type(q)==mp_open ) { 
18349     left_type(q)=mp_curl; left_curl(q)=unity;
18350   }
18351   link(q)=p;
18352 }
18353 mp_make_choices(mp, p);
18354 mp->cur_type=mp_path_type; mp->cur_exp=p
18355
18356 @ Finally, we sometimes need to scan an expression whose value is
18357 supposed to be either |true_code| or |false_code|.
18358
18359 @<Declare the basic parsing subroutines@>=
18360 void mp_get_boolean (MP mp) { 
18361   mp_get_x_next(mp); mp_scan_expression(mp);
18362   if ( mp->cur_type!=mp_boolean_type ) {
18363     exp_err("Undefined condition will be treated as `false'");
18364 @.Undefined condition...@>
18365     help2("The expression shown above should have had a definite")
18366       ("true-or-false value. I'm changing it to `false'.");
18367     mp_put_get_flush_error(mp, false_code); mp->cur_type=mp_boolean_type;
18368   }
18369 }
18370
18371 @* \[39] Doing the operations.
18372 The purpose of parsing is primarily to permit people to avoid piles of
18373 parentheses. But the real work is done after the structure of an expression
18374 has been recognized; that's when new expressions are generated. We
18375 turn now to the guts of \MP, which handles individual operators that
18376 have come through the parsing mechanism.
18377
18378 We'll start with the easy ones that take no operands, then work our way
18379 up to operators with one and ultimately two arguments. In other words,
18380 we will write the three procedures |do_nullary|, |do_unary|, and |do_binary|
18381 that are invoked periodically by the expression scanners.
18382
18383 First let's make sure that all of the primitive operators are in the
18384 hash table. Although |scan_primary| and its relatives made use of the
18385 \\{cmd} code for these operators, the \\{do} routines base everything
18386 on the \\{mod} code. For example, |do_binary| doesn't care whether the
18387 operation it performs is a |primary_binary| or |secondary_binary|, etc.
18388
18389 @<Put each...@>=
18390 mp_primitive(mp, "true",nullary,true_code);
18391 @:true_}{\&{true} primitive@>
18392 mp_primitive(mp, "false",nullary,false_code);
18393 @:false_}{\&{false} primitive@>
18394 mp_primitive(mp, "nullpicture",nullary,null_picture_code);
18395 @:null_picture_}{\&{nullpicture} primitive@>
18396 mp_primitive(mp, "nullpen",nullary,null_pen_code);
18397 @:null_pen_}{\&{nullpen} primitive@>
18398 mp_primitive(mp, "jobname",nullary,job_name_op);
18399 @:job_name_}{\&{jobname} primitive@>
18400 mp_primitive(mp, "readstring",nullary,read_string_op);
18401 @:read_string_}{\&{readstring} primitive@>
18402 mp_primitive(mp, "pencircle",nullary,pen_circle);
18403 @:pen_circle_}{\&{pencircle} primitive@>
18404 mp_primitive(mp, "normaldeviate",nullary,normal_deviate);
18405 @:normal_deviate_}{\&{normaldeviate} primitive@>
18406 mp_primitive(mp, "readfrom",unary,read_from_op);
18407 @:read_from_}{\&{readfrom} primitive@>
18408 mp_primitive(mp, "closefrom",unary,close_from_op);
18409 @:close_from_}{\&{closefrom} primitive@>
18410 mp_primitive(mp, "odd",unary,odd_op);
18411 @:odd_}{\&{odd} primitive@>
18412 mp_primitive(mp, "known",unary,known_op);
18413 @:known_}{\&{known} primitive@>
18414 mp_primitive(mp, "unknown",unary,unknown_op);
18415 @:unknown_}{\&{unknown} primitive@>
18416 mp_primitive(mp, "not",unary,not_op);
18417 @:not_}{\&{not} primitive@>
18418 mp_primitive(mp, "decimal",unary,decimal);
18419 @:decimal_}{\&{decimal} primitive@>
18420 mp_primitive(mp, "reverse",unary,reverse);
18421 @:reverse_}{\&{reverse} primitive@>
18422 mp_primitive(mp, "makepath",unary,make_path_op);
18423 @:make_path_}{\&{makepath} primitive@>
18424 mp_primitive(mp, "makepen",unary,make_pen_op);
18425 @:make_pen_}{\&{makepen} primitive@>
18426 mp_primitive(mp, "oct",unary,oct_op);
18427 @:oct_}{\&{oct} primitive@>
18428 mp_primitive(mp, "hex",unary,hex_op);
18429 @:hex_}{\&{hex} primitive@>
18430 mp_primitive(mp, "ASCII",unary,ASCII_op);
18431 @:ASCII_}{\&{ASCII} primitive@>
18432 mp_primitive(mp, "char",unary,char_op);
18433 @:char_}{\&{char} primitive@>
18434 mp_primitive(mp, "length",unary,length_op);
18435 @:length_}{\&{length} primitive@>
18436 mp_primitive(mp, "turningnumber",unary,turning_op);
18437 @:turning_number_}{\&{turningnumber} primitive@>
18438 mp_primitive(mp, "xpart",unary,x_part);
18439 @:x_part_}{\&{xpart} primitive@>
18440 mp_primitive(mp, "ypart",unary,y_part);
18441 @:y_part_}{\&{ypart} primitive@>
18442 mp_primitive(mp, "xxpart",unary,xx_part);
18443 @:xx_part_}{\&{xxpart} primitive@>
18444 mp_primitive(mp, "xypart",unary,xy_part);
18445 @:xy_part_}{\&{xypart} primitive@>
18446 mp_primitive(mp, "yxpart",unary,yx_part);
18447 @:yx_part_}{\&{yxpart} primitive@>
18448 mp_primitive(mp, "yypart",unary,yy_part);
18449 @:yy_part_}{\&{yypart} primitive@>
18450 mp_primitive(mp, "redpart",unary,red_part);
18451 @:red_part_}{\&{redpart} primitive@>
18452 mp_primitive(mp, "greenpart",unary,green_part);
18453 @:green_part_}{\&{greenpart} primitive@>
18454 mp_primitive(mp, "bluepart",unary,blue_part);
18455 @:blue_part_}{\&{bluepart} primitive@>
18456 mp_primitive(mp, "cyanpart",unary,cyan_part);
18457 @:cyan_part_}{\&{cyanpart} primitive@>
18458 mp_primitive(mp, "magentapart",unary,magenta_part);
18459 @:magenta_part_}{\&{magentapart} primitive@>
18460 mp_primitive(mp, "yellowpart",unary,yellow_part);
18461 @:yellow_part_}{\&{yellowpart} primitive@>
18462 mp_primitive(mp, "blackpart",unary,black_part);
18463 @:black_part_}{\&{blackpart} primitive@>
18464 mp_primitive(mp, "greypart",unary,grey_part);
18465 @:grey_part_}{\&{greypart} primitive@>
18466 mp_primitive(mp, "colormodel",unary,color_model_part);
18467 @:color_model_part_}{\&{colormodel} primitive@>
18468 mp_primitive(mp, "fontpart",unary,font_part);
18469 @:font_part_}{\&{fontpart} primitive@>
18470 mp_primitive(mp, "textpart",unary,text_part);
18471 @:text_part_}{\&{textpart} primitive@>
18472 mp_primitive(mp, "pathpart",unary,path_part);
18473 @:path_part_}{\&{pathpart} primitive@>
18474 mp_primitive(mp, "penpart",unary,pen_part);
18475 @:pen_part_}{\&{penpart} primitive@>
18476 mp_primitive(mp, "dashpart",unary,dash_part);
18477 @:dash_part_}{\&{dashpart} primitive@>
18478 mp_primitive(mp, "sqrt",unary,sqrt_op);
18479 @:sqrt_}{\&{sqrt} primitive@>
18480 mp_primitive(mp, "mexp",unary,m_exp_op);
18481 @:m_exp_}{\&{mexp} primitive@>
18482 mp_primitive(mp, "mlog",unary,m_log_op);
18483 @:m_log_}{\&{mlog} primitive@>
18484 mp_primitive(mp, "sind",unary,sin_d_op);
18485 @:sin_d_}{\&{sind} primitive@>
18486 mp_primitive(mp, "cosd",unary,cos_d_op);
18487 @:cos_d_}{\&{cosd} primitive@>
18488 mp_primitive(mp, "floor",unary,floor_op);
18489 @:floor_}{\&{floor} primitive@>
18490 mp_primitive(mp, "uniformdeviate",unary,uniform_deviate);
18491 @:uniform_deviate_}{\&{uniformdeviate} primitive@>
18492 mp_primitive(mp, "charexists",unary,char_exists_op);
18493 @:char_exists_}{\&{charexists} primitive@>
18494 mp_primitive(mp, "fontsize",unary,font_size);
18495 @:font_size_}{\&{fontsize} primitive@>
18496 mp_primitive(mp, "llcorner",unary,ll_corner_op);
18497 @:ll_corner_}{\&{llcorner} primitive@>
18498 mp_primitive(mp, "lrcorner",unary,lr_corner_op);
18499 @:lr_corner_}{\&{lrcorner} primitive@>
18500 mp_primitive(mp, "ulcorner",unary,ul_corner_op);
18501 @:ul_corner_}{\&{ulcorner} primitive@>
18502 mp_primitive(mp, "urcorner",unary,ur_corner_op);
18503 @:ur_corner_}{\&{urcorner} primitive@>
18504 mp_primitive(mp, "arclength",unary,arc_length);
18505 @:arc_length_}{\&{arclength} primitive@>
18506 mp_primitive(mp, "angle",unary,angle_op);
18507 @:angle_}{\&{angle} primitive@>
18508 mp_primitive(mp, "cycle",cycle,cycle_op);
18509 @:cycle_}{\&{cycle} primitive@>
18510 mp_primitive(mp, "stroked",unary,stroked_op);
18511 @:stroked_}{\&{stroked} primitive@>
18512 mp_primitive(mp, "filled",unary,filled_op);
18513 @:filled_}{\&{filled} primitive@>
18514 mp_primitive(mp, "textual",unary,textual_op);
18515 @:textual_}{\&{textual} primitive@>
18516 mp_primitive(mp, "clipped",unary,clipped_op);
18517 @:clipped_}{\&{clipped} primitive@>
18518 mp_primitive(mp, "bounded",unary,bounded_op);
18519 @:bounded_}{\&{bounded} primitive@>
18520 mp_primitive(mp, "+",plus_or_minus,plus);
18521 @:+ }{\.{+} primitive@>
18522 mp_primitive(mp, "-",plus_or_minus,minus);
18523 @:- }{\.{-} primitive@>
18524 mp_primitive(mp, "*",secondary_binary,times);
18525 @:* }{\.{*} primitive@>
18526 mp_primitive(mp, "/",slash,over); mp->eqtb[frozen_slash]=mp->eqtb[mp->cur_sym];
18527 @:/ }{\.{/} primitive@>
18528 mp_primitive(mp, "++",tertiary_binary,pythag_add);
18529 @:++_}{\.{++} primitive@>
18530 mp_primitive(mp, "+-+",tertiary_binary,pythag_sub);
18531 @:+-+_}{\.{+-+} primitive@>
18532 mp_primitive(mp, "or",tertiary_binary,or_op);
18533 @:or_}{\&{or} primitive@>
18534 mp_primitive(mp, "and",and_command,and_op);
18535 @:and_}{\&{and} primitive@>
18536 mp_primitive(mp, "<",expression_binary,less_than);
18537 @:< }{\.{<} primitive@>
18538 mp_primitive(mp, "<=",expression_binary,less_or_equal);
18539 @:<=_}{\.{<=} primitive@>
18540 mp_primitive(mp, ">",expression_binary,greater_than);
18541 @:> }{\.{>} primitive@>
18542 mp_primitive(mp, ">=",expression_binary,greater_or_equal);
18543 @:>=_}{\.{>=} primitive@>
18544 mp_primitive(mp, "=",equals,equal_to);
18545 @:= }{\.{=} primitive@>
18546 mp_primitive(mp, "<>",expression_binary,unequal_to);
18547 @:<>_}{\.{<>} primitive@>
18548 mp_primitive(mp, "substring",primary_binary,substring_of);
18549 @:substring_}{\&{substring} primitive@>
18550 mp_primitive(mp, "subpath",primary_binary,subpath_of);
18551 @:subpath_}{\&{subpath} primitive@>
18552 mp_primitive(mp, "directiontime",primary_binary,direction_time_of);
18553 @:direction_time_}{\&{directiontime} primitive@>
18554 mp_primitive(mp, "point",primary_binary,point_of);
18555 @:point_}{\&{point} primitive@>
18556 mp_primitive(mp, "precontrol",primary_binary,precontrol_of);
18557 @:precontrol_}{\&{precontrol} primitive@>
18558 mp_primitive(mp, "postcontrol",primary_binary,postcontrol_of);
18559 @:postcontrol_}{\&{postcontrol} primitive@>
18560 mp_primitive(mp, "penoffset",primary_binary,pen_offset_of);
18561 @:pen_offset_}{\&{penoffset} primitive@>
18562 mp_primitive(mp, "arctime",primary_binary,arc_time_of);
18563 @:arc_time_of_}{\&{arctime} primitive@>
18564 mp_primitive(mp, "mpversion",nullary,mp_version);
18565 @:mp_verison_}{\&{mpversion} primitive@>
18566 mp_primitive(mp, "&",ampersand,concatenate);
18567 @:!!!}{\.{\&} primitive@>
18568 mp_primitive(mp, "rotated",secondary_binary,rotated_by);
18569 @:rotated_}{\&{rotated} primitive@>
18570 mp_primitive(mp, "slanted",secondary_binary,slanted_by);
18571 @:slanted_}{\&{slanted} primitive@>
18572 mp_primitive(mp, "scaled",secondary_binary,scaled_by);
18573 @:scaled_}{\&{scaled} primitive@>
18574 mp_primitive(mp, "shifted",secondary_binary,shifted_by);
18575 @:shifted_}{\&{shifted} primitive@>
18576 mp_primitive(mp, "transformed",secondary_binary,transformed_by);
18577 @:transformed_}{\&{transformed} primitive@>
18578 mp_primitive(mp, "xscaled",secondary_binary,x_scaled);
18579 @:x_scaled_}{\&{xscaled} primitive@>
18580 mp_primitive(mp, "yscaled",secondary_binary,y_scaled);
18581 @:y_scaled_}{\&{yscaled} primitive@>
18582 mp_primitive(mp, "zscaled",secondary_binary,z_scaled);
18583 @:z_scaled_}{\&{zscaled} primitive@>
18584 mp_primitive(mp, "infont",secondary_binary,in_font);
18585 @:in_font_}{\&{infont} primitive@>
18586 mp_primitive(mp, "intersectiontimes",tertiary_binary,intersect);
18587 @:intersection_times_}{\&{intersectiontimes} primitive@>
18588 mp_primitive(mp, "envelope",primary_binary,envelope_of);
18589 @:envelope_}{\&{envelope} primitive@>
18590
18591 @ @<Cases of |print_cmd...@>=
18592 case nullary:
18593 case unary:
18594 case primary_binary:
18595 case secondary_binary:
18596 case tertiary_binary:
18597 case expression_binary:
18598 case cycle:
18599 case plus_or_minus:
18600 case slash:
18601 case ampersand:
18602 case equals:
18603 case and_command:
18604   mp_print_op(mp, m);
18605   break;
18606
18607 @ OK, let's look at the simplest \\{do} procedure first.
18608
18609 @c @<Declare nullary action procedure@>;
18610 void mp_do_nullary (MP mp,quarterword c) { 
18611   check_arith;
18612   if ( mp->internal[mp_tracing_commands]>two )
18613     mp_show_cmd_mod(mp, nullary,c);
18614   switch (c) {
18615   case true_code: case false_code: 
18616     mp->cur_type=mp_boolean_type; mp->cur_exp=c;
18617     break;
18618   case null_picture_code: 
18619     mp->cur_type=mp_picture_type;
18620     mp->cur_exp=mp_get_node(mp, edge_header_size); 
18621     mp_init_edges(mp, mp->cur_exp);
18622     break;
18623   case null_pen_code: 
18624     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, 0);
18625     break;
18626   case normal_deviate: 
18627     mp->cur_type=mp_known; mp->cur_exp=mp_norm_rand(mp);
18628     break;
18629   case pen_circle: 
18630     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, unity);
18631     break;
18632   case job_name_op:  
18633     if ( mp->job_name==NULL ) mp_open_log_file(mp);
18634     mp->cur_type=mp_string_type; mp->cur_exp=rts(mp->job_name);
18635     break;
18636   case mp_version: 
18637     mp->cur_type=mp_string_type; 
18638     mp->cur_exp=intern(metapost_version) ;
18639     break;
18640   case read_string_op:
18641     @<Read a string from the terminal@>;
18642     break;
18643   } /* there are no other cases */
18644   check_arith;
18645 }
18646
18647 @ @<Read a string...@>=
18648
18649   if ( mp->interaction<=mp_nonstop_mode )
18650     mp_fatal_error(mp, "*** (cannot readstring in nonstop modes)");
18651   mp_begin_file_reading(mp); name=is_read;
18652   limit=start; prompt_input("");
18653   mp_finish_read(mp);
18654 }
18655
18656 @ @<Declare nullary action procedure@>=
18657 void mp_finish_read (MP mp) { /* copy |buffer| line to |cur_exp| */
18658   size_t k;
18659   str_room((int)mp->last-start);
18660   for (k=start;k<=mp->last-1;k++) {
18661    append_char(mp->buffer[k]);
18662   }
18663   mp_end_file_reading(mp); mp->cur_type=mp_string_type; 
18664   mp->cur_exp=mp_make_string(mp);
18665 }
18666
18667 @ Things get a bit more interesting when there's an operand. The
18668 operand to |do_unary| appears in |cur_type| and |cur_exp|.
18669
18670 @c @<Declare unary action procedures@>;
18671 void mp_do_unary (MP mp,quarterword c) {
18672   pointer p,q,r; /* for list manipulation */
18673   integer x; /* a temporary register */
18674   check_arith;
18675   if ( mp->internal[mp_tracing_commands]>two )
18676     @<Trace the current unary operation@>;
18677   switch (c) {
18678   case plus:
18679     if ( mp->cur_type<mp_color_type ) mp_bad_unary(mp, plus);
18680     break;
18681   case minus:
18682     @<Negate the current expression@>;
18683     break;
18684   @<Additional cases of unary operators@>;
18685   } /* there are no other cases */
18686   check_arith;
18687 };
18688
18689 @ The |nice_pair| function returns |true| if both components of a pair
18690 are known.
18691
18692 @<Declare unary action procedures@>=
18693 boolean mp_nice_pair (MP mp,integer p, quarterword t) { 
18694   if ( t==mp_pair_type ) {
18695     p=value(p);
18696     if ( type(x_part_loc(p))==mp_known )
18697       if ( type(y_part_loc(p))==mp_known )
18698         return true;
18699   }
18700   return false;
18701 }
18702
18703 @ The |nice_color_or_pair| function is analogous except that it also accepts
18704 fully known colors.
18705
18706 @<Declare unary action procedures@>=
18707 boolean mp_nice_color_or_pair (MP mp,integer p, quarterword t) {
18708   pointer q,r; /* for scanning the big node */
18709   if ( (t!=mp_pair_type)&&(t!=mp_color_type)&&(t!=mp_cmykcolor_type) ) {
18710     return false;
18711   } else { 
18712     q=value(p);
18713     r=q+mp->big_node_size[type(p)];
18714     do {  
18715       r=r-2;
18716       if ( type(r)!=mp_known )
18717         return false;
18718     } while (r!=q);
18719     return true;
18720   }
18721 }
18722
18723 @ @<Declare unary action...@>=
18724 void mp_print_known_or_unknown_type (MP mp,small_number t, integer v) { 
18725   mp_print_char(mp, '(');
18726   if ( t>mp_known ) mp_print(mp, "unknown numeric");
18727   else { if ( (t==mp_pair_type)||(t==mp_color_type)||(t==mp_cmykcolor_type) )
18728     if ( ! mp_nice_color_or_pair(mp, v,t) ) mp_print(mp, "unknown ");
18729     mp_print_type(mp, t);
18730   }
18731   mp_print_char(mp, ')');
18732 }
18733
18734 @ @<Declare unary action...@>=
18735 void mp_bad_unary (MP mp,quarterword c) { 
18736   exp_err("Not implemented: "); mp_print_op(mp, c);
18737 @.Not implemented...@>
18738   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
18739   help3("I'm afraid I don't know how to apply that operation to that")
18740     ("particular type. Continue, and I'll simply return the")
18741     ("argument (shown above) as the result of the operation.");
18742   mp_put_get_error(mp);
18743 }
18744
18745 @ @<Trace the current unary operation@>=
18746
18747   mp_begin_diagnostic(mp); mp_print_nl(mp, "{"); 
18748   mp_print_op(mp, c); mp_print_char(mp, '(');
18749   mp_print_exp(mp, null,0); /* show the operand, but not verbosely */
18750   mp_print(mp, ")}"); mp_end_diagnostic(mp, false);
18751 }
18752
18753 @ Negation is easy except when the current expression
18754 is of type |independent|, or when it is a pair with one or more
18755 |independent| components.
18756
18757 It is tempting to argue that the negative of an independent variable
18758 is an independent variable, hence we don't have to do anything when
18759 negating it. The fallacy is that other dependent variables pointing
18760 to the current expression must change the sign of their
18761 coefficients if we make no change to the current expression.
18762
18763 Instead, we work around the problem by copying the current expression
18764 and recycling it afterwards (cf.~the |stash_in| routine).
18765
18766 @<Negate the current expression@>=
18767 switch (mp->cur_type) {
18768 case mp_color_type:
18769 case mp_cmykcolor_type:
18770 case mp_pair_type:
18771 case mp_independent: 
18772   q=mp->cur_exp; mp_make_exp_copy(mp, q);
18773   if ( mp->cur_type==mp_dependent ) {
18774     mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18775   } else if ( mp->cur_type<=mp_pair_type ) { /* |mp_color_type| or |mp_pair_type| */
18776     p=value(mp->cur_exp);
18777     r=p+mp->big_node_size[mp->cur_type];
18778     do {  
18779       r=r-2;
18780       if ( type(r)==mp_known ) negate(value(r));
18781       else mp_negate_dep_list(mp, dep_list(r));
18782     } while (r!=p);
18783   } /* if |cur_type=mp_known| then |cur_exp=0| */
18784   mp_recycle_value(mp, q); mp_free_node(mp, q,value_node_size);
18785   break;
18786 case mp_dependent:
18787 case mp_proto_dependent:
18788   mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18789   break;
18790 case mp_known:
18791   negate(mp->cur_exp);
18792   break;
18793 default:
18794   mp_bad_unary(mp, minus);
18795   break;
18796 }
18797
18798 @ @<Declare unary action...@>=
18799 void mp_negate_dep_list (MP mp,pointer p) { 
18800   while (1) { 
18801     negate(value(p));
18802     if ( info(p)==null ) return;
18803     p=link(p);
18804   }
18805 }
18806
18807 @ @<Additional cases of unary operators@>=
18808 case not_op: 
18809   if ( mp->cur_type!=mp_boolean_type ) mp_bad_unary(mp, not_op);
18810   else mp->cur_exp=true_code+false_code-mp->cur_exp;
18811   break;
18812
18813 @ @d three_sixty_units 23592960 /* that's |360*unity| */
18814 @d boolean_reset(A) if ( (A) ) mp->cur_exp=true_code; else mp->cur_exp=false_code
18815
18816 @<Additional cases of unary operators@>=
18817 case sqrt_op:
18818 case m_exp_op:
18819 case m_log_op:
18820 case sin_d_op:
18821 case cos_d_op:
18822 case floor_op:
18823 case  uniform_deviate:
18824 case odd_op:
18825 case char_exists_op:
18826   if ( mp->cur_type!=mp_known ) {
18827     mp_bad_unary(mp, c);
18828   } else {
18829     switch (c) {
18830     case sqrt_op:mp->cur_exp=mp_square_rt(mp, mp->cur_exp);break;
18831     case m_exp_op:mp->cur_exp=mp_m_exp(mp, mp->cur_exp);break;
18832     case m_log_op:mp->cur_exp=mp_m_log(mp, mp->cur_exp);break;
18833     case sin_d_op:
18834     case cos_d_op:
18835       mp_n_sin_cos(mp, (mp->cur_exp % three_sixty_units)*16);
18836       if ( c==sin_d_op ) mp->cur_exp=mp_round_fraction(mp, mp->n_sin);
18837       else mp->cur_exp=mp_round_fraction(mp, mp->n_cos);
18838       break;
18839     case floor_op:mp->cur_exp=mp_floor_scaled(mp, mp->cur_exp);break;
18840     case uniform_deviate:mp->cur_exp=mp_unif_rand(mp, mp->cur_exp);break;
18841     case odd_op: 
18842       boolean_reset(odd(mp_round_unscaled(mp, mp->cur_exp)));
18843       mp->cur_type=mp_boolean_type;
18844       break;
18845     case char_exists_op:
18846       @<Determine if a character has been shipped out@>;
18847       break;
18848     } /* there are no other cases */
18849   }
18850   break;
18851
18852 @ @<Additional cases of unary operators@>=
18853 case angle_op:
18854   if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) ) {
18855     p=value(mp->cur_exp);
18856     x=mp_n_arg(mp, value(x_part_loc(p)),value(y_part_loc(p)));
18857     if ( x>=0 ) mp_flush_cur_exp(mp, (x+8)/ 16);
18858     else mp_flush_cur_exp(mp, -((-x+8)/ 16));
18859   } else {
18860     mp_bad_unary(mp, angle_op);
18861   }
18862   break;
18863
18864 @ If the current expression is a pair, but the context wants it to
18865 be a path, we call |pair_to_path|.
18866
18867 @<Declare unary action...@>=
18868 void mp_pair_to_path (MP mp) { 
18869   mp->cur_exp=mp_new_knot(mp); 
18870   mp->cur_type=mp_path_type;
18871 };
18872
18873 @ @<Additional cases of unary operators@>=
18874 case x_part:
18875 case y_part:
18876   if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_transform_type) )
18877     mp_take_part(mp, c);
18878   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18879   else mp_bad_unary(mp, c);
18880   break;
18881 case xx_part:
18882 case xy_part:
18883 case yx_part:
18884 case yy_part: 
18885   if ( mp->cur_type==mp_transform_type ) mp_take_part(mp, c);
18886   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18887   else mp_bad_unary(mp, c);
18888   break;
18889 case red_part:
18890 case green_part:
18891 case blue_part: 
18892   if ( mp->cur_type==mp_color_type ) mp_take_part(mp, c);
18893   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18894   else mp_bad_unary(mp, c);
18895   break;
18896 case cyan_part:
18897 case magenta_part:
18898 case yellow_part:
18899 case black_part: 
18900   if ( mp->cur_type==mp_cmykcolor_type) mp_take_part(mp, c); 
18901   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18902   else mp_bad_unary(mp, c);
18903   break;
18904 case grey_part: 
18905   if ( mp->cur_type==mp_known ) mp->cur_exp=value(c);
18906   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18907   else mp_bad_unary(mp, c);
18908   break;
18909 case color_model_part: 
18910   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18911   else mp_bad_unary(mp, c);
18912   break;
18913
18914 @ In the following procedure, |cur_exp| points to a capsule, which points to
18915 a big node. We want to delete all but one part of the big node.
18916
18917 @<Declare unary action...@>=
18918 void mp_take_part (MP mp,quarterword c) {
18919   pointer p; /* the big node */
18920   p=value(mp->cur_exp); value(temp_val)=p; type(temp_val)=mp->cur_type;
18921   link(p)=temp_val; mp_free_node(mp, mp->cur_exp,value_node_size);
18922   mp_make_exp_copy(mp, p+mp->sector_offset[c+mp_x_part_sector-x_part]);
18923   mp_recycle_value(mp, temp_val);
18924 }
18925
18926 @ @<Initialize table entries...@>=
18927 name_type(temp_val)=mp_capsule;
18928
18929 @ @<Additional cases of unary operators@>=
18930 case font_part:
18931 case text_part:
18932 case path_part:
18933 case pen_part:
18934 case dash_part:
18935   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18936   else mp_bad_unary(mp, c);
18937   break;
18938
18939 @ @<Declarations@>=
18940 void mp_scale_edges (MP mp);
18941
18942 @ @<Declare unary action...@>=
18943 void mp_take_pict_part (MP mp,quarterword c) {
18944   pointer p; /* first graphical object in |cur_exp| */
18945   p=link(dummy_loc(mp->cur_exp));
18946   if ( p!=null ) {
18947     switch (c) {
18948     case x_part: case y_part: case xx_part:
18949     case xy_part: case yx_part: case yy_part:
18950       if ( type(p)==mp_text_code ) mp_flush_cur_exp(mp, text_trans_part(p+c));
18951       else goto NOT_FOUND;
18952       break;
18953     case red_part: case green_part: case blue_part:
18954       if ( has_color(p) ) mp_flush_cur_exp(mp, obj_color_part(p+c));
18955       else goto NOT_FOUND;
18956       break;
18957     case cyan_part: case magenta_part: case yellow_part:
18958     case black_part:
18959       if ( has_color(p) ) {
18960         if ( color_model(p)==mp_uninitialized_model )
18961           mp_flush_cur_exp(mp, unity);
18962         else
18963           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-cyan_part)));
18964       } else goto NOT_FOUND;
18965       break;
18966     case grey_part:
18967       if ( has_color(p) )
18968           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-grey_part)));
18969       else goto NOT_FOUND;
18970       break;
18971     case color_model_part:
18972       if ( has_color(p) ) {
18973         if ( color_model(p)==mp_uninitialized_model )
18974           mp_flush_cur_exp(mp, mp->internal[mp_default_color_model]);
18975         else
18976           mp_flush_cur_exp(mp, color_model(p)*unity);
18977       } else goto NOT_FOUND;
18978       break;
18979     @<Handle other cases in |take_pict_part| or |goto not_found|@>;
18980     } /* all cases have been enumerated */
18981     return;
18982   };
18983 NOT_FOUND:
18984   @<Convert the current expression to a null value appropriate
18985     for |c|@>;
18986 }
18987
18988 @ @<Handle other cases in |take_pict_part| or |goto not_found|@>=
18989 case text_part: 
18990   if ( type(p)!=mp_text_code ) goto NOT_FOUND;
18991   else { 
18992     mp_flush_cur_exp(mp, text_p(p));
18993     add_str_ref(mp->cur_exp);
18994     mp->cur_type=mp_string_type;
18995     };
18996   break;
18997 case font_part: 
18998   if ( type(p)!=mp_text_code ) goto NOT_FOUND;
18999   else { 
19000     mp_flush_cur_exp(mp, rts(mp->font_name[font_n(p)])); 
19001     add_str_ref(mp->cur_exp);
19002     mp->cur_type=mp_string_type;
19003   };
19004   break;
19005 case path_part:
19006   if ( type(p)==mp_text_code ) goto NOT_FOUND;
19007   else if ( is_stop(p) ) mp_confusion(mp, "pict");
19008 @:this can't happen pict}{\quad pict@>
19009   else { 
19010     mp_flush_cur_exp(mp, mp_copy_path(mp, path_p(p)));
19011     mp->cur_type=mp_path_type;
19012   }
19013   break;
19014 case pen_part: 
19015   if ( ! has_pen(p) ) goto NOT_FOUND;
19016   else {
19017     if ( pen_p(p)==null ) goto NOT_FOUND;
19018     else { mp_flush_cur_exp(mp, copy_pen(pen_p(p)));
19019       mp->cur_type=mp_pen_type;
19020     };
19021   }
19022   break;
19023 case dash_part: 
19024   if ( type(p)!=mp_stroked_code ) goto NOT_FOUND;
19025   else { if ( dash_p(p)==null ) goto NOT_FOUND;
19026     else { add_edge_ref(dash_p(p));
19027     mp->se_sf=dash_scale(p);
19028     mp->se_pic=dash_p(p);
19029     mp_scale_edges(mp);
19030     mp_flush_cur_exp(mp, mp->se_pic);
19031     mp->cur_type=mp_picture_type;
19032     };
19033   }
19034   break;
19035
19036 @ Since |scale_edges| had to be declared |forward|, it had to be declared as a
19037 parameterless procedure even though it really takes two arguments and updates
19038 one of them.  Hence the following globals are needed.
19039
19040 @<Global...@>=
19041 pointer se_pic;  /* edge header used and updated by |scale_edges| */
19042 scaled se_sf;  /* the scale factor argument to |scale_edges| */
19043
19044 @ @<Convert the current expression to a null value appropriate...@>=
19045 switch (c) {
19046 case text_part: case font_part: 
19047   mp_flush_cur_exp(mp, rts(""));
19048   mp->cur_type=mp_string_type;
19049   break;
19050 case path_part: 
19051   mp_flush_cur_exp(mp, mp_get_node(mp, knot_node_size));
19052   left_type(mp->cur_exp)=mp_endpoint;
19053   right_type(mp->cur_exp)=mp_endpoint;
19054   link(mp->cur_exp)=mp->cur_exp;
19055   x_coord(mp->cur_exp)=0;
19056   y_coord(mp->cur_exp)=0;
19057   originator(mp->cur_exp)=mp_metapost_user;
19058   mp->cur_type=mp_path_type;
19059   break;
19060 case pen_part: 
19061   mp_flush_cur_exp(mp, mp_get_pen_circle(mp, 0));
19062   mp->cur_type=mp_pen_type;
19063   break;
19064 case dash_part: 
19065   mp_flush_cur_exp(mp, mp_get_node(mp, edge_header_size));
19066   mp_init_edges(mp, mp->cur_exp);
19067   mp->cur_type=mp_picture_type;
19068   break;
19069 default: 
19070    mp_flush_cur_exp(mp, 0);
19071   break;
19072 }
19073
19074 @ @<Additional cases of unary...@>=
19075 case char_op: 
19076   if ( mp->cur_type!=mp_known ) { 
19077     mp_bad_unary(mp, char_op);
19078   } else { 
19079     mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256; 
19080     mp->cur_type=mp_string_type;
19081     if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
19082   }
19083   break;
19084 case decimal: 
19085   if ( mp->cur_type!=mp_known ) {
19086      mp_bad_unary(mp, decimal);
19087   } else { 
19088     mp->old_setting=mp->selector; mp->selector=new_string;
19089     mp_print_scaled(mp, mp->cur_exp); mp->cur_exp=mp_make_string(mp);
19090     mp->selector=mp->old_setting; mp->cur_type=mp_string_type;
19091   }
19092   break;
19093 case oct_op:
19094 case hex_op:
19095 case ASCII_op: 
19096   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
19097   else mp_str_to_num(mp, c);
19098   break;
19099 case font_size: 
19100   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, font_size);
19101   else @<Find the design size of the font whose name is |cur_exp|@>;
19102   break;
19103
19104 @ @<Declare unary action...@>=
19105 void mp_str_to_num (MP mp,quarterword c) { /* converts a string to a number */
19106   integer n; /* accumulator */
19107   ASCII_code m; /* current character */
19108   pool_pointer k; /* index into |str_pool| */
19109   int b; /* radix of conversion */
19110   boolean bad_char; /* did the string contain an invalid digit? */
19111   if ( c==ASCII_op ) {
19112     if ( length(mp->cur_exp)==0 ) n=-1;
19113     else n=mp->str_pool[mp->str_start[mp->cur_exp]];
19114   } else { 
19115     if ( c==oct_op ) b=8; else b=16;
19116     n=0; bad_char=false;
19117     for (k=mp->str_start[mp->cur_exp];k<=str_stop(mp->cur_exp)-1;k++) {
19118       m=mp->str_pool[k];
19119       if ( (m>='0')&&(m<='9') ) m=m-'0';
19120       else if ( (m>='A')&&(m<='F') ) m=m-'A'+10;
19121       else if ( (m>='a')&&(m<='f') ) m=m-'a'+10;
19122       else  { bad_char=true; m=0; };
19123       if ( m>=b ) { bad_char=true; m=0; };
19124       if ( n<32768 / b ) n=n*b+m; else n=32767;
19125     }
19126     @<Give error messages if |bad_char| or |n>=4096|@>;
19127   }
19128   mp_flush_cur_exp(mp, n*unity);
19129 }
19130
19131 @ @<Give error messages if |bad_char|...@>=
19132 if ( bad_char ) { 
19133   exp_err("String contains illegal digits");
19134 @.String contains illegal digits@>
19135   if ( c==oct_op ) {
19136     help1("I zeroed out characters that weren't in the range 0..7.");
19137   } else  {
19138     help1("I zeroed out characters that weren't hex digits.");
19139   }
19140   mp_put_get_error(mp);
19141 }
19142 if ( (n>4095) ) {
19143   if ( mp->internal[mp_warning_check]>0 ) {
19144     print_err("Number too large ("); 
19145     mp_print_int(mp, n); mp_print_char(mp, ')');
19146 @.Number too large@>
19147     help2("I have trouble with numbers greater than 4095; watch out.")
19148       ("(Set warningcheck:=0 to suppress this message.)");
19149     mp_put_get_error(mp);
19150   }
19151 }
19152
19153 @ The length operation is somewhat unusual in that it applies to a variety
19154 of different types of operands.
19155
19156 @<Additional cases of unary...@>=
19157 case length_op: 
19158   switch (mp->cur_type) {
19159   case mp_string_type: mp_flush_cur_exp(mp, length(mp->cur_exp)*unity); break;
19160   case mp_path_type: mp_flush_cur_exp(mp, mp_path_length(mp)); break;
19161   case mp_known: mp->cur_exp=abs(mp->cur_exp); break;
19162   case mp_picture_type: mp_flush_cur_exp(mp, mp_pict_length(mp)); break;
19163   default: 
19164     if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) )
19165       mp_flush_cur_exp(mp, mp_pyth_add(mp, 
19166         value(x_part_loc(value(mp->cur_exp))),
19167         value(y_part_loc(value(mp->cur_exp)))));
19168     else mp_bad_unary(mp, c);
19169     break;
19170   }
19171   break;
19172
19173 @ @<Declare unary action...@>=
19174 scaled mp_path_length (MP mp) { /* computes the length of the current path */
19175   scaled n; /* the path length so far */
19176   pointer p; /* traverser */
19177   p=mp->cur_exp;
19178   if ( left_type(p)==mp_endpoint ) n=-unity; else n=0;
19179   do {  p=link(p); n=n+unity; } while (p!=mp->cur_exp);
19180   return n;
19181 }
19182
19183 @ @<Declare unary action...@>=
19184 scaled mp_pict_length (MP mp) { 
19185   /* counts interior components in picture |cur_exp| */
19186   scaled n; /* the count so far */
19187   pointer p; /* traverser */
19188   n=0;
19189   p=link(dummy_loc(mp->cur_exp));
19190   if ( p!=null ) {
19191     if ( is_start_or_stop(p) )
19192       if ( mp_skip_1component(mp, p)==null ) p=link(p);
19193     while ( p!=null )  { 
19194       skip_component(p) return n; 
19195       n=n+unity;   
19196     }
19197   }
19198   return n;
19199 }
19200
19201 @ Implement |turningnumber|
19202
19203 @<Additional cases of unary...@>=
19204 case turning_op:
19205   if ( mp->cur_type==mp_pair_type ) mp_flush_cur_exp(mp, 0);
19206   else if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, turning_op);
19207   else if ( left_type(mp->cur_exp)==mp_endpoint )
19208      mp_flush_cur_exp(mp, 0); /* not a cyclic path */
19209   else
19210     mp_flush_cur_exp(mp, mp_turn_cycles_wrapper(mp, mp->cur_exp));
19211   break;
19212
19213 @ The function |an_angle| returns the value of the |angle| primitive, or $0$ if the
19214 argument is |origin|.
19215
19216 @<Declare unary action...@>=
19217 angle mp_an_angle (MP mp,scaled xpar, scaled ypar) {
19218   if ( (! ((xpar==0) && (ypar==0))) )
19219     return mp_n_arg(mp, xpar,ypar);
19220   return 0;
19221 }
19222
19223
19224 @ The actual turning number is (for the moment) computed in a C function
19225 that receives eight integers corresponding to the four controlling points,
19226 and returns a single angle.  Besides those, we have to account for discrete
19227 moves at the actual points.
19228
19229 @d floor(a) (a>=0 ? a : -(int)(-a))
19230 @d bezier_error (720<<20)+1
19231 @d sign(v) ((v)>0 ? 1 : ((v)<0 ? -1 : 0 ))
19232 @d print_roots(a) 
19233 @d out ((double)(xo>>20))
19234 @d mid ((double)(xm>>20))
19235 @d in  ((double)(xi>>20))
19236 @d divisor (256*256)
19237 @d double2angle(a) (int)floor(a*256.0*256.0*16.0)
19238
19239 @<Declare unary action...@>=
19240 angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19241             integer CX,integer CY,integer DX,integer DY);
19242
19243 @ @c 
19244 angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19245             integer CX,integer CY,integer DX,integer DY) {
19246   double a, b, c;
19247   integer deltax,deltay;
19248   double ax,ay,bx,by,cx,cy,dx,dy;
19249   angle xi = 0, xo = 0, xm = 0;
19250   double res = 0;
19251   ax=AX/divisor;  ay=AY/divisor;
19252   bx=BX/divisor;  by=BY/divisor;
19253   cx=CX/divisor;  cy=CY/divisor;
19254   dx=DX/divisor;  dy=DY/divisor;
19255
19256   deltax = (BX-AX); deltay = (BY-AY);
19257   if (deltax==0 && deltay == 0) { deltax=(CX-AX); deltay=(CY-AY); }
19258   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19259   xi = mp_an_angle(mp,deltax,deltay);
19260
19261   deltax = (CX-BX); deltay = (CY-BY);
19262   xm = mp_an_angle(mp,deltax,deltay);
19263
19264   deltax = (DX-CX); deltay = (DY-CY);
19265   if (deltax==0 && deltay == 0) { deltax=(DX-BX); deltay=(DY-BY); }
19266   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19267   xo = mp_an_angle(mp,deltax,deltay);
19268
19269   a = (bx-ax)*(cy-by) - (cx-bx)*(by-ay); /* a = (bp-ap)x(cp-bp); */
19270   b = (bx-ax)*(dy-cy) - (by-ay)*(dx-cx);; /* b = (bp-ap)x(dp-cp);*/
19271   c = (cx-bx)*(dy-cy) - (dx-cx)*(cy-by); /* c = (cp-bp)x(dp-cp);*/
19272
19273   if ((a==0)&&(c==0)) {
19274     res = (b==0 ?  0 :  (out-in)); 
19275     print_roots("no roots (a)");
19276   } else if ((a==0)||(c==0)) {
19277     if ((sign(b) == sign(a)) || (sign(b) == sign(c))) {
19278       res = out-in; /* ? */
19279       if (res<-180.0) 
19280         res += 360.0;
19281       else if (res>180.0)
19282         res -= 360.0;
19283       print_roots("no roots (b)");
19284     } else {
19285       res = out-in; /* ? */
19286       print_roots("one root (a)");
19287     }
19288   } else if ((sign(a)*sign(c))<0) {
19289     res = out-in; /* ? */
19290       if (res<-180.0) 
19291         res += 360.0;
19292       else if (res>180.0)
19293         res -= 360.0;
19294     print_roots("one root (b)");
19295   } else {
19296     if (sign(a) == sign(b)) {
19297       res = out-in; /* ? */
19298       if (res<-180.0) 
19299         res += 360.0;
19300       else if (res>180.0)
19301         res -= 360.0;
19302       print_roots("no roots (d)");
19303     } else {
19304       if ((b*b) == (4*a*c)) {
19305         res = bezier_error;
19306         print_roots("double root"); /* cusp */
19307       } else if ((b*b) < (4*a*c)) {
19308         res = out-in; /* ? */
19309         if (res<=0.0 &&res>-180.0) 
19310           res += 360.0;
19311         else if (res>=0.0 && res<180.0)
19312           res -= 360.0;
19313         print_roots("no roots (e)");
19314       } else {
19315         res = out-in;
19316         if (res<-180.0) 
19317           res += 360.0;
19318         else if (res>180.0)
19319           res -= 360.0;
19320         print_roots("two roots"); /* two inflections */
19321       }
19322     }
19323   }
19324   return double2angle(res);
19325 }
19326
19327 @
19328 @d p_nextnext link(link(p))
19329 @d p_next link(p)
19330 @d seven_twenty_deg 05500000000 /* $720\cdot2^{20}$, represents $720^\circ$ */
19331
19332 @<Declare unary action...@>=
19333 scaled mp_new_turn_cycles (MP mp,pointer c) {
19334   angle res,ang; /*  the angles of intermediate results  */
19335   scaled turns;  /*  the turn counter  */
19336   pointer p;     /*  for running around the path  */
19337   integer xp,yp;   /*  coordinates of next point  */
19338   integer x,y;   /*  helper coordinates  */
19339   angle in_angle,out_angle;     /*  helper angles */
19340   int old_setting; /* saved |selector| setting */
19341   res=0;
19342   turns= 0;
19343   p=c;
19344   old_setting = mp->selector; mp->selector=term_only;
19345   if ( mp->internal[mp_tracing_commands]>unity ) {
19346     mp_begin_diagnostic(mp);
19347     mp_print_nl(mp, "");
19348     mp_end_diagnostic(mp, false);
19349   }
19350   do { 
19351     xp = x_coord(p_next); yp = y_coord(p_next);
19352     ang  = mp_bezier_slope(mp,x_coord(p), y_coord(p), right_x(p), right_y(p),
19353              left_x(p_next), left_y(p_next), xp, yp);
19354     if ( ang>seven_twenty_deg ) {
19355       print_err("Strange path");
19356       mp_error(mp);
19357       mp->selector=old_setting;
19358       return 0;
19359     }
19360     res  = res + ang;
19361     if ( res > one_eighty_deg ) {
19362       res = res - three_sixty_deg;
19363       turns = turns + unity;
19364     }
19365     if ( res <= -one_eighty_deg ) {
19366       res = res + three_sixty_deg;
19367       turns = turns - unity;
19368     }
19369     /*  incoming angle at next point  */
19370     x = left_x(p_next);  y = left_y(p_next);
19371     if ( (xp==x)&&(yp==y) ) { x = right_x(p);  y = right_y(p);  };
19372     if ( (xp==x)&&(yp==y) ) { x = x_coord(p);  y = y_coord(p);  };
19373     in_angle = mp_an_angle(mp, xp - x, yp - y);
19374     /*  outgoing angle at next point  */
19375     x = right_x(p_next);  y = right_y(p_next);
19376     if ( (xp==x)&&(yp==y) ) { x = left_x(p_nextnext);  y = left_y(p_nextnext);  };
19377     if ( (xp==x)&&(yp==y) ) { x = x_coord(p_nextnext); y = y_coord(p_nextnext); };
19378     out_angle = mp_an_angle(mp, x - xp, y- yp);
19379     ang  = (out_angle - in_angle);
19380     reduce_angle(ang);
19381     if ( ang!=0 ) {
19382       res  = res + ang;
19383       if ( res >= one_eighty_deg ) {
19384         res = res - three_sixty_deg;
19385         turns = turns + unity;
19386       };
19387       if ( res <= -one_eighty_deg ) {
19388         res = res + three_sixty_deg;
19389         turns = turns - unity;
19390       };
19391     };
19392     p = link(p);
19393   } while (p!=c);
19394   mp->selector=old_setting;
19395   return turns;
19396 }
19397
19398
19399 @ This code is based on Bogus\l{}av Jackowski's
19400 |emergency_turningnumber| macro, with some minor changes by Taco
19401 Hoekwater. The macro code looked more like this:
19402 {\obeylines
19403 vardef turning\_number primary p =
19404 ~~save res, ang, turns;
19405 ~~res := 0;
19406 ~~if length p <= 2:
19407 ~~~~if Angle ((point 0 of p) - (postcontrol 0 of p)) >= 0:  1  else: -1 fi
19408 ~~else:
19409 ~~~~for t = 0 upto length p-1 :
19410 ~~~~~~angc := Angle ((point t+1 of p)  - (point t of p))
19411 ~~~~~~~~- Angle ((point t of p) - (point t-1 of p));
19412 ~~~~~~if angc > 180: angc := angc - 360; fi;
19413 ~~~~~~if angc < -180: angc := angc + 360; fi;
19414 ~~~~~~res  := res + angc;
19415 ~~~~endfor;
19416 ~~res/360
19417 ~~fi
19418 enddef;}
19419 The general idea is to calculate only the sum of the angles of
19420 straight lines between the points, of a path, not worrying about cusps
19421 or self-intersections in the segments at all. If the segment is not
19422 well-behaved, the result is not necesarily correct. But the old code
19423 was not always correct either, and worse, it sometimes failed for
19424 well-behaved paths as well. All known bugs that were triggered by the
19425 original code no longer occur with this code, and it runs roughly 3
19426 times as fast because the algorithm is much simpler.
19427
19428 @ It is possible to overflow the return value of the |turn_cycles|
19429 function when the path is sufficiently long and winding, but I am not
19430 going to bother testing for that. In any case, it would only return
19431 the looped result value, which is not a big problem.
19432
19433 The macro code for the repeat loop was a bit nicer to look
19434 at than the pascal code, because it could use |point -1 of p|. In
19435 pascal, the fastest way to loop around the path is not to look
19436 backward once, but forward twice. These defines help hide the trick.
19437
19438 @d p_to link(link(p))
19439 @d p_here link(p)
19440 @d p_from p
19441
19442 @<Declare unary action...@>=
19443 scaled mp_turn_cycles (MP mp,pointer c) {
19444   angle res,ang; /*  the angles of intermediate results  */
19445   scaled turns;  /*  the turn counter  */
19446   pointer p;     /*  for running around the path  */
19447   res=0;  turns= 0; p=c;
19448   do { 
19449     ang  = mp_an_angle (mp, x_coord(p_to) - x_coord(p_here), 
19450                             y_coord(p_to) - y_coord(p_here))
19451         - mp_an_angle (mp, x_coord(p_here) - x_coord(p_from), 
19452                            y_coord(p_here) - y_coord(p_from));
19453     reduce_angle(ang);
19454     res  = res + ang;
19455     if ( res >= three_sixty_deg )  {
19456       res = res - three_sixty_deg;
19457       turns = turns + unity;
19458     };
19459     if ( res <= -three_sixty_deg ) {
19460       res = res + three_sixty_deg;
19461       turns = turns - unity;
19462     };
19463     p = link(p);
19464   } while (p!=c);
19465   return turns;
19466 }
19467
19468 @ @<Declare unary action...@>=
19469 scaled mp_turn_cycles_wrapper (MP mp,pointer c) {
19470   scaled nval,oval;
19471   scaled saved_t_o; /* tracing\_online saved  */
19472   if ( (link(c)==c)||(link(link(c))==c) ) {
19473     if ( mp_an_angle (mp, x_coord(c) - right_x(c),  y_coord(c) - right_y(c)) > 0 )
19474       return unity;
19475     else
19476       return -unity;
19477   } else {
19478     nval = mp_new_turn_cycles(mp, c);
19479     oval = mp_turn_cycles(mp, c);
19480     if ( nval!=oval ) {
19481       saved_t_o=mp->internal[mp_tracing_online];
19482       mp->internal[mp_tracing_online]=unity;
19483       mp_begin_diagnostic(mp);
19484       mp_print_nl (mp, "Warning: the turningnumber algorithms do not agree."
19485                        " The current computed value is ");
19486       mp_print_scaled(mp, nval);
19487       mp_print(mp, ", but the 'connect-the-dots' algorithm returned ");
19488       mp_print_scaled(mp, oval);
19489       mp_end_diagnostic(mp, false);
19490       mp->internal[mp_tracing_online]=saved_t_o;
19491     }
19492     return nval;
19493   }
19494 }
19495
19496 @ @<Declare unary action...@>=
19497 scaled mp_count_turns (MP mp,pointer c) {
19498   pointer p; /* a knot in envelope spec |c| */
19499   integer t; /* total pen offset changes counted */
19500   t=0; p=c;
19501   do {  
19502     t=t+info(p)-zero_off;
19503     p=link(p);
19504   } while (p!=c);
19505   return ((t / 3)*unity);
19506 }
19507
19508 @ @d type_range(A,B) { 
19509   if ( (mp->cur_type>=(A)) && (mp->cur_type<=(B)) ) 
19510     mp_flush_cur_exp(mp, true_code);
19511   else mp_flush_cur_exp(mp, false_code);
19512   mp->cur_type=mp_boolean_type;
19513   }
19514 @d type_test(A) { 
19515   if ( mp->cur_type==(A) ) mp_flush_cur_exp(mp, true_code);
19516   else mp_flush_cur_exp(mp, false_code);
19517   mp->cur_type=mp_boolean_type;
19518   }
19519
19520 @<Additional cases of unary operators@>=
19521 case mp_boolean_type: 
19522   type_range(mp_boolean_type,mp_unknown_boolean); break;
19523 case mp_string_type: 
19524   type_range(mp_string_type,mp_unknown_string); break;
19525 case mp_pen_type: 
19526   type_range(mp_pen_type,mp_unknown_pen); break;
19527 case mp_path_type: 
19528   type_range(mp_path_type,mp_unknown_path); break;
19529 case mp_picture_type: 
19530   type_range(mp_picture_type,mp_unknown_picture); break;
19531 case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
19532 case mp_pair_type: 
19533   type_test(c); break;
19534 case mp_numeric_type: 
19535   type_range(mp_known,mp_independent); break;
19536 case known_op: case unknown_op: 
19537   mp_test_known(mp, c); break;
19538
19539 @ @<Declare unary action procedures@>=
19540 void mp_test_known (MP mp,quarterword c) {
19541   int b; /* is the current expression known? */
19542   pointer p,q; /* locations in a big node */
19543   b=false_code;
19544   switch (mp->cur_type) {
19545   case mp_vacuous: case mp_boolean_type: case mp_string_type:
19546   case mp_pen_type: case mp_path_type: case mp_picture_type:
19547   case mp_known: 
19548     b=true_code;
19549     break;
19550   case mp_transform_type:
19551   case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: 
19552     p=value(mp->cur_exp);
19553     q=p+mp->big_node_size[mp->cur_type];
19554     do {  
19555       q=q-2;
19556       if ( type(q)!=mp_known ) 
19557        goto DONE;
19558     } while (q!=p);
19559     b=true_code;
19560   DONE:  
19561     break;
19562   default: 
19563     break;
19564   }
19565   if ( c==known_op ) mp_flush_cur_exp(mp, b);
19566   else mp_flush_cur_exp(mp, true_code+false_code-b);
19567   mp->cur_type=mp_boolean_type;
19568 }
19569
19570 @ @<Additional cases of unary operators@>=
19571 case cycle_op: 
19572   if ( mp->cur_type!=mp_path_type ) mp_flush_cur_exp(mp, false_code);
19573   else if ( left_type(mp->cur_exp)!=mp_endpoint ) mp_flush_cur_exp(mp, true_code);
19574   else mp_flush_cur_exp(mp, false_code);
19575   mp->cur_type=mp_boolean_type;
19576   break;
19577
19578 @ @<Additional cases of unary operators@>=
19579 case arc_length: 
19580   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19581   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, arc_length);
19582   else mp_flush_cur_exp(mp, mp_get_arc_length(mp, mp->cur_exp));
19583   break;
19584
19585 @ Here we use the fact that |c-filled_op+fill_code| is the desired graphical
19586 object |type|.
19587 @^data structure assumptions@>
19588
19589 @<Additional cases of unary operators@>=
19590 case filled_op:
19591 case stroked_op:
19592 case textual_op:
19593 case clipped_op:
19594 case bounded_op:
19595   if ( mp->cur_type!=mp_picture_type ) mp_flush_cur_exp(mp, false_code);
19596   else if ( link(dummy_loc(mp->cur_exp))==null ) mp_flush_cur_exp(mp, false_code);
19597   else if ( type(link(dummy_loc(mp->cur_exp)))==c+mp_fill_code-filled_op )
19598     mp_flush_cur_exp(mp, true_code);
19599   else mp_flush_cur_exp(mp, false_code);
19600   mp->cur_type=mp_boolean_type;
19601   break;
19602
19603 @ @<Additional cases of unary operators@>=
19604 case make_pen_op: 
19605   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19606   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, make_pen_op);
19607   else { 
19608     mp->cur_type=mp_pen_type;
19609     mp->cur_exp=mp_make_pen(mp, mp->cur_exp,true);
19610   };
19611   break;
19612 case make_path_op: 
19613   if ( mp->cur_type!=mp_pen_type ) mp_bad_unary(mp, make_path_op);
19614   else  { 
19615     mp->cur_type=mp_path_type;
19616     mp_make_path(mp, mp->cur_exp);
19617   };
19618   break;
19619 case reverse: 
19620   if ( mp->cur_type==mp_path_type ) {
19621     p=mp_htap_ypoc(mp, mp->cur_exp);
19622     if ( right_type(p)==mp_endpoint ) p=link(p);
19623     mp_toss_knot_list(mp, mp->cur_exp); mp->cur_exp=p;
19624   } else if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19625   else mp_bad_unary(mp, reverse);
19626   break;
19627
19628 @ The |pair_value| routine changes the current expression to a
19629 given ordered pair of values.
19630
19631 @<Declare unary action procedures@>=
19632 void mp_pair_value (MP mp,scaled x, scaled y) {
19633   pointer p; /* a pair node */
19634   p=mp_get_node(mp, value_node_size); 
19635   mp_flush_cur_exp(mp, p); mp->cur_type=mp_pair_type;
19636   type(p)=mp_pair_type; name_type(p)=mp_capsule; mp_init_big_node(mp, p);
19637   p=value(p);
19638   type(x_part_loc(p))=mp_known; value(x_part_loc(p))=x;
19639   type(y_part_loc(p))=mp_known; value(y_part_loc(p))=y;
19640 }
19641
19642 @ @<Additional cases of unary operators@>=
19643 case ll_corner_op: 
19644   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ll_corner_op);
19645   else mp_pair_value(mp, minx,miny);
19646   break;
19647 case lr_corner_op: 
19648   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, lr_corner_op);
19649   else mp_pair_value(mp, maxx,miny);
19650   break;
19651 case ul_corner_op: 
19652   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ul_corner_op);
19653   else mp_pair_value(mp, minx,maxy);
19654   break;
19655 case ur_corner_op: 
19656   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ur_corner_op);
19657   else mp_pair_value(mp, maxx,maxy);
19658   break;
19659
19660 @ Here is a function that sets |minx|, |maxx|, |miny|, |maxy| to the bounding
19661 box of the current expression.  The boolean result is |false| if the expression
19662 has the wrong type.
19663
19664 @<Declare unary action procedures@>=
19665 boolean mp_get_cur_bbox (MP mp) { 
19666   switch (mp->cur_type) {
19667   case mp_picture_type: 
19668     mp_set_bbox(mp, mp->cur_exp,true);
19669     if ( minx_val(mp->cur_exp)>maxx_val(mp->cur_exp) ) {
19670       minx=0; maxx=0; miny=0; maxy=0;
19671     } else { 
19672       minx=minx_val(mp->cur_exp);
19673       maxx=maxx_val(mp->cur_exp);
19674       miny=miny_val(mp->cur_exp);
19675       maxy=maxy_val(mp->cur_exp);
19676     }
19677     break;
19678   case mp_path_type: 
19679     mp_path_bbox(mp, mp->cur_exp);
19680     break;
19681   case mp_pen_type: 
19682     mp_pen_bbox(mp, mp->cur_exp);
19683     break;
19684   default: 
19685     return false;
19686   }
19687   return true;
19688 }
19689
19690 @ @<Additional cases of unary operators@>=
19691 case read_from_op:
19692 case close_from_op: 
19693   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
19694   else mp_do_read_or_close(mp,c);
19695   break;
19696
19697 @ Here is a routine that interprets |cur_exp| as a file name and tries to read
19698 a line from the file or to close the file.
19699
19700 @<Declare unary action procedures@>=
19701 void mp_do_read_or_close (MP mp,quarterword c) {
19702   readf_index n,n0; /* indices for searching |rd_fname| */
19703   @<Find the |n| where |rd_fname[n]=cur_exp|; if |cur_exp| must be inserted,
19704     call |start_read_input| and |goto found| or |not_found|@>;
19705   mp_begin_file_reading(mp);
19706   name=is_read;
19707   if ( mp_input_ln(mp, mp->rd_file[n] ) ) 
19708     goto FOUND;
19709   mp_end_file_reading(mp);
19710 NOT_FOUND:
19711   @<Record the end of file and set |cur_exp| to a dummy value@>;
19712   return;
19713 CLOSE_FILE:
19714   mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous; 
19715   return;
19716 FOUND:
19717   mp_flush_cur_exp(mp, 0);
19718   mp_finish_read(mp);
19719 }
19720
19721 @ Free slots in the |rd_file| and |rd_fname| arrays are marked with NULL's in
19722 |rd_fname|.
19723
19724 @<Find the |n| where |rd_fname[n]=cur_exp|...@>=
19725 {   
19726   char *fn;
19727   n=mp->read_files;
19728   n0=mp->read_files;
19729   fn = str(mp->cur_exp);
19730   while (mp_xstrcmp(fn,mp->rd_fname[n])!=0) { 
19731     if ( n>0 ) {
19732       decr(n);
19733     } else if ( c==close_from_op ) {
19734       goto CLOSE_FILE;
19735     } else {
19736       if ( n0==mp->read_files ) {
19737         if ( mp->read_files<mp->max_read_files ) {
19738           incr(mp->read_files);
19739         } else {
19740           void **rd_file;
19741           char **rd_fname;
19742               readf_index l,k;
19743           l = mp->max_read_files + (mp->max_read_files>>2);
19744           rd_file = xmalloc((l+1), sizeof(void *));
19745           rd_fname = xmalloc((l+1), sizeof(char *));
19746               for (k=0;k<=l;k++) {
19747             if (k<=mp->max_read_files) {
19748                   rd_file[k]=mp->rd_file[k]; 
19749               rd_fname[k]=mp->rd_fname[k];
19750             } else {
19751               rd_file[k]=0; 
19752               rd_fname[k]=NULL;
19753             }
19754           }
19755               xfree(mp->rd_file); xfree(mp->rd_fname);
19756           mp->max_read_files = l;
19757           mp->rd_file = rd_file;
19758           mp->rd_fname = rd_fname;
19759         }
19760       }
19761       n=n0;
19762       if ( mp_start_read_input(mp,fn,n) ) 
19763         goto FOUND;
19764       else 
19765         goto NOT_FOUND;
19766     }
19767     if ( mp->rd_fname[n]==NULL ) { n0=n; }
19768   } 
19769   if ( c==close_from_op ) { 
19770     (mp->close_file)(mp,mp->rd_file[n]); 
19771     goto NOT_FOUND; 
19772   }
19773 }
19774
19775 @ @<Record the end of file and set |cur_exp| to a dummy value@>=
19776 xfree(mp->rd_fname[n]);
19777 mp->rd_fname[n]=NULL;
19778 if ( n==mp->read_files-1 ) mp->read_files=n;
19779 if ( c==close_from_op ) 
19780   goto CLOSE_FILE;
19781 mp_flush_cur_exp(mp, mp->eof_line);
19782 mp->cur_type=mp_string_type
19783
19784 @ The string denoting end-of-file is a one-byte string at position zero, by definition
19785
19786 @<Glob...@>=
19787 str_number eof_line;
19788
19789 @ @<Set init...@>=
19790 mp->eof_line=0;
19791
19792 @ Finally, we have the operations that combine a capsule~|p|
19793 with the current expression.
19794
19795 @c @<Declare binary action procedures@>;
19796 void mp_do_binary (MP mp,pointer p, quarterword c) {
19797   pointer q,r,rr; /* for list manipulation */
19798   pointer old_p,old_exp; /* capsules to recycle */
19799   integer v; /* for numeric manipulation */
19800   check_arith;
19801   if ( mp->internal[mp_tracing_commands]>two ) {
19802     @<Trace the current binary operation@>;
19803   }
19804   @<Sidestep |independent| cases in capsule |p|@>;
19805   @<Sidestep |independent| cases in the current expression@>;
19806   switch (c) {
19807   case plus: case minus:
19808     @<Add or subtract the current expression from |p|@>;
19809     break;
19810   @<Additional cases of binary operators@>;
19811   }; /* there are no other cases */
19812   mp_recycle_value(mp, p); 
19813   mp_free_node(mp, p,value_node_size); /* |return| to avoid this */
19814   check_arith; 
19815   @<Recycle any sidestepped |independent| capsules@>;
19816 }
19817
19818 @ @<Declare binary action...@>=
19819 void mp_bad_binary (MP mp,pointer p, quarterword c) { 
19820   mp_disp_err(mp, p,"");
19821   exp_err("Not implemented: ");
19822 @.Not implemented...@>
19823   if ( c>=min_of ) mp_print_op(mp, c);
19824   mp_print_known_or_unknown_type(mp, type(p),p);
19825   if ( c>=min_of ) mp_print(mp, "of"); else mp_print_op(mp, c);
19826   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
19827   help3("I'm afraid I don't know how to apply that operation to that")
19828        ("combination of types. Continue, and I'll return the second")
19829       ("argument (see above) as the result of the operation.");
19830   mp_put_get_error(mp);
19831 }
19832 void mp_bad_envelope_pen (MP mp) {
19833   mp_disp_err(mp, null,"");
19834   exp_err("Not implemented: envelope(elliptical pen)of(path)");
19835 @.Not implemented...@>
19836   help3("I'm afraid I don't know how to apply that operation to that")
19837        ("combination of types. Continue, and I'll return the second")
19838       ("argument (see above) as the result of the operation.");
19839   mp_put_get_error(mp);
19840 }
19841
19842 @ @<Trace the current binary operation@>=
19843
19844   mp_begin_diagnostic(mp); mp_print_nl(mp, "{(");
19845   mp_print_exp(mp,p,0); /* show the operand, but not verbosely */
19846   mp_print_char(mp,')'); mp_print_op(mp,c); mp_print_char(mp,'(');
19847   mp_print_exp(mp,null,0); mp_print(mp,")}"); 
19848   mp_end_diagnostic(mp, false);
19849 }
19850
19851 @ Several of the binary operations are potentially complicated by the
19852 fact that |independent| values can sneak into capsules. For example,
19853 we've seen an instance of this difficulty in the unary operation
19854 of negation. In order to reduce the number of cases that need to be
19855 handled, we first change the two operands (if necessary)
19856 to rid them of |independent| components. The original operands are
19857 put into capsules called |old_p| and |old_exp|, which will be
19858 recycled after the binary operation has been safely carried out.
19859
19860 @<Recycle any sidestepped |independent| capsules@>=
19861 if ( old_p!=null ) { 
19862   mp_recycle_value(mp, old_p); mp_free_node(mp, old_p,value_node_size);
19863 }
19864 if ( old_exp!=null ) {
19865   mp_recycle_value(mp, old_exp); mp_free_node(mp, old_exp,value_node_size);
19866 }
19867
19868 @ A big node is considered to be ``tarnished'' if it contains at least one
19869 independent component. We will define a simple function called `|tarnished|'
19870 that returns |null| if and only if its argument is not tarnished.
19871
19872 @<Sidestep |independent| cases in capsule |p|@>=
19873 switch (type(p)) {
19874 case mp_transform_type:
19875 case mp_color_type:
19876 case mp_cmykcolor_type:
19877 case mp_pair_type: 
19878   old_p=mp_tarnished(mp, p);
19879   break;
19880 case mp_independent: old_p=mp_void; break;
19881 default: old_p=null; break;
19882 };
19883 if ( old_p!=null ) {
19884   q=mp_stash_cur_exp(mp); old_p=p; mp_make_exp_copy(mp, old_p);
19885   p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
19886 }
19887
19888 @ @<Sidestep |independent| cases in the current expression@>=
19889 switch (mp->cur_type) {
19890 case mp_transform_type:
19891 case mp_color_type:
19892 case mp_cmykcolor_type:
19893 case mp_pair_type: 
19894   old_exp=mp_tarnished(mp, mp->cur_exp);
19895   break;
19896 case mp_independent:old_exp=mp_void; break;
19897 default: old_exp=null; break;
19898 };
19899 if ( old_exp!=null ) {
19900   old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
19901 }
19902
19903 @ @<Declare binary action...@>=
19904 pointer mp_tarnished (MP mp,pointer p) {
19905   pointer q; /* beginning of the big node */
19906   pointer r; /* current position in the big node */
19907   q=value(p); r=q+mp->big_node_size[type(p)];
19908   do {  
19909    r=r-2;
19910    if ( type(r)==mp_independent ) return mp_void; 
19911   } while (r!=q);
19912   return null;
19913 }
19914
19915 @ @<Add or subtract the current expression from |p|@>=
19916 if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
19917   mp_bad_binary(mp, p,c);
19918 } else  {
19919   if ((mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
19920     mp_add_or_subtract(mp, p,null,c);
19921   } else {
19922     if ( mp->cur_type!=type(p) )  {
19923       mp_bad_binary(mp, p,c);
19924     } else { 
19925       q=value(p); r=value(mp->cur_exp);
19926       rr=r+mp->big_node_size[mp->cur_type];
19927       while ( r<rr ) { 
19928         mp_add_or_subtract(mp, q,r,c);
19929         q=q+2; r=r+2;
19930       }
19931     }
19932   }
19933 }
19934
19935 @ The first argument to |add_or_subtract| is the location of a value node
19936 in a capsule or pair node that will soon be recycled. The second argument
19937 is either a location within a pair or transform node of |cur_exp|,
19938 or it is null (which means that |cur_exp| itself should be the second
19939 argument).  The third argument is either |plus| or |minus|.
19940
19941 The sum or difference of the numeric quantities will replace the second
19942 operand.  Arithmetic overflow may go undetected; users aren't supposed to
19943 be monkeying around with really big values.
19944
19945 @<Declare binary action...@>=
19946 @<Declare the procedure called |dep_finish|@>;
19947 void mp_add_or_subtract (MP mp,pointer p, pointer q, quarterword c) {
19948   small_number s,t; /* operand types */
19949   pointer r; /* list traverser */
19950   integer v; /* second operand value */
19951   if ( q==null ) { 
19952     t=mp->cur_type;
19953     if ( t<mp_dependent ) v=mp->cur_exp; else v=dep_list(mp->cur_exp);
19954   } else { 
19955     t=type(q);
19956     if ( t<mp_dependent ) v=value(q); else v=dep_list(q);
19957   }
19958   if ( t==mp_known ) {
19959     if ( c==minus ) negate(v);
19960     if ( type(p)==mp_known ) {
19961       v=mp_slow_add(mp, value(p),v);
19962       if ( q==null ) mp->cur_exp=v; else value(q)=v;
19963       return;
19964     }
19965     @<Add a known value to the constant term of |dep_list(p)|@>;
19966   } else  { 
19967     if ( c==minus ) mp_negate_dep_list(mp, v);
19968     @<Add operand |p| to the dependency list |v|@>;
19969   }
19970 }
19971
19972 @ @<Add a known value to the constant term of |dep_list(p)|@>=
19973 r=dep_list(p);
19974 while ( info(r)!=null ) r=link(r);
19975 value(r)=mp_slow_add(mp, value(r),v);
19976 if ( q==null ) {
19977   q=mp_get_node(mp, value_node_size); mp->cur_exp=q; mp->cur_type=type(p);
19978   name_type(q)=mp_capsule;
19979 }
19980 dep_list(q)=dep_list(p); type(q)=type(p);
19981 prev_dep(q)=prev_dep(p); link(prev_dep(p))=q;
19982 type(p)=mp_known; /* this will keep the recycler from collecting non-garbage */
19983
19984 @ We prefer |dependent| lists to |mp_proto_dependent| ones, because it is
19985 nice to retain the extra accuracy of |fraction| coefficients.
19986 But we have to handle both kinds, and mixtures too.
19987
19988 @<Add operand |p| to the dependency list |v|@>=
19989 if ( type(p)==mp_known ) {
19990   @<Add the known |value(p)| to the constant term of |v|@>;
19991 } else { 
19992   s=type(p); r=dep_list(p);
19993   if ( t==mp_dependent ) {
19994     if ( s==mp_dependent ) {
19995       if ( mp_max_coef(mp, r)+mp_max_coef(mp, v)<coef_bound )
19996         v=mp_p_plus_q(mp, v,r,mp_dependent); goto DONE;
19997       } /* |fix_needed| will necessarily be false */
19998       t=mp_proto_dependent; 
19999       v=mp_p_over_v(mp, v,unity,mp_dependent,mp_proto_dependent);
20000     }
20001     if ( s==mp_proto_dependent ) v=mp_p_plus_q(mp, v,r,mp_proto_dependent);
20002     else v=mp_p_plus_fq(mp, v,unity,r,mp_proto_dependent,mp_dependent);
20003  DONE:  
20004     @<Output the answer, |v| (which might have become |known|)@>;
20005   }
20006
20007 @ @<Add the known |value(p)| to the constant term of |v|@>=
20008
20009   while ( info(v)!=null ) v=link(v);
20010   value(v)=mp_slow_add(mp, value(p),value(v));
20011 }
20012
20013 @ @<Output the answer, |v| (which might have become |known|)@>=
20014 if ( q!=null ) mp_dep_finish(mp, v,q,t);
20015 else  { mp->cur_type=t; mp_dep_finish(mp, v,null,t); }
20016
20017 @ Here's the current situation: The dependency list |v| of type |t|
20018 should either be put into the current expression (if |q=null|) or
20019 into location |q| within a pair node (otherwise). The destination (|cur_exp|
20020 or |q|) formerly held a dependency list with the same
20021 final pointer as the list |v|.
20022
20023 @<Declare the procedure called |dep_finish|@>=
20024 void mp_dep_finish (MP mp, pointer v, pointer q, small_number t) {
20025   pointer p; /* the destination */
20026   scaled vv; /* the value, if it is |known| */
20027   if ( q==null ) p=mp->cur_exp; else p=q;
20028   dep_list(p)=v; type(p)=t;
20029   if ( info(v)==null ) { 
20030     vv=value(v);
20031     if ( q==null ) { 
20032       mp_flush_cur_exp(mp, vv);
20033     } else  { 
20034       mp_recycle_value(mp, p); type(q)=mp_known; value(q)=vv; 
20035     }
20036   } else if ( q==null ) {
20037     mp->cur_type=t;
20038   }
20039   if ( mp->fix_needed ) mp_fix_dependencies(mp);
20040 }
20041
20042 @ Let's turn now to the six basic relations of comparison.
20043
20044 @<Additional cases of binary operators@>=
20045 case less_than: case less_or_equal: case greater_than:
20046 case greater_or_equal: case equal_to: case unequal_to:
20047   check_arith; /* at this point |arith_error| should be |false|? */
20048   if ( (mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
20049     mp_add_or_subtract(mp, p,null,minus); /* |cur_exp:=(p)-cur_exp| */
20050   } else if ( mp->cur_type!=type(p) ) {
20051     mp_bad_binary(mp, p,c); goto DONE; 
20052   } else if ( mp->cur_type==mp_string_type ) {
20053     mp_flush_cur_exp(mp, mp_str_vs_str(mp, value(p),mp->cur_exp));
20054   } else if ((mp->cur_type==mp_unknown_string)||
20055            (mp->cur_type==mp_unknown_boolean) ) {
20056     @<Check if unknowns have been equated@>;
20057   } else if ( (mp->cur_type<=mp_pair_type)&&(mp->cur_type>=mp_transform_type)) {
20058     @<Reduce comparison of big nodes to comparison of scalars@>;
20059   } else if ( mp->cur_type==mp_boolean_type ) {
20060     mp_flush_cur_exp(mp, mp->cur_exp-value(p));
20061   } else { 
20062     mp_bad_binary(mp, p,c); goto DONE;
20063   }
20064   @<Compare the current expression with zero@>;
20065 DONE:  
20066   mp->arith_error=false; /* ignore overflow in comparisons */
20067   break;
20068
20069 @ @<Compare the current expression with zero@>=
20070 if ( mp->cur_type!=mp_known ) {
20071   if ( mp->cur_type<mp_known ) {
20072     mp_disp_err(mp, p,"");
20073     help1("The quantities shown above have not been equated.")
20074   } else  {
20075     help2("Oh dear. I can\'t decide if the expression above is positive,")
20076      ("negative, or zero. So this comparison test won't be `true'.");
20077   }
20078   exp_err("Unknown relation will be considered false");
20079 @.Unknown relation...@>
20080   mp_put_get_flush_error(mp, false_code);
20081 } else {
20082   switch (c) {
20083   case less_than: boolean_reset(mp->cur_exp<0); break;
20084   case less_or_equal: boolean_reset(mp->cur_exp<=0); break;
20085   case greater_than: boolean_reset(mp->cur_exp>0); break;
20086   case greater_or_equal: boolean_reset(mp->cur_exp>=0); break;
20087   case equal_to: boolean_reset(mp->cur_exp==0); break;
20088   case unequal_to: boolean_reset(mp->cur_exp!=0); break;
20089   }; /* there are no other cases */
20090 }
20091 mp->cur_type=mp_boolean_type
20092
20093 @ When two unknown strings are in the same ring, we know that they are
20094 equal. Otherwise, we don't know whether they are equal or not, so we
20095 make no change.
20096
20097 @<Check if unknowns have been equated@>=
20098
20099   q=value(mp->cur_exp);
20100   while ( (q!=mp->cur_exp)&&(q!=p) ) q=value(q);
20101   if ( q==p ) mp_flush_cur_exp(mp, 0);
20102 }
20103
20104 @ @<Reduce comparison of big nodes to comparison of scalars@>=
20105
20106   q=value(p); r=value(mp->cur_exp);
20107   rr=r+mp->big_node_size[mp->cur_type]-2;
20108   while (1) { mp_add_or_subtract(mp, q,r,minus);
20109     if ( type(r)!=mp_known ) break;
20110     if ( value(r)!=0 ) break;
20111     if ( r==rr ) break;
20112     q=q+2; r=r+2;
20113   }
20114   mp_take_part(mp, name_type(r)+x_part-mp_x_part_sector);
20115 }
20116
20117 @ Here we use the sneaky fact that |and_op-false_code=or_op-true_code|.
20118
20119 @<Additional cases of binary operators@>=
20120 case and_op:
20121 case or_op: 
20122   if ( (type(p)!=mp_boolean_type)||(mp->cur_type!=mp_boolean_type) )
20123     mp_bad_binary(mp, p,c);
20124   else if ( value(p)==c+false_code-and_op ) mp->cur_exp=value(p);
20125   break;
20126
20127 @ @<Additional cases of binary operators@>=
20128 case times: 
20129   if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
20130    mp_bad_binary(mp, p,times);
20131   } else if ( (mp->cur_type==mp_known)||(type(p)==mp_known) ) {
20132     @<Multiply when at least one operand is known@>;
20133   } else if ( (mp_nice_color_or_pair(mp, p,type(p))&&(mp->cur_type>mp_pair_type))
20134       ||(mp_nice_color_or_pair(mp, mp->cur_exp,mp->cur_type)&&
20135           (type(p)>mp_pair_type)) ) {
20136     mp_hard_times(mp, p); return;
20137   } else {
20138     mp_bad_binary(mp, p,times);
20139   }
20140   break;
20141
20142 @ @<Multiply when at least one operand is known@>=
20143
20144   if ( type(p)==mp_known ) {
20145     v=value(p); mp_free_node(mp, p,value_node_size); 
20146   } else {
20147     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20148   }
20149   if ( mp->cur_type==mp_known ) {
20150     mp->cur_exp=mp_take_scaled(mp, mp->cur_exp,v);
20151   } else if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_color_type)||
20152               (mp->cur_type==mp_cmykcolor_type) ) {
20153     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20154     do {  
20155        p=p-2; mp_dep_mult(mp, p,v,true);
20156     } while (p!=value(mp->cur_exp));
20157   } else {
20158     mp_dep_mult(mp, null,v,true);
20159   }
20160   return;
20161 }
20162
20163 @ @<Declare binary action...@>=
20164 void mp_dep_mult (MP mp,pointer p, integer v, boolean v_is_scaled) {
20165   pointer q; /* the dependency list being multiplied by |v| */
20166   small_number s,t; /* its type, before and after */
20167   if ( p==null ) {
20168     q=mp->cur_exp;
20169   } else if ( type(p)!=mp_known ) {
20170     q=p;
20171   } else { 
20172     if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
20173     else value(p)=mp_take_fraction(mp, value(p),v);
20174     return;
20175   };
20176   t=type(q); q=dep_list(q); s=t;
20177   if ( t==mp_dependent ) if ( v_is_scaled )
20178     if (mp_ab_vs_cd(mp, mp_max_coef(mp,q),abs(v),coef_bound-1,unity)>=0 ) 
20179       t=mp_proto_dependent;
20180   q=mp_p_times_v(mp, q,v,s,t,v_is_scaled); 
20181   mp_dep_finish(mp, q,p,t);
20182 }
20183
20184 @ Here is a routine that is similar to |times|; but it is invoked only
20185 internally, when |v| is a |fraction| whose magnitude is at most~1,
20186 and when |cur_type>=mp_color_type|.
20187
20188 @c void mp_frac_mult (MP mp,scaled n, scaled d) {
20189   /* multiplies |cur_exp| by |n/d| */
20190   pointer p; /* a pair node */
20191   pointer old_exp; /* a capsule to recycle */
20192   fraction v; /* |n/d| */
20193   if ( mp->internal[mp_tracing_commands]>two ) {
20194     @<Trace the fraction multiplication@>;
20195   }
20196   switch (mp->cur_type) {
20197   case mp_transform_type:
20198   case mp_color_type:
20199   case mp_cmykcolor_type:
20200   case mp_pair_type:
20201    old_exp=mp_tarnished(mp, mp->cur_exp);
20202    break;
20203   case mp_independent: old_exp=mp_void; break;
20204   default: old_exp=null; break;
20205   }
20206   if ( old_exp!=null ) { 
20207      old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
20208   }
20209   v=mp_make_fraction(mp, n,d);
20210   if ( mp->cur_type==mp_known ) {
20211     mp->cur_exp=mp_take_fraction(mp, mp->cur_exp,v);
20212   } else if ( mp->cur_type<=mp_pair_type ) { 
20213     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20214     do {  
20215       p=p-2;
20216       mp_dep_mult(mp, p,v,false);
20217     } while (p!=value(mp->cur_exp));
20218   } else {
20219     mp_dep_mult(mp, null,v,false);
20220   }
20221   if ( old_exp!=null ) {
20222     mp_recycle_value(mp, old_exp); 
20223     mp_free_node(mp, old_exp,value_node_size);
20224   }
20225 }
20226
20227 @ @<Trace the fraction multiplication@>=
20228
20229   mp_begin_diagnostic(mp); 
20230   mp_print_nl(mp, "{("); mp_print_scaled(mp,n); mp_print_char(mp,'/');
20231   mp_print_scaled(mp,d); mp_print(mp,")*("); mp_print_exp(mp,null,0); 
20232   mp_print(mp,")}");
20233   mp_end_diagnostic(mp, false);
20234 }
20235
20236 @ The |hard_times| routine multiplies a nice color or pair by a dependency list.
20237
20238 @<Declare binary action procedures@>=
20239 void mp_hard_times (MP mp,pointer p) {
20240   pointer q; /* a copy of the dependent variable |p| */
20241   pointer r; /* a component of the big node for the nice color or pair */
20242   scaled v; /* the known value for |r| */
20243   if ( type(p)<=mp_pair_type ) { 
20244      q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p); p=q;
20245   }; /* now |cur_type=mp_pair_type| or |cur_type=mp_color_type| */
20246   r=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20247   while (1) { 
20248     r=r-2;
20249     v=value(r);
20250     type(r)=type(p);
20251     if ( r==value(mp->cur_exp) ) 
20252       break;
20253     mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(p)));
20254     mp_dep_mult(mp, r,v,true);
20255   }
20256   mp->mem[value_loc(r)]=mp->mem[value_loc(p)];
20257   link(prev_dep(p))=r;
20258   mp_free_node(mp, p,value_node_size);
20259   mp_dep_mult(mp, r,v,true);
20260 }
20261
20262 @ @<Additional cases of binary operators@>=
20263 case over: 
20264   if ( (mp->cur_type!=mp_known)||(type(p)<mp_color_type) ) {
20265     mp_bad_binary(mp, p,over);
20266   } else { 
20267     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20268     if ( v==0 ) {
20269       @<Squeal about division by zero@>;
20270     } else { 
20271       if ( mp->cur_type==mp_known ) {
20272         mp->cur_exp=mp_make_scaled(mp, mp->cur_exp,v);
20273       } else if ( mp->cur_type<=mp_pair_type ) { 
20274         p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20275         do {  
20276           p=p-2;  mp_dep_div(mp, p,v);
20277         } while (p!=value(mp->cur_exp));
20278       } else {
20279         mp_dep_div(mp, null,v);
20280       }
20281     }
20282     return;
20283   }
20284   break;
20285
20286 @ @<Declare binary action...@>=
20287 void mp_dep_div (MP mp,pointer p, scaled v) {
20288   pointer q; /* the dependency list being divided by |v| */
20289   small_number s,t; /* its type, before and after */
20290   if ( p==null ) q=mp->cur_exp;
20291   else if ( type(p)!=mp_known ) q=p;
20292   else { value(p)=mp_make_scaled(mp, value(p),v); return; };
20293   t=type(q); q=dep_list(q); s=t;
20294   if ( t==mp_dependent )
20295     if ( mp_ab_vs_cd(mp, mp_max_coef(mp,q),unity,coef_bound-1,abs(v))>=0 ) 
20296       t=mp_proto_dependent;
20297   q=mp_p_over_v(mp, q,v,s,t); 
20298   mp_dep_finish(mp, q,p,t);
20299 }
20300
20301 @ @<Squeal about division by zero@>=
20302
20303   exp_err("Division by zero");
20304 @.Division by zero@>
20305   help2("You're trying to divide the quantity shown above the error")
20306     ("message by zero. I'm going to divide it by one instead.");
20307   mp_put_get_error(mp);
20308 }
20309
20310 @ @<Additional cases of binary operators@>=
20311 case pythag_add:
20312 case pythag_sub: 
20313    if ( (mp->cur_type==mp_known)&&(type(p)==mp_known) ) {
20314      if ( c==pythag_add ) mp->cur_exp=mp_pyth_add(mp, value(p),mp->cur_exp);
20315      else mp->cur_exp=mp_pyth_sub(mp, value(p),mp->cur_exp);
20316    } else mp_bad_binary(mp, p,c);
20317    break;
20318
20319 @ The next few sections of the program deal with affine transformations
20320 of coordinate data.
20321
20322 @<Additional cases of binary operators@>=
20323 case rotated_by: case slanted_by:
20324 case scaled_by: case shifted_by: case transformed_by:
20325 case x_scaled: case y_scaled: case z_scaled:
20326   if ( type(p)==mp_path_type ) { 
20327     path_trans(c,p); return;
20328   } else if ( type(p)==mp_pen_type ) { 
20329     pen_trans(c,p);
20330     mp->cur_exp=mp_convex_hull(mp, mp->cur_exp); 
20331       /* rounding error could destroy convexity */
20332     return;
20333   } else if ( (type(p)==mp_pair_type)||(type(p)==mp_transform_type) ) {
20334     mp_big_trans(mp, p,c);
20335   } else if ( type(p)==mp_picture_type ) {
20336     mp_do_edges_trans(mp, p,c); return;
20337   } else {
20338     mp_bad_binary(mp, p,c);
20339   }
20340   break;
20341
20342 @ Let |c| be one of the eight transform operators. The procedure call
20343 |set_up_trans(c)| first changes |cur_exp| to a transform that corresponds to
20344 |c| and the original value of |cur_exp|. (In particular, |cur_exp| doesn't
20345 change at all if |c=transformed_by|.)
20346
20347 Then, if all components of the resulting transform are |known|, they are
20348 moved to the global variables |txx|, |txy|, |tyx|, |tyy|, |tx|, |ty|;
20349 and |cur_exp| is changed to the known value zero.
20350
20351 @<Declare binary action...@>=
20352 void mp_set_up_trans (MP mp,quarterword c) {
20353   pointer p,q,r; /* list manipulation registers */
20354   if ( (c!=transformed_by)||(mp->cur_type!=mp_transform_type) ) {
20355     @<Put the current transform into |cur_exp|@>;
20356   }
20357   @<If the current transform is entirely known, stash it in global variables;
20358     otherwise |return|@>;
20359 }
20360
20361 @ @<Glob...@>=
20362 scaled txx;
20363 scaled txy;
20364 scaled tyx;
20365 scaled tyy;
20366 scaled tx;
20367 scaled ty; /* current transform coefficients */
20368
20369 @ @<Put the current transform...@>=
20370
20371   p=mp_stash_cur_exp(mp); 
20372   mp->cur_exp=mp_id_transform(mp); 
20373   mp->cur_type=mp_transform_type;
20374   q=value(mp->cur_exp);
20375   switch (c) {
20376   @<For each of the eight cases, change the relevant fields of |cur_exp|
20377     and |goto done|;
20378     but do nothing if capsule |p| doesn't have the appropriate type@>;
20379   }; /* there are no other cases */
20380   mp_disp_err(mp, p,"Improper transformation argument");
20381 @.Improper transformation argument@>
20382   help3("The expression shown above has the wrong type,")
20383        ("so I can\'t transform anything using it.")
20384        ("Proceed, and I'll omit the transformation.");
20385   mp_put_get_error(mp);
20386 DONE: 
20387   mp_recycle_value(mp, p); 
20388   mp_free_node(mp, p,value_node_size);
20389 }
20390
20391 @ @<If the current transform is entirely known, ...@>=
20392 q=value(mp->cur_exp); r=q+transform_node_size;
20393 do {  
20394   r=r-2;
20395   if ( type(r)!=mp_known ) return;
20396 } while (r!=q);
20397 mp->txx=value(xx_part_loc(q));
20398 mp->txy=value(xy_part_loc(q));
20399 mp->tyx=value(yx_part_loc(q));
20400 mp->tyy=value(yy_part_loc(q));
20401 mp->tx=value(x_part_loc(q));
20402 mp->ty=value(y_part_loc(q));
20403 mp_flush_cur_exp(mp, 0)
20404
20405 @ @<For each of the eight cases...@>=
20406 case rotated_by:
20407   if ( type(p)==mp_known )
20408     @<Install sines and cosines, then |goto done|@>;
20409   break;
20410 case slanted_by:
20411   if ( type(p)>mp_pair_type ) { 
20412    mp_install(mp, xy_part_loc(q),p); goto DONE;
20413   };
20414   break;
20415 case scaled_by:
20416   if ( type(p)>mp_pair_type ) { 
20417     mp_install(mp, xx_part_loc(q),p); mp_install(mp, yy_part_loc(q),p); 
20418     goto DONE;
20419   };
20420   break;
20421 case shifted_by:
20422   if ( type(p)==mp_pair_type ) {
20423     r=value(p); mp_install(mp, x_part_loc(q),x_part_loc(r));
20424     mp_install(mp, y_part_loc(q),y_part_loc(r)); goto DONE;
20425   };
20426   break;
20427 case x_scaled:
20428   if ( type(p)>mp_pair_type ) {
20429     mp_install(mp, xx_part_loc(q),p); goto DONE;
20430   };
20431   break;
20432 case y_scaled:
20433   if ( type(p)>mp_pair_type ) {
20434     mp_install(mp, yy_part_loc(q),p); goto DONE;
20435   };
20436   break;
20437 case z_scaled:
20438   if ( type(p)==mp_pair_type )
20439     @<Install a complex multiplier, then |goto done|@>;
20440   break;
20441 case transformed_by:
20442   break;
20443   
20444
20445 @ @<Install sines and cosines, then |goto done|@>=
20446 { mp_n_sin_cos(mp, (value(p) % three_sixty_units)*16);
20447   value(xx_part_loc(q))=mp_round_fraction(mp, mp->n_cos);
20448   value(yx_part_loc(q))=mp_round_fraction(mp, mp->n_sin);
20449   value(xy_part_loc(q))=-value(yx_part_loc(q));
20450   value(yy_part_loc(q))=value(xx_part_loc(q));
20451   goto DONE;
20452 }
20453
20454 @ @<Install a complex multiplier, then |goto done|@>=
20455
20456   r=value(p);
20457   mp_install(mp, xx_part_loc(q),x_part_loc(r));
20458   mp_install(mp, yy_part_loc(q),x_part_loc(r));
20459   mp_install(mp, yx_part_loc(q),y_part_loc(r));
20460   if ( type(y_part_loc(r))==mp_known ) negate(value(y_part_loc(r)));
20461   else mp_negate_dep_list(mp, dep_list(y_part_loc(r)));
20462   mp_install(mp, xy_part_loc(q),y_part_loc(r));
20463   goto DONE;
20464 }
20465
20466 @ Procedure |set_up_known_trans| is like |set_up_trans|, but it
20467 insists that the transformation be entirely known.
20468
20469 @<Declare binary action...@>=
20470 void mp_set_up_known_trans (MP mp,quarterword c) { 
20471   mp_set_up_trans(mp, c);
20472   if ( mp->cur_type!=mp_known ) {
20473     exp_err("Transform components aren't all known");
20474 @.Transform components...@>
20475     help3("I'm unable to apply a partially specified transformation")
20476       ("except to a fully known pair or transform.")
20477       ("Proceed, and I'll omit the transformation.");
20478     mp_put_get_flush_error(mp, 0);
20479     mp->txx=unity; mp->txy=0; mp->tyx=0; mp->tyy=unity; 
20480     mp->tx=0; mp->ty=0;
20481   }
20482 }
20483
20484 @ Here's a procedure that applies the transform |txx..ty| to a pair of
20485 coordinates in locations |p| and~|q|.
20486
20487 @<Declare binary action...@>= 
20488 void mp_trans (MP mp,pointer p, pointer q) {
20489   scaled v; /* the new |x| value */
20490   v=mp_take_scaled(mp, mp->mem[p].sc,mp->txx)+
20491   mp_take_scaled(mp, mp->mem[q].sc,mp->txy)+mp->tx;
20492   mp->mem[q].sc=mp_take_scaled(mp, mp->mem[p].sc,mp->tyx)+
20493   mp_take_scaled(mp, mp->mem[q].sc,mp->tyy)+mp->ty;
20494   mp->mem[p].sc=v;
20495 }
20496
20497 @ The simplest transformation procedure applies a transform to all
20498 coordinates of a path.  The |path_trans(c)(p)| macro applies
20499 a transformation defined by |cur_exp| and the transform operator |c|
20500 to the path~|p|.
20501
20502 @d path_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20503                      mp_unstash_cur_exp(mp, (B)); 
20504                      mp_do_path_trans(mp, mp->cur_exp); }
20505
20506 @<Declare binary action...@>=
20507 void mp_do_path_trans (MP mp,pointer p) {
20508   pointer q; /* list traverser */
20509   q=p;
20510   do { 
20511     if ( left_type(q)!=mp_endpoint ) 
20512       mp_trans(mp, q+3,q+4); /* that's |left_x| and |left_y| */
20513     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20514     if ( right_type(q)!=mp_endpoint ) 
20515       mp_trans(mp, q+5,q+6); /* that's |right_x| and |right_y| */
20516 @^data structure assumptions@>
20517     q=link(q);
20518   } while (q!=p);
20519 }
20520
20521 @ Transforming a pen is very similar, except that there are no |left_type|
20522 and |right_type| fields.
20523
20524 @d pen_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20525                     mp_unstash_cur_exp(mp, (B)); 
20526                     mp_do_pen_trans(mp, mp->cur_exp); }
20527
20528 @<Declare binary action...@>=
20529 void mp_do_pen_trans (MP mp,pointer p) {
20530   pointer q; /* list traverser */
20531   if ( pen_is_elliptical(p) ) {
20532     mp_trans(mp, p+3,p+4); /* that's |left_x| and |left_y| */
20533     mp_trans(mp, p+5,p+6); /* that's |right_x| and |right_y| */
20534   };
20535   q=p;
20536   do { 
20537     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20538 @^data structure assumptions@>
20539     q=link(q);
20540   } while (q!=p);
20541 }
20542
20543 @ The next transformation procedure applies to edge structures. It will do
20544 any transformation, but the results may be substandard if the picture contains
20545 text that uses downloaded bitmap fonts.  The binary action procedure is
20546 |do_edges_trans|, but we also need a function that just scales a picture.
20547 That routine is |scale_edges|.  Both it and the underlying routine |edges_trans|
20548 should be thought of as procedures that update an edge structure |h|, except
20549 that they have to return a (possibly new) structure because of the need to call
20550 |private_edges|.
20551
20552 @<Declare binary action...@>=
20553 pointer mp_edges_trans (MP mp, pointer h) {
20554   pointer q; /* the object being transformed */
20555   pointer r,s; /* for list manipulation */
20556   scaled sx,sy; /* saved transformation parameters */
20557   scaled sqdet; /* square root of determinant for |dash_scale| */
20558   integer sgndet; /* sign of the determinant */
20559   scaled v; /* a temporary value */
20560   h=mp_private_edges(mp, h);
20561   sqdet=mp_sqrt_det(mp, mp->txx,mp->txy,mp->tyx,mp->tyy);
20562   sgndet=mp_ab_vs_cd(mp, mp->txx,mp->tyy,mp->txy,mp->tyx);
20563   if ( dash_list(h)!=null_dash ) {
20564     @<Try to transform the dash list of |h|@>;
20565   }
20566   @<Make the bounding box of |h| unknown if it can't be updated properly
20567     without scanning the whole structure@>;  
20568   q=link(dummy_loc(h));
20569   while ( q!=null ) { 
20570     @<Transform graphical object |q|@>;
20571     q=link(q);
20572   }
20573   return h;
20574 }
20575 void mp_do_edges_trans (MP mp,pointer p, quarterword c) { 
20576   mp_set_up_known_trans(mp, c);
20577   value(p)=mp_edges_trans(mp, value(p));
20578   mp_unstash_cur_exp(mp, p);
20579 }
20580 void mp_scale_edges (MP mp) { 
20581   mp->txx=mp->se_sf; mp->tyy=mp->se_sf;
20582   mp->txy=0; mp->tyx=0; mp->tx=0; mp->ty=0;
20583   mp->se_pic=mp_edges_trans(mp, mp->se_pic);
20584 }
20585
20586 @ @<Try to transform the dash list of |h|@>=
20587 if ( (mp->txy!=0)||(mp->tyx!=0)||
20588      (mp->ty!=0)||(abs(mp->txx)!=abs(mp->tyy))) {
20589   mp_flush_dash_list(mp, h);
20590 } else { 
20591   if ( mp->txx<0 ) { @<Reverse the dash list of |h|@>; } 
20592   @<Scale the dash list by |txx| and shift it by |tx|@>;
20593   dash_y(h)=mp_take_scaled(mp, dash_y(h),abs(mp->tyy));
20594 }
20595
20596 @ @<Reverse the dash list of |h|@>=
20597
20598   r=dash_list(h);
20599   dash_list(h)=null_dash;
20600   while ( r!=null_dash ) {
20601     s=r; r=link(r);
20602     v=start_x(s); start_x(s)=stop_x(s); stop_x(s)=v;
20603     link(s)=dash_list(h);
20604     dash_list(h)=s;
20605   }
20606 }
20607
20608 @ @<Scale the dash list by |txx| and shift it by |tx|@>=
20609 r=dash_list(h);
20610 while ( r!=null_dash ) {
20611   start_x(r)=mp_take_scaled(mp, start_x(r),mp->txx)+mp->tx;
20612   stop_x(r)=mp_take_scaled(mp, stop_x(r),mp->txx)+mp->tx;
20613   r=link(r);
20614 }
20615
20616 @ @<Make the bounding box of |h| unknown if it can't be updated properly...@>=
20617 if ( (mp->txx==0)&&(mp->tyy==0) ) {
20618   @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>;
20619 } else if ( (mp->txy!=0)||(mp->tyx!=0) ) {
20620   mp_init_bbox(mp, h);
20621   goto DONE1;
20622 }
20623 if ( minx_val(h)<=maxx_val(h) ) {
20624   @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift by
20625    |(tx,ty)|@>;
20626 }
20627 DONE1:
20628
20629
20630
20631 @ @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>=
20632
20633   v=minx_val(h); minx_val(h)=miny_val(h); miny_val(h)=v;
20634   v=maxx_val(h); maxx_val(h)=maxy_val(h); maxy_val(h)=v;
20635 }
20636
20637 @ The sum ``|txx+txy|'' is whichever of |txx| or |txy| is nonzero.  The other
20638 sum is similar.
20639
20640 @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift...@>=
20641
20642   minx_val(h)=mp_take_scaled(mp, minx_val(h),mp->txx+mp->txy)+mp->tx;
20643   maxx_val(h)=mp_take_scaled(mp, maxx_val(h),mp->txx+mp->txy)+mp->tx;
20644   miny_val(h)=mp_take_scaled(mp, miny_val(h),mp->tyx+mp->tyy)+mp->ty;
20645   maxy_val(h)=mp_take_scaled(mp, maxy_val(h),mp->tyx+mp->tyy)+mp->ty;
20646   if ( mp->txx+mp->txy<0 ) {
20647     v=minx_val(h); minx_val(h)=maxx_val(h); maxx_val(h)=v;
20648   }
20649   if ( mp->tyx+mp->tyy<0 ) {
20650     v=miny_val(h); miny_val(h)=maxy_val(h); maxy_val(h)=v;
20651   }
20652 }
20653
20654 @ Now we ready for the main task of transforming the graphical objects in edge
20655 structure~|h|.
20656
20657 @<Transform graphical object |q|@>=
20658 switch (type(q)) {
20659 case mp_fill_code: case mp_stroked_code: 
20660   mp_do_path_trans(mp, path_p(q));
20661   @<Transform |pen_p(q)|, making sure polygonal pens stay counter-clockwise@>;
20662   break;
20663 case mp_start_clip_code: case mp_start_bounds_code: 
20664   mp_do_path_trans(mp, path_p(q));
20665   break;
20666 case mp_text_code: 
20667   r=text_tx_loc(q);
20668   @<Transform the compact transformation starting at |r|@>;
20669   break;
20670 case mp_stop_clip_code: case mp_stop_bounds_code: 
20671   break;
20672 } /* there are no other cases */
20673
20674 @ Note that the shift parameters |(tx,ty)| apply only to the path being stroked.
20675 The |dash_scale| has to be adjusted  to scale the dash lengths in |dash_p(q)|
20676 since the \ps\ output procedures will try to compensate for the transformation
20677 we are applying to |pen_p(q)|.  Since this compensation is based on the square
20678 root of the determinant, |sqdet| is the appropriate factor.
20679
20680 @<Transform |pen_p(q)|, making sure...@>=
20681 if ( pen_p(q)!=null ) {
20682   sx=mp->tx; sy=mp->ty;
20683   mp->tx=0; mp->ty=0;
20684   mp_do_pen_trans(mp, pen_p(q));
20685   if ( ((type(q)==mp_stroked_code)&&(dash_p(q)!=null)) )
20686     dash_scale(q)=mp_take_scaled(mp, dash_scale(q),sqdet);
20687   if ( ! pen_is_elliptical(pen_p(q)) )
20688     if ( sgndet<0 )
20689       pen_p(q)=mp_make_pen(mp, mp_copy_path(mp, pen_p(q)),true); 
20690          /* this unreverses the pen */
20691   mp->tx=sx; mp->ty=sy;
20692 }
20693
20694 @ This uses the fact that transformations are stored in the order
20695 |(tx,ty,txx,txy,tyx,tyy)|.
20696 @^data structure assumptions@>
20697
20698 @<Transform the compact transformation starting at |r|@>=
20699 mp_trans(mp, r,r+1);
20700 sx=mp->tx; sy=mp->ty;
20701 mp->tx=0; mp->ty=0;
20702 mp_trans(mp, r+2,r+4);
20703 mp_trans(mp, r+3,r+5);
20704 mp->tx=sx; mp->ty=sy
20705
20706 @ The hard cases of transformation occur when big nodes are involved,
20707 and when some of their components are unknown.
20708
20709 @<Declare binary action...@>=
20710 @<Declare subroutines needed by |big_trans|@>;
20711 void mp_big_trans (MP mp,pointer p, quarterword c) {
20712   pointer q,r,pp,qq; /* list manipulation registers */
20713   small_number s; /* size of a big node */
20714   s=mp->big_node_size[type(p)]; q=value(p); r=q+s;
20715   do {  
20716     r=r-2;
20717     if ( type(r)!=mp_known ) {
20718       @<Transform an unknown big node and |return|@>;
20719     }
20720   } while (r!=q);
20721   @<Transform a known big node@>;
20722 }; /* node |p| will now be recycled by |do_binary| */
20723
20724 @ @<Transform an unknown big node and |return|@>=
20725
20726   mp_set_up_known_trans(mp, c); mp_make_exp_copy(mp, p); 
20727   r=value(mp->cur_exp);
20728   if ( mp->cur_type==mp_transform_type ) {
20729     mp_bilin1(mp, yy_part_loc(r),mp->tyy,xy_part_loc(q),mp->tyx,0);
20730     mp_bilin1(mp, yx_part_loc(r),mp->tyy,xx_part_loc(q),mp->tyx,0);
20731     mp_bilin1(mp, xy_part_loc(r),mp->txx,yy_part_loc(q),mp->txy,0);
20732     mp_bilin1(mp, xx_part_loc(r),mp->txx,yx_part_loc(q),mp->txy,0);
20733   }
20734   mp_bilin1(mp, y_part_loc(r),mp->tyy,x_part_loc(q),mp->tyx,mp->ty);
20735   mp_bilin1(mp, x_part_loc(r),mp->txx,y_part_loc(q),mp->txy,mp->tx);
20736   return;
20737 }
20738
20739 @ Let |p| point to a two-word value field inside a big node of |cur_exp|,
20740 and let |q| point to a another value field. The |bilin1| procedure
20741 replaces |p| by $p\cdot t+q\cdot u+\delta$.
20742
20743 @<Declare subroutines needed by |big_trans|@>=
20744 void mp_bilin1 (MP mp, pointer p, scaled t, pointer q, 
20745                 scaled u, scaled delta) {
20746   pointer r; /* list traverser */
20747   if ( t!=unity ) mp_dep_mult(mp, p,t,true);
20748   if ( u!=0 ) {
20749     if ( type(q)==mp_known ) {
20750       delta+=mp_take_scaled(mp, value(q),u);
20751     } else { 
20752       @<Ensure that |type(p)=mp_proto_dependent|@>;
20753       dep_list(p)=mp_p_plus_fq(mp, dep_list(p),u,dep_list(q),
20754                                mp_proto_dependent,type(q));
20755     }
20756   }
20757   if ( type(p)==mp_known ) {
20758     value(p)+=delta;
20759   } else {
20760     r=dep_list(p);
20761     while ( info(r)!=null ) r=link(r);
20762     delta+=value(r);
20763     if ( r!=dep_list(p) ) value(r)=delta;
20764     else { mp_recycle_value(mp, p); type(p)=mp_known; value(p)=delta; };
20765   }
20766   if ( mp->fix_needed ) mp_fix_dependencies(mp);
20767 }
20768
20769 @ @<Ensure that |type(p)=mp_proto_dependent|@>=
20770 if ( type(p)!=mp_proto_dependent ) {
20771   if ( type(p)==mp_known ) 
20772     mp_new_dep(mp, p,mp_const_dependency(mp, value(p)));
20773   else 
20774     dep_list(p)=mp_p_times_v(mp, dep_list(p),unity,mp_dependent,
20775                              mp_proto_dependent,true);
20776   type(p)=mp_proto_dependent;
20777 }
20778
20779 @ @<Transform a known big node@>=
20780 mp_set_up_trans(mp, c);
20781 if ( mp->cur_type==mp_known ) {
20782   @<Transform known by known@>;
20783 } else { 
20784   pp=mp_stash_cur_exp(mp); qq=value(pp);
20785   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
20786   if ( mp->cur_type==mp_transform_type ) {
20787     mp_bilin2(mp, yy_part_loc(r),yy_part_loc(qq),
20788       value(xy_part_loc(q)),yx_part_loc(qq),null);
20789     mp_bilin2(mp, yx_part_loc(r),yy_part_loc(qq),
20790       value(xx_part_loc(q)),yx_part_loc(qq),null);
20791     mp_bilin2(mp, xy_part_loc(r),xx_part_loc(qq),
20792       value(yy_part_loc(q)),xy_part_loc(qq),null);
20793     mp_bilin2(mp, xx_part_loc(r),xx_part_loc(qq),
20794       value(yx_part_loc(q)),xy_part_loc(qq),null);
20795   };
20796   mp_bilin2(mp, y_part_loc(r),yy_part_loc(qq),
20797     value(x_part_loc(q)),yx_part_loc(qq),y_part_loc(qq));
20798   mp_bilin2(mp, x_part_loc(r),xx_part_loc(qq),
20799     value(y_part_loc(q)),xy_part_loc(qq),x_part_loc(qq));
20800   mp_recycle_value(mp, pp); mp_free_node(mp, pp,value_node_size);
20801 }
20802
20803 @ Let |p| be a |mp_proto_dependent| value whose dependency list ends
20804 at |dep_final|. The following procedure adds |v| times another
20805 numeric quantity to~|p|.
20806
20807 @<Declare subroutines needed by |big_trans|@>=
20808 void mp_add_mult_dep (MP mp,pointer p, scaled v, pointer r) { 
20809   if ( type(r)==mp_known ) {
20810     value(mp->dep_final)+=mp_take_scaled(mp, value(r),v);
20811   } else  { 
20812     dep_list(p)=mp_p_plus_fq(mp, dep_list(p),v,dep_list(r),
20813                                                          mp_proto_dependent,type(r));
20814     if ( mp->fix_needed ) mp_fix_dependencies(mp);
20815   }
20816 }
20817
20818 @ The |bilin2| procedure is something like |bilin1|, but with known
20819 and unknown quantities reversed. Parameter |p| points to a value field
20820 within the big node for |cur_exp|; and |type(p)=mp_known|. Parameters
20821 |t| and~|u| point to value fields elsewhere; so does parameter~|q|,
20822 unless it is |null| (which stands for zero). Location~|p| will be
20823 replaced by $p\cdot t+v\cdot u+q$.
20824
20825 @<Declare subroutines needed by |big_trans|@>=
20826 void mp_bilin2 (MP mp,pointer p, pointer t, scaled v, 
20827                 pointer u, pointer q) {
20828   scaled vv; /* temporary storage for |value(p)| */
20829   vv=value(p); type(p)=mp_proto_dependent;
20830   mp_new_dep(mp, p,mp_const_dependency(mp, 0)); /* this sets |dep_final| */
20831   if ( vv!=0 ) 
20832     mp_add_mult_dep(mp, p,vv,t); /* |dep_final| doesn't change */
20833   if ( v!=0 ) mp_add_mult_dep(mp, p,v,u);
20834   if ( q!=null ) mp_add_mult_dep(mp, p,unity,q);
20835   if ( dep_list(p)==mp->dep_final ) {
20836     vv=value(mp->dep_final); mp_recycle_value(mp, p);
20837     type(p)=mp_known; value(p)=vv;
20838   }
20839 }
20840
20841 @ @<Transform known by known@>=
20842
20843   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
20844   if ( mp->cur_type==mp_transform_type ) {
20845     mp_bilin3(mp, yy_part_loc(r),mp->tyy,value(xy_part_loc(q)),mp->tyx,0);
20846     mp_bilin3(mp, yx_part_loc(r),mp->tyy,value(xx_part_loc(q)),mp->tyx,0);
20847     mp_bilin3(mp, xy_part_loc(r),mp->txx,value(yy_part_loc(q)),mp->txy,0);
20848     mp_bilin3(mp, xx_part_loc(r),mp->txx,value(yx_part_loc(q)),mp->txy,0);
20849   }
20850   mp_bilin3(mp, y_part_loc(r),mp->tyy,value(x_part_loc(q)),mp->tyx,mp->ty);
20851   mp_bilin3(mp, x_part_loc(r),mp->txx,value(y_part_loc(q)),mp->txy,mp->tx);
20852 }
20853
20854 @ Finally, in |bilin3| everything is |known|.
20855
20856 @<Declare subroutines needed by |big_trans|@>=
20857 void mp_bilin3 (MP mp,pointer p, scaled t, 
20858                scaled v, scaled u, scaled delta) { 
20859   if ( t!=unity )
20860     delta+=mp_take_scaled(mp, value(p),t);
20861   else 
20862     delta+=value(p);
20863   if ( u!=0 ) value(p)=delta+mp_take_scaled(mp, v,u);
20864   else value(p)=delta;
20865 }
20866
20867 @ @<Additional cases of binary operators@>=
20868 case concatenate: 
20869   if ( (mp->cur_type==mp_string_type)&&(type(p)==mp_string_type) ) mp_cat(mp, p);
20870   else mp_bad_binary(mp, p,concatenate);
20871   break;
20872 case substring_of: 
20873   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_string_type) )
20874     mp_chop_string(mp, value(p));
20875   else mp_bad_binary(mp, p,substring_of);
20876   break;
20877 case subpath_of: 
20878   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
20879   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_path_type) )
20880     mp_chop_path(mp, value(p));
20881   else mp_bad_binary(mp, p,subpath_of);
20882   break;
20883
20884 @ @<Declare binary action...@>=
20885 void mp_cat (MP mp,pointer p) {
20886   str_number a,b; /* the strings being concatenated */
20887   pool_pointer k; /* index into |str_pool| */
20888   a=value(p); b=mp->cur_exp; str_room(length(a)+length(b));
20889   for (k=mp->str_start[a];k<=str_stop(a)-1;k++) {
20890     append_char(mp->str_pool[k]);
20891   }
20892   for (k=mp->str_start[b];k<=str_stop(b)-1;k++) {
20893     append_char(mp->str_pool[k]);
20894   }
20895   mp->cur_exp=mp_make_string(mp); delete_str_ref(b);
20896 }
20897
20898 @ @<Declare binary action...@>=
20899 void mp_chop_string (MP mp,pointer p) {
20900   integer a, b; /* start and stop points */
20901   integer l; /* length of the original string */
20902   integer k; /* runs from |a| to |b| */
20903   str_number s; /* the original string */
20904   boolean reversed; /* was |a>b|? */
20905   a=mp_round_unscaled(mp, value(x_part_loc(p)));
20906   b=mp_round_unscaled(mp, value(y_part_loc(p)));
20907   if ( a<=b ) reversed=false;
20908   else  { reversed=true; k=a; a=b; b=k; };
20909   s=mp->cur_exp; l=length(s);
20910   if ( a<0 ) { 
20911     a=0;
20912     if ( b<0 ) b=0;
20913   }
20914   if ( b>l ) { 
20915     b=l;
20916     if ( a>l ) a=l;
20917   }
20918   str_room(b-a);
20919   if ( reversed ) {
20920     for (k=mp->str_start[s]+b-1;k>=mp->str_start[s]+a;k--)  {
20921       append_char(mp->str_pool[k]);
20922     }
20923   } else  {
20924     for (k=mp->str_start[s]+a;k<=mp->str_start[s]+b-1;k++)  {
20925       append_char(mp->str_pool[k]);
20926     }
20927   }
20928   mp->cur_exp=mp_make_string(mp); delete_str_ref(s);
20929 }
20930
20931 @ @<Declare binary action...@>=
20932 void mp_chop_path (MP mp,pointer p) {
20933   pointer q; /* a knot in the original path */
20934   pointer pp,qq,rr,ss; /* link variables for copies of path nodes */
20935   scaled a,b,k,l; /* indices for chopping */
20936   boolean reversed; /* was |a>b|? */
20937   l=mp_path_length(mp); a=value(x_part_loc(p)); b=value(y_part_loc(p));
20938   if ( a<=b ) reversed=false;
20939   else  { reversed=true; k=a; a=b; b=k; };
20940   @<Dispense with the cases |a<0| and/or |b>l|@>;
20941   q=mp->cur_exp;
20942   while ( a>=unity ) {
20943     q=link(q); a=a-unity; b=b-unity;
20944   }
20945   if ( b==a ) {
20946     @<Construct a path from |pp| to |qq| of length zero@>; 
20947   } else { 
20948     @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>; 
20949   }
20950   left_type(pp)=mp_endpoint; right_type(qq)=mp_endpoint; link(qq)=pp;
20951   mp_toss_knot_list(mp, mp->cur_exp);
20952   if ( reversed ) {
20953     mp->cur_exp=link(mp_htap_ypoc(mp, pp)); mp_toss_knot_list(mp, pp);
20954   } else {
20955     mp->cur_exp=pp;
20956   }
20957 }
20958
20959 @ @<Dispense with the cases |a<0| and/or |b>l|@>=
20960 if ( a<0 ) {
20961   if ( left_type(mp->cur_exp)==mp_endpoint ) {
20962     a=0; if ( b<0 ) b=0;
20963   } else  {
20964     do {  a=a+l; b=b+l; } while (a<0); /* a cycle always has length |l>0| */
20965   }
20966 }
20967 if ( b>l ) {
20968   if ( left_type(mp->cur_exp)==mp_endpoint ) {
20969     b=l; if ( a>l ) a=l;
20970   } else {
20971     while ( a>=l ) { 
20972       a=a-l; b=b-l;
20973     }
20974   }
20975 }
20976
20977 @ @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>=
20978
20979   pp=mp_copy_knot(mp, q); qq=pp;
20980   do {  
20981     q=link(q); rr=qq; qq=mp_copy_knot(mp, q); link(rr)=qq; b=b-unity;
20982   } while (b>0);
20983   if ( a>0 ) {
20984     ss=pp; pp=link(pp);
20985     mp_split_cubic(mp, ss,a*010000); pp=link(ss);
20986     mp_free_node(mp, ss,knot_node_size);
20987     if ( rr==ss ) {
20988       b=mp_make_scaled(mp, b,unity-a); rr=pp;
20989     }
20990   }
20991   if ( b<0 ) {
20992     mp_split_cubic(mp, rr,(b+unity)*010000);
20993     mp_free_node(mp, qq,knot_node_size);
20994     qq=link(rr);
20995   }
20996 }
20997
20998 @ @<Construct a path from |pp| to |qq| of length zero@>=
20999
21000   if ( a>0 ) { mp_split_cubic(mp, q,a*010000); q=link(q); };
21001   pp=mp_copy_knot(mp, q); qq=pp;
21002 }
21003
21004 @ @<Additional cases of binary operators@>=
21005 case point_of: case precontrol_of: case postcontrol_of: 
21006   if ( mp->cur_type==mp_pair_type )
21007      mp_pair_to_path(mp);
21008   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
21009     mp_find_point(mp, value(p),c);
21010   else 
21011     mp_bad_binary(mp, p,c);
21012   break;
21013 case pen_offset_of: 
21014   if ( (mp->cur_type==mp_pen_type)&& mp_nice_pair(mp, p,type(p)) )
21015     mp_set_up_offset(mp, value(p));
21016   else 
21017     mp_bad_binary(mp, p,pen_offset_of);
21018   break;
21019 case direction_time_of: 
21020   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
21021   if ( (mp->cur_type==mp_path_type)&& mp_nice_pair(mp, p,type(p)) )
21022     mp_set_up_direction_time(mp, value(p));
21023   else 
21024     mp_bad_binary(mp, p,direction_time_of);
21025   break;
21026 case envelope_of:
21027   if ( (type(p) != mp_pen_type) || (mp->cur_type != mp_path_type) )
21028     mp_bad_binary(mp, p,envelope_of);
21029   else
21030     mp_set_up_envelope(mp, p);
21031   break;
21032
21033 @ @<Declare binary action...@>=
21034 void mp_set_up_offset (MP mp,pointer p) { 
21035   mp_find_offset(mp, value(x_part_loc(p)),value(y_part_loc(p)),mp->cur_exp);
21036   mp_pair_value(mp, mp->cur_x,mp->cur_y);
21037 }
21038 void mp_set_up_direction_time (MP mp,pointer p) { 
21039   mp_flush_cur_exp(mp, mp_find_direction_time(mp, value(x_part_loc(p)),
21040   value(y_part_loc(p)),mp->cur_exp));
21041 }
21042 void mp_set_up_envelope (MP mp,pointer p) {
21043   pointer q = mp_copy_path(mp, mp->cur_exp); /* the original path */
21044   /* TODO: accept elliptical pens for straight paths */
21045   if (pen_is_elliptical(value(p))) {
21046     mp_bad_envelope_pen(mp);
21047     mp->cur_exp = q;
21048     mp->cur_type = mp_path_type;
21049     return;
21050   }
21051   small_number ljoin, lcap;
21052   scaled miterlim;
21053   if ( mp->internal[mp_linejoin]>unity ) ljoin=2;
21054   else if ( mp->internal[mp_linejoin]>0 ) ljoin=1;
21055   else ljoin=0;
21056   if ( mp->internal[mp_linecap]>unity ) lcap=2;
21057   else if ( mp->internal[mp_linecap]>0 ) lcap=1;
21058   else lcap=0;
21059   if ( mp->internal[mp_miterlimit]<unity )
21060     miterlim=unity;
21061   else
21062     miterlim=mp->internal[mp_miterlimit];
21063   mp->cur_exp = mp_make_envelope(mp, q, value(p), ljoin,lcap,miterlim);
21064   mp->cur_type = mp_path_type;
21065 }
21066
21067 @ @<Declare binary action...@>=
21068 void mp_find_point (MP mp,scaled v, quarterword c) {
21069   pointer p; /* the path */
21070   scaled n; /* its length */
21071   p=mp->cur_exp;
21072   if ( left_type(p)==mp_endpoint ) n=-unity; else n=0;
21073   do {  p=link(p); n=n+unity; } while (p!=mp->cur_exp);
21074   if ( n==0 ) { 
21075     v=0; 
21076   } else if ( v<0 ) {
21077     if ( left_type(p)==mp_endpoint ) v=0;
21078     else v=n-1-((-v-1) % n);
21079   } else if ( v>n ) {
21080     if ( left_type(p)==mp_endpoint ) v=n;
21081     else v=v % n;
21082   }
21083   p=mp->cur_exp;
21084   while ( v>=unity ) { p=link(p); v=v-unity;  };
21085   if ( v!=0 ) {
21086      @<Insert a fractional node by splitting the cubic@>;
21087   }
21088   @<Set the current expression to the desired path coordinates@>;
21089 }
21090
21091 @ @<Insert a fractional node...@>=
21092 { mp_split_cubic(mp, p,v*010000); p=link(p); }
21093
21094 @ @<Set the current expression to the desired path coordinates...@>=
21095 switch (c) {
21096 case point_of: 
21097   mp_pair_value(mp, x_coord(p),y_coord(p));
21098   break;
21099 case precontrol_of: 
21100   if ( left_type(p)==mp_endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
21101   else mp_pair_value(mp, left_x(p),left_y(p));
21102   break;
21103 case postcontrol_of: 
21104   if ( right_type(p)==mp_endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
21105   else mp_pair_value(mp, right_x(p),right_y(p));
21106   break;
21107 } /* there are no other cases */
21108
21109 @ @<Additional cases of binary operators@>=
21110 case arc_time_of: 
21111   if ( mp->cur_type==mp_pair_type )
21112      mp_pair_to_path(mp);
21113   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
21114     mp_flush_cur_exp(mp, mp_get_arc_time(mp, mp->cur_exp,value(p)));
21115   else 
21116     mp_bad_binary(mp, p,c);
21117   break;
21118
21119 @ @<Additional cases of bin...@>=
21120 case intersect: 
21121   if ( type(p)==mp_pair_type ) {
21122     q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p);
21123     mp_pair_to_path(mp); p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
21124   };
21125   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
21126   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_path_type) ) {
21127     mp_path_intersection(mp, value(p),mp->cur_exp);
21128     mp_pair_value(mp, mp->cur_t,mp->cur_tt);
21129   } else {
21130     mp_bad_binary(mp, p,intersect);
21131   }
21132   break;
21133
21134 @ @<Additional cases of bin...@>=
21135 case in_font:
21136   if ( (mp->cur_type!=mp_string_type)||(type(p)!=mp_string_type)) 
21137     mp_bad_binary(mp, p,in_font);
21138   else { mp_do_infont(mp, p); return; }
21139   break;
21140
21141 @ Function |new_text_node| owns the reference count for its second argument
21142 (the text string) but not its first (the font name).
21143
21144 @<Declare binary action...@>=
21145 void mp_do_infont (MP mp,pointer p) {
21146   pointer q;
21147   q=mp_get_node(mp, edge_header_size);
21148   mp_init_edges(mp, q);
21149   link(obj_tail(q))=mp_new_text_node(mp,str(mp->cur_exp),value(p));
21150   obj_tail(q)=link(obj_tail(q));
21151   mp_free_node(mp, p,value_node_size);
21152   mp_flush_cur_exp(mp, q);
21153   mp->cur_type=mp_picture_type;
21154 }
21155
21156 @* \[40] Statements and commands.
21157 The chief executive of \MP\ is the |do_statement| routine, which
21158 contains the master switch that causes all the various pieces of \MP\
21159 to do their things, in the right order.
21160
21161 In a sense, this is the grand climax of the program: It applies all the
21162 tools that we have worked so hard to construct. In another sense, this is
21163 the messiest part of the program: It necessarily refers to other pieces
21164 of code all over the place, so that a person can't fully understand what is
21165 going on without paging back and forth to be reminded of conventions that
21166 are defined elsewhere. We are now at the hub of the web.
21167
21168 The structure of |do_statement| itself is quite simple.  The first token
21169 of the statement is fetched using |get_x_next|.  If it can be the first
21170 token of an expression, we look for an equation, an assignment, or a
21171 title. Otherwise we use a \&{case} construction to branch at high speed to
21172 the appropriate routine for various and sundry other types of commands,
21173 each of which has an ``action procedure'' that does the necessary work.
21174
21175 The program uses the fact that
21176 $$\hbox{|min_primary_command=max_statement_command=type_name|}$$
21177 to interpret a statement that starts with, e.g., `\&{string}',
21178 as a type declaration rather than a boolean expression.
21179
21180 @c void mp_do_statement (MP mp) { /* governs \MP's activities */
21181   mp->cur_type=mp_vacuous; mp_get_x_next(mp);
21182   if ( mp->cur_cmd>max_primary_command ) {
21183     @<Worry about bad statement@>;
21184   } else if ( mp->cur_cmd>max_statement_command ) {
21185     @<Do an equation, assignment, title, or
21186      `$\langle\,$expression$\,\rangle\,$\&{endgroup}'@>;
21187   } else {
21188     @<Do a statement that doesn't begin with an expression@>;
21189   }
21190   if ( mp->cur_cmd<semicolon )
21191     @<Flush unparsable junk that was found after the statement@>;
21192   mp->error_count=0;
21193 }
21194
21195 @ @<Declarations@>=
21196 @<Declare action procedures for use by |do_statement|@>;
21197
21198 @ The only command codes |>max_primary_command| that can be present
21199 at the beginning of a statement are |semicolon| and higher; these
21200 occur when the statement is null.
21201
21202 @<Worry about bad statement@>=
21203
21204   if ( mp->cur_cmd<semicolon ) {
21205     print_err("A statement can't begin with `");
21206 @.A statement can't begin with x@>
21207     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); mp_print_char(mp, '\'');
21208     help5("I was looking for the beginning of a new statement.")
21209       ("If you just proceed without changing anything, I'll ignore")
21210       ("everything up to the next `;'. Please insert a semicolon")
21211       ("now in front of anything that you don't want me to delete.")
21212       ("(See Chapter 27 of The METAFONTbook for an example.)");
21213 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21214     mp_back_error(mp); mp_get_x_next(mp);
21215   }
21216 }
21217
21218 @ The help message printed here says that everything is flushed up to
21219 a semicolon, but actually the commands |end_group| and |stop| will
21220 also terminate a statement.
21221
21222 @<Flush unparsable junk that was found after the statement@>=
21223
21224   print_err("Extra tokens will be flushed");
21225 @.Extra tokens will be flushed@>
21226   help6("I've just read as much of that statement as I could fathom,")
21227        ("so a semicolon should have been next. It's very puzzling...")
21228        ("but I'll try to get myself back together, by ignoring")
21229        ("everything up to the next `;'. Please insert a semicolon")
21230        ("now in front of anything that you don't want me to delete.")
21231        ("(See Chapter 27 of The METAFONTbook for an example.)");
21232 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21233   mp_back_error(mp); mp->scanner_status=flushing;
21234   do {  
21235     get_t_next;
21236     @<Decrease the string reference count...@>;
21237   } while (! end_of_statement); /* |cur_cmd=semicolon|, |end_group|, or |stop| */
21238   mp->scanner_status=normal;
21239 }
21240
21241 @ If |do_statement| ends with |cur_cmd=end_group|, we should have
21242 |cur_type=mp_vacuous| unless the statement was simply an expression;
21243 in the latter case, |cur_type| and |cur_exp| should represent that
21244 expression.
21245
21246 @<Do a statement that doesn't...@>=
21247
21248   if ( mp->internal[mp_tracing_commands]>0 ) 
21249     show_cur_cmd_mod;
21250   switch (mp->cur_cmd ) {
21251   case type_name:mp_do_type_declaration(mp); break;
21252   case macro_def:
21253     if ( mp->cur_mod>var_def ) mp_make_op_def(mp);
21254     else if ( mp->cur_mod>end_def ) mp_scan_def(mp);
21255      break;
21256   @<Cases of |do_statement| that invoke particular commands@>;
21257   } /* there are no other cases */
21258   mp->cur_type=mp_vacuous;
21259 }
21260
21261 @ The most important statements begin with expressions.
21262
21263 @<Do an equation, assignment, title, or...@>=
21264
21265   mp->var_flag=assignment; mp_scan_expression(mp);
21266   if ( mp->cur_cmd<end_group ) {
21267     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21268     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21269     else if ( mp->cur_type==mp_string_type ) {@<Do a title@> ; }
21270     else if ( mp->cur_type!=mp_vacuous ){ 
21271       exp_err("Isolated expression");
21272 @.Isolated expression@>
21273       help3("I couldn't find an `=' or `:=' after the")
21274         ("expression that is shown above this error message,")
21275         ("so I guess I'll just ignore it and carry on.");
21276       mp_put_get_error(mp);
21277     }
21278     mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous;
21279   }
21280 }
21281
21282 @ @<Do a title@>=
21283
21284   if ( mp->internal[mp_tracing_titles]>0 ) {
21285     mp_print_nl(mp, "");  mp_print_str(mp, mp->cur_exp); update_terminal;
21286   }
21287 }
21288
21289 @ Equations and assignments are performed by the pair of mutually recursive
21290 @^recursion@>
21291 routines |do_equation| and |do_assignment|. These routines are called when
21292 |cur_cmd=equals| and when |cur_cmd=assignment|, respectively; the left-hand
21293 side is in |cur_type| and |cur_exp|, while the right-hand side is yet
21294 to be scanned. After the routines are finished, |cur_type| and |cur_exp|
21295 will be equal to the right-hand side (which will normally be equal
21296 to the left-hand side).
21297
21298 @<Declare action procedures for use by |do_statement|@>=
21299 @<Declare the procedure called |try_eq|@>;
21300 @<Declare the procedure called |make_eq|@>;
21301 void mp_do_equation (MP mp) ;
21302
21303 @ @c
21304 void mp_do_equation (MP mp) {
21305   pointer lhs; /* capsule for the left-hand side */
21306   pointer p; /* temporary register */
21307   lhs=mp_stash_cur_exp(mp); mp_get_x_next(mp); 
21308   mp->var_flag=assignment; mp_scan_expression(mp);
21309   if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21310   else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21311   if ( mp->internal[mp_tracing_commands]>two ) 
21312     @<Trace the current equation@>;
21313   if ( mp->cur_type==mp_unknown_path ) if ( type(lhs)==mp_pair_type ) {
21314     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, lhs); lhs=p;
21315   }; /* in this case |make_eq| will change the pair to a path */
21316   mp_make_eq(mp, lhs); /* equate |lhs| to |(cur_type,cur_exp)| */
21317 }
21318
21319 @ And |do_assignment| is similar to |do_expression|:
21320
21321 @<Declarations@>=
21322 void mp_do_assignment (MP mp);
21323
21324 @ @<Declare action procedures for use by |do_statement|@>=
21325 void mp_do_assignment (MP mp) ;
21326
21327 @ @c
21328 void mp_do_assignment (MP mp) {
21329   pointer lhs; /* token list for the left-hand side */
21330   pointer p; /* where the left-hand value is stored */
21331   pointer q; /* temporary capsule for the right-hand value */
21332   if ( mp->cur_type!=mp_token_list ) { 
21333     exp_err("Improper `:=' will be changed to `='");
21334 @.Improper `:='@>
21335     help2("I didn't find a variable name at the left of the `:=',")
21336       ("so I'm going to pretend that you said `=' instead.");
21337     mp_error(mp); mp_do_equation(mp);
21338   } else { 
21339     lhs=mp->cur_exp; mp->cur_type=mp_vacuous;
21340     mp_get_x_next(mp); mp->var_flag=assignment; mp_scan_expression(mp);
21341     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21342     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21343     if ( mp->internal[mp_tracing_commands]>two ) 
21344       @<Trace the current assignment@>;
21345     if ( info(lhs)>hash_end ) {
21346       @<Assign the current expression to an internal variable@>;
21347     } else  {
21348       @<Assign the current expression to the variable |lhs|@>;
21349     }
21350     mp_flush_node_list(mp, lhs);
21351   }
21352 }
21353
21354 @ @<Trace the current equation@>=
21355
21356   mp_begin_diagnostic(mp); mp_print_nl(mp, "{("); mp_print_exp(mp,lhs,0);
21357   mp_print(mp,")=("); mp_print_exp(mp,null,0); 
21358   mp_print(mp,")}"); mp_end_diagnostic(mp, false);
21359 }
21360
21361 @ @<Trace the current assignment@>=
21362
21363   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
21364   if ( info(lhs)>hash_end ) 
21365      mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21366   else 
21367      mp_show_token_list(mp, lhs,null,1000,0);
21368   mp_print(mp, ":="); mp_print_exp(mp, null,0); 
21369   mp_print_char(mp, '}'); mp_end_diagnostic(mp, false);
21370 }
21371
21372 @ @<Assign the current expression to an internal variable@>=
21373 if ( mp->cur_type==mp_known )  {
21374   mp->internal[info(lhs)-(hash_end)]=mp->cur_exp;
21375 } else { 
21376   exp_err("Internal quantity `");
21377 @.Internal quantity...@>
21378   mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21379   mp_print(mp, "' must receive a known value");
21380   help2("I can\'t set an internal quantity to anything but a known")
21381     ("numeric value, so I'll have to ignore this assignment.");
21382   mp_put_get_error(mp);
21383 }
21384
21385 @ @<Assign the current expression to the variable |lhs|@>=
21386
21387   p=mp_find_variable(mp, lhs);
21388   if ( p!=null ) {
21389     q=mp_stash_cur_exp(mp); mp->cur_type=mp_und_type(mp, p); 
21390     mp_recycle_value(mp, p);
21391     type(p)=mp->cur_type; value(p)=null; mp_make_exp_copy(mp, p);
21392     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q); mp_make_eq(mp, p);
21393   } else  { 
21394     mp_obliterated(mp, lhs); mp_put_get_error(mp);
21395   }
21396 }
21397
21398
21399 @ And now we get to the nitty-gritty. The |make_eq| procedure is given
21400 a pointer to a capsule that is to be equated to the current expression.
21401
21402 @<Declare the procedure called |make_eq|@>=
21403 void mp_make_eq (MP mp,pointer lhs) ;
21404
21405
21406
21407 @c void mp_make_eq (MP mp,pointer lhs) {
21408   small_number t; /* type of the left-hand side */
21409   pointer p,q; /* pointers inside of big nodes */
21410   integer v=0; /* value of the left-hand side */
21411 RESTART: 
21412   t=type(lhs);
21413   if ( t<=mp_pair_type ) v=value(lhs);
21414   switch (t) {
21415   @<For each type |t|, make an equation and |goto done| unless |cur_type|
21416     is incompatible with~|t|@>;
21417   } /* all cases have been listed */
21418   @<Announce that the equation cannot be performed@>;
21419 DONE:
21420   check_arith; mp_recycle_value(mp, lhs); 
21421   mp_free_node(mp, lhs,value_node_size);
21422 }
21423
21424 @ @<Announce that the equation cannot be performed@>=
21425 mp_disp_err(mp, lhs,""); 
21426 exp_err("Equation cannot be performed (");
21427 @.Equation cannot be performed@>
21428 if ( type(lhs)<=mp_pair_type ) mp_print_type(mp, type(lhs));
21429 else mp_print(mp, "numeric");
21430 mp_print_char(mp, '=');
21431 if ( mp->cur_type<=mp_pair_type ) mp_print_type(mp, mp->cur_type);
21432 else mp_print(mp, "numeric");
21433 mp_print_char(mp, ')');
21434 help2("I'm sorry, but I don't know how to make such things equal.")
21435      ("(See the two expressions just above the error message.)");
21436 mp_put_get_error(mp)
21437
21438 @ @<For each type |t|, make an equation and |goto done| unless...@>=
21439 case mp_boolean_type: case mp_string_type: case mp_pen_type:
21440 case mp_path_type: case mp_picture_type:
21441   if ( mp->cur_type==t+unknown_tag ) { 
21442     mp_nonlinear_eq(mp, v,mp->cur_exp,false); goto DONE;
21443   } else if ( mp->cur_type==t ) {
21444     @<Report redundant or inconsistent equation and |goto done|@>;
21445   }
21446   break;
21447 case unknown_types:
21448   if ( mp->cur_type==t-unknown_tag ) { 
21449     mp_nonlinear_eq(mp, mp->cur_exp,lhs,true); goto DONE;
21450   } else if ( mp->cur_type==t ) { 
21451     mp_ring_merge(mp, lhs,mp->cur_exp); goto DONE;
21452   } else if ( mp->cur_type==mp_pair_type ) {
21453     if ( t==mp_unknown_path ) { 
21454      mp_pair_to_path(mp); goto RESTART;
21455     };
21456   }
21457   break;
21458 case mp_transform_type: case mp_color_type:
21459 case mp_cmykcolor_type: case mp_pair_type:
21460   if ( mp->cur_type==t ) {
21461     @<Do multiple equations and |goto done|@>;
21462   }
21463   break;
21464 case mp_known: case mp_dependent:
21465 case mp_proto_dependent: case mp_independent:
21466   if ( mp->cur_type>=mp_known ) { 
21467     mp_try_eq(mp, lhs,null); goto DONE;
21468   };
21469   break;
21470 case mp_vacuous:
21471   break;
21472
21473 @ @<Report redundant or inconsistent equation and |goto done|@>=
21474
21475   if ( mp->cur_type<=mp_string_type ) {
21476     if ( mp->cur_type==mp_string_type ) {
21477       if ( mp_str_vs_str(mp, v,mp->cur_exp)!=0 ) {
21478         goto NOT_FOUND;
21479       }
21480     } else if ( v!=mp->cur_exp ) {
21481       goto NOT_FOUND;
21482     }
21483     @<Exclaim about a redundant equation@>; goto DONE;
21484   }
21485   print_err("Redundant or inconsistent equation");
21486 @.Redundant or inconsistent equation@>
21487   help2("An equation between already-known quantities can't help.")
21488        ("But don't worry; continue and I'll just ignore it.");
21489   mp_put_get_error(mp); goto DONE;
21490 NOT_FOUND: 
21491   print_err("Inconsistent equation");
21492 @.Inconsistent equation@>
21493   help2("The equation I just read contradicts what was said before.")
21494        ("But don't worry; continue and I'll just ignore it.");
21495   mp_put_get_error(mp); goto DONE;
21496 }
21497
21498 @ @<Do multiple equations and |goto done|@>=
21499
21500   p=v+mp->big_node_size[t]; 
21501   q=value(mp->cur_exp)+mp->big_node_size[t];
21502   do {  
21503     p=p-2; q=q-2; mp_try_eq(mp, p,q);
21504   } while (p!=v);
21505   goto DONE;
21506 }
21507
21508 @ The first argument to |try_eq| is the location of a value node
21509 in a capsule that will soon be recycled. The second argument is
21510 either a location within a pair or transform node pointed to by
21511 |cur_exp|, or it is |null| (which means that |cur_exp| itself
21512 serves as the second argument). The idea is to leave |cur_exp| unchanged,
21513 but to equate the two operands.
21514
21515 @<Declare the procedure called |try_eq|@>=
21516 void mp_try_eq (MP mp,pointer l, pointer r) ;
21517
21518
21519 @c void mp_try_eq (MP mp,pointer l, pointer r) {
21520   pointer p; /* dependency list for right operand minus left operand */
21521   int t; /* the type of list |p| */
21522   pointer q; /* the constant term of |p| is here */
21523   pointer pp; /* dependency list for right operand */
21524   int tt; /* the type of list |pp| */
21525   boolean copied; /* have we copied a list that ought to be recycled? */
21526   @<Remove the left operand from its container, negate it, and
21527     put it into dependency list~|p| with constant term~|q|@>;
21528   @<Add the right operand to list |p|@>;
21529   if ( info(p)==null ) {
21530     @<Deal with redundant or inconsistent equation@>;
21531   } else { 
21532     mp_linear_eq(mp, p,t);
21533     if ( r==null ) if ( mp->cur_type!=mp_known ) {
21534       if ( type(mp->cur_exp)==mp_known ) {
21535         pp=mp->cur_exp; mp->cur_exp=value(mp->cur_exp); mp->cur_type=mp_known;
21536         mp_free_node(mp, pp,value_node_size);
21537       }
21538     }
21539   }
21540 }
21541
21542 @ @<Remove the left operand from its container, negate it, and...@>=
21543 t=type(l);
21544 if ( t==mp_known ) { 
21545   t=mp_dependent; p=mp_const_dependency(mp, -value(l)); q=p;
21546 } else if ( t==mp_independent ) {
21547   t=mp_dependent; p=mp_single_dependency(mp, l); negate(value(p));
21548   q=mp->dep_final;
21549 } else { 
21550   p=dep_list(l); q=p;
21551   while (1) { 
21552     negate(value(q));
21553     if ( info(q)==null ) break;
21554     q=link(q);
21555   }
21556   link(prev_dep(l))=link(q); prev_dep(link(q))=prev_dep(l);
21557   type(l)=mp_known;
21558 }
21559
21560 @ @<Deal with redundant or inconsistent equation@>=
21561
21562   if ( abs(value(p))>64 ) { /* off by .001 or more */
21563     print_err("Inconsistent equation");
21564 @.Inconsistent equation@>
21565     mp_print(mp, " (off by "); mp_print_scaled(mp, value(p)); 
21566     mp_print_char(mp, ')');
21567     help2("The equation I just read contradicts what was said before.")
21568       ("But don't worry; continue and I'll just ignore it.");
21569     mp_put_get_error(mp);
21570   } else if ( r==null ) {
21571     @<Exclaim about a redundant equation@>;
21572   }
21573   mp_free_node(mp, p,dep_node_size);
21574 }
21575
21576 @ @<Add the right operand to list |p|@>=
21577 if ( r==null ) {
21578   if ( mp->cur_type==mp_known ) {
21579     value(q)=value(q)+mp->cur_exp; goto DONE1;
21580   } else { 
21581     tt=mp->cur_type;
21582     if ( tt==mp_independent ) pp=mp_single_dependency(mp, mp->cur_exp);
21583     else pp=dep_list(mp->cur_exp);
21584   } 
21585 } else {
21586   if ( type(r)==mp_known ) {
21587     value(q)=value(q)+value(r); goto DONE1;
21588   } else { 
21589     tt=type(r);
21590     if ( tt==mp_independent ) pp=mp_single_dependency(mp, r);
21591     else pp=dep_list(r);
21592   }
21593 }
21594 if ( tt!=mp_independent ) copied=false;
21595 else  { copied=true; tt=mp_dependent; };
21596 @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>;
21597 if ( copied ) mp_flush_node_list(mp, pp);
21598 DONE1:
21599
21600 @ @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>=
21601 mp->watch_coefs=false;
21602 if ( t==tt ) {
21603   p=mp_p_plus_q(mp, p,pp,t);
21604 } else if ( t==mp_proto_dependent ) {
21605   p=mp_p_plus_fq(mp, p,unity,pp,mp_proto_dependent,mp_dependent);
21606 } else { 
21607   q=p;
21608   while ( info(q)!=null ) {
21609     value(q)=mp_round_fraction(mp, value(q)); q=link(q);
21610   }
21611   t=mp_proto_dependent; p=mp_p_plus_q(mp, p,pp,t);
21612 }
21613 mp->watch_coefs=true;
21614
21615 @ Our next goal is to process type declarations. For this purpose it's
21616 convenient to have a procedure that scans a $\langle\,$declared
21617 variable$\,\rangle$ and returns the corresponding token list. After the
21618 following procedure has acted, the token after the declared variable
21619 will have been scanned, so it will appear in |cur_cmd|, |cur_mod|,
21620 and~|cur_sym|.
21621
21622 @<Declare the function called |scan_declared_variable|@>=
21623 pointer mp_scan_declared_variable (MP mp) {
21624   pointer x; /* hash address of the variable's root */
21625   pointer h,t; /* head and tail of the token list to be returned */
21626   pointer l; /* hash address of left bracket */
21627   mp_get_symbol(mp); x=mp->cur_sym;
21628   if ( mp->cur_cmd!=tag_token ) mp_clear_symbol(mp, x,false);
21629   h=mp_get_avail(mp); info(h)=x; t=h;
21630   while (1) { 
21631     mp_get_x_next(mp);
21632     if ( mp->cur_sym==0 ) break;
21633     if ( mp->cur_cmd!=tag_token ) if ( mp->cur_cmd!=internal_quantity)  {
21634       if ( mp->cur_cmd==left_bracket ) {
21635         @<Descend past a collective subscript@>;
21636       } else {
21637         break;
21638       }
21639     }
21640     link(t)=mp_get_avail(mp); t=link(t); info(t)=mp->cur_sym;
21641   }
21642   if ( eq_type(x)!=tag_token ) mp_clear_symbol(mp, x,false);
21643   if ( equiv(x)==null ) mp_new_root(mp, x);
21644   return h;
21645 }
21646
21647 @ If the subscript isn't collective, we don't accept it as part of the
21648 declared variable.
21649
21650 @<Descend past a collective subscript@>=
21651
21652   l=mp->cur_sym; mp_get_x_next(mp);
21653   if ( mp->cur_cmd!=right_bracket ) {
21654     mp_back_input(mp); mp->cur_sym=l; mp->cur_cmd=left_bracket; break;
21655   } else {
21656     mp->cur_sym=collective_subscript;
21657   }
21658 }
21659
21660 @ Type declarations are introduced by the following primitive operations.
21661
21662 @<Put each...@>=
21663 mp_primitive(mp, "numeric",type_name,mp_numeric_type);
21664 @:numeric_}{\&{numeric} primitive@>
21665 mp_primitive(mp, "string",type_name,mp_string_type);
21666 @:string_}{\&{string} primitive@>
21667 mp_primitive(mp, "boolean",type_name,mp_boolean_type);
21668 @:boolean_}{\&{boolean} primitive@>
21669 mp_primitive(mp, "path",type_name,mp_path_type);
21670 @:path_}{\&{path} primitive@>
21671 mp_primitive(mp, "pen",type_name,mp_pen_type);
21672 @:pen_}{\&{pen} primitive@>
21673 mp_primitive(mp, "picture",type_name,mp_picture_type);
21674 @:picture_}{\&{picture} primitive@>
21675 mp_primitive(mp, "transform",type_name,mp_transform_type);
21676 @:transform_}{\&{transform} primitive@>
21677 mp_primitive(mp, "color",type_name,mp_color_type);
21678 @:color_}{\&{color} primitive@>
21679 mp_primitive(mp, "rgbcolor",type_name,mp_color_type);
21680 @:color_}{\&{rgbcolor} primitive@>
21681 mp_primitive(mp, "cmykcolor",type_name,mp_cmykcolor_type);
21682 @:color_}{\&{cmykcolor} primitive@>
21683 mp_primitive(mp, "pair",type_name,mp_pair_type);
21684 @:pair_}{\&{pair} primitive@>
21685
21686 @ @<Cases of |print_cmd...@>=
21687 case type_name: mp_print_type(mp, m); break;
21688
21689 @ Now we are ready to handle type declarations, assuming that a
21690 |type_name| has just been scanned.
21691
21692 @<Declare action procedures for use by |do_statement|@>=
21693 void mp_do_type_declaration (MP mp) ;
21694
21695 @ @c
21696 void mp_do_type_declaration (MP mp) {
21697   small_number t; /* the type being declared */
21698   pointer p; /* token list for a declared variable */
21699   pointer q; /* value node for the variable */
21700   if ( mp->cur_mod>=mp_transform_type ) 
21701     t=mp->cur_mod;
21702   else 
21703     t=mp->cur_mod+unknown_tag;
21704   do {  
21705     p=mp_scan_declared_variable(mp);
21706     mp_flush_variable(mp, equiv(info(p)),link(p),false);
21707     q=mp_find_variable(mp, p);
21708     if ( q!=null ) { 
21709       type(q)=t; value(q)=null; 
21710     } else  { 
21711       print_err("Declared variable conflicts with previous vardef");
21712 @.Declared variable conflicts...@>
21713       help2("You can't use, e.g., `numeric foo[]' after `vardef foo'.")
21714            ("Proceed, and I'll ignore the illegal redeclaration.");
21715       mp_put_get_error(mp);
21716     }
21717     mp_flush_list(mp, p);
21718     if ( mp->cur_cmd<comma ) {
21719       @<Flush spurious symbols after the declared variable@>;
21720     }
21721   } while (! end_of_statement);
21722 }
21723
21724 @ @<Flush spurious symbols after the declared variable@>=
21725
21726   print_err("Illegal suffix of declared variable will be flushed");
21727 @.Illegal suffix...flushed@>
21728   help5("Variables in declarations must consist entirely of")
21729     ("names and collective subscripts, e.g., `x[]a'.")
21730     ("Are you trying to use a reserved word in a variable name?")
21731     ("I'm going to discard the junk I found here,")
21732     ("up to the next comma or the end of the declaration.");
21733   if ( mp->cur_cmd==numeric_token )
21734     mp->help_line[2]="Explicit subscripts like `x15a' aren't permitted.";
21735   mp_put_get_error(mp); mp->scanner_status=flushing;
21736   do {  
21737     get_t_next;
21738     @<Decrease the string reference count...@>;
21739   } while (mp->cur_cmd<comma); /* either |end_of_statement| or |cur_cmd=comma| */
21740   mp->scanner_status=normal;
21741 }
21742
21743 @ \MP's |main_control| procedure just calls |do_statement| repeatedly
21744 until coming to the end of the user's program.
21745 Each execution of |do_statement| concludes with
21746 |cur_cmd=semicolon|, |end_group|, or |stop|.
21747
21748 @c void mp_main_control (MP mp) { 
21749   do {  
21750     mp_do_statement(mp);
21751     if ( mp->cur_cmd==end_group ) {
21752       print_err("Extra `endgroup'");
21753 @.Extra `endgroup'@>
21754       help2("I'm not currently working on a `begingroup',")
21755         ("so I had better not try to end anything.");
21756       mp_flush_error(mp, 0);
21757     }
21758   } while (mp->cur_cmd!=stop);
21759 }
21760 int __attribute__((noinline)) 
21761 mp_run (MP mp) {
21762   if (mp->history < mp_fatal_error_stop ) {
21763     @<Install and test the non-local jump buffer@>;
21764     mp_main_control(mp); /* come to life */
21765     mp_final_cleanup(mp); /* prepare for death */
21766     mp_close_files_and_terminate(mp);
21767   }
21768   return mp->history;
21769 }
21770 int __attribute__((noinline)) 
21771 mp_execute (MP mp) {
21772   if (mp->history < mp_fatal_error_stop ) {
21773     mp->history = mp_spotless;
21774     mp->file_offset = 0;
21775     mp->term_offset = 0;
21776     mp->tally = 0; 
21777     @<Install and test the non-local jump buffer@>;
21778         if (mp->run_state==0) {
21779       mp->run_state = 1;
21780     } else {
21781       mp_input_ln(mp,mp->term_in);
21782       mp_firm_up_the_line(mp);  
21783       mp->buffer[limit]='%';
21784       mp->first=limit+1; 
21785       loc=start;
21786     }
21787     mp_main_control(mp); /* come to life */ 
21788   }
21789   return mp->history;
21790 }
21791 int __attribute__((noinline)) 
21792 mp_finish (MP mp) {
21793   if (mp->history < mp_fatal_error_stop ) {
21794     @<Install and test the non-local jump buffer@>;
21795     mp_final_cleanup(mp); /* prepare for death */
21796     mp_close_files_and_terminate(mp);
21797   }
21798   return mp->history;
21799 }
21800 char * mp_mplib_version (MP mp) {
21801   assert(mp);
21802   return mplib_version;
21803 }
21804 char * mp_metapost_version (MP mp) {
21805   assert(mp);
21806   return metapost_version;
21807 }
21808
21809 @ @<Exported function headers@>=
21810 int mp_run (MP mp);
21811 int mp_execute (MP mp);
21812 int mp_finish (MP mp);
21813 char * mp_mplib_version (MP mp);
21814 char * mp_metapost_version (MP mp);
21815
21816 @ @<Put each...@>=
21817 mp_primitive(mp, "end",stop,0);
21818 @:end_}{\&{end} primitive@>
21819 mp_primitive(mp, "dump",stop,1);
21820 @:dump_}{\&{dump} primitive@>
21821
21822 @ @<Cases of |print_cmd...@>=
21823 case stop:
21824   if ( m==0 ) mp_print(mp, "end");
21825   else mp_print(mp, "dump");
21826   break;
21827
21828 @* \[41] Commands.
21829 Let's turn now to statements that are classified as ``commands'' because
21830 of their imperative nature. We'll begin with simple ones, so that it
21831 will be clear how to hook command processing into the |do_statement| routine;
21832 then we'll tackle the tougher commands.
21833
21834 Here's one of the simplest:
21835
21836 @<Cases of |do_statement|...@>=
21837 case mp_random_seed: mp_do_random_seed(mp);  break;
21838
21839 @ @<Declare action procedures for use by |do_statement|@>=
21840 void mp_do_random_seed (MP mp) ;
21841
21842 @ @c void mp_do_random_seed (MP mp) { 
21843   mp_get_x_next(mp);
21844   if ( mp->cur_cmd!=assignment ) {
21845     mp_missing_err(mp, ":=");
21846 @.Missing `:='@>
21847     help1("Always say `randomseed:=<numeric expression>'.");
21848     mp_back_error(mp);
21849   };
21850   mp_get_x_next(mp); mp_scan_expression(mp);
21851   if ( mp->cur_type!=mp_known ) {
21852     exp_err("Unknown value will be ignored");
21853 @.Unknown value...ignored@>
21854     help2("Your expression was too random for me to handle,")
21855       ("so I won't change the random seed just now.");
21856     mp_put_get_flush_error(mp, 0);
21857   } else {
21858    @<Initialize the random seed to |cur_exp|@>;
21859   }
21860 }
21861
21862 @ @<Initialize the random seed to |cur_exp|@>=
21863
21864   mp_init_randoms(mp, mp->cur_exp);
21865   if ( mp->selector>=log_only && mp->selector<write_file) {
21866     mp->old_setting=mp->selector; mp->selector=log_only;
21867     mp_print_nl(mp, "{randomseed:="); 
21868     mp_print_scaled(mp, mp->cur_exp); 
21869     mp_print_char(mp, '}');
21870     mp_print_nl(mp, ""); mp->selector=mp->old_setting;
21871   }
21872 }
21873
21874 @ And here's another simple one (somewhat different in flavor):
21875
21876 @<Cases of |do_statement|...@>=
21877 case mode_command: 
21878   mp_print_ln(mp); mp->interaction=mp->cur_mod;
21879   @<Initialize the print |selector| based on |interaction|@>;
21880   if ( mp->log_opened ) mp->selector=mp->selector+2;
21881   mp_get_x_next(mp);
21882   break;
21883
21884 @ @<Put each...@>=
21885 mp_primitive(mp, "batchmode",mode_command,mp_batch_mode);
21886 @:mp_batch_mode_}{\&{batchmode} primitive@>
21887 mp_primitive(mp, "nonstopmode",mode_command,mp_nonstop_mode);
21888 @:mp_nonstop_mode_}{\&{nonstopmode} primitive@>
21889 mp_primitive(mp, "scrollmode",mode_command,mp_scroll_mode);
21890 @:mp_scroll_mode_}{\&{scrollmode} primitive@>
21891 mp_primitive(mp, "errorstopmode",mode_command,mp_error_stop_mode);
21892 @:mp_error_stop_mode_}{\&{errorstopmode} primitive@>
21893
21894 @ @<Cases of |print_cmd_mod|...@>=
21895 case mode_command: 
21896   switch (m) {
21897   case mp_batch_mode: mp_print(mp, "batchmode"); break;
21898   case mp_nonstop_mode: mp_print(mp, "nonstopmode"); break;
21899   case mp_scroll_mode: mp_print(mp, "scrollmode"); break;
21900   default: mp_print(mp, "errorstopmode"); break;
21901   }
21902   break;
21903
21904 @ The `\&{inner}' and `\&{outer}' commands are only slightly harder.
21905
21906 @<Cases of |do_statement|...@>=
21907 case protection_command: mp_do_protection(mp); break;
21908
21909 @ @<Put each...@>=
21910 mp_primitive(mp, "inner",protection_command,0);
21911 @:inner_}{\&{inner} primitive@>
21912 mp_primitive(mp, "outer",protection_command,1);
21913 @:outer_}{\&{outer} primitive@>
21914
21915 @ @<Cases of |print_cmd...@>=
21916 case protection_command: 
21917   if ( m==0 ) mp_print(mp, "inner");
21918   else mp_print(mp, "outer");
21919   break;
21920
21921 @ @<Declare action procedures for use by |do_statement|@>=
21922 void mp_do_protection (MP mp) ;
21923
21924 @ @c void mp_do_protection (MP mp) {
21925   int m; /* 0 to unprotect, 1 to protect */
21926   halfword t; /* the |eq_type| before we change it */
21927   m=mp->cur_mod;
21928   do {  
21929     mp_get_symbol(mp); t=eq_type(mp->cur_sym);
21930     if ( m==0 ) { 
21931       if ( t>=outer_tag ) 
21932         eq_type(mp->cur_sym)=t-outer_tag;
21933     } else if ( t<outer_tag ) {
21934       eq_type(mp->cur_sym)=t+outer_tag;
21935     }
21936     mp_get_x_next(mp);
21937   } while (mp->cur_cmd==comma);
21938 }
21939
21940 @ \MP\ never defines the tokens `\.(' and `\.)' to be primitives, but
21941 plain \MP\ begins with the declaration `\&{delimiters} \.{()}'. Such a
21942 declaration assigns the command code |left_delimiter| to `\.{(}' and
21943 |right_delimiter| to `\.{)}'; the |equiv| of each delimiter is the
21944 hash address of its mate.
21945
21946 @<Cases of |do_statement|...@>=
21947 case delimiters: mp_def_delims(mp); break;
21948
21949 @ @<Declare action procedures for use by |do_statement|@>=
21950 void mp_def_delims (MP mp) ;
21951
21952 @ @c void mp_def_delims (MP mp) {
21953   pointer l_delim,r_delim; /* the new delimiter pair */
21954   mp_get_clear_symbol(mp); l_delim=mp->cur_sym;
21955   mp_get_clear_symbol(mp); r_delim=mp->cur_sym;
21956   eq_type(l_delim)=left_delimiter; equiv(l_delim)=r_delim;
21957   eq_type(r_delim)=right_delimiter; equiv(r_delim)=l_delim;
21958   mp_get_x_next(mp);
21959 }
21960
21961 @ Here is a procedure that is called when \MP\ has reached a point
21962 where some right delimiter is mandatory.
21963
21964 @<Declare the procedure called |check_delimiter|@>=
21965 void mp_check_delimiter (MP mp,pointer l_delim, pointer r_delim) {
21966   if ( mp->cur_cmd==right_delimiter ) 
21967     if ( mp->cur_mod==l_delim ) 
21968       return;
21969   if ( mp->cur_sym!=r_delim ) {
21970      mp_missing_err(mp, str(text(r_delim)));
21971 @.Missing `)'@>
21972     help2("I found no right delimiter to match a left one. So I've")
21973       ("put one in, behind the scenes; this may fix the problem.");
21974     mp_back_error(mp);
21975   } else { 
21976     print_err("The token `"); mp_print_text(r_delim);
21977 @.The token...delimiter@>
21978     mp_print(mp, "' is no longer a right delimiter");
21979     help3("Strange: This token has lost its former meaning!")
21980       ("I'll read it as a right delimiter this time;")
21981       ("but watch out, I'll probably miss it later.");
21982     mp_error(mp);
21983   }
21984 }
21985
21986 @ The next four commands save or change the values associated with tokens.
21987
21988 @<Cases of |do_statement|...@>=
21989 case save_command: 
21990   do {  
21991     mp_get_symbol(mp); mp_save_variable(mp, mp->cur_sym); mp_get_x_next(mp);
21992   } while (mp->cur_cmd==comma);
21993   break;
21994 case interim_command: mp_do_interim(mp); break;
21995 case let_command: mp_do_let(mp); break;
21996 case new_internal: mp_do_new_internal(mp); break;
21997
21998 @ @<Declare action procedures for use by |do_statement|@>=
21999 void mp_do_statement (MP mp);
22000 void mp_do_interim (MP mp);
22001
22002 @ @c void mp_do_interim (MP mp) { 
22003   mp_get_x_next(mp);
22004   if ( mp->cur_cmd!=internal_quantity ) {
22005      print_err("The token `");
22006 @.The token...quantity@>
22007     if ( mp->cur_sym==0 ) mp_print(mp, "(%CAPSULE)");
22008     else mp_print_text(mp->cur_sym);
22009     mp_print(mp, "' isn't an internal quantity");
22010     help1("Something like `tracingonline' should follow `interim'.");
22011     mp_back_error(mp);
22012   } else { 
22013     mp_save_internal(mp, mp->cur_mod); mp_back_input(mp);
22014   }
22015   mp_do_statement(mp);
22016 }
22017
22018 @ The following procedure is careful not to undefine the left-hand symbol
22019 too soon, lest commands like `{\tt let x=x}' have a surprising effect.
22020
22021 @<Declare action procedures for use by |do_statement|@>=
22022 void mp_do_let (MP mp) ;
22023
22024 @ @c void mp_do_let (MP mp) {
22025   pointer l; /* hash location of the left-hand symbol */
22026   mp_get_symbol(mp); l=mp->cur_sym; mp_get_x_next(mp);
22027   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
22028      mp_missing_err(mp, "=");
22029 @.Missing `='@>
22030     help3("You should have said `let symbol = something'.")
22031       ("But don't worry; I'll pretend that an equals sign")
22032       ("was present. The next token I read will be `something'.");
22033     mp_back_error(mp);
22034   }
22035   mp_get_symbol(mp);
22036   switch (mp->cur_cmd) {
22037   case defined_macro: case secondary_primary_macro:
22038   case tertiary_secondary_macro: case expression_tertiary_macro: 
22039     add_mac_ref(mp->cur_mod);
22040     break;
22041   default: 
22042     break;
22043   }
22044   mp_clear_symbol(mp, l,false); eq_type(l)=mp->cur_cmd;
22045   if ( mp->cur_cmd==tag_token ) equiv(l)=null;
22046   else equiv(l)=mp->cur_mod;
22047   mp_get_x_next(mp);
22048 }
22049
22050 @ @<Declarations@>=
22051 void mp_grow_internals (MP mp, int l);
22052 void mp_do_new_internal (MP mp) ;
22053
22054 @ @c
22055 void mp_grow_internals (MP mp, int l) {
22056   scaled *internal;
22057   char * *int_name; 
22058   int k;
22059   if ( hash_end+l>max_halfword ) {
22060     mp_confusion(mp, "out of memory space"); /* can't be reached */
22061   }
22062   int_name = xmalloc ((l+1),sizeof(char *));
22063   internal = xmalloc ((l+1),sizeof(scaled));
22064   for (k=0;k<=l; k++ ) { 
22065     if (k<=mp->max_internal) {
22066       internal[k]=mp->internal[k]; 
22067       int_name[k]=mp->int_name[k]; 
22068     } else {
22069       internal[k]=0; 
22070       int_name[k]=NULL; 
22071     }
22072   }
22073   xfree(mp->internal); xfree(mp->int_name);
22074   mp->int_name = int_name;
22075   mp->internal = internal;
22076   mp->max_internal = l;
22077 }
22078
22079
22080 void mp_do_new_internal (MP mp) { 
22081   do {  
22082     if ( mp->int_ptr==mp->max_internal ) {
22083       mp_grow_internals(mp, (mp->max_internal + (mp->max_internal>>2)));
22084     }
22085     mp_get_clear_symbol(mp); incr(mp->int_ptr);
22086     eq_type(mp->cur_sym)=internal_quantity; 
22087     equiv(mp->cur_sym)=mp->int_ptr;
22088     if(mp->int_name[mp->int_ptr]!=NULL)
22089       xfree(mp->int_name[mp->int_ptr]);
22090     mp->int_name[mp->int_ptr]=str(text(mp->cur_sym)); 
22091     mp->internal[mp->int_ptr]=0;
22092     mp_get_x_next(mp);
22093   } while (mp->cur_cmd==comma);
22094 }
22095
22096 @ @<Dealloc variables@>=
22097 for (k=0;k<=mp->max_internal;k++) {
22098    xfree(mp->int_name[k]);
22099 }
22100 xfree(mp->internal); 
22101 xfree(mp->int_name); 
22102
22103
22104 @ The various `\&{show}' commands are distinguished by modifier fields
22105 in the usual way.
22106
22107 @d show_token_code 0 /* show the meaning of a single token */
22108 @d show_stats_code 1 /* show current memory and string usage */
22109 @d show_code 2 /* show a list of expressions */
22110 @d show_var_code 3 /* show a variable and its descendents */
22111 @d show_dependencies_code 4 /* show dependent variables in terms of independents */
22112
22113 @<Put each...@>=
22114 mp_primitive(mp, "showtoken",show_command,show_token_code);
22115 @:show_token_}{\&{showtoken} primitive@>
22116 mp_primitive(mp, "showstats",show_command,show_stats_code);
22117 @:show_stats_}{\&{showstats} primitive@>
22118 mp_primitive(mp, "show",show_command,show_code);
22119 @:show_}{\&{show} primitive@>
22120 mp_primitive(mp, "showvariable",show_command,show_var_code);
22121 @:show_var_}{\&{showvariable} primitive@>
22122 mp_primitive(mp, "showdependencies",show_command,show_dependencies_code);
22123 @:show_dependencies_}{\&{showdependencies} primitive@>
22124
22125 @ @<Cases of |print_cmd...@>=
22126 case show_command: 
22127   switch (m) {
22128   case show_token_code:mp_print(mp, "showtoken"); break;
22129   case show_stats_code:mp_print(mp, "showstats"); break;
22130   case show_code:mp_print(mp, "show"); break;
22131   case show_var_code:mp_print(mp, "showvariable"); break;
22132   default: mp_print(mp, "showdependencies"); break;
22133   }
22134   break;
22135
22136 @ @<Cases of |do_statement|...@>=
22137 case show_command:mp_do_show_whatever(mp); break;
22138
22139 @ The value of |cur_mod| controls the |verbosity| in the |print_exp| routine:
22140 if it's |show_code|, complicated structures are abbreviated, otherwise
22141 they aren't.
22142
22143 @<Declare action procedures for use by |do_statement|@>=
22144 void mp_do_show (MP mp) ;
22145
22146 @ @c void mp_do_show (MP mp) { 
22147   do {  
22148     mp_get_x_next(mp); mp_scan_expression(mp);
22149     mp_print_nl(mp, ">> ");
22150 @.>>@>
22151     mp_print_exp(mp, null,2); mp_flush_cur_exp(mp, 0);
22152   } while (mp->cur_cmd==comma);
22153 }
22154
22155 @ @<Declare action procedures for use by |do_statement|@>=
22156 void mp_disp_token (MP mp) ;
22157
22158 @ @c void mp_disp_token (MP mp) { 
22159   mp_print_nl(mp, "> ");
22160 @.>\relax@>
22161   if ( mp->cur_sym==0 ) {
22162     @<Show a numeric or string or capsule token@>;
22163   } else { 
22164     mp_print_text(mp->cur_sym); mp_print_char(mp, '=');
22165     if ( eq_type(mp->cur_sym)>=outer_tag ) mp_print(mp, "(outer) ");
22166     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod);
22167     if ( mp->cur_cmd==defined_macro ) {
22168       mp_print_ln(mp); mp_show_macro(mp, mp->cur_mod,null,100000);
22169     } /* this avoids recursion between |show_macro| and |print_cmd_mod| */
22170 @^recursion@>
22171   }
22172 }
22173
22174 @ @<Show a numeric or string or capsule token@>=
22175
22176   if ( mp->cur_cmd==numeric_token ) {
22177     mp_print_scaled(mp, mp->cur_mod);
22178   } else if ( mp->cur_cmd==capsule_token ) {
22179     mp_print_capsule(mp,mp->cur_mod);
22180   } else  { 
22181     mp_print_char(mp, '"'); 
22182     mp_print_str(mp, mp->cur_mod); mp_print_char(mp, '"');
22183     delete_str_ref(mp->cur_mod);
22184   }
22185 }
22186
22187 @ The following cases of |print_cmd_mod| might arise in connection
22188 with |disp_token|, although they don't correspond to any
22189 primitive tokens.
22190
22191 @<Cases of |print_cmd_...@>=
22192 case left_delimiter:
22193 case right_delimiter: 
22194   if ( c==left_delimiter ) mp_print(mp, "left");
22195   else mp_print(mp, "right");
22196   mp_print(mp, " delimiter that matches "); 
22197   mp_print_text(m);
22198   break;
22199 case tag_token:
22200   if ( m==null ) mp_print(mp, "tag");
22201    else mp_print(mp, "variable");
22202    break;
22203 case defined_macro: 
22204    mp_print(mp, "macro:");
22205    break;
22206 case secondary_primary_macro:
22207 case tertiary_secondary_macro:
22208 case expression_tertiary_macro:
22209   mp_print_cmd_mod(mp, macro_def,c); 
22210   mp_print(mp, "'d macro:");
22211   mp_print_ln(mp); mp_show_token_list(mp, link(link(m)),null,1000,0);
22212   break;
22213 case repeat_loop:
22214   mp_print(mp, "[repeat the loop]");
22215   break;
22216 case internal_quantity:
22217   mp_print(mp, mp->int_name[m]);
22218   break;
22219
22220 @ @<Declare action procedures for use by |do_statement|@>=
22221 void mp_do_show_token (MP mp) ;
22222
22223 @ @c void mp_do_show_token (MP mp) { 
22224   do {  
22225     get_t_next; mp_disp_token(mp);
22226     mp_get_x_next(mp);
22227   } while (mp->cur_cmd==comma);
22228 }
22229
22230 @ @<Declare action procedures for use by |do_statement|@>=
22231 void mp_do_show_stats (MP mp) ;
22232
22233 @ @c void mp_do_show_stats (MP mp) { 
22234   mp_print_nl(mp, "Memory usage ");
22235 @.Memory usage...@>
22236   mp_print_int(mp, mp->var_used); mp_print_char(mp, '&'); mp_print_int(mp, mp->dyn_used);
22237   if ( false )
22238     mp_print(mp, "unknown");
22239   mp_print(mp, " ("); mp_print_int(mp, mp->hi_mem_min-mp->lo_mem_max-1);
22240   mp_print(mp, " still untouched)"); mp_print_ln(mp);
22241   mp_print_nl(mp, "String usage ");
22242   mp_print_int(mp, mp->strs_in_use-mp->init_str_use);
22243   mp_print_char(mp, '&'); mp_print_int(mp, mp->pool_in_use-mp->init_pool_ptr);
22244   if ( false )
22245     mp_print(mp, "unknown");
22246   mp_print(mp, " (");
22247   mp_print_int(mp, mp->max_strings-1-mp->strs_used_up); mp_print_char(mp, '&');
22248   mp_print_int(mp, mp->pool_size-mp->pool_ptr); 
22249   mp_print(mp, " now untouched)"); mp_print_ln(mp);
22250   mp_get_x_next(mp);
22251 }
22252
22253 @ Here's a recursive procedure that gives an abbreviated account
22254 of a variable, for use by |do_show_var|.
22255
22256 @<Declare action procedures for use by |do_statement|@>=
22257 void mp_disp_var (MP mp,pointer p) ;
22258
22259 @ @c void mp_disp_var (MP mp,pointer p) {
22260   pointer q; /* traverses attributes and subscripts */
22261   int n; /* amount of macro text to show */
22262   if ( type(p)==mp_structured )  {
22263     @<Descend the structure@>;
22264   } else if ( type(p)>=mp_unsuffixed_macro ) {
22265     @<Display a variable macro@>;
22266   } else if ( type(p)!=undefined ){ 
22267     mp_print_nl(mp, ""); mp_print_variable_name(mp, p); 
22268     mp_print_char(mp, '=');
22269     mp_print_exp(mp, p,0);
22270   }
22271 }
22272
22273 @ @<Descend the structure@>=
22274
22275   q=attr_head(p);
22276   do {  mp_disp_var(mp, q); q=link(q); } while (q!=end_attr);
22277   q=subscr_head(p);
22278   while ( name_type(q)==mp_subscr ) { 
22279     mp_disp_var(mp, q); q=link(q);
22280   }
22281 }
22282
22283 @ @<Display a variable macro@>=
22284
22285   mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22286   if ( type(p)>mp_unsuffixed_macro ) 
22287     mp_print(mp, "@@#"); /* |suffixed_macro| */
22288   mp_print(mp, "=macro:");
22289   if ( (int)mp->file_offset>=mp->max_print_line-20 ) n=5;
22290   else n=mp->max_print_line-mp->file_offset-15;
22291   mp_show_macro(mp, value(p),null,n);
22292 }
22293
22294 @ @<Declare action procedures for use by |do_statement|@>=
22295 void mp_do_show_var (MP mp) ;
22296
22297 @ @c void mp_do_show_var (MP mp) { 
22298   do {  
22299     get_t_next;
22300     if ( mp->cur_sym>0 ) if ( mp->cur_sym<=hash_end )
22301       if ( mp->cur_cmd==tag_token ) if ( mp->cur_mod!=null ) {
22302       mp_disp_var(mp, mp->cur_mod); goto DONE;
22303     }
22304    mp_disp_token(mp);
22305   DONE:
22306    mp_get_x_next(mp);
22307   } while (mp->cur_cmd==comma);
22308 }
22309
22310 @ @<Declare action procedures for use by |do_statement|@>=
22311 void mp_do_show_dependencies (MP mp) ;
22312
22313 @ @c void mp_do_show_dependencies (MP mp) {
22314   pointer p; /* link that runs through all dependencies */
22315   p=link(dep_head);
22316   while ( p!=dep_head ) {
22317     if ( mp_interesting(mp, p) ) {
22318       mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22319       if ( type(p)==mp_dependent ) mp_print_char(mp, '=');
22320       else mp_print(mp, " = "); /* extra spaces imply proto-dependency */
22321       mp_print_dependency(mp, dep_list(p),type(p));
22322     }
22323     p=dep_list(p);
22324     while ( info(p)!=null ) p=link(p);
22325     p=link(p);
22326   }
22327   mp_get_x_next(mp);
22328 }
22329
22330 @ Finally we are ready for the procedure that governs all of the
22331 show commands.
22332
22333 @<Declare action procedures for use by |do_statement|@>=
22334 void mp_do_show_whatever (MP mp) ;
22335
22336 @ @c void mp_do_show_whatever (MP mp) { 
22337   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
22338   switch (mp->cur_mod) {
22339   case show_token_code:mp_do_show_token(mp); break;
22340   case show_stats_code:mp_do_show_stats(mp); break;
22341   case show_code:mp_do_show(mp); break;
22342   case show_var_code:mp_do_show_var(mp); break;
22343   case show_dependencies_code:mp_do_show_dependencies(mp); break;
22344   } /* there are no other cases */
22345   if ( mp->internal[mp_showstopping]>0 ){ 
22346     print_err("OK");
22347 @.OK@>
22348     if ( mp->interaction<mp_error_stop_mode ) { 
22349       help0; decr(mp->error_count);
22350     } else {
22351       help1("This isn't an error message; I'm just showing something.");
22352     }
22353     if ( mp->cur_cmd==semicolon ) mp_error(mp);
22354      else mp_put_get_error(mp);
22355   }
22356 }
22357
22358 @ The `\&{addto}' command needs the following additional primitives:
22359
22360 @d double_path_code 0 /* command modifier for `\&{doublepath}' */
22361 @d contour_code 1 /* command modifier for `\&{contour}' */
22362 @d also_code 2 /* command modifier for `\&{also}' */
22363
22364 @ Pre and postscripts need two new identifiers:
22365
22366 @d with_pre_script 11
22367 @d with_post_script 13
22368
22369 @<Put each...@>=
22370 mp_primitive(mp, "doublepath",thing_to_add,double_path_code);
22371 @:double_path_}{\&{doublepath} primitive@>
22372 mp_primitive(mp, "contour",thing_to_add,contour_code);
22373 @:contour_}{\&{contour} primitive@>
22374 mp_primitive(mp, "also",thing_to_add,also_code);
22375 @:also_}{\&{also} primitive@>
22376 mp_primitive(mp, "withpen",with_option,mp_pen_type);
22377 @:with_pen_}{\&{withpen} primitive@>
22378 mp_primitive(mp, "dashed",with_option,mp_picture_type);
22379 @:dashed_}{\&{dashed} primitive@>
22380 mp_primitive(mp, "withprescript",with_option,with_pre_script);
22381 @:with_pre_script_}{\&{withprescript} primitive@>
22382 mp_primitive(mp, "withpostscript",with_option,with_post_script);
22383 @:with_post_script_}{\&{withpostscript} primitive@>
22384 mp_primitive(mp, "withoutcolor",with_option,mp_no_model);
22385 @:with_color_}{\&{withoutcolor} primitive@>
22386 mp_primitive(mp, "withgreyscale",with_option,mp_grey_model);
22387 @:with_color_}{\&{withgreyscale} primitive@>
22388 mp_primitive(mp, "withcolor",with_option,mp_uninitialized_model);
22389 @:with_color_}{\&{withcolor} primitive@>
22390 /*  \&{withrgbcolor} is an alias for \&{withcolor} */
22391 mp_primitive(mp, "withrgbcolor",with_option,mp_rgb_model);
22392 @:with_color_}{\&{withrgbcolor} primitive@>
22393 mp_primitive(mp, "withcmykcolor",with_option,mp_cmyk_model);
22394 @:with_color_}{\&{withcmykcolor} primitive@>
22395
22396 @ @<Cases of |print_cmd...@>=
22397 case thing_to_add:
22398   if ( m==contour_code ) mp_print(mp, "contour");
22399   else if ( m==double_path_code ) mp_print(mp, "doublepath");
22400   else mp_print(mp, "also");
22401   break;
22402 case with_option:
22403   if ( m==mp_pen_type ) mp_print(mp, "withpen");
22404   else if ( m==with_pre_script ) mp_print(mp, "withprescript");
22405   else if ( m==with_post_script ) mp_print(mp, "withpostscript");
22406   else if ( m==mp_no_model ) mp_print(mp, "withoutcolor");
22407   else if ( m==mp_rgb_model ) mp_print(mp, "withrgbcolor");
22408   else if ( m==mp_uninitialized_model ) mp_print(mp, "withcolor");
22409   else if ( m==mp_cmyk_model ) mp_print(mp, "withcmykcolor");
22410   else if ( m==mp_grey_model ) mp_print(mp, "withgreyscale");
22411   else mp_print(mp, "dashed");
22412   break;
22413
22414 @ The |scan_with_list| procedure parses a $\langle$with list$\rangle$ and
22415 updates the list of graphical objects starting at |p|.  Each $\langle$with
22416 clause$\rangle$ updates all graphical objects whose |type| is compatible.
22417 Other objects are ignored.
22418
22419 @<Declare action procedures for use by |do_statement|@>=
22420 void mp_scan_with_list (MP mp,pointer p) ;
22421
22422 @ @c void mp_scan_with_list (MP mp,pointer p) {
22423   small_number t; /* |cur_mod| of the |with_option| (should match |cur_type|) */
22424   pointer q; /* for list manipulation */
22425   int old_setting; /* saved |selector| setting */
22426   pointer k; /* for finding the near-last item in a list  */
22427   str_number s; /* for string cleanup after combining  */
22428   pointer cp,pp,dp,ap,bp;
22429     /* objects being updated; |void| initially; |null| to suppress update */
22430   cp=mp_void; pp=mp_void; dp=mp_void; ap=mp_void; bp=mp_void;
22431   k=0;
22432   while ( mp->cur_cmd==with_option ){ 
22433     t=mp->cur_mod;
22434     mp_get_x_next(mp);
22435     if ( t!=mp_no_model ) mp_scan_expression(mp);
22436     if (((t==with_pre_script)&&(mp->cur_type!=mp_string_type))||
22437      ((t==with_post_script)&&(mp->cur_type!=mp_string_type))||
22438      ((t==mp_uninitialized_model)&&
22439         ((mp->cur_type!=mp_cmykcolor_type)&&(mp->cur_type!=mp_color_type)
22440           &&(mp->cur_type!=mp_known)&&(mp->cur_type!=mp_boolean_type)))||
22441      ((t==mp_cmyk_model)&&(mp->cur_type!=mp_cmykcolor_type))||
22442      ((t==mp_rgb_model)&&(mp->cur_type!=mp_color_type))||
22443      ((t==mp_grey_model)&&(mp->cur_type!=mp_known))||
22444      ((t==mp_pen_type)&&(mp->cur_type!=t))||
22445      ((t==mp_picture_type)&&(mp->cur_type!=t)) ) {
22446       @<Complain about improper type@>;
22447     } else if ( t==mp_uninitialized_model ) {
22448       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22449       if ( cp!=null )
22450         @<Transfer a color from the current expression to object~|cp|@>;
22451       mp_flush_cur_exp(mp, 0);
22452     } else if ( t==mp_rgb_model ) {
22453       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22454       if ( cp!=null )
22455         @<Transfer a rgbcolor from the current expression to object~|cp|@>;
22456       mp_flush_cur_exp(mp, 0);
22457     } else if ( t==mp_cmyk_model ) {
22458       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22459       if ( cp!=null )
22460         @<Transfer a cmykcolor from the current expression to object~|cp|@>;
22461       mp_flush_cur_exp(mp, 0);
22462     } else if ( t==mp_grey_model ) {
22463       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22464       if ( cp!=null )
22465         @<Transfer a greyscale from the current expression to object~|cp|@>;
22466       mp_flush_cur_exp(mp, 0);
22467     } else if ( t==mp_no_model ) {
22468       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22469       if ( cp!=null )
22470         @<Transfer a noncolor from the current expression to object~|cp|@>;
22471     } else if ( t==mp_pen_type ) {
22472       if ( pp==mp_void ) @<Make |pp| an object in list~|p| that needs a pen@>;
22473       if ( pp!=null ) {
22474         if ( pen_p(pp)!=null ) mp_toss_knot_list(mp, pen_p(pp));
22475         pen_p(pp)=mp->cur_exp; mp->cur_type=mp_vacuous;
22476       }
22477     } else if ( t==with_pre_script ) {
22478       if ( ap==mp_void )
22479         ap=p;
22480       while ( (ap!=null)&&(! has_color(ap)) )
22481          ap=link(ap);
22482       if ( ap!=null ) {
22483         if ( pre_script(ap)!=null ) { /*  build a new,combined string  */
22484           s=pre_script(ap);
22485           old_setting=mp->selector;
22486               mp->selector=new_string;
22487           str_room(length(pre_script(ap))+length(mp->cur_exp)+2);
22488               mp_print_str(mp, mp->cur_exp);
22489           append_char(13);  /* a forced \ps\ newline  */
22490           mp_print_str(mp, pre_script(ap));
22491           pre_script(ap)=mp_make_string(mp);
22492           delete_str_ref(s);
22493           mp->selector=old_setting;
22494         } else {
22495           pre_script(ap)=mp->cur_exp;
22496         }
22497         mp->cur_type=mp_vacuous;
22498       }
22499     } else if ( t==with_post_script ) {
22500       if ( bp==mp_void )
22501         k=p; 
22502       bp=k;
22503       while ( link(k)!=null ) {
22504         k=link(k);
22505         if ( has_color(k) ) bp=k;
22506       }
22507       if ( bp!=null ) {
22508          if ( post_script(bp)!=null ) {
22509            s=post_script(bp);
22510            old_setting=mp->selector;
22511                mp->selector=new_string;
22512            str_room(length(post_script(bp))+length(mp->cur_exp)+2);
22513            mp_print_str(mp, post_script(bp));
22514            append_char(13); /* a forced \ps\ newline  */
22515            mp_print_str(mp, mp->cur_exp);
22516            post_script(bp)=mp_make_string(mp);
22517            delete_str_ref(s);
22518            mp->selector=old_setting;
22519          } else {
22520            post_script(bp)=mp->cur_exp;
22521          }
22522          mp->cur_type=mp_vacuous;
22523        }
22524     } else { 
22525       if ( dp==mp_void ) {
22526         @<Make |dp| a stroked node in list~|p|@>;
22527       }
22528       if ( dp!=null ) {
22529         if ( dash_p(dp)!=null ) delete_edge_ref(dash_p(dp));
22530         dash_p(dp)=mp_make_dashes(mp, mp->cur_exp);
22531         dash_scale(dp)=unity;
22532         mp->cur_type=mp_vacuous;
22533       }
22534     }
22535   }
22536   @<Copy the information from objects |cp|, |pp|, and |dp| into the rest
22537     of the list@>;
22538 };
22539
22540 @ @<Complain about improper type@>=
22541 { exp_err("Improper type");
22542 @.Improper type@>
22543 help2("Next time say `withpen <known pen expression>';")
22544   ("I'll ignore the bad `with' clause and look for another.");
22545 if ( t==with_pre_script )
22546   mp->help_line[1]="Next time say `withprescript <known string expression>';";
22547 else if ( t==with_post_script )
22548   mp->help_line[1]="Next time say `withpostscript <known string expression>';";
22549 else if ( t==mp_picture_type )
22550   mp->help_line[1]="Next time say `dashed <known picture expression>';";
22551 else if ( t==mp_uninitialized_model )
22552   mp->help_line[1]="Next time say `withcolor <known color expression>';";
22553 else if ( t==mp_rgb_model )
22554   mp->help_line[1]="Next time say `withrgbcolor <known color expression>';";
22555 else if ( t==mp_cmyk_model )
22556   mp->help_line[1]="Next time say `withcmykcolor <known cmykcolor expression>';";
22557 else if ( t==mp_grey_model )
22558   mp->help_line[1]="Next time say `withgreyscale <known numeric expression>';";;
22559 mp_put_get_flush_error(mp, 0);
22560 }
22561
22562 @ Forcing the color to be between |0| and |unity| here guarantees that no
22563 picture will ever contain a color outside the legal range for \ps\ graphics.
22564
22565 @<Transfer a color from the current expression to object~|cp|@>=
22566 { if ( mp->cur_type==mp_color_type )
22567    @<Transfer a rgbcolor from the current expression to object~|cp|@>
22568 else if ( mp->cur_type==mp_cmykcolor_type )
22569    @<Transfer a cmykcolor from the current expression to object~|cp|@>
22570 else if ( mp->cur_type==mp_known )
22571    @<Transfer a greyscale from the current expression to object~|cp|@>
22572 else if ( mp->cur_exp==false_code )
22573    @<Transfer a noncolor from the current expression to object~|cp|@>;
22574 }
22575
22576 @ @<Transfer a rgbcolor from the current expression to object~|cp|@>=
22577 { q=value(mp->cur_exp);
22578 cyan_val(cp)=0;
22579 magenta_val(cp)=0;
22580 yellow_val(cp)=0;
22581 black_val(cp)=0;
22582 red_val(cp)=value(red_part_loc(q));
22583 green_val(cp)=value(green_part_loc(q));
22584 blue_val(cp)=value(blue_part_loc(q));
22585 color_model(cp)=mp_rgb_model;
22586 if ( red_val(cp)<0 ) red_val(cp)=0;
22587 if ( green_val(cp)<0 ) green_val(cp)=0;
22588 if ( blue_val(cp)<0 ) blue_val(cp)=0;
22589 if ( red_val(cp)>unity ) red_val(cp)=unity;
22590 if ( green_val(cp)>unity ) green_val(cp)=unity;
22591 if ( blue_val(cp)>unity ) blue_val(cp)=unity;
22592 }
22593
22594 @ @<Transfer a cmykcolor from the current expression to object~|cp|@>=
22595 { q=value(mp->cur_exp);
22596 cyan_val(cp)=value(cyan_part_loc(q));
22597 magenta_val(cp)=value(magenta_part_loc(q));
22598 yellow_val(cp)=value(yellow_part_loc(q));
22599 black_val(cp)=value(black_part_loc(q));
22600 color_model(cp)=mp_cmyk_model;
22601 if ( cyan_val(cp)<0 ) cyan_val(cp)=0;
22602 if ( magenta_val(cp)<0 ) magenta_val(cp)=0;
22603 if ( yellow_val(cp)<0 ) yellow_val(cp)=0;
22604 if ( black_val(cp)<0 ) black_val(cp)=0;
22605 if ( cyan_val(cp)>unity ) cyan_val(cp)=unity;
22606 if ( magenta_val(cp)>unity ) magenta_val(cp)=unity;
22607 if ( yellow_val(cp)>unity ) yellow_val(cp)=unity;
22608 if ( black_val(cp)>unity ) black_val(cp)=unity;
22609 }
22610
22611 @ @<Transfer a greyscale from the current expression to object~|cp|@>=
22612 { q=mp->cur_exp;
22613 cyan_val(cp)=0;
22614 magenta_val(cp)=0;
22615 yellow_val(cp)=0;
22616 black_val(cp)=0;
22617 grey_val(cp)=q;
22618 color_model(cp)=mp_grey_model;
22619 if ( grey_val(cp)<0 ) grey_val(cp)=0;
22620 if ( grey_val(cp)>unity ) grey_val(cp)=unity;
22621 }
22622
22623 @ @<Transfer a noncolor from the current expression to object~|cp|@>=
22624 {
22625 cyan_val(cp)=0;
22626 magenta_val(cp)=0;
22627 yellow_val(cp)=0;
22628 black_val(cp)=0;
22629 grey_val(cp)=0;
22630 color_model(cp)=mp_no_model;
22631 }
22632
22633 @ @<Make |cp| a colored object in object list~|p|@>=
22634 { cp=p;
22635   while ( cp!=null ){ 
22636     if ( has_color(cp) ) break;
22637     cp=link(cp);
22638   }
22639 }
22640
22641 @ @<Make |pp| an object in list~|p| that needs a pen@>=
22642 { pp=p;
22643   while ( pp!=null ) {
22644     if ( has_pen(pp) ) break;
22645     pp=link(pp);
22646   }
22647 }
22648
22649 @ @<Make |dp| a stroked node in list~|p|@>=
22650 { dp=p;
22651   while ( dp!=null ) {
22652     if ( type(dp)==mp_stroked_code ) break;
22653     dp=link(dp);
22654   }
22655 }
22656
22657 @ @<Copy the information from objects |cp|, |pp|, and |dp| into...@>=
22658 @<Copy |cp|'s color into the colored objects linked to~|cp|@>;
22659 if ( pp>mp_void ) {
22660   @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>;
22661 }
22662 if ( dp>mp_void ) {
22663   @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>;
22664 }
22665
22666
22667 @ @<Copy |cp|'s color into the colored objects linked to~|cp|@>=
22668 { q=link(cp);
22669   while ( q!=null ) { 
22670     if ( has_color(q) ) {
22671       red_val(q)=red_val(cp);
22672       green_val(q)=green_val(cp);
22673       blue_val(q)=blue_val(cp);
22674       black_val(q)=black_val(cp);
22675       color_model(q)=color_model(cp);
22676     }
22677     q=link(q);
22678   }
22679 }
22680
22681 @ @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>=
22682 { q=link(pp);
22683   while ( q!=null ) {
22684     if ( has_pen(q) ) {
22685       if ( pen_p(q)!=null ) mp_toss_knot_list(mp, pen_p(q));
22686       pen_p(q)=copy_pen(pen_p(pp));
22687     }
22688     q=link(q);
22689   }
22690 }
22691
22692 @ @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>=
22693 { q=link(dp);
22694   while ( q!=null ) {
22695     if ( type(q)==mp_stroked_code ) {
22696       if ( dash_p(q)!=null ) delete_edge_ref(dash_p(q));
22697       dash_p(q)=dash_p(dp);
22698       dash_scale(q)=unity;
22699       if ( dash_p(q)!=null ) add_edge_ref(dash_p(q));
22700     }
22701     q=link(q);
22702   }
22703 }
22704
22705 @ One of the things we need to do when we've parsed an \&{addto} or
22706 similar command is find the header of a supposed \&{picture} variable, given
22707 a token list for that variable.  Since the edge structure is about to be
22708 updated, we use |private_edges| to make sure that this is possible.
22709
22710 @<Declare action procedures for use by |do_statement|@>=
22711 pointer mp_find_edges_var (MP mp, pointer t) ;
22712
22713 @ @c pointer mp_find_edges_var (MP mp, pointer t) {
22714   pointer p;
22715   pointer cur_edges; /* the return value */
22716   p=mp_find_variable(mp, t); cur_edges=null;
22717   if ( p==null ) { 
22718     mp_obliterated(mp, t); mp_put_get_error(mp);
22719   } else if ( type(p)!=mp_picture_type )  { 
22720     print_err("Variable "); mp_show_token_list(mp, t,null,1000,0);
22721 @.Variable x is the wrong type@>
22722     mp_print(mp, " is the wrong type ("); 
22723     mp_print_type(mp, type(p)); mp_print_char(mp, ')');
22724     help2("I was looking for a \"known\" picture variable.")
22725          ("So I'll not change anything just now."); 
22726     mp_put_get_error(mp);
22727   } else { 
22728     value(p)=mp_private_edges(mp, value(p));
22729     cur_edges=value(p);
22730   }
22731   mp_flush_node_list(mp, t);
22732   return cur_edges;
22733 };
22734
22735 @ @<Cases of |do_statement|...@>=
22736 case add_to_command: mp_do_add_to(mp); break;
22737 case bounds_command:mp_do_bounds(mp); break;
22738
22739 @ @<Put each...@>=
22740 mp_primitive(mp, "clip",bounds_command,mp_start_clip_code);
22741 @:clip_}{\&{clip} primitive@>
22742 mp_primitive(mp, "setbounds",bounds_command,mp_start_bounds_code);
22743 @:set_bounds_}{\&{setbounds} primitive@>
22744
22745 @ @<Cases of |print_cmd...@>=
22746 case bounds_command: 
22747   if ( m==mp_start_clip_code ) mp_print(mp, "clip");
22748   else mp_print(mp, "setbounds");
22749   break;
22750
22751 @ The following function parses the beginning of an \&{addto} or \&{clip}
22752 command: it expects a variable name followed by a token with |cur_cmd=sep|
22753 and then an expression.  The function returns the token list for the variable
22754 and stores the command modifier for the separator token in the global variable
22755 |last_add_type|.  We must be careful because this variable might get overwritten
22756 any time we call |get_x_next|.
22757
22758 @<Glob...@>=
22759 quarterword last_add_type;
22760   /* command modifier that identifies the last \&{addto} command */
22761
22762 @ @<Declare action procedures for use by |do_statement|@>=
22763 pointer mp_start_draw_cmd (MP mp,quarterword sep) ;
22764
22765 @ @c pointer mp_start_draw_cmd (MP mp,quarterword sep) {
22766   pointer lhv; /* variable to add to left */
22767   quarterword add_type=0; /* value to be returned in |last_add_type| */
22768   lhv=null;
22769   mp_get_x_next(mp); mp->var_flag=sep; mp_scan_primary(mp);
22770   if ( mp->cur_type!=mp_token_list ) {
22771     @<Abandon edges command because there's no variable@>;
22772   } else  { 
22773     lhv=mp->cur_exp; add_type=mp->cur_mod;
22774     mp->cur_type=mp_vacuous; mp_get_x_next(mp); mp_scan_expression(mp);
22775   }
22776   mp->last_add_type=add_type;
22777   return lhv;
22778 }
22779
22780 @ @<Abandon edges command because there's no variable@>=
22781 { exp_err("Not a suitable variable");
22782 @.Not a suitable variable@>
22783   help4("At this point I needed to see the name of a picture variable.")
22784     ("(Or perhaps you have indeed presented me with one; I might")
22785     ("have missed it, if it wasn't followed by the proper token.)")
22786     ("So I'll not change anything just now.");
22787   mp_put_get_flush_error(mp, 0);
22788 }
22789
22790 @ Here is an example of how to use |start_draw_cmd|.
22791
22792 @<Declare action procedures for use by |do_statement|@>=
22793 void mp_do_bounds (MP mp) ;
22794
22795 @ @c void mp_do_bounds (MP mp) {
22796   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
22797   pointer p; /* for list manipulation */
22798   integer m; /* initial value of |cur_mod| */
22799   m=mp->cur_mod;
22800   lhv=mp_start_draw_cmd(mp, to_token);
22801   if ( lhv!=null ) {
22802     lhe=mp_find_edges_var(mp, lhv);
22803     if ( lhe==null ) {
22804       mp_flush_cur_exp(mp, 0);
22805     } else if ( mp->cur_type!=mp_path_type ) {
22806       exp_err("Improper `clip'");
22807 @.Improper `addto'@>
22808       help2("This expression should have specified a known path.")
22809         ("So I'll not change anything just now."); 
22810       mp_put_get_flush_error(mp, 0);
22811     } else if ( left_type(mp->cur_exp)==mp_endpoint ) {
22812       @<Complain about a non-cycle@>;
22813     } else {
22814       @<Make |cur_exp| into a \&{setbounds} or clipping path and add it to |lhe|@>;
22815     }
22816   }
22817 }
22818
22819 @ @<Complain about a non-cycle@>=
22820 { print_err("Not a cycle");
22821 @.Not a cycle@>
22822   help2("That contour should have ended with `..cycle' or `&cycle'.")
22823     ("So I'll not change anything just now."); mp_put_get_error(mp);
22824 }
22825
22826 @ @<Make |cur_exp| into a \&{setbounds} or clipping path and add...@>=
22827 { p=mp_new_bounds_node(mp, mp->cur_exp,m);
22828   link(p)=link(dummy_loc(lhe));
22829   link(dummy_loc(lhe))=p;
22830   if ( obj_tail(lhe)==dummy_loc(lhe) ) obj_tail(lhe)=p;
22831   p=mp_get_node(mp, mp->gr_object_size[stop_type(m)]);
22832   type(p)=stop_type(m);
22833   link(obj_tail(lhe))=p;
22834   obj_tail(lhe)=p;
22835   mp_init_bbox(mp, lhe);
22836 }
22837
22838 @ The |do_add_to| procedure is a little like |do_clip| but there are a lot more
22839 cases to deal with.
22840
22841 @<Declare action procedures for use by |do_statement|@>=
22842 void mp_do_add_to (MP mp) ;
22843
22844 @ @c void mp_do_add_to (MP mp) {
22845   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
22846   pointer p; /* the graphical object or list for |scan_with_list| to update */
22847   pointer e; /* an edge structure to be merged */
22848   quarterword add_type; /* |also_code|, |contour_code|, or |double_path_code| */
22849   lhv=mp_start_draw_cmd(mp, thing_to_add); add_type=mp->last_add_type;
22850   if ( lhv!=null ) {
22851     if ( add_type==also_code ) {
22852       @<Make sure the current expression is a suitable picture and set |e| and |p|
22853        appropriately@>;
22854     } else {
22855       @<Create a graphical object |p| based on |add_type| and the current
22856         expression@>;
22857     }
22858     mp_scan_with_list(mp, p);
22859     @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>;
22860   }
22861 }
22862
22863 @ Setting |p:=null| causes the $\langle$with list$\rangle$ to be ignored;
22864 setting |e:=null| prevents anything from being added to |lhe|.
22865
22866 @ @<Make sure the current expression is a suitable picture and set |e|...@>=
22867
22868   p=null; e=null;
22869   if ( mp->cur_type!=mp_picture_type ) {
22870     exp_err("Improper `addto'");
22871 @.Improper `addto'@>
22872     help2("This expression should have specified a known picture.")
22873       ("So I'll not change anything just now."); mp_put_get_flush_error(mp, 0);
22874   } else { 
22875     e=mp_private_edges(mp, mp->cur_exp); mp->cur_type=mp_vacuous;
22876     p=link(dummy_loc(e));
22877   }
22878 }
22879
22880 @ In this case |add_type<>also_code| so setting |p:=null| suppresses future
22881 attempts to add to the edge structure.
22882
22883 @<Create a graphical object |p| based on |add_type| and the current...@>=
22884 { e=null; p=null;
22885   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
22886   if ( mp->cur_type!=mp_path_type ) {
22887     exp_err("Improper `addto'");
22888 @.Improper `addto'@>
22889     help2("This expression should have specified a known path.")
22890       ("So I'll not change anything just now."); 
22891     mp_put_get_flush_error(mp, 0);
22892   } else if ( add_type==contour_code ) {
22893     if ( left_type(mp->cur_exp)==mp_endpoint ) {
22894       @<Complain about a non-cycle@>;
22895     } else { 
22896       p=mp_new_fill_node(mp, mp->cur_exp);
22897       mp->cur_type=mp_vacuous;
22898     }
22899   } else { 
22900     p=mp_new_stroked_node(mp, mp->cur_exp);
22901     mp->cur_type=mp_vacuous;
22902   }
22903 }
22904
22905 @ @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>=
22906 lhe=mp_find_edges_var(mp, lhv);
22907 if ( lhe==null ) {
22908   if ( (e==null)&&(p!=null) ) e=mp_toss_gr_object(mp, p);
22909   if ( e!=null ) delete_edge_ref(e);
22910 } else if ( add_type==also_code ) {
22911   if ( e!=null ) {
22912     @<Merge |e| into |lhe| and delete |e|@>;
22913   } else { 
22914     do_nothing;
22915   }
22916 } else if ( p!=null ) {
22917   link(obj_tail(lhe))=p;
22918   obj_tail(lhe)=p;
22919   if ( add_type==double_path_code )
22920     if ( pen_p(p)==null ) 
22921       pen_p(p)=mp_get_pen_circle(mp, 0);
22922 }
22923
22924 @ @<Merge |e| into |lhe| and delete |e|@>=
22925 { if ( link(dummy_loc(e))!=null ) {
22926     link(obj_tail(lhe))=link(dummy_loc(e));
22927     obj_tail(lhe)=obj_tail(e);
22928     obj_tail(e)=dummy_loc(e);
22929     link(dummy_loc(e))=null;
22930     mp_flush_dash_list(mp, lhe);
22931   }
22932   mp_toss_edges(mp, e);
22933 }
22934
22935 @ @<Cases of |do_statement|...@>=
22936 case ship_out_command: mp_do_ship_out(mp); break;
22937
22938 @ @<Declare action procedures for use by |do_statement|@>=
22939 @<Declare the function called |tfm_check|@>;
22940 @<Declare the \ps\ output procedures@>;
22941 void mp_do_ship_out (MP mp) ;
22942
22943 @ @c void mp_do_ship_out (MP mp) {
22944   integer c; /* the character code */
22945   mp_get_x_next(mp); mp_scan_expression(mp);
22946   if ( mp->cur_type!=mp_picture_type ) {
22947     @<Complain that it's not a known picture@>;
22948   } else { 
22949     c=mp_round_unscaled(mp, mp->internal[mp_char_code]) % 256;
22950     if ( c<0 ) c=c+256;
22951     @<Store the width information for character code~|c|@>;
22952     mp_ship_out(mp, mp->cur_exp);
22953     mp_flush_cur_exp(mp, 0);
22954   }
22955 }
22956
22957 @ @<Complain that it's not a known picture@>=
22958
22959   exp_err("Not a known picture");
22960   help1("I can only output known pictures.");
22961   mp_put_get_flush_error(mp, 0);
22962 }
22963
22964 @ The \&{everyjob} command simply assigns a nonzero value to the global variable
22965 |start_sym|.
22966
22967 @<Cases of |do_statement|...@>=
22968 case every_job_command: 
22969   mp_get_symbol(mp); mp->start_sym=mp->cur_sym; mp_get_x_next(mp);
22970   break;
22971
22972 @ @<Glob...@>=
22973 halfword start_sym; /* a symbolic token to insert at beginning of job */
22974
22975 @ @<Set init...@>=
22976 mp->start_sym=0;
22977
22978 @ Finally, we have only the ``message'' commands remaining.
22979
22980 @d message_code 0
22981 @d err_message_code 1
22982 @d err_help_code 2
22983 @d filename_template_code 3
22984 @d print_with_leading_zeroes(A)  g = mp->pool_ptr;
22985               mp_print_int(mp, (A)); g = mp->pool_ptr-g;
22986               if ( f>g ) {
22987                 mp->pool_ptr = mp->pool_ptr - g;
22988                 while ( f>g ) {
22989                   mp_print_char(mp, '0');
22990                   decr(f);
22991                   };
22992                 mp_print_int(mp, (A));
22993               };
22994               f = 0
22995
22996 @<Put each...@>=
22997 mp_primitive(mp, "message",message_command,message_code);
22998 @:message_}{\&{message} primitive@>
22999 mp_primitive(mp, "errmessage",message_command,err_message_code);
23000 @:err_message_}{\&{errmessage} primitive@>
23001 mp_primitive(mp, "errhelp",message_command,err_help_code);
23002 @:err_help_}{\&{errhelp} primitive@>
23003 mp_primitive(mp, "filenametemplate",message_command,filename_template_code);
23004 @:filename_template_}{\&{filenametemplate} primitive@>
23005
23006 @ @<Cases of |print_cmd...@>=
23007 case message_command: 
23008   if ( m<err_message_code ) mp_print(mp, "message");
23009   else if ( m==err_message_code ) mp_print(mp, "errmessage");
23010   else if ( m==filename_template_code ) mp_print(mp, "filenametemplate");
23011   else mp_print(mp, "errhelp");
23012   break;
23013
23014 @ @<Cases of |do_statement|...@>=
23015 case message_command: mp_do_message(mp); break;
23016
23017 @ @<Declare action procedures for use by |do_statement|@>=
23018 @<Declare a procedure called |no_string_err|@>;
23019 void mp_do_message (MP mp) ;
23020
23021
23022 @c void mp_do_message (MP mp) {
23023   int m; /* the type of message */
23024   m=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
23025   if ( mp->cur_type!=mp_string_type )
23026     mp_no_string_err(mp, "A message should be a known string expression.");
23027   else {
23028     switch (m) {
23029     case message_code: 
23030       mp_print_nl(mp, ""); mp_print_str(mp, mp->cur_exp);
23031       break;
23032     case err_message_code:
23033       @<Print string |cur_exp| as an error message@>;
23034       break;
23035     case err_help_code:
23036       @<Save string |cur_exp| as the |err_help|@>;
23037       break;
23038     case filename_template_code:
23039       @<Save the filename template@>;
23040       break;
23041     } /* there are no other cases */
23042   }
23043   mp_flush_cur_exp(mp, 0);
23044 }
23045
23046 @ @<Declare a procedure called |no_string_err|@>=
23047 void mp_no_string_err (MP mp,char *s) { 
23048    exp_err("Not a string");
23049 @.Not a string@>
23050   help1(s);
23051   mp_put_get_error(mp);
23052 }
23053
23054 @ The global variable |err_help| is zero when the user has most recently
23055 given an empty help string, or if none has ever been given.
23056
23057 @<Save string |cur_exp| as the |err_help|@>=
23058
23059   if ( mp->err_help!=0 ) delete_str_ref(mp->err_help);
23060   if ( length(mp->cur_exp)==0 ) mp->err_help=0;
23061   else  { mp->err_help=mp->cur_exp; add_str_ref(mp->err_help); }
23062 }
23063
23064 @ If \&{errmessage} occurs often in |mp_scroll_mode|, without user-defined
23065 \&{errhelp}, we don't want to give a long help message each time. So we
23066 give a verbose explanation only once.
23067
23068 @<Glob...@>=
23069 boolean long_help_seen; /* has the long \.{\\errmessage} help been used? */
23070
23071 @ @<Set init...@>=mp->long_help_seen=false;
23072
23073 @ @<Print string |cur_exp| as an error message@>=
23074
23075   print_err(""); mp_print_str(mp, mp->cur_exp);
23076   if ( mp->err_help!=0 ) {
23077     mp->use_err_help=true;
23078   } else if ( mp->long_help_seen ) { 
23079     help1("(That was another `errmessage'.)") ; 
23080   } else  { 
23081    if ( mp->interaction<mp_error_stop_mode ) mp->long_help_seen=true;
23082     help4("This error message was generated by an `errmessage'")
23083      ("command, so I can\'t give any explicit help.")
23084      ("Pretend that you're Miss Marple: Examine all clues,")
23085 @^Marple, Jane@>
23086      ("and deduce the truth by inspired guesses.");
23087   }
23088   mp_put_get_error(mp); mp->use_err_help=false;
23089 }
23090
23091 @ @<Cases of |do_statement|...@>=
23092 case write_command: mp_do_write(mp); break;
23093
23094 @ @<Declare action procedures for use by |do_statement|@>=
23095 void mp_do_write (MP mp) ;
23096
23097 @ @c void mp_do_write (MP mp) {
23098   str_number t; /* the line of text to be written */
23099   write_index n,n0; /* for searching |wr_fname| and |wr_file| arrays */
23100   int old_setting; /* for saving |selector| during output */
23101   mp_get_x_next(mp);
23102   mp_scan_expression(mp);
23103   if ( mp->cur_type!=mp_string_type ) {
23104     mp_no_string_err(mp, "The text to be written should be a known string expression");
23105   } else if ( mp->cur_cmd!=to_token ) { 
23106     print_err("Missing `to' clause");
23107     help1("A write command should end with `to <filename>'");
23108     mp_put_get_error(mp);
23109   } else { 
23110     t=mp->cur_exp; mp->cur_type=mp_vacuous;
23111     mp_get_x_next(mp);
23112     mp_scan_expression(mp);
23113     if ( mp->cur_type!=mp_string_type )
23114       mp_no_string_err(mp, "I can\'t write to that file name.  It isn't a known string");
23115     else {
23116       @<Write |t| to the file named by |cur_exp|@>;
23117     }
23118     delete_str_ref(t);
23119   }
23120   mp_flush_cur_exp(mp, 0);
23121 }
23122
23123 @ @<Write |t| to the file named by |cur_exp|@>=
23124
23125   @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if
23126     |cur_exp| must be inserted@>;
23127   if ( mp_str_vs_str(mp, t,mp->eof_line)==0 ) {
23128     @<Record the end of file on |wr_file[n]|@>;
23129   } else { 
23130     old_setting=mp->selector;
23131     mp->selector=n+write_file;
23132     mp_print_str(mp, t); mp_print_ln(mp);
23133     mp->selector = old_setting;
23134   }
23135 }
23136
23137 @ @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if...@>=
23138 {
23139   char *fn = str(mp->cur_exp);
23140   n=mp->write_files;
23141   n0=mp->write_files;
23142   while (mp_xstrcmp(fn,mp->wr_fname[n])!=0) { 
23143     if ( n==0 ) { /* bottom reached */
23144           if ( n0==mp->write_files ) {
23145         if ( mp->write_files<mp->max_write_files ) {
23146           incr(mp->write_files);
23147         } else {
23148           void **wr_file;
23149           char **wr_fname;
23150               write_index l,k;
23151           l = mp->max_write_files + (mp->max_write_files>>2);
23152           wr_file = xmalloc((l+1),sizeof(void *));
23153           wr_fname = xmalloc((l+1),sizeof(char *));
23154               for (k=0;k<=l;k++) {
23155             if (k<=mp->max_write_files) {
23156                   wr_file[k]=mp->wr_file[k]; 
23157               wr_fname[k]=mp->wr_fname[k];
23158             } else {
23159                   wr_file[k]=0; 
23160               wr_fname[k]=NULL;
23161             }
23162           }
23163               xfree(mp->wr_file); xfree(mp->wr_fname);
23164           mp->max_write_files = l;
23165           mp->wr_file = wr_file;
23166           mp->wr_fname = wr_fname;
23167         }
23168       }
23169       n=n0;
23170       mp_open_write_file(mp, fn ,n);
23171     } else { 
23172       decr(n);
23173           if ( mp->wr_fname[n]==NULL )  n0=n; 
23174     }
23175   }
23176 }
23177
23178 @ @<Record the end of file on |wr_file[n]|@>=
23179 { (mp->close_file)(mp,mp->wr_file[n]);
23180   xfree(mp->wr_fname[n]);
23181   mp->wr_fname[n]=NULL;
23182   if ( n==mp->write_files-1 ) mp->write_files=n;
23183 }
23184
23185
23186 @* \[42] Writing font metric data.
23187 \TeX\ gets its knowledge about fonts from font metric files, also called
23188 \.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
23189 but other programs know about them too. One of \MP's duties is to
23190 write \.{TFM} files so that the user's fonts can readily be
23191 applied to typesetting.
23192 @:TFM files}{\.{TFM} files@>
23193 @^font metric files@>
23194
23195 The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
23196 Since the number of bytes is always a multiple of~4, we could
23197 also regard the file as a sequence of 32-bit words, but \MP\ uses the
23198 byte interpretation. The format of \.{TFM} files was designed by
23199 Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
23200 @^Ramshaw, Lyle Harold@>
23201 of information in a compact but useful form.
23202
23203 @<Glob...@>=
23204 void * tfm_file; /* the font metric output goes here */
23205 char * metric_file_name; /* full name of the font metric file */
23206
23207 @ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
23208 integers that give the lengths of the various subsequent portions
23209 of the file. These twelve integers are, in order:
23210 $$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
23211 |lf|&length of the entire file, in words;\cr
23212 |lh|&length of the header data, in words;\cr
23213 |bc|&smallest character code in the font;\cr
23214 |ec|&largest character code in the font;\cr
23215 |nw|&number of words in the width table;\cr
23216 |nh|&number of words in the height table;\cr
23217 |nd|&number of words in the depth table;\cr
23218 |ni|&number of words in the italic correction table;\cr
23219 |nl|&number of words in the lig/kern table;\cr
23220 |nk|&number of words in the kern table;\cr
23221 |ne|&number of words in the extensible character table;\cr
23222 |np|&number of font parameter words.\cr}}$$
23223 They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
23224 |ne<=256|, and
23225 $$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
23226 Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|),
23227 and as few as 0 characters (if |bc=ec+1|).
23228
23229 Incidentally, when two or more 8-bit bytes are combined to form an integer of
23230 16 or more bits, the most significant bytes appear first in the file.
23231 This is called BigEndian order.
23232 @^BigEndian order@>
23233
23234 @ The rest of the \.{TFM} file may be regarded as a sequence of ten data
23235 arrays.
23236
23237 The most important data type used here is a |fix_word|, which is
23238 a 32-bit representation of a binary fraction. A |fix_word| is a signed
23239 quantity, with the two's complement of the entire word used to represent
23240 negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
23241 binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
23242 the smallest is $-2048$. We will see below, however, that all but two of
23243 the |fix_word| values must lie between $-16$ and $+16$.
23244
23245 @ The first data array is a block of header information, which contains
23246 general facts about the font. The header must contain at least two words,
23247 |header[0]| and |header[1]|, whose meaning is explained below.  Additional
23248 header information of use to other software routines might also be
23249 included, and \MP\ will generate it if the \.{headerbyte} command occurs.
23250 For example, 16 more words of header information are in use at the Xerox
23251 Palo Alto Research Center; the first ten specify the character coding
23252 scheme used (e.g., `\.{XEROX TEXT}' or `\.{TEX MATHSY}'), the next five
23253 give the font family name (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
23254 last gives the ``face byte.''
23255
23256 \yskip\hang|header[0]| is a 32-bit check sum that \MP\ will copy into
23257 the \.{GF} output file. This helps ensure consistency between files,
23258 since \TeX\ records the check sums from the \.{TFM}'s it reads, and these
23259 should match the check sums on actual fonts that are used.  The actual
23260 relation between this check sum and the rest of the \.{TFM} file is not
23261 important; the check sum is simply an identification number with the
23262 property that incompatible fonts almost always have distinct check sums.
23263 @^check sum@>
23264
23265 \yskip\hang|header[1]| is a |fix_word| containing the design size of the
23266 font, in units of \TeX\ points. This number must be at least 1.0; it is
23267 fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
23268 font, i.e., a font that was designed to look best at a 10-point size,
23269 whatever that really means. When a \TeX\ user asks for a font `\.{at}
23270 $\delta$ \.{pt}', the effect is to override the design size and replace it
23271 by $\delta$, and to multiply the $x$ and~$y$ coordinates of the points in
23272 the font image by a factor of $\delta$ divided by the design size.  {\sl
23273 All other dimensions in the\/ \.{TFM} file are |fix_word|\kern-1pt\
23274 numbers in design-size units.} Thus, for example, the value of |param[6]|,
23275 which defines the \.{em} unit, is often the |fix_word| value $2^{20}=1.0$,
23276 since many fonts have a design size equal to one em.  The other dimensions
23277 must be less than 16 design-size units in absolute value; thus,
23278 |header[1]| and |param[1]| are the only |fix_word| entries in the whole
23279 \.{TFM} file whose first byte might be something besides 0 or 255.
23280
23281 @ Next comes the |char_info| array, which contains one |char_info_word|
23282 per character. Each word in this part of the file contains six fields
23283 packed into four bytes as follows.
23284
23285 \yskip\hang first byte: |width_index| (8 bits)\par
23286 \hang second byte: |height_index| (4 bits) times 16, plus |depth_index|
23287   (4~bits)\par
23288 \hang third byte: |italic_index| (6 bits) times 4, plus |tag|
23289   (2~bits)\par
23290 \hang fourth byte: |remainder| (8 bits)\par
23291 \yskip\noindent
23292 The actual width of a character is \\{width}|[width_index]|, in design-size
23293 units; this is a device for compressing information, since many characters
23294 have the same width. Since it is quite common for many characters
23295 to have the same height, depth, or italic correction, the \.{TFM} format
23296 imposes a limit of 16 different heights, 16 different depths, and
23297 64 different italic corrections.
23298
23299 Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
23300 \\{italic}[0]=0$ should always hold, so that an index of zero implies a
23301 value of zero.  The |width_index| should never be zero unless the
23302 character does not exist in the font, since a character is valid if and
23303 only if it lies between |bc| and |ec| and has a nonzero |width_index|.
23304
23305 @ The |tag| field in a |char_info_word| has four values that explain how to
23306 interpret the |remainder| field.
23307
23308 \yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
23309 \hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
23310 program starting at location |remainder| in the |lig_kern| array.\par
23311 \hang|tag=2| (|list_tag|) means that this character is part of a chain of
23312 characters of ascending sizes, and not the largest in the chain.  The
23313 |remainder| field gives the character code of the next larger character.\par
23314 \hang|tag=3| (|ext_tag|) means that this character code represents an
23315 extensible character, i.e., a character that is built up of smaller pieces
23316 so that it can be made arbitrarily large. The pieces are specified in
23317 |exten[remainder]|.\par
23318 \yskip\noindent
23319 Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
23320 unless they are used in special circumstances in math formulas. For example,
23321 \TeX's \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
23322 operation looks for both |list_tag| and |ext_tag|.
23323
23324 @d no_tag 0 /* vanilla character */
23325 @d lig_tag 1 /* character has a ligature/kerning program */
23326 @d list_tag 2 /* character has a successor in a charlist */
23327 @d ext_tag 3 /* character is extensible */
23328
23329 @ The |lig_kern| array contains instructions in a simple programming language
23330 that explains what to do for special letter pairs. Each word in this array is a
23331 |lig_kern_command| of four bytes.
23332
23333 \yskip\hang first byte: |skip_byte|, indicates that this is the final program
23334   step if the byte is 128 or more, otherwise the next step is obtained by
23335   skipping this number of intervening steps.\par
23336 \hang second byte: |next_char|, ``if |next_char| follows the current character,
23337   then perform the operation and stop, otherwise continue.''\par
23338 \hang third byte: |op_byte|, indicates a ligature step if less than~128,
23339   a kern step otherwise.\par
23340 \hang fourth byte: |remainder|.\par
23341 \yskip\noindent
23342 In a kern step, an
23343 additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
23344 between the current character and |next_char|. This amount is
23345 often negative, so that the characters are brought closer together
23346 by kerning; but it might be positive.
23347
23348 There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
23349 $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
23350 |remainder| is inserted between the current character and |next_char|;
23351 then the current character is deleted if $b=0$, and |next_char| is
23352 deleted if $c=0$; then we pass over $a$~characters to reach the next
23353 current character (which may have a ligature/kerning program of its own).
23354
23355 If the very first instruction of the |lig_kern| array has |skip_byte=255|,
23356 the |next_char| byte is the so-called right boundary character of this font;
23357 the value of |next_char| need not lie between |bc| and~|ec|.
23358 If the very last instruction of the |lig_kern| array has |skip_byte=255|,
23359 there is a special ligature/kerning program for a left boundary character,
23360 beginning at location |256*op_byte+remainder|.
23361 The interpretation is that \TeX\ puts implicit boundary characters
23362 before and after each consecutive string of characters from the same font.
23363 These implicit characters do not appear in the output, but they can affect
23364 ligatures and kerning.
23365
23366 If the very first instruction of a character's |lig_kern| program has
23367 |skip_byte>128|, the program actually begins in location
23368 |256*op_byte+remainder|. This feature allows access to large |lig_kern|
23369 arrays, because the first instruction must otherwise
23370 appear in a location |<=255|.
23371
23372 Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy
23373 the condition
23374 $$\hbox{|256*op_byte+remainder<nl|.}$$
23375 If such an instruction is encountered during
23376 normal program execution, it denotes an unconditional halt; no ligature
23377 command is performed.
23378
23379 @d stop_flag (128)
23380   /* value indicating `\.{STOP}' in a lig/kern program */
23381 @d kern_flag (128) /* op code for a kern step */
23382 @d skip_byte(A) mp->lig_kern[(A)].b0
23383 @d next_char(A) mp->lig_kern[(A)].b1
23384 @d op_byte(A) mp->lig_kern[(A)].b2
23385 @d rem_byte(A) mp->lig_kern[(A)].b3
23386
23387 @ Extensible characters are specified by an |extensible_recipe|, which
23388 consists of four bytes called |top|, |mid|, |bot|, and |rep| (in this
23389 order). These bytes are the character codes of individual pieces used to
23390 build up a large symbol.  If |top|, |mid|, or |bot| are zero, they are not
23391 present in the built-up result. For example, an extensible vertical line is
23392 like an extensible bracket, except that the top and bottom pieces are missing.
23393
23394 Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
23395 if the piece isn't present. Then the extensible characters have the form
23396 $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent;
23397 in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
23398 The width of the extensible character is the width of $R$; and the
23399 height-plus-depth is the sum of the individual height-plus-depths of the
23400 components used, since the pieces are butted together in a vertical list.
23401
23402 @d ext_top(A) mp->exten[(A)].b0 /* |top| piece in a recipe */
23403 @d ext_mid(A) mp->exten[(A)].b1 /* |mid| piece in a recipe */
23404 @d ext_bot(A) mp->exten[(A)].b2 /* |bot| piece in a recipe */
23405 @d ext_rep(A) mp->exten[(A)].b3 /* |rep| piece in a recipe */
23406
23407 @ The final portion of a \.{TFM} file is the |param| array, which is another
23408 sequence of |fix_word| values.
23409
23410 \yskip\hang|param[1]=slant| is the amount of italic slant, which is used
23411 to help position accents. For example, |slant=.25| means that when you go
23412 up one unit, you also go .25 units to the right. The |slant| is a pure
23413 number; it is the only |fix_word| other than the design size itself that is
23414 not scaled by the design size.
23415
23416 \hang|param[2]=space| is the normal spacing between words in text.
23417 Note that character 040 in the font need not have anything to do with
23418 blank spaces.
23419
23420 \hang|param[3]=space_stretch| is the amount of glue stretching between words.
23421
23422 \hang|param[4]=space_shrink| is the amount of glue shrinking between words.
23423
23424 \hang|param[5]=x_height| is the size of one ex in the font; it is also
23425 the height of letters for which accents don't have to be raised or lowered.
23426
23427 \hang|param[6]=quad| is the size of one em in the font.
23428
23429 \hang|param[7]=extra_space| is the amount added to |param[2]| at the
23430 ends of sentences.
23431
23432 \yskip\noindent
23433 If fewer than seven parameters are present, \TeX\ sets the missing parameters
23434 to zero.
23435
23436 @d slant_code 1
23437 @d space_code 2
23438 @d space_stretch_code 3
23439 @d space_shrink_code 4
23440 @d x_height_code 5
23441 @d quad_code 6
23442 @d extra_space_code 7
23443
23444 @ So that is what \.{TFM} files hold. One of \MP's duties is to output such
23445 information, and it does this all at once at the end of a job.
23446 In order to prepare for such frenetic activity, it squirrels away the
23447 necessary facts in various arrays as information becomes available.
23448
23449 Character dimensions (\&{charwd}, \&{charht}, \&{chardp}, and \&{charic})
23450 are stored respectively in |tfm_width|, |tfm_height|, |tfm_depth|, and
23451 |tfm_ital_corr|. Other information about a character (e.g., about
23452 its ligatures or successors) is accessible via the |char_tag| and
23453 |char_remainder| arrays. Other information about the font as a whole
23454 is kept in additional arrays called |header_byte|, |lig_kern|,
23455 |kern|, |exten|, and |param|.
23456
23457 @d max_tfm_int 32510
23458 @d undefined_label max_tfm_int /* an undefined local label */
23459
23460 @<Glob...@>=
23461 #define TFM_ITEMS 257
23462 eight_bits bc;
23463 eight_bits ec; /* smallest and largest character codes shipped out */
23464 scaled tfm_width[TFM_ITEMS]; /* \&{charwd} values */
23465 scaled tfm_height[TFM_ITEMS]; /* \&{charht} values */
23466 scaled tfm_depth[TFM_ITEMS]; /* \&{chardp} values */
23467 scaled tfm_ital_corr[TFM_ITEMS]; /* \&{charic} values */
23468 boolean char_exists[TFM_ITEMS]; /* has this code been shipped out? */
23469 int char_tag[TFM_ITEMS]; /* |remainder| category */
23470 int char_remainder[TFM_ITEMS]; /* the |remainder| byte */
23471 char *header_byte; /* bytes of the \.{TFM} header */
23472 int header_last; /* last initialized \.{TFM} header byte */
23473 int header_size; /* size of the \.{TFM} header */
23474 four_quarters *lig_kern; /* the ligature/kern table */
23475 short nl; /* the number of ligature/kern steps so far */
23476 scaled *kern; /* distinct kerning amounts */
23477 short nk; /* the number of distinct kerns so far */
23478 four_quarters exten[TFM_ITEMS]; /* extensible character recipes */
23479 short ne; /* the number of extensible characters so far */
23480 scaled *param; /* \&{fontinfo} parameters */
23481 short np; /* the largest \&{fontinfo} parameter specified so far */
23482 short nw;short nh;short nd;short ni; /* sizes of \.{TFM} subtables */
23483 short skip_table[TFM_ITEMS]; /* local label status */
23484 boolean lk_started; /* has there been a lig/kern step in this command yet? */
23485 integer bchar; /* right boundary character */
23486 short bch_label; /* left boundary starting location */
23487 short ll;short lll; /* registers used for lig/kern processing */
23488 short label_loc[257]; /* lig/kern starting addresses */
23489 eight_bits label_char[257]; /* characters for |label_loc| */
23490 short label_ptr; /* highest position occupied in |label_loc| */
23491
23492 @ @<Allocate or initialize ...@>=
23493 mp->header_last = 0; mp->header_size = 128; /* just for init */
23494 mp->header_byte = xmalloc(mp->header_size, sizeof(char));
23495 mp->lig_kern = NULL; /* allocated when needed */
23496 mp->kern = NULL; /* allocated when needed */ 
23497 mp->param = NULL; /* allocated when needed */
23498
23499 @ @<Dealloc variables@>=
23500 xfree(mp->header_byte);
23501 xfree(mp->lig_kern);
23502 xfree(mp->kern);
23503 xfree(mp->param);
23504
23505 @ @<Set init...@>=
23506 for (k=0;k<= 255;k++ ) {
23507   mp->tfm_width[k]=0; mp->tfm_height[k]=0; mp->tfm_depth[k]=0; mp->tfm_ital_corr[k]=0;
23508   mp->char_exists[k]=false; mp->char_tag[k]=no_tag; mp->char_remainder[k]=0;
23509   mp->skip_table[k]=undefined_label;
23510 };
23511 memset(mp->header_byte,0,mp->header_size);
23512 mp->bc=255; mp->ec=0; mp->nl=0; mp->nk=0; mp->ne=0; mp->np=0;
23513 mp->internal[mp_boundary_char]=-unity;
23514 mp->bch_label=undefined_label;
23515 mp->label_loc[0]=-1; mp->label_ptr=0;
23516
23517 @ @<Declarations@>=
23518 scaled mp_tfm_check (MP mp,small_number m) ;
23519
23520 @ @<Declare the function called |tfm_check|@>=
23521 scaled mp_tfm_check (MP mp,small_number m) {
23522   if ( abs(mp->internal[m])>=fraction_half ) {
23523     print_err("Enormous "); mp_print(mp, mp->int_name[m]);
23524 @.Enormous charwd...@>
23525 @.Enormous chardp...@>
23526 @.Enormous charht...@>
23527 @.Enormous charic...@>
23528 @.Enormous designsize...@>
23529     mp_print(mp, " has been reduced");
23530     help1("Font metric dimensions must be less than 2048pt.");
23531     mp_put_get_error(mp);
23532     if ( mp->internal[m]>0 ) return (fraction_half-1);
23533     else return (1-fraction_half);
23534   } else {
23535     return mp->internal[m];
23536   }
23537 }
23538
23539 @ @<Store the width information for character code~|c|@>=
23540 if ( c<mp->bc ) mp->bc=c;
23541 if ( c>mp->ec ) mp->ec=c;
23542 mp->char_exists[c]=true;
23543 mp->tfm_width[c]=mp_tfm_check(mp, mp_char_wd);
23544 mp->tfm_height[c]=mp_tfm_check(mp, mp_char_ht);
23545 mp->tfm_depth[c]=mp_tfm_check(mp, mp_char_dp);
23546 mp->tfm_ital_corr[c]=mp_tfm_check(mp, mp_char_ic)
23547
23548 @ Now let's consider \MP's special \.{TFM}-oriented commands.
23549
23550 @<Cases of |do_statement|...@>=
23551 case tfm_command: mp_do_tfm_command(mp); break;
23552
23553 @ @d char_list_code 0
23554 @d lig_table_code 1
23555 @d extensible_code 2
23556 @d header_byte_code 3
23557 @d font_dimen_code 4
23558
23559 @<Put each...@>=
23560 mp_primitive(mp, "charlist",tfm_command,char_list_code);
23561 @:char_list_}{\&{charlist} primitive@>
23562 mp_primitive(mp, "ligtable",tfm_command,lig_table_code);
23563 @:lig_table_}{\&{ligtable} primitive@>
23564 mp_primitive(mp, "extensible",tfm_command,extensible_code);
23565 @:extensible_}{\&{extensible} primitive@>
23566 mp_primitive(mp, "headerbyte",tfm_command,header_byte_code);
23567 @:header_byte_}{\&{headerbyte} primitive@>
23568 mp_primitive(mp, "fontdimen",tfm_command,font_dimen_code);
23569 @:font_dimen_}{\&{fontdimen} primitive@>
23570
23571 @ @<Cases of |print_cmd...@>=
23572 case tfm_command: 
23573   switch (m) {
23574   case char_list_code:mp_print(mp, "charlist"); break;
23575   case lig_table_code:mp_print(mp, "ligtable"); break;
23576   case extensible_code:mp_print(mp, "extensible"); break;
23577   case header_byte_code:mp_print(mp, "headerbyte"); break;
23578   default: mp_print(mp, "fontdimen"); break;
23579   }
23580   break;
23581
23582 @ @<Declare action procedures for use by |do_statement|@>=
23583 eight_bits mp_get_code (MP mp) ;
23584
23585 @ @c eight_bits mp_get_code (MP mp) { /* scans a character code value */
23586   integer c; /* the code value found */
23587   mp_get_x_next(mp); mp_scan_expression(mp);
23588   if ( mp->cur_type==mp_known ) { 
23589     c=mp_round_unscaled(mp, mp->cur_exp);
23590     if ( c>=0 ) if ( c<256 ) return c;
23591   } else if ( mp->cur_type==mp_string_type ) {
23592     if ( length(mp->cur_exp)==1 )  { 
23593       c=mp->str_pool[mp->str_start[mp->cur_exp]];
23594       return c;
23595     }
23596   }
23597   exp_err("Invalid code has been replaced by 0");
23598 @.Invalid code...@>
23599   help2("I was looking for a number between 0 and 255, or for a")
23600        ("string of length 1. Didn't find it; will use 0 instead.");
23601   mp_put_get_flush_error(mp, 0); c=0;
23602   return c;
23603 };
23604
23605 @ @<Declare action procedures for use by |do_statement|@>=
23606 void mp_set_tag (MP mp,halfword c, small_number t, halfword r) ;
23607
23608 @ @c void mp_set_tag (MP mp,halfword c, small_number t, halfword r) { 
23609   if ( mp->char_tag[c]==no_tag ) {
23610     mp->char_tag[c]=t; mp->char_remainder[c]=r;
23611     if ( t==lig_tag ){ 
23612       incr(mp->label_ptr); mp->label_loc[mp->label_ptr]=r; 
23613       mp->label_char[mp->label_ptr]=c;
23614     }
23615   } else {
23616     @<Complain about a character tag conflict@>;
23617   }
23618 }
23619
23620 @ @<Complain about a character tag conflict@>=
23621
23622   print_err("Character ");
23623   if ( (c>' ')&&(c<127) ) mp_print_char(mp,c);
23624   else if ( c==256 ) mp_print(mp, "||");
23625   else  { mp_print(mp, "code "); mp_print_int(mp, c); };
23626   mp_print(mp, " is already ");
23627 @.Character c is already...@>
23628   switch (mp->char_tag[c]) {
23629   case lig_tag: mp_print(mp, "in a ligtable"); break;
23630   case list_tag: mp_print(mp, "in a charlist"); break;
23631   case ext_tag: mp_print(mp, "extensible"); break;
23632   } /* there are no other cases */
23633   help2("It's not legal to label a character more than once.")
23634     ("So I'll not change anything just now.");
23635   mp_put_get_error(mp); 
23636 }
23637
23638 @ @<Declare action procedures for use by |do_statement|@>=
23639 void mp_do_tfm_command (MP mp) ;
23640
23641 @ @c void mp_do_tfm_command (MP mp) {
23642   int c,cc; /* character codes */
23643   int k; /* index into the |kern| array */
23644   int j; /* index into |header_byte| or |param| */
23645   switch (mp->cur_mod) {
23646   case char_list_code: 
23647     c=mp_get_code(mp);
23648      /* we will store a list of character successors */
23649     while ( mp->cur_cmd==colon )   { 
23650       cc=mp_get_code(mp); mp_set_tag(mp, c,list_tag,cc); c=cc;
23651     };
23652     break;
23653   case lig_table_code: 
23654     if (mp->lig_kern==NULL) 
23655        mp->lig_kern = xmalloc((max_tfm_int+1),sizeof(four_quarters));
23656     if (mp->kern==NULL) 
23657        mp->kern = xmalloc((max_tfm_int+1),sizeof(scaled));
23658     @<Store a list of ligature/kern steps@>;
23659     break;
23660   case extensible_code: 
23661     @<Define an extensible recipe@>;
23662     break;
23663   case header_byte_code: 
23664   case font_dimen_code: 
23665     c=mp->cur_mod; mp_get_x_next(mp);
23666     mp_scan_expression(mp);
23667     if ( (mp->cur_type!=mp_known)||(mp->cur_exp<half_unit) ) {
23668       exp_err("Improper location");
23669 @.Improper location@>
23670       help2("I was looking for a known, positive number.")
23671        ("For safety's sake I'll ignore the present command.");
23672       mp_put_get_error(mp);
23673     } else  { 
23674       j=mp_round_unscaled(mp, mp->cur_exp);
23675       if ( mp->cur_cmd!=colon ) {
23676         mp_missing_err(mp, ":");
23677 @.Missing `:'@>
23678         help1("A colon should follow a headerbyte or fontinfo location.");
23679         mp_back_error(mp);
23680       }
23681       if ( c==header_byte_code ) { 
23682         @<Store a list of header bytes@>;
23683       } else {     
23684         if (mp->param==NULL) 
23685           mp->param = xmalloc((max_tfm_int+1),sizeof(scaled));
23686         @<Store a list of font dimensions@>;
23687       }
23688     }
23689     break;
23690   } /* there are no other cases */
23691 };
23692
23693 @ @<Store a list of ligature/kern steps@>=
23694
23695   mp->lk_started=false;
23696 CONTINUE: 
23697   mp_get_x_next(mp);
23698   if ((mp->cur_cmd==skip_to)&& mp->lk_started )
23699     @<Process a |skip_to| command and |goto done|@>;
23700   if ( mp->cur_cmd==bchar_label ) { c=256; mp->cur_cmd=colon; }
23701   else { mp_back_input(mp); c=mp_get_code(mp); };
23702   if ((mp->cur_cmd==colon)||(mp->cur_cmd==double_colon)) {
23703     @<Record a label in a lig/kern subprogram and |goto continue|@>;
23704   }
23705   if ( mp->cur_cmd==lig_kern_token ) { 
23706     @<Compile a ligature/kern command@>; 
23707   } else  { 
23708     print_err("Illegal ligtable step");
23709 @.Illegal ligtable step@>
23710     help1("I was looking for `=:' or `kern' here.");
23711     mp_back_error(mp); next_char(mp->nl)=qi(0); 
23712     op_byte(mp->nl)=qi(0); rem_byte(mp->nl)=qi(0);
23713     skip_byte(mp->nl)=stop_flag+1; /* this specifies an unconditional stop */
23714   }
23715   if ( mp->nl==max_tfm_int) mp_fatal_error(mp, "ligtable too large");
23716   incr(mp->nl);
23717   if ( mp->cur_cmd==comma ) goto CONTINUE;
23718   if ( skip_byte(mp->nl-1)<stop_flag ) skip_byte(mp->nl-1)=stop_flag;
23719 }
23720 DONE:
23721
23722 @ @<Put each...@>=
23723 mp_primitive(mp, "=:",lig_kern_token,0);
23724 @:=:_}{\.{=:} primitive@>
23725 mp_primitive(mp, "=:|",lig_kern_token,1);
23726 @:=:/_}{\.{=:\char'174} primitive@>
23727 mp_primitive(mp, "=:|>",lig_kern_token,5);
23728 @:=:/>_}{\.{=:\char'174>} primitive@>
23729 mp_primitive(mp, "|=:",lig_kern_token,2);
23730 @:=:/_}{\.{\char'174=:} primitive@>
23731 mp_primitive(mp, "|=:>",lig_kern_token,6);
23732 @:=:/>_}{\.{\char'174=:>} primitive@>
23733 mp_primitive(mp, "|=:|",lig_kern_token,3);
23734 @:=:/_}{\.{\char'174=:\char'174} primitive@>
23735 mp_primitive(mp, "|=:|>",lig_kern_token,7);
23736 @:=:/>_}{\.{\char'174=:\char'174>} primitive@>
23737 mp_primitive(mp, "|=:|>>",lig_kern_token,11);
23738 @:=:/>_}{\.{\char'174=:\char'174>>} primitive@>
23739 mp_primitive(mp, "kern",lig_kern_token,128);
23740 @:kern_}{\&{kern} primitive@>
23741
23742 @ @<Cases of |print_cmd...@>=
23743 case lig_kern_token: 
23744   switch (m) {
23745   case 0:mp_print(mp, "=:"); break;
23746   case 1:mp_print(mp, "=:|"); break;
23747   case 2:mp_print(mp, "|=:"); break;
23748   case 3:mp_print(mp, "|=:|"); break;
23749   case 5:mp_print(mp, "=:|>"); break;
23750   case 6:mp_print(mp, "|=:>"); break;
23751   case 7:mp_print(mp, "|=:|>"); break;
23752   case 11:mp_print(mp, "|=:|>>"); break;
23753   default: mp_print(mp, "kern"); break;
23754   }
23755   break;
23756
23757 @ Local labels are implemented by maintaining the |skip_table| array,
23758 where |skip_table[c]| is either |undefined_label| or the address of the
23759 most recent lig/kern instruction that skips to local label~|c|. In the
23760 latter case, the |skip_byte| in that instruction will (temporarily)
23761 be zero if there were no prior skips to this label, or it will be the
23762 distance to the prior skip.
23763
23764 We may need to cancel skips that span more than 127 lig/kern steps.
23765
23766 @d cancel_skips(A) mp->ll=(A);
23767   do {  
23768     mp->lll=qo(skip_byte(mp->ll)); 
23769     skip_byte(mp->ll)=stop_flag; mp->ll=mp->ll-mp->lll;
23770   } while (mp->lll!=0)
23771 @d skip_error(A) { print_err("Too far to skip");
23772 @.Too far to skip@>
23773   help1("At most 127 lig/kern steps can separate skipto1 from 1::.");
23774   mp_error(mp); cancel_skips((A));
23775   }
23776
23777 @<Process a |skip_to| command and |goto done|@>=
23778
23779   c=mp_get_code(mp);
23780   if ( mp->nl-mp->skip_table[c]>128 ) { /* |skip_table[c]<<nl<=undefined_label| */
23781     skip_error(mp->skip_table[c]); mp->skip_table[c]=undefined_label;
23782   }
23783   if ( mp->skip_table[c]==undefined_label ) skip_byte(mp->nl-1)=qi(0);
23784   else skip_byte(mp->nl-1)=qi(mp->nl-mp->skip_table[c]-1);
23785   mp->skip_table[c]=mp->nl-1; goto DONE;
23786 }
23787
23788 @ @<Record a label in a lig/kern subprogram and |goto continue|@>=
23789
23790   if ( mp->cur_cmd==colon ) {
23791     if ( c==256 ) mp->bch_label=mp->nl;
23792     else mp_set_tag(mp, c,lig_tag,mp->nl);
23793   } else if ( mp->skip_table[c]<undefined_label ) {
23794     mp->ll=mp->skip_table[c]; mp->skip_table[c]=undefined_label;
23795     do {  
23796       mp->lll=qo(skip_byte(mp->ll));
23797       if ( mp->nl-mp->ll>128 ) {
23798         skip_error(mp->ll); goto CONTINUE;
23799       }
23800       skip_byte(mp->ll)=qi(mp->nl-mp->ll-1); mp->ll=mp->ll-mp->lll;
23801     } while (mp->lll!=0);
23802   }
23803   goto CONTINUE;
23804 }
23805
23806 @ @<Compile a ligature/kern...@>=
23807
23808   next_char(mp->nl)=qi(c); skip_byte(mp->nl)=qi(0);
23809   if ( mp->cur_mod<128 ) { /* ligature op */
23810     op_byte(mp->nl)=qi(mp->cur_mod); rem_byte(mp->nl)=qi(mp_get_code(mp));
23811   } else { 
23812     mp_get_x_next(mp); mp_scan_expression(mp);
23813     if ( mp->cur_type!=mp_known ) {
23814       exp_err("Improper kern");
23815 @.Improper kern@>
23816       help2("The amount of kern should be a known numeric value.")
23817         ("I'm zeroing this one. Proceed, with fingers crossed.");
23818       mp_put_get_flush_error(mp, 0);
23819     }
23820     mp->kern[mp->nk]=mp->cur_exp;
23821     k=0; 
23822     while ( mp->kern[k]!=mp->cur_exp ) incr(k);
23823     if ( k==mp->nk ) {
23824       if ( mp->nk==max_tfm_int ) mp_fatal_error(mp, "too many TFM kerns");
23825       incr(mp->nk);
23826     }
23827     op_byte(mp->nl)=kern_flag+(k / 256);
23828     rem_byte(mp->nl)=qi((k % 256));
23829   }
23830   mp->lk_started=true;
23831 }
23832
23833 @ @d missing_extensible_punctuation(A) 
23834   { mp_missing_err(mp, (A));
23835 @.Missing `\char`\#'@>
23836   help1("I'm processing `extensible c: t,m,b,r'."); mp_back_error(mp);
23837   }
23838
23839 @<Define an extensible recipe@>=
23840
23841   if ( mp->ne==256 ) mp_fatal_error(mp, "too many extensible recipies");
23842   c=mp_get_code(mp); mp_set_tag(mp, c,ext_tag,mp->ne);
23843   if ( mp->cur_cmd!=colon ) missing_extensible_punctuation(":");
23844   ext_top(mp->ne)=qi(mp_get_code(mp));
23845   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23846   ext_mid(mp->ne)=qi(mp_get_code(mp));
23847   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23848   ext_bot(mp->ne)=qi(mp_get_code(mp));
23849   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23850   ext_rep(mp->ne)=qi(mp_get_code(mp));
23851   incr(mp->ne);
23852 }
23853
23854 @ The header could contain ASCII zeroes, so can't use |strdup|.
23855
23856 @<Store a list of header bytes@>=
23857 do {  
23858   if ( j>=mp->header_size ) {
23859     int l = mp->header_size + (mp->header_size >> 2);
23860     char *t = xmalloc(l,sizeof(char));
23861     memset(t,0,l); 
23862     memcpy(t,mp->header_byte,mp->header_size);
23863     xfree (mp->header_byte);
23864     mp->header_byte = t;
23865     mp->header_size = l;
23866   }
23867   mp->header_byte[j]=mp_get_code(mp); 
23868   incr(j); incr(mp->header_last);
23869 } while (mp->cur_cmd==comma)
23870
23871 @ @<Store a list of font dimensions@>=
23872 do {  
23873   if ( j>max_tfm_int ) mp_fatal_error(mp, "too many fontdimens");
23874   while ( j>mp->np ) { incr(mp->np); mp->param[mp->np]=0; };
23875   mp_get_x_next(mp); mp_scan_expression(mp);
23876   if ( mp->cur_type!=mp_known ){ 
23877     exp_err("Improper font parameter");
23878 @.Improper font parameter@>
23879     help1("I'm zeroing this one. Proceed, with fingers crossed.");
23880     mp_put_get_flush_error(mp, 0);
23881   }
23882   mp->param[j]=mp->cur_exp; incr(j);
23883 } while (mp->cur_cmd==comma)
23884
23885 @ OK: We've stored all the data that is needed for the \.{TFM} file.
23886 All that remains is to output it in the correct format.
23887
23888 An interesting problem needs to be solved in this connection, because
23889 the \.{TFM} format allows at most 256~widths, 16~heights, 16~depths,
23890 and 64~italic corrections. If the data has more distinct values than
23891 this, we want to meet the necessary restrictions by perturbing the
23892 given values as little as possible.
23893
23894 \MP\ solves this problem in two steps. First the values of a given
23895 kind (widths, heights, depths, or italic corrections) are sorted;
23896 then the list of sorted values is perturbed, if necessary.
23897
23898 The sorting operation is facilitated by having a special node of
23899 essentially infinite |value| at the end of the current list.
23900
23901 @<Initialize table entries...@>=
23902 value(inf_val)=fraction_four;
23903
23904 @ Straight linear insertion is good enough for sorting, since the lists
23905 are usually not terribly long. As we work on the data, the current list
23906 will start at |link(temp_head)| and end at |inf_val|; the nodes in this
23907 list will be in increasing order of their |value| fields.
23908
23909 Given such a list, the |sort_in| function takes a value and returns a pointer
23910 to where that value can be found in the list. The value is inserted in
23911 the proper place, if necessary.
23912
23913 At the time we need to do these operations, most of \MP's work has been
23914 completed, so we will have plenty of memory to play with. The value nodes
23915 that are allocated for sorting will never be returned to free storage.
23916
23917 @d clear_the_list link(temp_head)=inf_val
23918
23919 @c pointer mp_sort_in (MP mp,scaled v) {
23920   pointer p,q,r; /* list manipulation registers */
23921   p=temp_head;
23922   while (1) { 
23923     q=link(p);
23924     if ( v<=value(q) ) break;
23925     p=q;
23926   }
23927   if ( v<value(q) ) {
23928     r=mp_get_node(mp, value_node_size); value(r)=v; link(r)=q; link(p)=r;
23929   }
23930   return link(p);
23931 }
23932
23933 @ Now we come to the interesting part, where we reduce the list if necessary
23934 until it has the required size. The |min_cover| routine is basic to this
23935 process; it computes the minimum number~|m| such that the values of the
23936 current sorted list can be covered by |m|~intervals of width~|d|. It
23937 also sets the global value |perturbation| to the smallest value $d'>d$
23938 such that the covering found by this algorithm would be different.
23939
23940 In particular, |min_cover(0)| returns the number of distinct values in the
23941 current list and sets |perturbation| to the minimum distance between
23942 adjacent values.
23943
23944 @c integer mp_min_cover (MP mp,scaled d) {
23945   pointer p; /* runs through the current list */
23946   scaled l; /* the least element covered by the current interval */
23947   integer m; /* lower bound on the size of the minimum cover */
23948   m=0; p=link(temp_head); mp->perturbation=el_gordo;
23949   while ( p!=inf_val ){ 
23950     incr(m); l=value(p);
23951     do {  p=link(p); } while (value(p)<=l+d);
23952     if ( value(p)-l<mp->perturbation ) 
23953       mp->perturbation=value(p)-l;
23954   }
23955   return m;
23956 }
23957
23958 @ @<Glob...@>=
23959 scaled perturbation; /* quantity related to \.{TFM} rounding */
23960 integer excess; /* the list is this much too long */
23961
23962 @ The smallest |d| such that a given list can be covered with |m| intervals
23963 is determined by the |threshold| routine, which is sort of an inverse
23964 to |min_cover|. The idea is to increase the interval size rapidly until
23965 finding the range, then to go sequentially until the exact borderline has
23966 been discovered.
23967
23968 @c scaled mp_threshold (MP mp,integer m) {
23969   scaled d; /* lower bound on the smallest interval size */
23970   mp->excess=mp_min_cover(mp, 0)-m;
23971   if ( mp->excess<=0 ) {
23972     return 0;
23973   } else  { 
23974     do {  
23975       d=mp->perturbation;
23976     } while (mp_min_cover(mp, d+d)>m);
23977     while ( mp_min_cover(mp, d)>m ) 
23978       d=mp->perturbation;
23979     return d;
23980   }
23981 }
23982
23983 @ The |skimp| procedure reduces the current list to at most |m| entries,
23984 by changing values if necessary. It also sets |info(p):=k| if |value(p)|
23985 is the |k|th distinct value on the resulting list, and it sets
23986 |perturbation| to the maximum amount by which a |value| field has
23987 been changed. The size of the resulting list is returned as the
23988 value of |skimp|.
23989
23990 @c integer mp_skimp (MP mp,integer m) {
23991   scaled d; /* the size of intervals being coalesced */
23992   pointer p,q,r; /* list manipulation registers */
23993   scaled l; /* the least value in the current interval */
23994   scaled v; /* a compromise value */
23995   d=mp_threshold(mp, m); mp->perturbation=0;
23996   q=temp_head; m=0; p=link(temp_head);
23997   while ( p!=inf_val ) {
23998     incr(m); l=value(p); info(p)=m;
23999     if ( value(link(p))<=l+d ) {
24000       @<Replace an interval of values by its midpoint@>;
24001     }
24002     q=p; p=link(p);
24003   }
24004   return m;
24005 }
24006
24007 @ @<Replace an interval...@>=
24008
24009   do {  
24010     p=link(p); info(p)=m;
24011     decr(mp->excess); if ( mp->excess==0 ) d=0;
24012   } while (value(link(p))<=l+d);
24013   v=l+halfp(value(p)-l);
24014   if ( value(p)-v>mp->perturbation ) 
24015     mp->perturbation=value(p)-v;
24016   r=q;
24017   do {  
24018     r=link(r); value(r)=v;
24019   } while (r!=p);
24020   link(q)=p; /* remove duplicate values from the current list */
24021 }
24022
24023 @ A warning message is issued whenever something is perturbed by
24024 more than 1/16\thinspace pt.
24025
24026 @c void mp_tfm_warning (MP mp,small_number m) { 
24027   mp_print_nl(mp, "(some "); 
24028   mp_print(mp, mp->int_name[m]);
24029 @.some charwds...@>
24030 @.some chardps...@>
24031 @.some charhts...@>
24032 @.some charics...@>
24033   mp_print(mp, " values had to be adjusted by as much as ");
24034   mp_print_scaled(mp, mp->perturbation); mp_print(mp, "pt)");
24035 }
24036
24037 @ Here's an example of how we use these routines.
24038 The width data needs to be perturbed only if there are 256 distinct
24039 widths, but \MP\ must check for this case even though it is
24040 highly unusual.
24041
24042 An integer variable |k| will be defined when we use this code.
24043 The |dimen_head| array will contain pointers to the sorted
24044 lists of dimensions.
24045
24046 @<Massage the \.{TFM} widths@>=
24047 clear_the_list;
24048 for (k=mp->bc;k<=mp->ec;k++)  {
24049   if ( mp->char_exists[k] )
24050     mp->tfm_width[k]=mp_sort_in(mp, mp->tfm_width[k]);
24051 }
24052 mp->nw=mp_skimp(mp, 255)+1; mp->dimen_head[1]=link(temp_head);
24053 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_wd)
24054
24055 @ @<Glob...@>=
24056 pointer dimen_head[5]; /* lists of \.{TFM} dimensions */
24057
24058 @ Heights, depths, and italic corrections are different from widths
24059 not only because their list length is more severely restricted, but
24060 also because zero values do not need to be put into the lists.
24061
24062 @<Massage the \.{TFM} heights, depths, and italic corrections@>=
24063 clear_the_list;
24064 for (k=mp->bc;k<=mp->ec;k++) {
24065   if ( mp->char_exists[k] ) {
24066     if ( mp->tfm_height[k]==0 ) mp->tfm_height[k]=zero_val;
24067     else mp->tfm_height[k]=mp_sort_in(mp, mp->tfm_height[k]);
24068   }
24069 }
24070 mp->nh=mp_skimp(mp, 15)+1; mp->dimen_head[2]=link(temp_head);
24071 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_ht);
24072 clear_the_list;
24073 for (k=mp->bc;k<=mp->ec;k++) {
24074   if ( mp->char_exists[k] ) {
24075     if ( mp->tfm_depth[k]==0 ) mp->tfm_depth[k]=zero_val;
24076     else mp->tfm_depth[k]=mp_sort_in(mp, mp->tfm_depth[k]);
24077   }
24078 }
24079 mp->nd=mp_skimp(mp, 15)+1; mp->dimen_head[3]=link(temp_head);
24080 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_dp);
24081 clear_the_list;
24082 for (k=mp->bc;k<=mp->ec;k++) {
24083   if ( mp->char_exists[k] ) {
24084     if ( mp->tfm_ital_corr[k]==0 ) mp->tfm_ital_corr[k]=zero_val;
24085     else mp->tfm_ital_corr[k]=mp_sort_in(mp, mp->tfm_ital_corr[k]);
24086   }
24087 }
24088 mp->ni=mp_skimp(mp, 63)+1; mp->dimen_head[4]=link(temp_head);
24089 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_ic)
24090
24091 @ @<Initialize table entries...@>=
24092 value(zero_val)=0; info(zero_val)=0;
24093
24094 @ Bytes 5--8 of the header are set to the design size, unless the user has
24095 some crazy reason for specifying them differently.
24096
24097 Error messages are not allowed at the time this procedure is called,
24098 so a warning is printed instead.
24099
24100 The value of |max_tfm_dimen| is calculated so that
24101 $$\hbox{|make_scaled(16*max_tfm_dimen,internal[mp_design_size])|}
24102  < \\{three\_bytes}.$$
24103
24104 @d three_bytes 0100000000 /* $2^{24}$ */
24105
24106 @c 
24107 void mp_fix_design_size (MP mp) {
24108   scaled d; /* the design size */
24109   d=mp->internal[mp_design_size];
24110   if ( (d<unity)||(d>=fraction_half) ) {
24111     if ( d!=0 )
24112       mp_print_nl(mp, "(illegal design size has been changed to 128pt)");
24113 @.illegal design size...@>
24114     d=040000000; mp->internal[mp_design_size]=d;
24115   }
24116   if ( mp->header_byte[4]<0 ) if ( mp->header_byte[5]<0 )
24117     if ( mp->header_byte[6]<0 ) if ( mp->header_byte[7]<0 ) {
24118      mp->header_byte[4]=d / 04000000;
24119      mp->header_byte[5]=(d / 4096) % 256;
24120      mp->header_byte[6]=(d / 16) % 256;
24121      mp->header_byte[7]=(d % 16)*16;
24122   };
24123   mp->max_tfm_dimen=16*mp->internal[mp_design_size]-mp->internal[mp_design_size] / 010000000;
24124   if ( mp->max_tfm_dimen>=fraction_half ) mp->max_tfm_dimen=fraction_half-1;
24125 }
24126
24127 @ The |dimen_out| procedure computes a |fix_word| relative to the
24128 design size. If the data was out of range, it is corrected and the
24129 global variable |tfm_changed| is increased by~one.
24130
24131 @c integer mp_dimen_out (MP mp,scaled x) { 
24132   if ( abs(x)>mp->max_tfm_dimen ) {
24133     incr(mp->tfm_changed);
24134     if ( x>0 ) x=three_bytes-1; else x=1-three_bytes;
24135   } else {
24136     x=mp_make_scaled(mp, x*16,mp->internal[mp_design_size]);
24137   }
24138   return x;
24139 }
24140
24141 @ @<Glob...@>=
24142 scaled max_tfm_dimen; /* bound on widths, heights, kerns, etc. */
24143 integer tfm_changed; /* the number of data entries that were out of bounds */
24144
24145 @ If the user has not specified any of the first four header bytes,
24146 the |fix_check_sum| procedure replaces them by a ``check sum'' computed
24147 from the |tfm_width| data relative to the design size.
24148 @^check sum@>
24149
24150 @c void mp_fix_check_sum (MP mp) {
24151   eight_bits k; /* runs through character codes */
24152   eight_bits B1,B2,B3,B4; /* bytes of the check sum */
24153   integer x;  /* hash value used in check sum computation */
24154   if ( mp->header_byte[0]==0 && mp->header_byte[1]==0 &&
24155        mp->header_byte[2]==0 && mp->header_byte[3]==0 ) {
24156     @<Compute a check sum in |(b1,b2,b3,b4)|@>;
24157     mp->header_byte[0]=B1; mp->header_byte[1]=B2;
24158     mp->header_byte[2]=B3; mp->header_byte[3]=B4; 
24159     return;
24160   }
24161 }
24162
24163 @ @<Compute a check sum in |(b1,b2,b3,b4)|@>=
24164 B1=mp->bc; B2=mp->ec; B3=mp->bc; B4=mp->ec; mp->tfm_changed=0;
24165 for (k=mp->bc;k<=mp->ec;k++) { 
24166   if ( mp->char_exists[k] ) {
24167     x=mp_dimen_out(mp, value(mp->tfm_width[k]))+(k+4)*020000000; /* this is positive */
24168     B1=(B1+B1+x) % 255;
24169     B2=(B2+B2+x) % 253;
24170     B3=(B3+B3+x) % 251;
24171     B4=(B4+B4+x) % 247;
24172   }
24173 }
24174
24175 @ Finally we're ready to actually write the \.{TFM} information.
24176 Here are some utility routines for this purpose.
24177
24178 @d tfm_out(A) do { /* output one byte to |tfm_file| */
24179   unsigned char s=(A); 
24180   (mp->write_binary_file)(mp,mp->tfm_file,(void *)&s,1); 
24181   } while (0)
24182
24183 @c void mp_tfm_two (MP mp,integer x) { /* output two bytes to |tfm_file| */
24184   tfm_out(x / 256); tfm_out(x % 256);
24185 }
24186 void mp_tfm_four (MP mp,integer x) { /* output four bytes to |tfm_file| */
24187   if ( x>=0 ) tfm_out(x / three_bytes);
24188   else { 
24189     x=x+010000000000; /* use two's complement for negative values */
24190     x=x+010000000000;
24191     tfm_out((x / three_bytes) + 128);
24192   };
24193   x=x % three_bytes; tfm_out(x / unity);
24194   x=x % unity; tfm_out(x / 0400);
24195   tfm_out(x % 0400);
24196 }
24197 void mp_tfm_qqqq (MP mp,four_quarters x) { /* output four quarterwords to |tfm_file| */
24198   tfm_out(qo(x.b0)); tfm_out(qo(x.b1)); 
24199   tfm_out(qo(x.b2)); tfm_out(qo(x.b3));
24200 }
24201
24202 @ @<Finish the \.{TFM} file@>=
24203 if ( mp->job_name==NULL ) mp_open_log_file(mp);
24204 mp_pack_job_name(mp, ".tfm");
24205 while ( ! mp_b_open_out(mp, &mp->tfm_file, mp_filetype_metrics) )
24206   mp_prompt_file_name(mp, "file name for font metrics",".tfm");
24207 mp->metric_file_name=xstrdup(mp->name_of_file);
24208 @<Output the subfile sizes and header bytes@>;
24209 @<Output the character information bytes, then
24210   output the dimensions themselves@>;
24211 @<Output the ligature/kern program@>;
24212 @<Output the extensible character recipes and the font metric parameters@>;
24213   if ( mp->internal[mp_tracing_stats]>0 )
24214   @<Log the subfile sizes of the \.{TFM} file@>;
24215 mp_print_nl(mp, "Font metrics written on "); 
24216 mp_print(mp, mp->metric_file_name); mp_print_char(mp, '.');
24217 @.Font metrics written...@>
24218 (mp->close_file)(mp,mp->tfm_file)
24219
24220 @ Integer variables |lh|, |k|, and |lk_offset| will be defined when we use
24221 this code.
24222
24223 @<Output the subfile sizes and header bytes@>=
24224 k=mp->header_last;
24225 LH=(k+3) / 4; /* this is the number of header words */
24226 if ( mp->bc>mp->ec ) mp->bc=1; /* if there are no characters, |ec=0| and |bc=1| */
24227 @<Compute the ligature/kern program offset and implant the
24228   left boundary label@>;
24229 mp_tfm_two(mp,6+LH+(mp->ec-mp->bc+1)+mp->nw+mp->nh+mp->nd+mp->ni+mp->nl
24230      +lk_offset+mp->nk+mp->ne+mp->np);
24231   /* this is the total number of file words that will be output */
24232 mp_tfm_two(mp, LH); mp_tfm_two(mp, mp->bc); mp_tfm_two(mp, mp->ec); 
24233 mp_tfm_two(mp, mp->nw); mp_tfm_two(mp, mp->nh);
24234 mp_tfm_two(mp, mp->nd); mp_tfm_two(mp, mp->ni); mp_tfm_two(mp, mp->nl+lk_offset); 
24235 mp_tfm_two(mp, mp->nk); mp_tfm_two(mp, mp->ne);
24236 mp_tfm_two(mp, mp->np);
24237 for (k=0;k< 4*LH;k++)   { 
24238   tfm_out(mp->header_byte[k]);
24239 }
24240
24241 @ @<Output the character information bytes...@>=
24242 for (k=mp->bc;k<=mp->ec;k++) {
24243   if ( ! mp->char_exists[k] ) {
24244     mp_tfm_four(mp, 0);
24245   } else { 
24246     tfm_out(info(mp->tfm_width[k])); /* the width index */
24247     tfm_out((info(mp->tfm_height[k]))*16+info(mp->tfm_depth[k]));
24248     tfm_out((info(mp->tfm_ital_corr[k]))*4+mp->char_tag[k]);
24249     tfm_out(mp->char_remainder[k]);
24250   };
24251 }
24252 mp->tfm_changed=0;
24253 for (k=1;k<=4;k++) { 
24254   mp_tfm_four(mp, 0); p=mp->dimen_head[k];
24255   while ( p!=inf_val ) {
24256     mp_tfm_four(mp, mp_dimen_out(mp, value(p))); p=link(p);
24257   }
24258 }
24259
24260
24261 @ We need to output special instructions at the beginning of the
24262 |lig_kern| array in order to specify the right boundary character
24263 and/or to handle starting addresses that exceed 255. The |label_loc|
24264 and |label_char| arrays have been set up to record all the
24265 starting addresses; we have $-1=|label_loc|[0]<|label_loc|[1]\le\cdots
24266 \le|label_loc|[|label_ptr]|$.
24267
24268 @<Compute the ligature/kern program offset...@>=
24269 mp->bchar=mp_round_unscaled(mp, mp->internal[mp_boundary_char]);
24270 if ((mp->bchar<0)||(mp->bchar>255))
24271   { mp->bchar=-1; mp->lk_started=false; lk_offset=0; }
24272 else { mp->lk_started=true; lk_offset=1; };
24273 @<Find the minimum |lk_offset| and adjust all remainders@>;
24274 if ( mp->bch_label<undefined_label )
24275   { skip_byte(mp->nl)=qi(255); next_char(mp->nl)=qi(0);
24276   op_byte(mp->nl)=qi(((mp->bch_label+lk_offset)/ 256));
24277   rem_byte(mp->nl)=qi(((mp->bch_label+lk_offset)% 256));
24278   incr(mp->nl); /* possibly |nl=lig_table_size+1| */
24279   }
24280
24281 @ @<Find the minimum |lk_offset|...@>=
24282 k=mp->label_ptr; /* pointer to the largest unallocated label */
24283 if ( mp->label_loc[k]+lk_offset>255 ) {
24284   lk_offset=0; mp->lk_started=false; /* location 0 can do double duty */
24285   do {  
24286     mp->char_remainder[mp->label_char[k]]=lk_offset;
24287     while ( mp->label_loc[k-1]==mp->label_loc[k] ) {
24288        decr(k); mp->char_remainder[mp->label_char[k]]=lk_offset;
24289     }
24290     incr(lk_offset); decr(k);
24291   } while (! (lk_offset+mp->label_loc[k]<256));
24292     /* N.B.: |lk_offset=256| satisfies this when |k=0| */
24293 };
24294 if ( lk_offset>0 ) {
24295   while ( k>0 ) {
24296     mp->char_remainder[mp->label_char[k]]
24297      =mp->char_remainder[mp->label_char[k]]+lk_offset;
24298     decr(k);
24299   }
24300 }
24301
24302 @ @<Output the ligature/kern program@>=
24303 for (k=0;k<= 255;k++ ) {
24304   if ( mp->skip_table[k]<undefined_label ) {
24305      mp_print_nl(mp, "(local label "); mp_print_int(mp, k); mp_print(mp, ":: was missing)");
24306 @.local label l:: was missing@>
24307     cancel_skips(mp->skip_table[k]);
24308   }
24309 }
24310 if ( mp->lk_started ) { /* |lk_offset=1| for the special |bchar| */
24311   tfm_out(255); tfm_out(mp->bchar); mp_tfm_two(mp, 0);
24312 } else {
24313   for (k=1;k<=lk_offset;k++) {/* output the redirection specs */
24314     mp->ll=mp->label_loc[mp->label_ptr];
24315     if ( mp->bchar<0 ) { tfm_out(254); tfm_out(0);   }
24316     else { tfm_out(255); tfm_out(mp->bchar);   };
24317     mp_tfm_two(mp, mp->ll+lk_offset);
24318     do {  
24319       decr(mp->label_ptr);
24320     } while (! (mp->label_loc[mp->label_ptr]<mp->ll));
24321   }
24322 }
24323 for (k=0;k<=mp->nl-1;k++) mp_tfm_qqqq(mp, mp->lig_kern[k]);
24324 for (k=0;k<=mp->nk-1;k++) mp_tfm_four(mp, mp_dimen_out(mp, mp->kern[k]))
24325
24326 @ @<Output the extensible character recipes...@>=
24327 for (k=0;k<=mp->ne-1;k++) 
24328   mp_tfm_qqqq(mp, mp->exten[k]);
24329 for (k=1;k<=mp->np;k++) {
24330   if ( k==1 ) {
24331     if ( abs(mp->param[1])<fraction_half ) {
24332       mp_tfm_four(mp, mp->param[1]*16);
24333     } else  { 
24334       incr(mp->tfm_changed);
24335       if ( mp->param[1]>0 ) mp_tfm_four(mp, el_gordo);
24336       else mp_tfm_four(mp, -el_gordo);
24337     }
24338   } else {
24339     mp_tfm_four(mp, mp_dimen_out(mp, mp->param[k]));
24340   }
24341 }
24342 if ( mp->tfm_changed>0 )  { 
24343   if ( mp->tfm_changed==1 ) mp_print_nl(mp, "(a font metric dimension");
24344 @.a font metric dimension...@>
24345   else  { 
24346     mp_print_nl(mp, "("); mp_print_int(mp, mp->tfm_changed);
24347 @.font metric dimensions...@>
24348     mp_print(mp, " font metric dimensions");
24349   }
24350   mp_print(mp, " had to be decreased)");
24351 }
24352
24353 @ @<Log the subfile sizes of the \.{TFM} file@>=
24354
24355   char s[200];
24356   wlog_ln(" ");
24357   if ( mp->bch_label<undefined_label ) decr(mp->nl);
24358   snprintf(s,128,"(You used %iw,%ih,%id,%ii,%il,%ik,%ie,%ip metric file positions)",
24359                  mp->nw, mp->nh, mp->nd, mp->ni, mp->nl, mp->nk, mp->ne,mp->np);
24360   wlog_ln(s);
24361 }
24362
24363 @* \[43] Reading font metric data.
24364
24365 \MP\ isn't a typesetting program but it does need to find the bounding box
24366 of a sequence of typeset characters.  Thus it needs to read \.{TFM} files as
24367 well as write them.
24368
24369 @<Glob...@>=
24370 void * tfm_infile;
24371
24372 @ All the width, height, and depth information is stored in an array called
24373 |font_info|.  This array is allocated sequentially and each font is stored
24374 as a series of |char_info| words followed by the width, height, and depth
24375 tables.  Since |font_name| entries are permanent, their |str_ref| values are
24376 set to |max_str_ref|.
24377
24378 @<Types...@>=
24379 typedef unsigned int font_number; /* |0..font_max| */
24380
24381 @ The |font_info| array is indexed via a group directory arrays.
24382 For example, the |char_info| data for character~|c| in font~|f| will be
24383 in |font_info[char_base[f]+c].qqqq|.
24384
24385 @<Glob...@>=
24386 font_number font_max; /* maximum font number for included text fonts */
24387 size_t      font_mem_size; /* number of words for \.{TFM} information for text fonts */
24388 memory_word *font_info; /* height, width, and depth data */
24389 char        **font_enc_name; /* encoding names, if any */
24390 boolean     *font_ps_name_fixed; /* are the postscript names fixed already?  */
24391 int         next_fmem; /* next unused entry in |font_info| */
24392 font_number last_fnum; /* last font number used so far */
24393 scaled      *font_dsize;  /* 16 times the ``design'' size in \ps\ points */
24394 char        **font_name;  /* name as specified in the \&{infont} command */
24395 char        **font_ps_name;  /* PostScript name for use when |internal[mp_prologues]>0| */
24396 font_number last_ps_fnum; /* last valid |font_ps_name| index */
24397 eight_bits  *font_bc;
24398 eight_bits  *font_ec;  /* first and last character code */
24399 int         *char_base;  /* base address for |char_info| */
24400 int         *width_base; /* index for zeroth character width */
24401 int         *height_base; /* index for zeroth character height */
24402 int         *depth_base; /* index for zeroth character depth */
24403 pointer     *font_sizes;
24404
24405 @ @<Allocate or initialize ...@>=
24406 mp->font_mem_size = 10000; 
24407 mp->font_info = xmalloc ((mp->font_mem_size+1),sizeof(memory_word));
24408 memset (mp->font_info,0,sizeof(memory_word)*(mp->font_mem_size+1));
24409 mp->font_enc_name = NULL;
24410 mp->font_ps_name_fixed = NULL;
24411 mp->font_dsize = NULL;
24412 mp->font_name = NULL;
24413 mp->font_ps_name = NULL;
24414 mp->font_bc = NULL;
24415 mp->font_ec = NULL;
24416 mp->last_fnum = null_font;
24417 mp->char_base = NULL;
24418 mp->width_base = NULL;
24419 mp->height_base = NULL;
24420 mp->depth_base = NULL;
24421 mp->font_sizes = null;
24422
24423 @ @<Dealloc variables@>=
24424 for (k=1;k<=(int)mp->last_fnum;k++) {
24425   xfree(mp->font_enc_name[k]);
24426   xfree(mp->font_name[k]);
24427   xfree(mp->font_ps_name[k]);
24428 }
24429 xfree(mp->font_info);
24430 xfree(mp->font_enc_name);
24431 xfree(mp->font_ps_name_fixed);
24432 xfree(mp->font_dsize);
24433 xfree(mp->font_name);
24434 xfree(mp->font_ps_name);
24435 xfree(mp->font_bc);
24436 xfree(mp->font_ec);
24437 xfree(mp->char_base);
24438 xfree(mp->width_base);
24439 xfree(mp->height_base);
24440 xfree(mp->depth_base);
24441 xfree(mp->font_sizes);
24442
24443
24444 @c 
24445 void mp_reallocate_fonts (MP mp, font_number l) {
24446   font_number f;
24447   XREALLOC(mp->font_enc_name,      l, char *);
24448   XREALLOC(mp->font_ps_name_fixed, l, boolean);
24449   XREALLOC(mp->font_dsize,         l, scaled);
24450   XREALLOC(mp->font_name,          l, char *);
24451   XREALLOC(mp->font_ps_name,       l, char *);
24452   XREALLOC(mp->font_bc,            l, eight_bits);
24453   XREALLOC(mp->font_ec,            l, eight_bits);
24454   XREALLOC(mp->char_base,          l, int);
24455   XREALLOC(mp->width_base,         l, int);
24456   XREALLOC(mp->height_base,        l, int);
24457   XREALLOC(mp->depth_base,         l, int);
24458   XREALLOC(mp->font_sizes,         l, pointer);
24459   for (f=(mp->last_fnum+1);f<=l;f++) {
24460     mp->font_enc_name[f]=NULL;
24461     mp->font_ps_name_fixed[f] = false;
24462     mp->font_name[f]=NULL;
24463     mp->font_ps_name[f]=NULL;
24464     mp->font_sizes[f]=null;
24465   }
24466   mp->font_max = l;
24467 }
24468
24469 @ @<Declare |mp_reallocate| functions@>=
24470 void mp_reallocate_fonts (MP mp, font_number l);
24471
24472
24473 @ A |null_font| containing no characters is useful for error recovery.  Its
24474 |font_name| entry starts out empty but is reset each time an erroneous font is
24475 found.  This helps to cut down on the number of duplicate error messages without
24476 wasting a lot of space.
24477
24478 @d null_font 0 /* the |font_number| for an empty font */
24479
24480 @<Set initial...@>=
24481 mp->font_dsize[null_font]=0;
24482 mp->font_bc[null_font]=1;
24483 mp->font_ec[null_font]=0;
24484 mp->char_base[null_font]=0;
24485 mp->width_base[null_font]=0;
24486 mp->height_base[null_font]=0;
24487 mp->depth_base[null_font]=0;
24488 mp->next_fmem=0;
24489 mp->last_fnum=null_font;
24490 mp->last_ps_fnum=null_font;
24491 mp->font_name[null_font]="nullfont";
24492 mp->font_ps_name[null_font]="";
24493 mp->font_ps_name_fixed[null_font] = false;
24494 mp->font_enc_name[null_font]=NULL;
24495 mp->font_sizes[null_font]=null;
24496
24497 @ Each |char_info| word is of type |four_quarters|.  The |b0| field contains
24498 the |width index|; the |b1| field contains the height
24499 index; the |b2| fields contains the depth index, and the |b3| field used only
24500 for temporary storage. (It is used to keep track of which characters occur in
24501 an edge structure that is being shipped out.)
24502 The corresponding words in the width, height, and depth tables are stored as
24503 |scaled| values in units of \ps\ points.
24504
24505 With the macros below, the |char_info| word for character~|c| in font~|f| is
24506 |char_info(f)(c)| and the width is
24507 $$\hbox{|char_width(f)(char_info(f)(c)).sc|.}$$
24508
24509 @d char_info_end(A) (A)].qqqq
24510 @d char_info(A) mp->font_info[mp->char_base[(A)]+char_info_end
24511 @d char_width_end(A) (A).b0].sc
24512 @d char_width(A) mp->font_info[mp->width_base[(A)]+char_width_end
24513 @d char_height_end(A) (A).b1].sc
24514 @d char_height(A) mp->font_info[mp->height_base[(A)]+char_height_end
24515 @d char_depth_end(A) (A).b2].sc
24516 @d char_depth(A) mp->font_info[mp->depth_base[(A)]+char_depth_end
24517 @d ichar_exists(A) ((A).b0>0)
24518
24519 @ The |font_ps_name| for a built-in font should be what PostScript expects.
24520 A preliminary name is obtained here from the \.{TFM} name as given in the
24521 |fname| argument.  This gets updated later from an external table if necessary.
24522
24523 @<Declare text measuring subroutines@>=
24524 @<Declare subroutines for parsing file names@>;
24525 font_number mp_read_font_info (MP mp, char *fname) {
24526   boolean file_opened; /* has |tfm_infile| been opened? */
24527   font_number n; /* the number to return */
24528   halfword lf,tfm_lh,bc,ec,nw,nh,nd; /* subfile size parameters */
24529   size_t whd_size; /* words needed for heights, widths, and depths */
24530   int i,ii; /* |font_info| indices */
24531   int jj; /* counts bytes to be ignored */
24532   scaled z; /* used to compute the design size */
24533   fraction d;
24534   /* height, width, or depth as a fraction of design size times $2^{-8}$ */
24535   eight_bits h_and_d; /* height and depth indices being unpacked */
24536   unsigned char tfbyte; /* a byte read from the file */
24537   n=null_font;
24538   @<Open |tfm_infile| for input@>;
24539   @<Read data from |tfm_infile|; if there is no room, say so and |goto done|;
24540     otherwise |goto bad_tfm| or |goto done| as appropriate@>;
24541 BAD_TFM:
24542   @<Complain that the \.{TFM} file is bad@>;
24543 DONE:
24544   if ( file_opened ) (mp->close_file)(mp,mp->tfm_infile);
24545   if ( n!=null_font ) { 
24546     mp->font_ps_name[n]=mp_xstrdup(mp,fname);
24547     mp->font_name[n]=mp_xstrdup(mp,fname);
24548   }
24549   return n;
24550 }
24551
24552 @ \MP\ doesn't bother to check the entire \.{TFM} file for errors or explain
24553 precisely what is wrong if it does find a problem.  Programs called \.{TFtoPL}
24554 @.TFtoPL@> @.PLtoTF@>
24555 and \.{PLtoTF} can be used to debug \.{TFM} files.
24556
24557 @<Complain that the \.{TFM} file is bad@>=
24558 print_err("Font ");
24559 mp_print(mp, fname);
24560 if ( file_opened ) mp_print(mp, " not usable: TFM file is bad");
24561 else mp_print(mp, " not usable: TFM file not found");
24562 help3("I wasn't able to read the size data for this font so this")
24563   ("`infont' operation won't produce anything. If the font name")
24564   ("is right, you might ask an expert to make a TFM file");
24565 if ( file_opened )
24566   mp->help_line[0]="is right, try asking an expert to fix the TFM file";
24567 mp_error(mp)
24568
24569 @ @<Read data from |tfm_infile|; if there is no room, say so...@>=
24570 @<Read the \.{TFM} size fields@>;
24571 @<Use the size fields to allocate space in |font_info|@>;
24572 @<Read the \.{TFM} header@>;
24573 @<Read the character data and the width, height, and depth tables and
24574   |goto done|@>
24575
24576 @ A bad \.{TFM} file can be shorter than it claims to be.  The code given here
24577 might try to read past the end of the file if this happens.  Changes will be
24578 needed if it causes a system error to refer to |tfm_infile^| or call
24579 |get_tfm_infile| when |eof(tfm_infile)| is true.  For example, the definition
24580 @^system dependencies@>
24581 of |tfget| could be changed to
24582 ``|begin get(tfm_infile); if eof(tfm_infile) then goto bad_tfm; end|.''
24583
24584 @d tfget do { 
24585   size_t wanted=1; 
24586   void *tfbyte_ptr = &tfbyte;
24587   (mp->read_binary_file)(mp,mp->tfm_infile,&tfbyte_ptr,&wanted); 
24588   if (wanted==0) goto BAD_TFM; 
24589 } while (0)
24590 @d read_two(A) { (A)=tfbyte;
24591   if ( (A)>127 ) goto BAD_TFM;
24592   tfget; (A)=(A)*0400+tfbyte;
24593 }
24594 @d tf_ignore(A) { for (jj=(A);jj>=1;jj--) tfget; }
24595
24596 @<Read the \.{TFM} size fields@>=
24597 tfget; read_two(lf);
24598 tfget; read_two(tfm_lh);
24599 tfget; read_two(bc);
24600 tfget; read_two(ec);
24601 if ( (bc>1+ec)||(ec>255) ) goto BAD_TFM;
24602 tfget; read_two(nw);
24603 tfget; read_two(nh);
24604 tfget; read_two(nd);
24605 whd_size=(ec+1-bc)+nw+nh+nd;
24606 if ( lf<(int)(6+tfm_lh+whd_size) ) goto BAD_TFM;
24607 tf_ignore(10)
24608
24609 @ Offsets are added to |char_base[n]| and |width_base[n]| so that is not
24610 necessary to apply the |so|  and |qo| macros when looking up the width of a
24611 character in the string pool.  In order to ensure nonnegative |char_base|
24612 values when |bc>0|, it may be necessary to reserve a few unused |font_info|
24613 elements.
24614
24615 @<Use the size fields to allocate space in |font_info|@>=
24616 if ( mp->next_fmem<bc) mp->next_fmem=bc;  /* ensure nonnegative |char_base| */
24617 if (mp->last_fnum==mp->font_max)
24618   mp_reallocate_fonts(mp,(mp->font_max+(mp->font_max>>2)));
24619 while (mp->next_fmem+whd_size>=mp->font_mem_size) {
24620   size_t l = mp->font_mem_size+(mp->font_mem_size>>2);
24621   memory_word *font_info;
24622   font_info = xmalloc ((l+1),sizeof(memory_word));
24623   memset (font_info,0,sizeof(memory_word)*(l+1));
24624   memcpy (font_info,mp->font_info,sizeof(memory_word)*(mp->font_mem_size+1));
24625   xfree(mp->font_info);
24626   mp->font_info = font_info;
24627   mp->font_mem_size = l;
24628 }
24629 incr(mp->last_fnum);
24630 n=mp->last_fnum;
24631 mp->font_bc[n]=bc;
24632 mp->font_ec[n]=ec;
24633 mp->char_base[n]=mp->next_fmem-bc;
24634 mp->width_base[n]=mp->next_fmem+ec-bc+1;
24635 mp->height_base[n]=mp->width_base[n]+nw;
24636 mp->depth_base[n]=mp->height_base[n]+nh;
24637 mp->next_fmem=mp->next_fmem+whd_size;
24638
24639
24640 @ @<Read the \.{TFM} header@>=
24641 if ( tfm_lh<2 ) goto BAD_TFM;
24642 tf_ignore(4);
24643 tfget; read_two(z);
24644 tfget; z=z*0400+tfbyte;
24645 tfget; z=z*0400+tfbyte; /* now |z| is 16 times the design size */
24646 mp->font_dsize[n]=mp_take_fraction(mp, z,267432584);
24647   /* times ${72\over72.27}2^{28}$ to convert from \TeX\ points */
24648 tf_ignore(4*(tfm_lh-2))
24649
24650 @ @<Read the character data and the width, height, and depth tables...@>=
24651 ii=mp->width_base[n];
24652 i=mp->char_base[n]+bc;
24653 while ( i<ii ) { 
24654   tfget; mp->font_info[i].qqqq.b0=qi(tfbyte);
24655   tfget; h_and_d=tfbyte;
24656   mp->font_info[i].qqqq.b1=h_and_d / 16;
24657   mp->font_info[i].qqqq.b2=h_and_d % 16;
24658   tfget; tfget;
24659   incr(i);
24660 }
24661 while ( i<mp->next_fmem ) {
24662   @<Read a four byte dimension, scale it by the design size, store it in
24663     |font_info[i]|, and increment |i|@>;
24664 }
24665 goto DONE
24666
24667 @ The raw dimension read into |d| should have magnitude at most $2^{24}$ when
24668 interpreted as an integer, and this includes a scale factor of $2^{20}$.  Thus
24669 we can multiply it by sixteen and think of it as a |fraction| that has been
24670 divided by sixteen.  This cancels the extra scale factor contained in
24671 |font_dsize[n|.
24672
24673 @<Read a four byte dimension, scale it by the design size, store it in...@>=
24674
24675 tfget; d=tfbyte;
24676 if ( d>=0200 ) d=d-0400;
24677 tfget; d=d*0400+tfbyte;
24678 tfget; d=d*0400+tfbyte;
24679 tfget; d=d*0400+tfbyte;
24680 mp->font_info[i].sc=mp_take_fraction(mp, d*16,mp->font_dsize[n]);
24681 incr(i);
24682 }
24683
24684 @ This function does no longer use the file name parser, because |fname| is
24685 a C string already.
24686 @<Open |tfm_infile| for input@>=
24687 file_opened=false;
24688 mp_ptr_scan_file(mp, fname);
24689 if ( strlen(mp->cur_area)==0 ) { xfree(mp->cur_area); }
24690 if ( strlen(mp->cur_ext)==0 )  { xfree(mp->cur_ext); mp->cur_ext=xstrdup(".tfm"); }
24691 pack_cur_name;
24692 mp->tfm_infile = (mp->open_file)(mp, mp->name_of_file, "rb",mp_filetype_metrics);
24693 if ( !mp->tfm_infile  ) goto BAD_TFM;
24694 file_opened=true
24695
24696 @ When we have a font name and we don't know whether it has been loaded yet,
24697 we scan the |font_name| array before calling |read_font_info|.
24698
24699 @<Declare text measuring subroutines@>=
24700 font_number mp_find_font (MP mp, char *f) {
24701   font_number n;
24702   for (n=0;n<=mp->last_fnum;n++) {
24703     if (mp_xstrcmp(f,mp->font_name[n])==0 ) {
24704       mp_xfree(f);
24705       return n;
24706     }
24707   }
24708   n = mp_read_font_info(mp, f);
24709   mp_xfree(f);
24710   return n;
24711 }
24712
24713 @ One simple application of |find_font| is the implementation of the |font_size|
24714 operator that gets the design size for a given font name.
24715
24716 @<Find the design size of the font whose name is |cur_exp|@>=
24717 mp_flush_cur_exp(mp, (mp->font_dsize[mp_find_font(mp, str(mp->cur_exp))]+8) / 16)
24718
24719 @ If we discover that the font doesn't have a requested character, we omit it
24720 from the bounding box computation and expect the \ps\ interpreter to drop it.
24721 This routine issues a warning message if the user has asked for it.
24722
24723 @<Declare text measuring subroutines@>=
24724 void mp_lost_warning (MP mp,font_number f, pool_pointer k) { 
24725   if ( mp->internal[mp_tracing_lost_chars]>0 ) { 
24726     mp_begin_diagnostic(mp);
24727     if ( mp->selector==log_only ) incr(mp->selector);
24728     mp_print_nl(mp, "Missing character: There is no ");
24729 @.Missing character@>
24730     mp_print_str(mp, mp->str_pool[k]); 
24731     mp_print(mp, " in font ");
24732     mp_print(mp, mp->font_name[f]); mp_print_char(mp, '!'); 
24733     mp_end_diagnostic(mp, false);
24734   }
24735 }
24736
24737 @ The whole purpose of saving the height, width, and depth information is to be
24738 able to find the bounding box of an item of text in an edge structure.  The
24739 |set_text_box| procedure takes a text node and adds this information.
24740
24741 @<Declare text measuring subroutines@>=
24742 void mp_set_text_box (MP mp,pointer p) {
24743   font_number f; /* |font_n(p)| */
24744   ASCII_code bc,ec; /* range of valid characters for font |f| */
24745   pool_pointer k,kk; /* current character and character to stop at */
24746   four_quarters cc; /* the |char_info| for the current character */
24747   scaled h,d; /* dimensions of the current character */
24748   width_val(p)=0;
24749   height_val(p)=-el_gordo;
24750   depth_val(p)=-el_gordo;
24751   f=font_n(p);
24752   bc=mp->font_bc[f];
24753   ec=mp->font_ec[f];
24754   kk=str_stop(text_p(p));
24755   k=mp->str_start[text_p(p)];
24756   while ( k<kk ) {
24757     @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>;
24758   }
24759   @<Set the height and depth to zero if the bounding box is empty@>;
24760 }
24761
24762 @ @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>=
24763
24764   if ( (mp->str_pool[k]<bc)||(mp->str_pool[k]>ec) ) {
24765     mp_lost_warning(mp, f,k);
24766   } else { 
24767     cc=char_info(f)(mp->str_pool[k]);
24768     if ( ! ichar_exists(cc) ) {
24769       mp_lost_warning(mp, f,k);
24770     } else { 
24771       width_val(p)=width_val(p)+char_width(f)(cc);
24772       h=char_height(f)(cc);
24773       d=char_depth(f)(cc);
24774       if ( h>height_val(p) ) height_val(p)=h;
24775       if ( d>depth_val(p) ) depth_val(p)=d;
24776     }
24777   }
24778   incr(k);
24779 }
24780
24781 @ Let's hope modern compilers do comparisons correctly when the difference would
24782 overflow.
24783
24784 @<Set the height and depth to zero if the bounding box is empty@>=
24785 if ( height_val(p)<-depth_val(p) ) { 
24786   height_val(p)=0;
24787   depth_val(p)=0;
24788 }
24789
24790 @ The new primitives fontmapfile and fontmapline.
24791
24792 @<Declare action procedures for use by |do_statement|@>=
24793 void mp_do_mapfile (MP mp) ;
24794 void mp_do_mapline (MP mp) ;
24795
24796 @ @c void mp_do_mapfile (MP mp) { 
24797   mp_get_x_next(mp); mp_scan_expression(mp);
24798   if ( mp->cur_type!=mp_string_type ) {
24799     @<Complain about improper map operation@>;
24800   } else {
24801     mp_map_file(mp,mp->cur_exp);
24802   }
24803 }
24804 void mp_do_mapline (MP mp) { 
24805   mp_get_x_next(mp); mp_scan_expression(mp);
24806   if ( mp->cur_type!=mp_string_type ) {
24807      @<Complain about improper map operation@>;
24808   } else { 
24809      mp_map_line(mp,mp->cur_exp);
24810   }
24811 }
24812
24813 @ @<Complain about improper map operation@>=
24814
24815   exp_err("Unsuitable expression");
24816   help1("Only known strings can be map files or map lines.");
24817   mp_put_get_error(mp);
24818 }
24819
24820 @ To print |scaled| value to PDF output we need some subroutines to ensure
24821 accurary.
24822
24823 @d max_integer   0x7FFFFFFF /* $2^{31}-1$ */
24824
24825 @<Glob...@>=
24826 scaled one_bp; /* scaled value corresponds to 1bp */
24827 scaled one_hundred_bp; /* scaled value corresponds to 100bp */
24828 scaled one_hundred_inch; /* scaled value corresponds to 100in */
24829 integer ten_pow[10]; /* $10^0..10^9$ */
24830 integer scaled_out; /* amount of |scaled| that was taken out in |divide_scaled| */
24831
24832 @ @<Set init...@>=
24833 mp->one_bp = 65782; /* 65781.76 */
24834 mp->one_hundred_bp = 6578176;
24835 mp->one_hundred_inch = 473628672;
24836 mp->ten_pow[0] = 1;
24837 for (i = 1;i<= 9; i++ ) {
24838   mp->ten_pow[i] = 10*mp->ten_pow[i - 1];
24839 }
24840
24841 @ The following function divides |s| by |m|. |dd| is number of decimal digits.
24842
24843 @c scaled mp_divide_scaled (MP mp,scaled s, scaled m, integer  dd) {
24844   scaled q,r;
24845   integer sign,i;
24846   sign = 1;
24847   if ( s < 0 ) { sign = -sign; s = -s; }
24848   if ( m < 0 ) { sign = -sign; m = -m; }
24849   if ( m == 0 )
24850     mp_confusion(mp, "arithmetic: divided by zero");
24851   else if ( m >= (max_integer / 10) )
24852     mp_confusion(mp, "arithmetic: number too big");
24853   q = s / m;
24854   r = s % m;
24855   for (i = 1;i<=dd;i++) {
24856     q = 10*q + (10*r) / m;
24857     r = (10*r) % m;
24858   }
24859   if ( 2*r >= m ) { incr(q); r = r - m; }
24860   mp->scaled_out = sign*(s - (r / mp->ten_pow[dd]));
24861   return (sign*q);
24862 }
24863
24864 @* \[44] Shipping pictures out.
24865 The |ship_out| procedure, to be described below, is given a pointer to
24866 an edge structure. Its mission is to output a file containing the \ps\
24867 description of an edge structure.
24868
24869 @ Each time an edge structure is shipped out we write a new \ps\ output
24870 file named according to the current \&{charcode}.
24871 @:char_code_}{\&{charcode} primitive@>
24872
24873 This is the only backend function that remains in the main |mpost.w| file. 
24874 There are just too many variable accesses needed for status reporting 
24875 etcetera to make it worthwile to move the code to |psout.w|.
24876
24877 @<Internal library declarations@>=
24878 void mp_open_output_file (MP mp) ;
24879
24880 @ @c 
24881 char *mp_set_output_file_name (MP mp, integer c) {
24882   char *ss = NULL; /* filename extension proposal */  
24883   int old_setting; /* previous |selector| setting */
24884   pool_pointer i; /*  indexes into |filename_template|  */
24885   integer cc; /* a temporary integer for template building  */
24886   integer f,g=0; /* field widths */
24887   if ( mp->job_name==NULL ) mp_open_log_file(mp);
24888   if ( mp->filename_template==0 ) {
24889     char *s; /* a file extension derived from |c| */
24890     if ( c<0 ) 
24891       s=xstrdup(".ps");
24892     else 
24893       @<Use |c| to compute the file extension |s|@>;
24894     mp_pack_job_name(mp, s);
24895     ss = s ;
24896   } else { /* initializations */
24897     str_number s, n; /* a file extension derived from |c| */
24898     old_setting=mp->selector; 
24899     mp->selector=new_string;
24900     f = 0;
24901     i = mp->str_start[mp->filename_template];
24902     n = rts(""); /* initialize */
24903     while ( i<str_stop(mp->filename_template) ) {
24904        if ( mp->str_pool[i]=='%' ) {
24905       CONTINUE:
24906         incr(i);
24907         if ( i<str_stop(mp->filename_template) ) {
24908           if ( mp->str_pool[i]=='j' ) {
24909             mp_print(mp, mp->job_name);
24910           } else if ( mp->str_pool[i]=='d' ) {
24911              cc= mp_round_unscaled(mp, mp->internal[mp_day]);
24912              print_with_leading_zeroes(cc);
24913           } else if ( mp->str_pool[i]=='m' ) {
24914              cc= mp_round_unscaled(mp, mp->internal[mp_month]);
24915              print_with_leading_zeroes(cc);
24916           } else if ( mp->str_pool[i]=='y' ) {
24917              cc= mp_round_unscaled(mp, mp->internal[mp_year]);
24918              print_with_leading_zeroes(cc);
24919           } else if ( mp->str_pool[i]=='H' ) {
24920              cc= mp_round_unscaled(mp, mp->internal[mp_time]) / 60;
24921              print_with_leading_zeroes(cc);
24922           }  else if ( mp->str_pool[i]=='M' ) {
24923              cc= mp_round_unscaled(mp, mp->internal[mp_time]) % 60;
24924              print_with_leading_zeroes(cc);
24925           } else if ( mp->str_pool[i]=='c' ) {
24926             if ( c<0 ) mp_print(mp, "ps");
24927             else print_with_leading_zeroes(c);
24928           } else if ( (mp->str_pool[i]>='0') && 
24929                       (mp->str_pool[i]<='9') ) {
24930             if ( (f<10)  )
24931               f = (f*10) + mp->str_pool[i]-'0';
24932             goto CONTINUE;
24933           } else {
24934             mp_print_str(mp, mp->str_pool[i]);
24935           }
24936         }
24937       } else {
24938         if ( mp->str_pool[i]=='.' )
24939           if (length(n)==0)
24940             n = mp_make_string(mp);
24941         mp_print_str(mp, mp->str_pool[i]);
24942       };
24943       incr(i);
24944     };
24945     s = mp_make_string(mp);
24946     mp->selector= old_setting;
24947     if (length(n)==0) {
24948        n=s;
24949        s=rts("");
24950     };
24951     mp_pack_file_name(mp, str(n),"",str(s));
24952     delete_str_ref(n);
24953         ss = str(s);
24954     delete_str_ref(s);
24955   }
24956   return ss;
24957 }
24958
24959 char * mp_get_output_file_name (MP mp) {
24960   char *fname; /* return value */
24961   char *saved_name;  /* saved |name_of_file| */
24962   saved_name = mp_xstrdup(mp, mp->name_of_file);
24963   (void)mp_set_output_file_name(mp, mp_round_unscaled(mp, mp->internal[mp_char_code]));
24964   fname = mp_xstrdup(mp, mp->name_of_file);
24965   mp_pack_file_name(mp, saved_name,NULL,NULL);
24966   return fname;
24967 }
24968
24969 void mp_open_output_file (MP mp) {
24970   char *ss; /* filename extension proposal */
24971   integer c; /* \&{charcode} rounded to the nearest integer */
24972   c=mp_round_unscaled(mp, mp->internal[mp_char_code]);
24973   ss = mp_set_output_file_name(mp, c);
24974   while ( ! mp_a_open_out(mp, (void *)&mp->ps_file, mp_filetype_postscript) )
24975     mp_prompt_file_name(mp, "file name for output",ss);
24976   xfree(ss);
24977   @<Store the true output file name if appropriate@>;
24978 }
24979
24980 @ The file extension created here could be up to five characters long in
24981 extreme cases so it may have to be shortened on some systems.
24982 @^system dependencies@>
24983
24984 @<Use |c| to compute the file extension |s|@>=
24985
24986   s = xmalloc(7,1);
24987   snprintf(s,7,".%i",(int)c);
24988 }
24989
24990 @ The user won't want to see all the output file names so we only save the
24991 first and last ones and a count of how many there were.  For this purpose
24992 files are ordered primarily by \&{charcode} and secondarily by order of
24993 creation.
24994 @:char_code_}{\&{charcode} primitive@>
24995
24996 @<Store the true output file name if appropriate@>=
24997 if ((c<mp->first_output_code)&&(mp->first_output_code>=0)) {
24998   mp->first_output_code=c;
24999   xfree(mp->first_file_name);
25000   mp->first_file_name=xstrdup(mp->name_of_file);
25001 }
25002 if ( c>=mp->last_output_code ) {
25003   mp->last_output_code=c;
25004   xfree(mp->last_file_name);
25005   mp->last_file_name=xstrdup(mp->name_of_file);
25006 }
25007
25008 @ @<Glob...@>=
25009 char * first_file_name;
25010 char * last_file_name; /* full file names */
25011 integer first_output_code;integer last_output_code; /* rounded \&{charcode} values */
25012 @:char_code_}{\&{charcode} primitive@>
25013 integer total_shipped; /* total number of |ship_out| operations completed */
25014
25015 @ @<Set init...@>=
25016 mp->first_file_name=xstrdup("");
25017 mp->last_file_name=xstrdup("");
25018 mp->first_output_code=32768;
25019 mp->last_output_code=-32768;
25020 mp->total_shipped=0;
25021
25022 @ @<Dealloc variables@>=
25023 xfree(mp->first_file_name);
25024 xfree(mp->last_file_name);
25025
25026 @ @<Begin the progress report for the output of picture~|c|@>=
25027 if ( (int)mp->term_offset>mp->max_print_line-6 ) mp_print_ln(mp);
25028 else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, ' ');
25029 mp_print_char(mp, '[');
25030 if ( c>=0 ) mp_print_int(mp, c)
25031
25032 @ @<End progress report@>=
25033 mp_print_char(mp, ']');
25034 update_terminal;
25035 incr(mp->total_shipped)
25036
25037 @ @<Explain what output files were written@>=
25038 if ( mp->total_shipped>0 ) { 
25039   mp_print_nl(mp, "");
25040   mp_print_int(mp, mp->total_shipped);
25041   mp_print(mp, " output file");
25042   if ( mp->total_shipped>1 ) mp_print_char(mp, 's');
25043   mp_print(mp, " written: ");
25044   mp_print(mp, mp->first_file_name);
25045   if ( mp->total_shipped>1 ) {
25046     if ( 31+strlen(mp->first_file_name)+
25047          strlen(mp->last_file_name)> (unsigned)mp->max_print_line) 
25048       mp_print_ln(mp);
25049     mp_print(mp, " .. ");
25050     mp_print(mp, mp->last_file_name);
25051   }
25052 }
25053
25054 @ @<Internal library declarations@>=
25055 boolean mp_has_font_size(MP mp, font_number f );
25056
25057 @ @c 
25058 boolean mp_has_font_size(MP mp, font_number f ) {
25059   return (mp->font_sizes[f]!=null);
25060 }
25061
25062 @ The \&{special} command saves up lines of text to be printed during the next
25063 |ship_out| operation.  The saved items are stored as a list of capsule tokens.
25064
25065 @<Glob...@>=
25066 pointer last_pending; /* the last token in a list of pending specials */
25067
25068 @ @<Set init...@>=
25069 mp->last_pending=spec_head;
25070
25071 @ @<Cases of |do_statement|...@>=
25072 case special_command: 
25073   if ( mp->cur_mod==0 ) mp_do_special(mp); else 
25074   if ( mp->cur_mod==1 ) mp_do_mapfile(mp); else 
25075   mp_do_mapline(mp);
25076   break;
25077
25078 @ @<Declare action procedures for use by |do_statement|@>=
25079 void mp_do_special (MP mp) ;
25080
25081 @ @c void mp_do_special (MP mp) { 
25082   mp_get_x_next(mp); mp_scan_expression(mp);
25083   if ( mp->cur_type!=mp_string_type ) {
25084     @<Complain about improper special operation@>;
25085   } else { 
25086     link(mp->last_pending)=mp_stash_cur_exp(mp);
25087     mp->last_pending=link(mp->last_pending);
25088     link(mp->last_pending)=null;
25089   }
25090 }
25091
25092 @ @<Complain about improper special operation@>=
25093
25094   exp_err("Unsuitable expression");
25095   help1("Only known strings are allowed for output as specials.");
25096   mp_put_get_error(mp);
25097 }
25098
25099 @ On the export side, we need an extra object type for special strings.
25100
25101 @<Graphical object codes@>=
25102 mp_special_code=8, 
25103
25104 @ @<Export pending specials@>=
25105 p=link(spec_head);
25106 while ( p!=null ) {
25107   hq = mp_new_graphic_object(mp,mp_special_code);
25108   gr_pre_script(hq)  = str(value(p));
25109   if (hh->body==NULL) hh->body=hq; else gr_link(hp) = hq;
25110   hp = hq;
25111   p=link(p);
25112 }
25113 mp_flush_token_list(mp, link(spec_head));
25114 link(spec_head)=null;
25115 mp->last_pending=spec_head
25116
25117 @ We are now ready for the main output procedure.  Note that the |selector|
25118 setting is saved in a global variable so that |begin_diagnostic| can access it.
25119
25120 @<Declare the \ps\ output procedures@>=
25121 void mp_ship_out (MP mp, pointer h) ;
25122
25123 @ Once again, the |gr_XXXX| macros are defined in |mppsout.h|
25124
25125 @c
25126 struct mp_edge_object *mp_gr_export(MP mp, pointer h) {
25127   pointer p; /* the current graphical object */
25128   integer t; /* a temporary value */
25129   struct mp_edge_object *hh; /* the first graphical object */
25130   struct mp_graphic_object *hp; /* the current graphical object */
25131   struct mp_graphic_object *hq; /* something |hp| points to  */
25132   mp_set_bbox(mp, h, true);
25133   hh = mp_xmalloc(mp,1,sizeof(struct mp_edge_object));
25134   hh->body = NULL;
25135   hh->_next = NULL;
25136   hh->_parent = mp;
25137   hh->_minx = minx_val(h);
25138   hh->_miny = miny_val(h);
25139   hh->_maxx = maxx_val(h);
25140   hh->_maxy = maxy_val(h);
25141   hh->_filename = mp_get_output_file_name(mp);
25142   @<Export pending specials@>;
25143   p=link(dummy_loc(h));
25144   while ( p!=null ) { 
25145     hq = mp_new_graphic_object(mp,type(p));
25146     switch (type(p)) {
25147     case mp_fill_code:
25148       gr_pen_p(hq)        = mp_export_knot_list(mp,pen_p(p));
25149       if ((pen_p(p)==null) || pen_is_elliptical(pen_p(p)))  {
25150           gr_path_p(hq)       = mp_export_knot_list(mp,path_p(p));
25151       } else {
25152         pointer pc, pp;
25153         pc = mp_copy_path(mp, path_p(p));
25154         pp = mp_make_envelope(mp, pc, pen_p(p),ljoin_val(p),0,miterlim_val(p));
25155         gr_path_p(hq)       = mp_export_knot_list(mp,pp);
25156         mp_toss_knot_list(mp, pp);
25157         pc = mp_htap_ypoc(mp, path_p(p));
25158         pp = mp_make_envelope(mp, pc, pen_p(p),ljoin_val(p),0,miterlim_val(p));
25159         gr_htap_p(hq)       = mp_export_knot_list(mp,pp);
25160         mp_toss_knot_list(mp, pp);
25161       }
25162       @<Export object color@>;
25163       @<Export object scripts@>;
25164       gr_ljoin_val(hq)    = ljoin_val(p);
25165       gr_miterlim_val(hq) = miterlim_val(p);
25166       break;
25167     case mp_stroked_code:
25168       gr_pen_p(hq)        = mp_export_knot_list(mp,pen_p(p));
25169       if (pen_is_elliptical(pen_p(p)))  {
25170               gr_path_p(hq)       = mp_export_knot_list(mp,path_p(p));
25171       } else {
25172         pointer pc;
25173         pc=mp_copy_path(mp, path_p(p));
25174         t=lcap_val(p);
25175         if ( left_type(pc)!=mp_endpoint ) { 
25176           left_type(mp_insert_knot(mp, pc,x_coord(pc),y_coord(pc)))=mp_endpoint;
25177           right_type(pc)=mp_endpoint;
25178           pc=link(pc);
25179           t=1;
25180         }
25181         pc=mp_make_envelope(mp,pc,pen_p(p),ljoin_val(p),t,miterlim_val(p));
25182         gr_path_p(hq)       = mp_export_knot_list(mp,pc);
25183         mp_toss_knot_list(mp, pc);
25184       }
25185       @<Export object color@>;
25186       @<Export object scripts@>;
25187       gr_ljoin_val(hq)    = ljoin_val(p);
25188       gr_miterlim_val(hq) = miterlim_val(p);
25189       gr_lcap_val(hq)     = lcap_val(p);
25190       gr_dash_scale(hq)   = dash_scale(p);
25191       gr_dash_p(hq)       = mp_export_dashes(mp,dash_p(p));
25192       break;
25193     case mp_text_code:
25194       gr_text_p(hq)       = str(text_p(p));
25195       gr_font_n(hq)       = font_n(p);
25196       gr_font_name(hq)    = mp_xstrdup(mp,mp->font_name[font_n(p)]);
25197       gr_font_dsize(hq)   = mp->font_dsize[font_n(p)];
25198       @<Export object color@>;
25199       @<Export object scripts@>;
25200       gr_width_val(hq)    = width_val(p);
25201       gr_height_val(hq)   = height_val(p);
25202       gr_depth_val(hq)    = depth_val(p);
25203       gr_tx_val(hq)       = tx_val(p);
25204       gr_ty_val(hq)       = ty_val(p);
25205       gr_txx_val(hq)      = txx_val(p);
25206       gr_txy_val(hq)      = txy_val(p);
25207       gr_tyx_val(hq)      = tyx_val(p);
25208       gr_tyy_val(hq)      = tyy_val(p);
25209       break;
25210     case mp_start_clip_code: 
25211     case mp_start_bounds_code:
25212       gr_path_p(hq) = mp_export_knot_list(mp,path_p(p));
25213       break;
25214     case mp_stop_clip_code: 
25215     case mp_stop_bounds_code:
25216       /* nothing to do here */
25217       break;
25218     } 
25219     if (hh->body==NULL) hh->body=hq; else  gr_link(hp) = hq;
25220     hp = hq;
25221     p=link(p);
25222   }
25223   return hh;
25224 }
25225
25226 @ @<Exported function ...@>=
25227 struct mp_edge_object *mp_gr_export(MP mp, int h);
25228
25229 @ This function is now nearly trivial.
25230
25231 @c
25232 void mp_ship_out (MP mp, pointer h) { /* output edge structure |h| */
25233   integer c; /* \&{charcode} rounded to the nearest integer */
25234   c=mp_round_unscaled(mp, mp->internal[mp_char_code]);
25235   @<Begin the progress report for the output of picture~|c|@>;
25236   (mp->shipout_backend) (mp, h);
25237   @<End progress report@>;
25238   if ( mp->internal[mp_tracing_output]>0 ) 
25239    mp_print_edges(mp, h," (just shipped out)",true);
25240 }
25241
25242 @ @<Declarations@>=
25243 void mp_shipout_backend (MP mp, pointer h);
25244
25245 @ @c
25246 void mp_shipout_backend (MP mp, pointer h) {
25247   struct mp_edge_object *hh; /* the first graphical object */
25248   hh = mp_gr_export(mp,h);
25249   mp_gr_ship_out (hh,
25250                  (mp->internal[mp_prologues]>>16),
25251                  (mp->internal[mp_procset]>>16));
25252   mp_gr_toss_objects(hh);
25253 }
25254
25255 @ @<Exported types@>=
25256 typedef void (*mp_backend_writer)(MP, int);
25257
25258 @ @<Option variables@>=
25259 mp_backend_writer shipout_backend;
25260
25261 @ @<Allocate or initialize ...@>=
25262 set_callback_option(shipout_backend);
25263
25264
25265
25266 @ Once again, the |gr_XXXX| macros are defined in |mppsout.h|
25267
25268 @<Export object color@>=
25269 gr_color_model(hq)  = color_model(p);
25270 gr_cyan_val(hq)     = cyan_val(p);
25271 gr_magenta_val(hq)  = magenta_val(p);
25272 gr_yellow_val(hq)   = yellow_val(p);
25273 gr_black_val(hq)    = black_val(p);
25274 gr_red_val(hq)      = red_val(p);
25275 gr_green_val(hq)    = green_val(p);
25276 gr_blue_val(hq)     = blue_val(p);
25277 gr_grey_val(hq)     = grey_val(p)
25278
25279
25280 @ @<Export object scripts@>=
25281 if (pre_script(p)!=null)
25282   gr_pre_script(hq)   = str(pre_script(p));
25283 if (post_script(p)!=null)
25284   gr_post_script(hq)  = str(post_script(p));
25285
25286 @ Now that we've finished |ship_out|, let's look at the other commands
25287 by which a user can send things to the \.{GF} file.
25288
25289 @ @<Determine if a character has been shipped out@>=
25290
25291   mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256;
25292   if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
25293   boolean_reset(mp->char_exists[mp->cur_exp]);
25294   mp->cur_type=mp_boolean_type;
25295 }
25296
25297 @ @<Glob...@>=
25298 psout_data ps;
25299
25300 @ @<Allocate or initialize ...@>=
25301 mp_backend_initialize(mp);
25302
25303 @ @<Dealloc...@>=
25304 mp_backend_free(mp);
25305
25306
25307 @* \[45] Dumping and undumping the tables.
25308 After \.{INIMP} has seen a collection of macros, it
25309 can write all the necessary information on an auxiliary file so
25310 that production versions of \MP\ are able to initialize their
25311 memory at high speed. The present section of the program takes
25312 care of such output and input. We shall consider simultaneously
25313 the processes of storing and restoring,
25314 so that the inverse relation between them is clear.
25315 @.INIMP@>
25316
25317 The global variable |mem_ident| is a string that is printed right
25318 after the |banner| line when \MP\ is ready to start. For \.{INIMP} this
25319 string says simply `\.{(INIMP)}'; for other versions of \MP\ it says,
25320 for example, `\.{(mem=plain 90.4.14)}', showing the year,
25321 month, and day that the mem file was created. We have |mem_ident=0|
25322 before \MP's tables are loaded.
25323
25324 @<Glob...@>=
25325 char * mem_ident;
25326
25327 @ @<Set init...@>=
25328 mp->mem_ident=NULL;
25329
25330 @ @<Initialize table entries...@>=
25331 mp->mem_ident=xstrdup(" (INIMP)");
25332
25333 @ @<Declare act...@>=
25334 void mp_store_mem_file (MP mp) ;
25335
25336 @ @c void mp_store_mem_file (MP mp) {
25337   integer k;  /* all-purpose index */
25338   pointer p,q; /* all-purpose pointers */
25339   integer x; /* something to dump */
25340   four_quarters w; /* four ASCII codes */
25341   memory_word WW;
25342   @<Create the |mem_ident|, open the mem file,
25343     and inform the user that dumping has begun@>;
25344   @<Dump constants for consistency check@>;
25345   @<Dump the string pool@>;
25346   @<Dump the dynamic memory@>;
25347   @<Dump the table of equivalents and the hash table@>;
25348   @<Dump a few more things and the closing check word@>;
25349   @<Close the mem file@>;
25350 }
25351
25352 @ Corresponding to the procedure that dumps a mem file, we also have a function
25353 that reads~one~in. The function returns |false| if the dumped mem is
25354 incompatible with the present \MP\ table sizes, etc.
25355
25356 @d off_base 6666 /* go here if the mem file is unacceptable */
25357 @d too_small(A) { wake_up_terminal;
25358   wterm_ln("---! Must increase the "); wterm((A));
25359 @.Must increase the x@>
25360   goto OFF_BASE;
25361   }
25362
25363 @c 
25364 boolean mp_load_mem_file (MP mp) {
25365   integer k; /* all-purpose index */
25366   pointer p,q; /* all-purpose pointers */
25367   integer x; /* something undumped */
25368   str_number s; /* some temporary string */
25369   four_quarters w; /* four ASCII codes */
25370   memory_word WW;
25371   @<Undump constants for consistency check@>;
25372   @<Undump the string pool@>;
25373   @<Undump the dynamic memory@>;
25374   @<Undump the table of equivalents and the hash table@>;
25375   @<Undump a few more things and the closing check word@>;
25376   return true; /* it worked! */
25377 OFF_BASE: 
25378   wake_up_terminal;
25379   wterm_ln("(Fatal mem file error; I'm stymied)\n");
25380 @.Fatal mem file error@>
25381    return false;
25382 }
25383
25384 @ @<Declarations@>=
25385 boolean mp_load_mem_file (MP mp) ;
25386
25387 @ Mem files consist of |memory_word| items, and we use the following
25388 macros to dump words of different types:
25389
25390 @d dump_wd(A)   { WW=(A);       (mp->write_binary_file)(mp,mp->mem_file,&WW,sizeof(WW)); }
25391 @d dump_int(A)  { int cint=(A); (mp->write_binary_file)(mp,mp->mem_file,&cint,sizeof(cint)); }
25392 @d dump_hh(A)   { WW.hh=(A);    (mp->write_binary_file)(mp,mp->mem_file,&WW,sizeof(WW)); }
25393 @d dump_qqqq(A) { WW.qqqq=(A);  (mp->write_binary_file)(mp,mp->mem_file,&WW,sizeof(WW)); }
25394 @d dump_string(A) { dump_int(strlen(A)+1);
25395                     (mp->write_binary_file)(mp,mp->mem_file,A,strlen(A)+1); }
25396
25397 @<Glob...@>=
25398 void * mem_file; /* for input or output of mem information */
25399
25400 @ The inverse macros are slightly more complicated, since we need to check
25401 the range of the values we are reading in. We say `|undump(a)(b)(x)|' to
25402 read an integer value |x| that is supposed to be in the range |a<=x<=b|.
25403
25404 @d mgeti(A) do {
25405   size_t wanted = sizeof(A);
25406   void *A_ptr = &A;
25407   (mp->read_binary_file)(mp, mp->mem_file,&A_ptr,&wanted);
25408   if (wanted!=sizeof(A)) goto OFF_BASE;
25409 } while (0)
25410
25411 @d mgetw(A) do {
25412   size_t wanted = sizeof(A);
25413   void *A_ptr = &A;
25414   (mp->read_binary_file)(mp, mp->mem_file,&A_ptr,&wanted);
25415   if (wanted!=sizeof(A)) goto OFF_BASE;
25416 } while (0)
25417
25418 @d undump_wd(A)   { mgetw(WW); A=WW; }
25419 @d undump_int(A)  { int cint; mgeti(cint); A=cint; }
25420 @d undump_hh(A)   { mgetw(WW); A=WW.hh; }
25421 @d undump_qqqq(A) { mgetw(WW); A=WW.qqqq; }
25422 @d undump_strings(A,B,C) { 
25423    undump_int(x); if ( (x<(A)) || (x>(B)) ) goto OFF_BASE; else C=str(x); }
25424 @d undump(A,B,C) { undump_int(x); if ( (x<(A)) || (x>(int)(B)) ) goto OFF_BASE; else C=x; }
25425 @d undump_size(A,B,C,D) { undump_int(x);
25426                           if (x<(A)) goto OFF_BASE; 
25427                           if (x>(B)) { too_small((C)); } else { D=x;} }
25428 @d undump_string(A) do { 
25429   size_t wanted; 
25430   integer XX=0; 
25431   undump_int(XX);
25432   wanted = XX;
25433   A = xmalloc(XX,sizeof(char));
25434   (mp->read_binary_file)(mp,mp->mem_file,(void **)&A,&wanted);
25435   if (wanted!=(size_t)XX) goto OFF_BASE;
25436 } while (0)
25437
25438 @ The next few sections of the program should make it clear how we use the
25439 dump/undump macros.
25440
25441 @<Dump constants for consistency check@>=
25442 dump_int(mp->mem_top);
25443 dump_int(mp->hash_size);
25444 dump_int(mp->hash_prime)
25445 dump_int(mp->param_size);
25446 dump_int(mp->max_in_open);
25447
25448 @ Sections of a \.{WEB} program that are ``commented out'' still contribute
25449 strings to the string pool; therefore \.{INIMP} and \MP\ will have
25450 the same strings. (And it is, of course, a good thing that they do.)
25451 @.WEB@>
25452 @^string pool@>
25453
25454 @<Undump constants for consistency check@>=
25455 undump_int(x); mp->mem_top = x;
25456 undump_int(x); if (mp->hash_size != x) goto OFF_BASE;
25457 undump_int(x); if (mp->hash_prime != x) goto OFF_BASE;
25458 undump_int(x); if (mp->param_size != x) goto OFF_BASE;
25459 undump_int(x); if (mp->max_in_open != x) goto OFF_BASE
25460
25461 @ We do string pool compaction to avoid dumping unused strings.
25462
25463 @d dump_four_ASCII 
25464   w.b0=qi(mp->str_pool[k]); w.b1=qi(mp->str_pool[k+1]);
25465   w.b2=qi(mp->str_pool[k+2]); w.b3=qi(mp->str_pool[k+3]);
25466   dump_qqqq(w)
25467
25468 @<Dump the string pool@>=
25469 mp_do_compaction(mp, mp->pool_size);
25470 dump_int(mp->pool_ptr);
25471 dump_int(mp->max_str_ptr);
25472 dump_int(mp->str_ptr);
25473 k=0;
25474 while ( (mp->next_str[k]==k+1) && (k<=mp->max_str_ptr) ) 
25475   incr(k);
25476 dump_int(k);
25477 while ( k<=mp->max_str_ptr ) { 
25478   dump_int(mp->next_str[k]); incr(k);
25479 }
25480 k=0;
25481 while (1)  { 
25482   dump_int(mp->str_start[k]); /* TODO: valgrind warning here */
25483   if ( k==mp->str_ptr ) {
25484     break;
25485   } else { 
25486     k=mp->next_str[k]; 
25487   }
25488 };
25489 k=0;
25490 while (k+4<mp->pool_ptr ) { 
25491   dump_four_ASCII; k=k+4; 
25492 }
25493 k=mp->pool_ptr-4; dump_four_ASCII;
25494 mp_print_ln(mp); mp_print(mp, "at most "); mp_print_int(mp, mp->max_str_ptr);
25495 mp_print(mp, " strings of total length ");
25496 mp_print_int(mp, mp->pool_ptr)
25497
25498 @ @d undump_four_ASCII 
25499   undump_qqqq(w);
25500   mp->str_pool[k]=qo(w.b0); mp->str_pool[k+1]=qo(w.b1);
25501   mp->str_pool[k+2]=qo(w.b2); mp->str_pool[k+3]=qo(w.b3)
25502
25503 @<Undump the string pool@>=
25504 undump_int(mp->pool_ptr);
25505 mp_reallocate_pool(mp, mp->pool_ptr) ;
25506 undump_int(mp->max_str_ptr);
25507 mp_reallocate_strings (mp,mp->max_str_ptr) ;
25508 undump(0,mp->max_str_ptr,mp->str_ptr);
25509 undump(0,mp->max_str_ptr+1,s);
25510 for (k=0;k<=s-1;k++) 
25511   mp->next_str[k]=k+1;
25512 for (k=s;k<=mp->max_str_ptr;k++) 
25513   undump(s+1,mp->max_str_ptr+1,mp->next_str[k]);
25514 mp->fixed_str_use=0;
25515 k=0;
25516 while (1) { 
25517   undump(0,mp->pool_ptr,mp->str_start[k]);
25518   if ( k==mp->str_ptr ) break;
25519   mp->str_ref[k]=max_str_ref;
25520   incr(mp->fixed_str_use);
25521   mp->last_fixed_str=k; k=mp->next_str[k];
25522 }
25523 k=0;
25524 while ( k+4<mp->pool_ptr ) { 
25525   undump_four_ASCII; k=k+4;
25526 }
25527 k=mp->pool_ptr-4; undump_four_ASCII;
25528 mp->init_str_use=mp->fixed_str_use; mp->init_pool_ptr=mp->pool_ptr;
25529 mp->max_pool_ptr=mp->pool_ptr;
25530 mp->strs_used_up=mp->fixed_str_use;
25531 mp->pool_in_use=mp->str_start[mp->str_ptr]; mp->strs_in_use=mp->fixed_str_use;
25532 mp->max_pl_used=mp->pool_in_use; mp->max_strs_used=mp->strs_in_use;
25533 mp->pact_count=0; mp->pact_chars=0; mp->pact_strs=0;
25534
25535 @ By sorting the list of available spaces in the variable-size portion of
25536 |mem|, we are usually able to get by without having to dump very much
25537 of the dynamic memory.
25538
25539 We recompute |var_used| and |dyn_used|, so that \.{INIMP} dumps valid
25540 information even when it has not been gathering statistics.
25541
25542 @<Dump the dynamic memory@>=
25543 mp_sort_avail(mp); mp->var_used=0;
25544 dump_int(mp->lo_mem_max); dump_int(mp->rover);
25545 p=0; q=mp->rover; x=0;
25546 do {  
25547   for (k=p;k<= q+1;k++) 
25548     dump_wd(mp->mem[k]);
25549   x=x+q+2-p; mp->var_used=mp->var_used+q-p;
25550   p=q+node_size(q); q=rlink(q);
25551 } while (q!=mp->rover);
25552 mp->var_used=mp->var_used+mp->lo_mem_max-p; 
25553 mp->dyn_used=mp->mem_end+1-mp->hi_mem_min;
25554 for (k=p;k<= mp->lo_mem_max;k++ ) 
25555   dump_wd(mp->mem[k]);
25556 x=x+mp->lo_mem_max+1-p;
25557 dump_int(mp->hi_mem_min); dump_int(mp->avail);
25558 for (k=mp->hi_mem_min;k<=mp->mem_end;k++ ) 
25559   dump_wd(mp->mem[k]);
25560 x=x+mp->mem_end+1-mp->hi_mem_min;
25561 p=mp->avail;
25562 while ( p!=null ) { 
25563   decr(mp->dyn_used); p=link(p);
25564 }
25565 dump_int(mp->var_used); dump_int(mp->dyn_used);
25566 mp_print_ln(mp); mp_print_int(mp, x);
25567 mp_print(mp, " memory locations dumped; current usage is ");
25568 mp_print_int(mp, mp->var_used); mp_print_char(mp, '&'); mp_print_int(mp, mp->dyn_used)
25569
25570 @ @<Undump the dynamic memory@>=
25571 undump(lo_mem_stat_max+1000,hi_mem_stat_min-1,mp->lo_mem_max);
25572 undump(lo_mem_stat_max+1,mp->lo_mem_max,mp->rover);
25573 p=0; q=mp->rover;
25574 do {  
25575   for (k=p;k<= q+1; k++) 
25576     undump_wd(mp->mem[k]);
25577   p=q+node_size(q);
25578   if ( (p>mp->lo_mem_max)||((q>=rlink(q))&&(rlink(q)!=mp->rover)) ) 
25579     goto OFF_BASE;
25580   q=rlink(q);
25581 } while (q!=mp->rover);
25582 for (k=p;k<=mp->lo_mem_max;k++ ) 
25583   undump_wd(mp->mem[k]);
25584 undump(mp->lo_mem_max+1,hi_mem_stat_min,mp->hi_mem_min);
25585 undump(null,mp->mem_top,mp->avail); mp->mem_end=mp->mem_top;
25586 for (k=mp->hi_mem_min;k<= mp->mem_end;k++) 
25587   undump_wd(mp->mem[k]);
25588 undump_int(mp->var_used); undump_int(mp->dyn_used)
25589
25590 @ A different scheme is used to compress the hash table, since its lower region
25591 is usually sparse. When |text(p)<>0| for |p<=hash_used|, we output three
25592 words: |p|, |hash[p]|, and |eqtb[p]|. The hash table is, of course, densely
25593 packed for |p>=hash_used|, so the remaining entries are output in~a~block.
25594
25595 @<Dump the table of equivalents and the hash table@>=
25596 dump_int(mp->hash_used); 
25597 mp->st_count=frozen_inaccessible-1-mp->hash_used;
25598 for (p=1;p<=mp->hash_used;p++) {
25599   if ( text(p)!=0 ) {
25600      dump_int(p); dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]); incr(mp->st_count);
25601   }
25602 }
25603 for (p=mp->hash_used+1;p<=(int)hash_end;p++) {
25604   dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]);
25605 }
25606 dump_int(mp->st_count);
25607 mp_print_ln(mp); mp_print_int(mp, mp->st_count); mp_print(mp, " symbolic tokens")
25608
25609 @ @<Undump the table of equivalents and the hash table@>=
25610 undump(1,frozen_inaccessible,mp->hash_used); 
25611 p=0;
25612 do {  
25613   undump(p+1,mp->hash_used,p); 
25614   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
25615 } while (p!=mp->hash_used);
25616 for (p=mp->hash_used+1;p<=(int)hash_end;p++ )  { 
25617   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
25618 }
25619 undump_int(mp->st_count)
25620
25621 @ We have already printed a lot of statistics, so we set |mp_tracing_stats:=0|
25622 to prevent them appearing again.
25623
25624 @<Dump a few more things and the closing check word@>=
25625 dump_int(mp->max_internal);
25626 dump_int(mp->int_ptr);
25627 for (k=1;k<= mp->int_ptr;k++ ) { 
25628   dump_int(mp->internal[k]); 
25629   dump_string(mp->int_name[k]);
25630 }
25631 dump_int(mp->start_sym); 
25632 dump_int(mp->interaction); 
25633 dump_string(mp->mem_ident);
25634 dump_int(mp->bg_loc); dump_int(mp->eg_loc); dump_int(mp->serial_no); dump_int(69073);
25635 mp->internal[mp_tracing_stats]=0
25636
25637 @ @<Undump a few more things and the closing check word@>=
25638 undump_int(x);
25639 if (x>mp->max_internal) mp_grow_internals(mp,x);
25640 undump_int(mp->int_ptr);
25641 for (k=1;k<= mp->int_ptr;k++) { 
25642   undump_int(mp->internal[k]);
25643   undump_string(mp->int_name[k]);
25644 }
25645 undump(0,frozen_inaccessible,mp->start_sym);
25646 if (mp->interaction==mp_unspecified_mode) {
25647   undump(mp_unspecified_mode,mp_error_stop_mode,mp->interaction);
25648 } else {
25649   undump(mp_unspecified_mode,mp_error_stop_mode,x);
25650 }
25651 undump_string(mp->mem_ident);
25652 undump(1,hash_end,mp->bg_loc);
25653 undump(1,hash_end,mp->eg_loc);
25654 undump_int(mp->serial_no);
25655 undump_int(x); 
25656 if (x!=69073) goto OFF_BASE
25657
25658 @ @<Create the |mem_ident|...@>=
25659
25660   xfree(mp->mem_ident);
25661   mp->mem_ident = xmalloc(256,1);
25662   snprintf(mp->mem_ident,256," (mem=%s %i.%i.%i)", 
25663            mp->job_name,
25664            (int)(mp_round_unscaled(mp, mp->internal[mp_year]) % 100),
25665            (int)mp_round_unscaled(mp, mp->internal[mp_month]),
25666            (int)mp_round_unscaled(mp, mp->internal[mp_day]));
25667   mp_pack_job_name(mp, mem_extension);
25668   while (! mp_w_open_out(mp, &mp->mem_file) )
25669     mp_prompt_file_name(mp, "mem file name", mem_extension);
25670   mp_print_nl(mp, "Beginning to dump on file ");
25671 @.Beginning to dump...@>
25672   mp_print(mp, mp->name_of_file); 
25673   mp_print_nl(mp, mp->mem_ident);
25674 }
25675
25676 @ @<Dealloc variables@>=
25677 xfree(mp->mem_ident);
25678
25679 @ @<Close the mem file@>=
25680 (mp->close_file)(mp,mp->mem_file)
25681
25682 @* \[46] The main program.
25683 This is it: the part of \MP\ that executes all those procedures we have
25684 written.
25685
25686 Well---almost. We haven't put the parsing subroutines into the
25687 program yet; and we'd better leave space for a few more routines that may
25688 have been forgotten.
25689
25690 @c @<Declare the basic parsing subroutines@>;
25691 @<Declare miscellaneous procedures that were declared |forward|@>;
25692 @<Last-minute procedures@>
25693
25694 @ We've noted that there are two versions of \MP. One, called \.{INIMP},
25695 @.INIMP@>
25696 has to be run first; it initializes everything from scratch, without
25697 reading a mem file, and it has the capability of dumping a mem file.
25698 The other one is called `\.{VIRMP}'; it is a ``virgin'' program that needs
25699 @.VIRMP@>
25700 to input a mem file in order to get started. \.{VIRMP} typically has
25701 a bit more memory capacity than \.{INIMP}, because it does not need the
25702 space consumed by the dumping/undumping routines and the numerous calls on
25703 |primitive|, etc.
25704
25705 The \.{VIRMP} program cannot read a mem file instantaneously, of course;
25706 the best implementations therefore allow for production versions of \MP\ that
25707 not only avoid the loading routine for object code, they also have
25708 a mem file pre-loaded. 
25709
25710 @ @<Option variables@>=
25711 int ini_version; /* are we iniMP? */
25712
25713 @ @<Set |ini_version|@>=
25714 mp->ini_version = (opt->ini_version ? true : false);
25715
25716 @ Here we do whatever is needed to complete \MP's job gracefully on the
25717 local operating system. The code here might come into play after a fatal
25718 error; it must therefore consist entirely of ``safe'' operations that
25719 cannot produce error messages. For example, it would be a mistake to call
25720 |str_room| or |make_string| at this time, because a call on |overflow|
25721 might lead to an infinite loop.
25722 @^system dependencies@>
25723
25724 This program doesn't bother to close the input files that may still be open.
25725
25726 @<Last-minute...@>=
25727 void mp_close_files_and_terminate (MP mp) {
25728   integer k; /* all-purpose index */
25729   integer LH; /* the length of the \.{TFM} header, in words */
25730   int lk_offset; /* extra words inserted at beginning of |lig_kern| array */
25731   pointer p; /* runs through a list of \.{TFM} dimensions */
25732   @<Close all open files in the |rd_file| and |wr_file| arrays@>;
25733   if ( mp->internal[mp_tracing_stats]>0 )
25734     @<Output statistics about this job@>;
25735   wake_up_terminal; 
25736   @<Do all the finishing work on the \.{TFM} file@>;
25737   @<Explain what output files were written@>;
25738   if ( mp->log_opened ){ 
25739     wlog_cr;
25740     (mp->close_file)(mp,mp->log_file); 
25741     mp->selector=mp->selector-2;
25742     if ( mp->selector==term_only ) {
25743       mp_print_nl(mp, "Transcript written on ");
25744 @.Transcript written...@>
25745       mp_print(mp, mp->log_name); mp_print_char(mp, '.');
25746     }
25747   }
25748   mp_print_ln(mp);
25749   t_close_out;
25750   t_close_in;
25751 }
25752
25753 @ @<Declarations@>=
25754 void mp_close_files_and_terminate (MP mp) ;
25755
25756 @ @<Close all open files in the |rd_file| and |wr_file| arrays@>=
25757 if (mp->rd_fname!=NULL) {
25758   for (k=0;k<=(int)mp->read_files-1;k++ ) {
25759     if ( mp->rd_fname[k]!=NULL ) {
25760       (mp->close_file)(mp,mp->rd_file[k]);
25761    }
25762  }
25763 }
25764 if (mp->wr_fname!=NULL) {
25765   for (k=0;k<=(int)mp->write_files-1;k++) {
25766     if ( mp->wr_fname[k]!=NULL ) {
25767      (mp->close_file)(mp,mp->wr_file[k]);
25768     }
25769   }
25770 }
25771
25772 @ @<Dealloc ...@>=
25773 for (k=0;k<(int)mp->max_read_files;k++ ) {
25774   if ( mp->rd_fname[k]!=NULL ) {
25775     (mp->close_file)(mp,mp->rd_file[k]);
25776     mp_xfree(mp->rd_fname[k]); 
25777   }
25778 }
25779 mp_xfree(mp->rd_file);
25780 mp_xfree(mp->rd_fname);
25781 for (k=0;k<(int)mp->max_write_files;k++) {
25782   if ( mp->wr_fname[k]!=NULL ) {
25783     (mp->close_file)(mp,mp->wr_file[k]);
25784     mp_xfree(mp->wr_fname[k]); 
25785   }
25786 }
25787 mp_xfree(mp->wr_file);
25788 mp_xfree(mp->wr_fname);
25789
25790
25791 @ We want to produce a \.{TFM} file if and only if |mp_fontmaking| is positive.
25792
25793 We reclaim all of the variable-size memory at this point, so that
25794 there is no chance of another memory overflow after the memory capacity
25795 has already been exceeded.
25796
25797 @<Do all the finishing work on the \.{TFM} file@>=
25798 if ( mp->internal[mp_fontmaking]>0 ) {
25799   @<Make the dynamic memory into one big available node@>;
25800   @<Massage the \.{TFM} widths@>;
25801   mp_fix_design_size(mp); mp_fix_check_sum(mp);
25802   @<Massage the \.{TFM} heights, depths, and italic corrections@>;
25803   mp->internal[mp_fontmaking]=0; /* avoid loop in case of fatal error */
25804   @<Finish the \.{TFM} file@>;
25805 }
25806
25807 @ @<Make the dynamic memory into one big available node@>=
25808 mp->rover=lo_mem_stat_max+1; link(mp->rover)=empty_flag; mp->lo_mem_max=mp->hi_mem_min-1;
25809 if ( mp->lo_mem_max-mp->rover>max_halfword ) mp->lo_mem_max=max_halfword+mp->rover;
25810 node_size(mp->rover)=mp->lo_mem_max-mp->rover; 
25811 llink(mp->rover)=mp->rover; rlink(mp->rover)=mp->rover;
25812 link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null
25813
25814 @ The present section goes directly to the log file instead of using
25815 |print| commands, because there's no need for these strings to take
25816 up |str_pool| memory when a non-{\bf stat} version of \MP\ is being used.
25817
25818 @<Output statistics...@>=
25819 if ( mp->log_opened ) { 
25820   char s[128];
25821   wlog_ln(" ");
25822   wlog_ln("Here is how much of MetaPost's memory you used:");
25823 @.Here is how much...@>
25824   snprintf(s,128," %i string%s out of %i",(int)mp->max_strs_used-mp->init_str_use,
25825           (mp->max_strs_used!=mp->init_str_use+1 ? "s" : ""),
25826           (int)(mp->max_strings-1-mp->init_str_use));
25827   wlog_ln(s);
25828   snprintf(s,128," %i string characters out of %i",
25829            (int)mp->max_pl_used-mp->init_pool_ptr,
25830            (int)mp->pool_size-mp->init_pool_ptr);
25831   wlog_ln(s);
25832   snprintf(s,128," %i words of memory out of %i",
25833            (int)mp->lo_mem_max+mp->mem_end-mp->hi_mem_min+2,
25834            (int)mp->mem_end+1);
25835   wlog_ln(s);
25836   snprintf(s,128," %i symbolic tokens out of %i", (int)mp->st_count, (int)mp->hash_size);
25837   wlog_ln(s);
25838   snprintf(s,128," %ii, %in, %ip, %ib stack positions out of %ii, %in, %ip, %ib",
25839            (int)mp->max_in_stack,(int)mp->int_ptr,
25840            (int)mp->max_param_stack,(int)mp->max_buf_stack+1,
25841            (int)mp->stack_size,(int)mp->max_internal,(int)mp->param_size,(int)mp->buf_size);
25842   wlog_ln(s);
25843   snprintf(s,128," %i string compactions (moved %i characters, %i strings)",
25844           (int)mp->pact_count,(int)mp->pact_chars,(int)mp->pact_strs);
25845   wlog_ln(s);
25846 }
25847
25848 @ We get to the |final_cleanup| routine when \&{end} or \&{dump} has
25849 been scanned.
25850
25851 @<Last-minute...@>=
25852 void mp_final_cleanup (MP mp) {
25853   small_number c; /* 0 for \&{end}, 1 for \&{dump} */
25854   c=mp->cur_mod;
25855   if ( mp->job_name==NULL ) mp_open_log_file(mp);
25856   while ( mp->input_ptr>0 ) {
25857     if ( token_state ) mp_end_token_list(mp);
25858     else  mp_end_file_reading(mp);
25859   }
25860   while ( mp->loop_ptr!=null ) mp_stop_iteration(mp);
25861   while ( mp->open_parens>0 ) { 
25862     mp_print(mp, " )"); decr(mp->open_parens);
25863   };
25864   while ( mp->cond_ptr!=null ) {
25865     mp_print_nl(mp, "(end occurred when ");
25866 @.end occurred...@>
25867     mp_print_cmd_mod(mp, fi_or_else,mp->cur_if);
25868     /* `\.{if}' or `\.{elseif}' or `\.{else}' */
25869     if ( mp->if_line!=0 ) {
25870       mp_print(mp, " on line "); mp_print_int(mp, mp->if_line);
25871     }
25872     mp_print(mp, " was incomplete)");
25873     mp->if_line=if_line_field(mp->cond_ptr);
25874     mp->cur_if=name_type(mp->cond_ptr); mp->cond_ptr=link(mp->cond_ptr);
25875   }
25876   if ( mp->history!=mp_spotless )
25877     if ( ((mp->history==mp_warning_issued)||(mp->interaction<mp_error_stop_mode)) )
25878       if ( mp->selector==term_and_log ) {
25879     mp->selector=term_only;
25880     mp_print_nl(mp, "(see the transcript file for additional information)");
25881 @.see the transcript file...@>
25882     mp->selector=term_and_log;
25883   }
25884   if ( c==1 ) {
25885     if (mp->ini_version) {
25886       mp_store_mem_file(mp); return;
25887     }
25888     mp_print_nl(mp, "(dump is performed only by INIMP)"); return;
25889 @.dump...only by INIMP@>
25890   }
25891 }
25892
25893 @ @<Declarations@>=
25894 void mp_final_cleanup (MP mp) ;
25895 void mp_init_prim (MP mp) ;
25896 void mp_init_tab (MP mp) ;
25897
25898 @ @<Last-minute...@>=
25899 void mp_init_prim (MP mp) { /* initialize all the primitives */
25900   @<Put each...@>;
25901 }
25902 @#
25903 void mp_init_tab (MP mp) { /* initialize other tables */
25904   integer k; /* all-purpose index */
25905   @<Initialize table entries (done by \.{INIMP} only)@>;
25906 }
25907
25908
25909 @ When we begin the following code, \MP's tables may still contain garbage;
25910 the strings might not even be present. Thus we must proceed cautiously to get
25911 bootstrapped in.
25912
25913 But when we finish this part of the program, \MP\ is ready to call on the
25914 |main_control| routine to do its work.
25915
25916 @<Get the first line...@>=
25917
25918   @<Initialize the input routines@>;
25919   if ( (mp->mem_ident==NULL)||(mp->buffer[loc]=='&') ) {
25920     if ( mp->mem_ident!=NULL ) {
25921       mp_do_initialize(mp); /* erase preloaded mem */
25922     }
25923     if ( ! mp_open_mem_file(mp) ) return mp_fatal_error_stop;
25924     if ( ! mp_load_mem_file(mp) ) {
25925       (mp->close_file)(mp, mp->mem_file); 
25926       return mp_fatal_error_stop;
25927     }
25928     (mp->close_file)(mp, mp->mem_file);
25929     while ( (loc<limit)&&(mp->buffer[loc]==' ') ) incr(loc);
25930   }
25931   mp->buffer[limit]='%';
25932   mp_fix_date_and_time(mp);
25933   if (mp->random_seed==0)
25934     mp->random_seed = (mp->internal[mp_time] / unity)+mp->internal[mp_day];
25935   mp_init_randoms(mp, mp->random_seed);
25936   @<Initialize the print |selector|...@>;
25937   if ( loc<limit ) if ( mp->buffer[loc]!='\\' ) 
25938     mp_start_input(mp); /* \&{input} assumed */
25939 }
25940
25941 @ @<Run inimpost commands@>=
25942 {
25943   mp_get_strings_started(mp);
25944   mp_init_tab(mp); /* initialize the tables */
25945   mp_init_prim(mp); /* call |primitive| for each primitive */
25946   mp->init_str_use=mp->str_ptr; mp->init_pool_ptr=mp->pool_ptr;
25947   mp->max_str_ptr=mp->str_ptr; mp->max_pool_ptr=mp->pool_ptr;
25948   mp_fix_date_and_time(mp);
25949 }
25950
25951
25952 @* \[47] Debugging.
25953 Once \MP\ is working, you should be able to diagnose most errors with
25954 the \.{show} commands and other diagnostic features. But for the initial
25955 stages of debugging, and for the revelation of really deep mysteries, you
25956 can compile \MP\ with a few more aids. An additional routine called |debug_help|
25957 will also come into play when you type `\.D' after an error message;
25958 |debug_help| also occurs just before a fatal error causes \MP\ to succumb.
25959 @^debugging@>
25960 @^system dependencies@>
25961
25962 The interface to |debug_help| is primitive, but it is good enough when used
25963 with a debugger that allows you to set breakpoints and to read
25964 variables and change their values. After getting the prompt `\.{debug \#}', you
25965 type either a negative number (this exits |debug_help|), or zero (this
25966 goes to a location where you can set a breakpoint, thereby entering into
25967 dialog with the debugger), or a positive number |m| followed by
25968 an argument |n|. The meaning of |m| and |n| will be clear from the
25969 program below. (If |m=13|, there is an additional argument, |l|.)
25970 @.debug \#@>
25971
25972 @<Last-minute...@>=
25973 void mp_debug_help (MP mp) { /* routine to display various things */
25974   integer k;
25975   int l,m,n;
25976   char *aline;
25977   size_t len;
25978   while (1) { 
25979     wake_up_terminal;
25980     mp_print_nl(mp, "debug # (-1 to exit):"); update_terminal;
25981 @.debug \#@>
25982     m = 0;
25983     aline = (mp->read_ascii_file)(mp,mp->term_in, &len);
25984     if (len) { sscanf(aline,"%i",&m); xfree(aline); }
25985     if ( m<=0 )
25986       return;
25987     n = 0 ;
25988     aline = (mp->read_ascii_file)(mp,mp->term_in, &len);
25989     if (len) { sscanf(aline,"%i",&n); xfree(aline); }
25990     switch (m) {
25991     @<Numbered cases for |debug_help|@>;
25992     default: mp_print(mp, "?"); break;
25993     }
25994   }
25995 }
25996
25997 @ @<Numbered cases...@>=
25998 case 1: mp_print_word(mp, mp->mem[n]); /* display |mem[n]| in all forms */
25999   break;
26000 case 2: mp_print_int(mp, info(n));
26001   break;
26002 case 3: mp_print_int(mp, link(n));
26003   break;
26004 case 4: mp_print_int(mp, eq_type(n)); mp_print_char(mp, ':'); mp_print_int(mp, equiv(n));
26005   break;
26006 case 5: mp_print_variable_name(mp, n);
26007   break;
26008 case 6: mp_print_int(mp, mp->internal[n]);
26009   break;
26010 case 7: mp_do_show_dependencies(mp);
26011   break;
26012 case 9: mp_show_token_list(mp, n,null,100000,0);
26013   break;
26014 case 10: mp_print_str(mp, n);
26015   break;
26016 case 11: mp_check_mem(mp, n>0); /* check wellformedness; print new busy locations if |n>0| */
26017   break;
26018 case 12: mp_search_mem(mp, n); /* look for pointers to |n| */
26019   break;
26020 case 13: 
26021   l = 0;  
26022   aline = (mp->read_ascii_file)(mp,mp->term_in, &len);
26023   if (len) { sscanf(aline,"%i",&l); xfree(aline); }
26024   mp_print_cmd_mod(mp, n,l); 
26025   break;
26026 case 14: for (k=0;k<=n;k++) mp_print_str(mp, mp->buffer[k]);
26027   break;
26028 case 15: mp->panicking=! mp->panicking;
26029   break;
26030
26031
26032 @ Saving the filename template
26033
26034 @<Save the filename template@>=
26035
26036   if ( mp->filename_template!=0 ) delete_str_ref(mp->filename_template);
26037   if ( length(mp->cur_exp)==0 ) mp->filename_template=0;
26038   else { 
26039     mp->filename_template=mp->cur_exp; add_str_ref(mp->filename_template);
26040   }
26041 }
26042
26043 @* \[48] System-dependent changes.
26044 This section should be replaced, if necessary, by any special
26045 modification of the program
26046 that are necessary to make \MP\ work at a particular installation.
26047 It is usually best to design your change file so that all changes to
26048 previous sections preserve the section numbering; then everybody's version
26049 will be consistent with the published program. More extensive changes,
26050 which introduce new sections, can be inserted here; then only the index
26051 itself will get a new section number.
26052 @^system dependencies@>
26053
26054 @* \[49] Index.
26055 Here is where you can find all uses of each identifier in the program,
26056 with underlined entries pointing to where the identifier was defined.
26057 If the identifier is only one letter long, however, you get to see only
26058 the underlined entries. {\sl All references are to section numbers instead of
26059 page numbers.}
26060
26061 This index also lists error messages and other aspects of the program
26062 that you might want to look up some day. For example, the entry
26063 for ``system dependencies'' lists all sections that should receive
26064 special attention from people who are installing \MP\ in a new
26065 operating environment. A list of various things that can't happen appears
26066 under ``this can't happen''.
26067 Approximately 25 sections are listed under ``inner loop''; these account
26068 for more than 60\pct! of \MP's running time, exclusive of input and output.