modernc.org/knuth@v0.0.4/mf/internal/trap/mf.go (about) 1 // Code generated by '[/tmp/go-build1429805405/b001/exe/generate]', DO NOT EDIT. 2 3 // % This program is copyright (C) 1984 by D. E. Knuth; all rights are reserved. 4 // % Unlimited copying and redistribution of this file are permitted as long 5 // % as this file is not modified. Modifications are permitted, but only if 6 // % the resulting file is not named mf.web. (The WEB system provides 7 // % for alterations via an auxiliary file; the master file should stay intact.) 8 // % In other words, METAFONT is under essentially the same ground rules as TeX. 9 // 10 // % TeX is a trademark of the American Mathematical Society. 11 // % METAFONT is a trademark of Addison-Wesley Publishing Company. 12 // 13 // % Version 0 was completed on July 28, 1984. 14 // % Version 1 was completed on January 4, 1986; it corresponds to "Volume D". 15 // % Version 1.1 trivially corrected the punctuation in one message (June 1986). 16 // % Version 1.2 corrected an arithmetic overflow problem (July 1986). 17 // % Version 1.3 improved rounding when elliptical pens are made (November 1986). 18 // % Version 1.4 corrected scan_declared_variable timing (May 1988). 19 // % Version 1.5 fixed negative halving in allocator when mem_min<0 (June 1988). 20 // % Version 1.6 kept open_log_file from calling fatal_error (November 1988). 21 // % Version 1.7 solved that problem a better way (December 1988). 22 // % Version 1.8 introduced major changes for 8-bit extensions (September 1989). 23 // % Version 1.9 improved skimping and was edited for style (December 1989). 24 // % Version 2.0 fixed bug in addto; released with TeX version 3.0 (March 1990). 25 // % Version 2.7 made consistent with TeX version 3.1 (September 1990). 26 // % Version 2.71 fixed bug in draw, allowed unprintable filenames (March 1992). 27 // % Version 2.718 fixed bug in <Choose a dependent...> (March 1995). 28 // % Version 2.7182 fixed bugs related to "<unprintable char>" (August 1996). 29 // % Version 2.71828 suppressed autorounding in dangerous cases (June 2003). 30 // % Version 2.718281 was a general cleanup with minor fixes (February 2008). 31 // % Version 2.7182818 was similar (January 2014). 32 // % Version 2.71828182 was similar (January 2021). 33 // 34 // % A reward of $327.68 will be paid to the first finder of any remaining bug. 35 // 36 // % Although considerable effort has been expended to make the METAFONT program 37 // % correct and reliable, no warranty is implied; the author disclaims any 38 // % obligation or liability for damages, including but not limited to 39 // % special, indirect, or consequential damages arising out of or in 40 // % connection with the use or performance of this software. This work has 41 // % been a ``labor of love'' and the author hopes that users enjoy it. 42 // 43 // % Here is TeX material that gets inserted after \input webmac 44 // \def\hang[\hangindent 3em\noindent\ignorespaces] 45 // \def\textindent#1[\hangindent2.5em\noindent\hbox to2.5em[\hss#1 ]\ignorespaces] 46 // \font\ninerm=cmr9 47 // \let\mc=\ninerm % medium caps for names like SAIL 48 // \def\PASCAL[Pascal] 49 // \def\ph[\hbox[Pascal-H]] 50 // \def\psqrt#1[\sqrt[\mathstrut#1]] 51 // \def\k[_[k+1]] 52 // \def\pct![[\char`\%]] % percent sign in ordinary text 53 // \font\tenlogo=logo10 % font used for the METAFONT logo 54 // \font\logos=logosl10 55 // \font\eightlogo=logo8 56 // \def\MF[[\tenlogo META]\-[\tenlogo FONT]] 57 // \def\<#1>[$\langle#1\rangle$] 58 // \def\section[\mathhexbox278] 59 // \let\swap=\leftrightarrow 60 // \def\round[\mathop[\rm round]\nolimits] 61 // 62 // \def\(#1)[] % this is used to make section names sort themselves better 63 // \def\9#1[] % this is used for sort keys in the index via @:sort key][entry@> 64 // 65 // \outer\def\N#1. \[#2]#3.[\MN#1.\vfil\eject % begin starred section 66 // \def\rhead[PART #2:\uppercase[#3]] % define running headline 67 // \message[*\modno] % progress report 68 // \edef\next[\write\cont[\Z[\?#2]#3][\modno][\the\pageno]]]\next 69 // \ifon\startsection[\bf\ignorespaces#3.\quad]\ignorespaces] 70 // \let\?=\relax % we want to be able to \write a \? 71 // 72 // \def\title[[\eightlogo METAFONT]] 73 // \def\topofcontents[\hsize 5.5in 74 // \vglue -30pt plus 1fil minus 1.5in 75 // \def\?##1][\hbox to 1in[\hfil##1.\ ]] 76 // ] 77 // \def\botofcontents[\vskip 0pt plus 1fil minus 1.5in] 78 // \pageno=3 79 // \def\glob[13] % this should be the section number of "<Global...>" 80 // \def\gglob[20, 26] % this should be the next two sections of "<Global...>" 81 // 82 // 83 84 // 1. \[1] Introduction 85 86 // tangle:pos ../../mf.web:80:22: 87 88 // This is \MF, a font compiler intended to produce typefaces of high quality. 89 // The \PASCAL\ program that follows is the definition of \MF84, a standard 90 // \xref[PASCAL][\PASCAL] 91 // \xref[METAFONT84][\MF84] 92 // version of \MF\ that is designed to be highly portable so that identical output 93 // will be obtainable on a great variety of computers. The conventions 94 // of \MF84 are the same as those of \TeX82. 95 // 96 // The main purpose of the following program is to explain the algorithms of \MF\ 97 // as clearly as possible. As a result, the program will not necessarily be very 98 // efficient when a particular \PASCAL\ compiler has translated it into a 99 // particular machine language. However, the program has been written so that it 100 // can be tuned to run efficiently in a wide variety of operating environments 101 // by making comparatively few changes. Such flexibility is possible because 102 // the documentation that follows is written in the \.[WEB] language, which is 103 // at a higher level than \PASCAL; the preprocessing step that converts \.[WEB] 104 // to \PASCAL\ is able to introduce most of the necessary refinements. 105 // Semi-automatic translation to other languages is also feasible, because the 106 // program below does not make extensive use of features that are peculiar to 107 // \PASCAL. 108 // 109 // A large piece of software like \MF\ has inherent complexity that cannot 110 // be reduced below a certain level of difficulty, although each individual 111 // part is fairly simple by itself. The \.[WEB] language is intended to make 112 // the algorithms as readable as possible, by reflecting the way the 113 // individual program pieces fit together and by providing the 114 // cross-references that connect different parts. Detailed comments about 115 // what is going on, and about why things were done in certain ways, have 116 // been liberally sprinkled throughout the program. These comments explain 117 // features of the implementation, but they rarely attempt to explain the 118 // \MF\ language itself, since the reader is supposed to be familiar with 119 // [\sl The [\logos METAFONT\/]book]. 120 // \xref[WEB] 121 // \xref[METAFONTbook][\sl The [\logos METAFONT\/]book] 122 123 // 2. 124 125 // tangle:pos ../../mf.web:116:3: 126 127 // The present implementation has a long ancestry, beginning in the spring 128 // of~1977, when its author wrote a prototype set of subroutines and macros 129 // \xref[Knuth, Donald Ervin] 130 // that were used to develop the first Computer Modern fonts. 131 // This original proto-\MF\ required the user to recompile a [\mc SAIL] program 132 // whenever any character was changed, because it was not a ``language'' for 133 // font design; the language was [\mc SAIL]. After several hundred characters 134 // had been designed in that way, the author developed an interpretable language 135 // called \MF, in which it was possible to express the Computer Modern programs 136 // less cryptically. A complete \MF\ processor was designed and coded by the 137 // author in 1979. This program, written in [\mc SAIL], was adapted for use 138 // with a variety of typesetting equipment and display terminals by Leo Guibas, 139 // Lyle Ramshaw, and David Fuchs. 140 // \xref[Guibas, Leonidas Ioannis] 141 // \xref[Ramshaw, Lyle Harold] 142 // \xref[Fuchs, David Raymond] 143 // Major improvements to the design of Computer Modern fonts were made in the 144 // spring of 1982, after which it became clear that a new language would 145 // better express the needs of letterform designers. Therefore an entirely 146 // new \MF\ language and system were developed in 1984; the present system 147 // retains the name and some of the spirit of \MF79, but all of the details 148 // have changed. 149 // 150 // No doubt there still is plenty of room for improvement, but the author 151 // is firmly committed to keeping \MF84 ``frozen'' from now on; stability 152 // and reliability are to be its main virtues. 153 // 154 // On the other hand, the \.[WEB] description can be extended without changing 155 // the core of \MF84 itself, and the program has been designed so that such 156 // extensions are not extremely difficult to make. 157 // The |banner| string defined here should be changed whenever \MF\ 158 // undergoes any modifications, so that it will be clear which version of 159 // \MF\ might be the guilty party when a problem arises. 160 // \xref[extensions to \MF] 161 // \xref[system dependencies] 162 // 163 // If this program is changed, the resulting system should not be called 164 // `\MF\kern.5pt'; the official name `\MF\kern.5pt' by itself is reserved 165 // for software systems that are fully compatible with each other. 166 // A special test suite called the ``\.[TRAP] test'' is available for 167 // helping to determine whether an implementation deserves to be 168 // known as `\MF\kern.5pt' [cf.~Stanford Computer Science report CS1095, 169 // January 1986]. 170 171 // 3. 172 173 // tangle:pos ../../mf.web:162:3: 174 175 // Different \PASCAL s have slightly different conventions, and the present 176 // \xref[PASCAL H][\ph] 177 // program expresses \MF\ in terms of the \PASCAL\ that was 178 // available to the author in 1984. Constructions that apply to 179 // this particular compiler, which we shall call \ph, should help the 180 // reader see how to make an appropriate interface for other systems 181 // if necessary. (\ph\ is Charles Hedrick's modification of a compiler 182 // \xref[Hedrick, Charles Locke] 183 // for the DECsystem-10 that was originally developed at the University of 184 // Hamburg; cf.\ [\sl Software---Practice and Experience \bf6] (1976), 185 // 29--42. The \MF\ program below is intended to be adaptable, without 186 // extensive changes, to most other versions of \PASCAL, so it does not fully 187 // use the admirable features of \ph. Indeed, a conscious effort has been 188 // made here to avoid using several idiosyncratic features of standard 189 // \PASCAL\ itself, so that most of the code can be translated mechanically 190 // into other high-level languages. For example, the `\&[with]' and `\\[new]' 191 // features are not used, nor are pointer types, set types, or enumerated 192 // scalar types; there are no `\&[var]' parameters, except in the case of files 193 // or in the system-dependent |paint_row| procedure; 194 // there are no tag fields on variant records; there are no |real| variables; 195 // no procedures are declared local to other procedures.) 196 // 197 // The portions of this program that involve system-dependent code, where 198 // changes might be necessary because of differences between \PASCAL\ compilers 199 // and/or differences between 200 // operating systems, can be identified by looking at the sections whose 201 // numbers are listed under `system dependencies' in the index. Furthermore, 202 // the index entries for `dirty \PASCAL' list all places where the restrictions 203 // of \PASCAL\ have not been followed perfectly, for one reason or another. 204 // \xref[system dependencies] 205 // \xref[dirty \PASCAL] 206 207 // 4. 208 209 // tangle:pos ../../mf.web:194:3: 210 211 // The program begins with a normal \PASCAL\ program heading, whose 212 // components will be filled in later, using the conventions of \.[WEB]. 213 // \xref[WEB] 214 // For example, the portion of the program called `\X\glob:Global 215 // variables\X' below will be replaced by a sequence of variable declarations 216 // that starts in $\section\glob$ of this documentation. In this way, we are able 217 // to define each individual global variable when we are prepared to 218 // understand what it means; we do not have to define all of the globals at 219 // once. Cross references in $\section\glob$, where it says ``See also 220 // sections \gglob, \dots,'' also make it possible to look at the set of 221 // all global variables, if desired. Similar remarks apply to the other 222 // portions of the program heading. 223 // 224 // Actually the heading shown here is not quite normal: The |program| line 225 // does not mention any |output| file, because \ph\ would ask the \MF\ user 226 // to specify a file name if |output| were specified here. 227 // \xref[PASCAL H][\ph] 228 // \xref[system dependencies] 229 // \4 230 // Compiler directives 231 // $C-,A+,D- 232 // no range check, catch arithmetic overflow, no debug overhead 233 // [$C+,D+] [ ] 234 // but turn everything on when debugging 235 236 package trap 237 238 import ( 239 "math" 240 "unsafe" 241 242 "modernc.org/knuth" 243 ) 244 245 var ( 246 _ = math.MaxInt32 247 _ unsafe.Pointer 248 ) 249 250 type ( 251 char = byte 252 signal int 253 ) 254 255 func strcopy(dst []char, src string) { 256 for i := 0; i < len(dst) && i < len(src); i++ { 257 dst[i] = src[i] 258 } 259 } 260 261 func arraystr(a []char) string { 262 b := make([]byte, len(a)) 263 for i, c := range a { 264 b[i] = c 265 } 266 return string(b) 267 } 268 269 func abs(n int32) int32 { 270 if n >= 0 { 271 return n 272 } 273 274 return -n 275 } 276 277 func fabs(f float64) float64 { 278 if f >= 0 { 279 return f 280 } 281 282 return -f 283 } 284 285 func round(f float64) int32 { 286 if f >= 0 { 287 return int32(f + 0.5) 288 } 289 290 return int32(f - 0.5) 291 } 292 293 // key control points 294 295 const ( 296 startOfMf = 1 /* go here when \MF's variables are initialized */ 297 endOfMf = 9998 /* go here to close files and terminate gracefully */ 298 finalEnd = 9999 /* this label marks the ending of the program */ 299 memMin = 0 // smallest index in the |mem| array, must not be less 300 // than |min_halfword| 301 302 hashSize = 2100 // maximum number of symbolic tokens, 303 // must be less than |max_halfword-3*param_size| 304 305 hashPrime = 1777 /* a prime number equal to about 85\pct! of |hash_size| */ 306 maxInOpen = 6 // maximum number of input files and error insertions that 307 // can be going on simultaneously 308 309 paramSize = 150 // maximum number of simultaneous macro parameters 310 // \xref[system dependencies] 311 312 exit = 10 /* go here to leave a procedure */ 313 restart = 20 /* go here to start a procedure again */ 314 reswitch = 21 /* go here to start a case statement again */ 315 continue1 = 22 /* go here to resume a loop */ 316 done = 30 /* go here to exit a loop */ 317 done1 = 31 /* like |done|, when there is more than one loop */ 318 done2 = 32 /* for exiting the second loop in a long block */ 319 done3 = 33 /* for exiting the third loop in a very long block */ 320 done4 = 34 /* for exiting the fourth loop in an extremely long block */ 321 done5 = 35 /* for exiting the fifth loop in an immense block */ 322 done6 = 36 /* for exiting the sixth loop in a block */ 323 found = 40 /* go here when you've found it */ 324 found1 = 41 /* like |found|, when there's more than one per routine */ 325 found2 = 42 /* like |found|, when there's more than two per routine */ 326 notFound = 45 /* go here when you've found nothing */ 327 commonEnding = 50 /* go here when you want to merge with another branch */ 328 firstTextChar = 0 /* ordinal number of the smallest element of |text_char| */ 329 lastTextChar = 255 /* ordinal number of the largest element of |text_char| */ 330 maxStrRef = 127 /* ``infinite'' number of references */ 331 noPrint = 0 /* |selector| setting that makes data disappear */ 332 termOnly = 1 /* printing is destined for the terminal only */ 333 logOnly = 2 /* printing is destined for the transcript file only */ 334 termAndLog = 3 /* normal |selector| setting */ 335 pseudo = 4 /* special |selector| setting for |show_context| */ 336 newString = 5 /* printing is deflected to the string pool */ 337 maxSelector = 5 /* highest selector setting */ 338 batchMode = 0 /* omits all stops and omits terminal output */ 339 nonstopMode = 1 /* omits all stops */ 340 scrollMode = 2 /* omits error stops */ 341 errorStopMode = 3 /* stops at every opportunity to interact */ 342 spotless = 0 /* |history| value when nothing has been amiss yet */ 343 warningIssued = 1 /* |history| value when |begin_diagnostic| has been called */ 344 errorMessageIssued = 2 /* |history| value when |error| has been called */ 345 fatalErrorStop = 3 /* |history| value when termination was premature */ 346 negateX = 1 347 negateY = 2 348 switchXAndY = 4 349 firstOctant = 1 350 secondOctant = firstOctant + switchXAndY 351 thirdOctant = firstOctant + switchXAndY + negateX 352 fourthOctant = firstOctant + negateX 353 fifthOctant = firstOctant + negateX + negateY 354 sixthOctant = firstOctant + switchXAndY + negateX + negateY 355 seventhOctant = firstOctant + switchXAndY + negateY 356 eighthOctant = firstOctant + negateY 357 minQuarterword = 0 /* smallest allowable value in a |quarterword| */ 358 maxQuarterword = 255 /* largest allowable value in a |quarterword| */ 359 ifTest = 1 /* conditional text (\&[if]) */ 360 fiOrElse = 2 /* delimiters for conditionals (\&[elseif], \&[else], \&[fi]) */ 361 input = 3 /* input a source file (\&[input], \&[endinput]) */ 362 iteration = 4 /* iterate (\&[for], \&[forsuffixes], \&[forever], \&[endfor]) */ 363 repeatLoop = 5 /* special command substituted for \&[endfor] */ 364 exitTest = 6 /* premature exit from a loop (\&[exitif]) */ 365 relax = 7 /* do nothing (\.[\char`\\]) */ 366 scanTokens = 8 /* put a string into the input buffer */ 367 expandAfter = 9 /* look ahead one token */ 368 definedMacro = 10 /* a macro defined by the user */ 369 minCommand = definedMacro + 1 370 displayCommand = 11 /* online graphic output (\&[display]) */ 371 saveCommand = 12 /* save a list of tokens (\&[save]) */ 372 interimCommand = 13 /* save an internal quantity (\&[interim]) */ 373 letCommand = 14 /* redefine a symbolic token (\&[let]) */ 374 newInternal = 15 /* define a new internal quantity (\&[newinternal]) */ 375 macroDef = 16 /* define a macro (\&[def], \&[vardef], etc.) */ 376 shipOutCommand = 17 /* output a character (\&[shipout]) */ 377 addToCommand = 18 /* add to edges (\&[addto]) */ 378 cullCommand = 19 /* cull and normalize edges (\&[cull]) */ 379 tfmCommand = 20 /* command for font metric info (\&[ligtable], etc.) */ 380 protectionCommand = 21 /* set protection flag (\&[outer], \&[inner]) */ 381 showCommand = 22 /* diagnostic output (\&[show], \&[showvariable], etc.) */ 382 modeCommand = 23 /* set interaction level (\&[batchmode], etc.) */ 383 randomSeed = 24 /* initialize random number generator (\&[randomseed]) */ 384 messageCommand = 25 /* communicate to user (\&[message], \&[errmessage]) */ 385 everyJobCommand = 26 /* designate a starting token (\&[everyjob]) */ 386 delimiters = 27 /* define a pair of delimiters (\&[delimiters]) */ 387 openWindow = 28 /* define a window on the screen (\&[openwindow]) */ 388 specialCommand = 29 /* output special info (\&[special], \&[numspecial]) */ 389 typeName = 30 /* declare a type (\&[numeric], \&[pair], etc.) */ 390 maxStatementCommand = typeName 391 minPrimaryCommand = typeName 392 leftDelimiter = 31 /* the left delimiter of a matching pair */ 393 beginGroup = 32 /* beginning of a group (\&[begingroup]) */ 394 nullary = 33 /* an operator without arguments (e.g., \&[normaldeviate]) */ 395 unary = 34 /* an operator with one argument (e.g., \&[sqrt]) */ 396 strOp = 35 /* convert a suffix to a string (\&[str]) */ 397 cycle = 36 /* close a cyclic path (\&[cycle]) */ 398 primaryBinary = 37 /* binary operation taking `\&[of]' (e.g., \&[point]) */ 399 capsuleToken = 38 /* a value that has been put into a token list */ 400 stringToken = 39 /* a string constant (e.g., |"hello"|) */ 401 internalQuantity = 40 /* internal numeric parameter (e.g., \&[pausing]) */ 402 minSuffixToken = internalQuantity 403 tagToken = 41 /* a symbolic token without a primitive meaning */ 404 numericToken = 42 /* a numeric constant (e.g., \.[3.14159]) */ 405 maxSuffixToken = numericToken 406 plusOrMinus = 43 /* either `\.+' or `\.-' */ 407 maxPrimaryCommand = plusOrMinus /* should also be |numeric_token+1| */ 408 minTertiaryCommand = plusOrMinus 409 tertiarySecondaryMacro = 44 /* a macro defined by \&[secondarydef] */ 410 tertiaryBinary = 45 /* an operator at the tertiary level (e.g., `\.[++]') */ 411 maxTertiaryCommand = tertiaryBinary 412 leftBrace = 46 /* the operator `\.[\char`\[]' */ 413 minExpressionCommand = leftBrace 414 pathJoin = 47 /* the operator `\.[..]' */ 415 ampersand = 48 /* the operator `\.\&' */ 416 expressionTertiaryMacro = 49 /* a macro defined by \&[tertiarydef] */ 417 expressionBinary = 50 /* an operator at the expression level (e.g., `\.<') */ 418 equals = 51 /* the operator `\.=' */ 419 maxExpressionCommand = equals 420 andCommand = 52 /* the operator `\&[and]' */ 421 minSecondaryCommand = andCommand 422 secondaryPrimaryMacro = 53 /* a macro defined by \&[primarydef] */ 423 slash = 54 /* the operator `\./' */ 424 secondaryBinary = 55 /* an operator at the binary level (e.g., \&[shifted]) */ 425 maxSecondaryCommand = secondaryBinary 426 paramType = 56 /* type of parameter (\&[primary], \&[expr], \&[suffix], etc.) */ 427 controls = 57 /* specify control points explicitly (\&[controls]) */ 428 tension = 58 /* specify tension between knots (\&[tension]) */ 429 atLeast = 59 /* bounded tension value (\&[atleast]) */ 430 curlCommand = 60 /* specify curl at an end knot (\&[curl]) */ 431 macroSpecial = 61 /* special macro operators (\&[quote], \.[\#\AT!], etc.) */ 432 rightDelimiter = 62 /* the right delimiter of a matching pair */ 433 leftBracket = 63 /* the operator `\.[' */ 434 rightBracket = 64 /* the operator `\.]' */ 435 rightBrace = 65 /* the operator `\.[\char`\]]' */ 436 withOption = 66 /* option for filling (\&[withpen], \&[withweight]) */ 437 cullOp = 67 /* the operator `\&[keeping]' or `\&[dropping]' */ 438 thingToAdd = 68 439 /* variant of \&[addto] (\&[contour], \&[doublepath], \&[also]) */ 440 ofToken = 69 /* the operator `\&[of]' */ 441 fromToken = 70 /* the operator `\&[from]' */ 442 toToken = 71 /* the operator `\&[to]' */ 443 atToken = 72 /* the operator `\&[at]' */ 444 inWindow = 73 /* the operator `\&[inwindow]' */ 445 stepToken = 74 /* the operator `\&[step]' */ 446 untilToken = 75 /* the operator `\&[until]' */ 447 ligKernToken = 76 448 /* the operators `\&[kern]' and `\.[=:]' and `\.[=:\char'174]', etc. */ 449 assignment = 77 /* the operator `\.[:=]' */ 450 skipTo = 78 /* the operation `\&[skipto]' */ 451 bcharLabel = 79 /* the operator `\.[\char'174\char'174:]' */ 452 doubleColon = 80 /* the operator `\.[::]' */ 453 colon = 81 /* the operator `\.:' */ 454 comma = 82 /* the operator `\.,', must be |colon+1| */ 455 semicolon = 83 /* the operator `\.;', must be |comma+1| */ 456 endGroup = 84 /* end a group (\&[endgroup]), must be |semicolon+1| */ 457 stop = 85 /* end a job (\&[end], \&[dump]), must be |end_group+1| */ 458 maxCommandCode = stop 459 outerTag = maxCommandCode + 1 /* protection code added to command code */ 460 undefined = 0 /* no type has been declared */ 461 unknownTag = 1 /* this constant is added to certain type codes below */ 462 vacuous = 1 /* no expression was present */ 463 booleanType = 2 /* \&[boolean] with a known value */ 464 unknownBoolean = booleanType + unknownTag 465 stringType = 4 /* \&[string] with a known value */ 466 unknownString = stringType + unknownTag 467 penType = 6 /* \&[pen] with a known value */ 468 unknownPen = penType + unknownTag 469 futurePen = 8 /* subexpression that will become a \&[pen] at a higher level */ 470 pathType = 9 /* \&[path] with a known value */ 471 unknownPath = pathType + unknownTag 472 pictureType = 11 /* \&[picture] with a known value */ 473 unknownPicture = pictureType + unknownTag 474 transformType = 13 /* \&[transform] variable or capsule */ 475 pairType = 14 /* \&[pair] variable or capsule */ 476 numericType = 15 /* variable that has been declared \&[numeric] but not used */ 477 known = 16 /* \&[numeric] with a known value */ 478 dependent = 17 /* a linear combination with |fraction| coefficients */ 479 protoDependent = 18 /* a linear combination with |scaled| coefficients */ 480 independent = 19 /* \&[numeric] with unknown value */ 481 tokenList = 20 /* variable name or suffix argument or text argument */ 482 structured = 21 /* variable with subscripts and attributes */ 483 unsuffixedMacro = 22 /* variable defined with \&[vardef] but no \.[\AT!\#] */ 484 suffixedMacro = 23 /* variable defined with \&[vardef] and \.[\AT!\#] */ 485 root = 0 /* |name_type| at the top level of a variable */ 486 savedRoot = 1 /* same, when the variable has been saved */ 487 structuredRoot = 2 /* |name_type| where a |structured| branch occurs */ 488 subscr = 3 /* |name_type| in a subscript node */ 489 attr = 4 /* |name_type| in an attribute node */ 490 xPartSector = 5 /* |name_type| in the \&[xpart] of a node */ 491 yPartSector = 6 /* |name_type| in the \&[ypart] of a node */ 492 xxPartSector = 7 /* |name_type| in the \&[xxpart] of a node */ 493 xyPartSector = 8 /* |name_type| in the \&[xypart] of a node */ 494 yxPartSector = 9 /* |name_type| in the \&[yxpart] of a node */ 495 yyPartSector = 10 /* |name_type| in the \&[yypart] of a node */ 496 capsule = 11 /* |name_type| in stashed-away subexpressions */ 497 token = 12 /* |name_type| in a numeric token or string token */ 498 trueCode = 30 /* operation code for \.[true] */ 499 falseCode = 31 /* operation code for \.[false] */ 500 nullPictureCode = 32 /* operation code for \.[nullpicture] */ 501 nullPenCode = 33 /* operation code for \.[nullpen] */ 502 jobNameOp = 34 /* operation code for \.[jobname] */ 503 readStringOp = 35 /* operation code for \.[readstring] */ 504 penCircle = 36 /* operation code for \.[pencircle] */ 505 normalDeviate = 37 /* operation code for \.[normaldeviate] */ 506 oddOp = 38 /* operation code for \.[odd] */ 507 knownOp = 39 /* operation code for \.[known] */ 508 unknownOp = 40 /* operation code for \.[unknown] */ 509 notOp = 41 /* operation code for \.[not] */ 510 decimal = 42 /* operation code for \.[decimal] */ 511 reverse = 43 /* operation code for \.[reverse] */ 512 makePathOp = 44 /* operation code for \.[makepath] */ 513 makePenOp = 45 /* operation code for \.[makepen] */ 514 totalWeightOp = 46 /* operation code for \.[totalweight] */ 515 octOp = 47 /* operation code for \.[oct] */ 516 hexOp = 48 /* operation code for \.[hex] */ 517 asciiOp = 49 /* operation code for \.[ASCII] */ 518 charOp = 50 /* operation code for \.[char] */ 519 lengthOp = 51 /* operation code for \.[length] */ 520 turningOp = 52 /* operation code for \.[turningnumber] */ 521 xPart = 53 /* operation code for \.[xpart] */ 522 yPart = 54 /* operation code for \.[ypart] */ 523 xxPart = 55 /* operation code for \.[xxpart] */ 524 xyPart = 56 /* operation code for \.[xypart] */ 525 yxPart = 57 /* operation code for \.[yxpart] */ 526 yyPart = 58 /* operation code for \.[yypart] */ 527 sqrtOp = 59 /* operation code for \.[sqrt] */ 528 mExpOp = 60 /* operation code for \.[mexp] */ 529 mLogOp = 61 /* operation code for \.[mlog] */ 530 sinDOp = 62 /* operation code for \.[sind] */ 531 cosDOp = 63 /* operation code for \.[cosd] */ 532 floorOp = 64 /* operation code for \.[floor] */ 533 uniformDeviate = 65 /* operation code for \.[uniformdeviate] */ 534 charExistsOp = 66 /* operation code for \.[charexists] */ 535 angleOp = 67 /* operation code for \.[angle] */ 536 cycleOp = 68 /* operation code for \.[cycle] */ 537 plus = 69 /* operation code for \.+ */ 538 minus = 70 /* operation code for \.- */ 539 times = 71 /* operation code for \.* */ 540 over = 72 /* operation code for \./ */ 541 pythagAdd = 73 /* operation code for \.[++] */ 542 pythagSub = 74 /* operation code for \.[+-+] */ 543 orOp = 75 /* operation code for \.[or] */ 544 andOp = 76 /* operation code for \.[and] */ 545 lessThan = 77 /* operation code for \.< */ 546 lessOrEqual = 78 /* operation code for \.[<=] */ 547 greaterThan = 79 /* operation code for \.> */ 548 greaterOrEqual = 80 /* operation code for \.[>=] */ 549 equalTo = 81 /* operation code for \.= */ 550 unequalTo = 82 /* operation code for \.[<>] */ 551 concatenate = 83 /* operation code for \.\& */ 552 rotatedBy = 84 /* operation code for \.[rotated] */ 553 slantedBy = 85 /* operation code for \.[slanted] */ 554 scaledBy = 86 /* operation code for \.[scaled] */ 555 shiftedBy = 87 /* operation code for \.[shifted] */ 556 transformedBy = 88 /* operation code for \.[transformed] */ 557 xScaled = 89 /* operation code for \.[xscaled] */ 558 yScaled = 90 /* operation code for \.[yscaled] */ 559 zScaled = 91 /* operation code for \.[zscaled] */ 560 intersect = 92 /* operation code for \.[intersectiontimes] */ 561 doubleDot = 93 /* operation code for improper \.[..] */ 562 substringOf = 94 /* operation code for \.[substring] */ 563 minOf = substringOf 564 subpathOf = 95 /* operation code for \.[subpath] */ 565 directionTimeOf = 96 /* operation code for \.[directiontime] */ 566 pointOf = 97 /* operation code for \.[point] */ 567 precontrolOf = 98 /* operation code for \.[precontrol] */ 568 postcontrolOf = 99 /* operation code for \.[postcontrol] */ 569 penOffsetOf = 100 /* operation code for \.[penoffset] */ 570 tracingTitles = 1 /* show titles online when they appear */ 571 tracingEquations = 2 /* show each variable when it becomes known */ 572 tracingCapsules = 3 /* show capsules too */ 573 tracingChoices = 4 /* show the control points chosen for paths */ 574 tracingSpecs = 5 /* show subdivision of paths into octants before digitizing */ 575 tracingPens = 6 /* show details of pens that are made */ 576 tracingCommands = 7 /* show commands and operations before they are performed */ 577 tracingRestores = 8 /* show when a variable or internal is restored */ 578 tracingMacros = 9 /* show macros before they are expanded */ 579 tracingEdges = 10 /* show digitized edges as they are computed */ 580 tracingOutput = 11 /* show digitized edges as they are output */ 581 tracingStats = 12 /* show memory usage at end of job */ 582 tracingOnline = 13 /* show long diagnostics on terminal and in the log file */ 583 year = 14 /* the current year (e.g., 1984) */ 584 month = 15 /* the current month (e.g., 3 $\equiv$ March) */ 585 day = 16 /* the current day of the month */ 586 time = 17 /* the number of minutes past midnight when this job started */ 587 charCode = 18 /* the number of the next character to be output */ 588 charExt = 19 /* the extension code of the next character to be output */ 589 charWd = 20 /* the width of the next character to be output */ 590 charHt = 21 /* the height of the next character to be output */ 591 charDp = 22 /* the depth of the next character to be output */ 592 charIc = 23 /* the italic correction of the next character to be output */ 593 charDx = 24 /* the device's $x$ movement for the next character, in pixels */ 594 charDy = 25 /* the device's $y$ movement for the next character, in pixels */ 595 designSize = 26 /* the unit of measure used for |char_wd..char_ic|, in points */ 596 hppp = 27 /* the number of horizontal pixels per point */ 597 vppp = 28 /* the number of vertical pixels per point */ 598 xOffset = 29 /* horizontal displacement of shipped-out characters */ 599 yOffset = 30 /* vertical displacement of shipped-out characters */ 600 pausing = 31 /* positive to display lines on the terminal before they are read */ 601 showstopping = 32 /* positive to stop after each \&[show] command */ 602 fontmaking = 33 /* positive if font metric output is to be produced */ 603 proofing = 34 /* positive for proof mode, negative to suppress output */ 604 smoothing = 35 /* positive if moves are to be ``smoothed'' */ 605 autorounding = 36 /* controls path modification to ``good'' points */ 606 granularity = 37 /* autorounding uses this pixel size */ 607 fillin = 38 /* extra darkness of diagonal lines */ 608 turningCheck = 39 /* controls reorientation of clockwise paths */ 609 warningCheck = 40 /* controls error message when variable value is large */ 610 boundaryChar = 41 /* the boundary character for ligatures */ 611 maxGivenInternal = 41 612 digitClass = 0 /* the class number of \.[0123456789] */ 613 periodClass = 1 /* the class number of `\..' */ 614 spaceClass = 2 /* the class number of spaces and nonstandard characters */ 615 percentClass = 3 /* the class number of `\.\%' */ 616 stringClass = 4 /* the class number of `\."' */ 617 rightParenClass = 8 /* the class number of `\.)' */ 618 letterClass = 9 /* letters and the underline character */ 619 leftBracketClass = 17 /* `\.[' */ 620 rightBracketClass = 18 /* `\.]' */ 621 invalidClass = 20 /* bad character in the input */ 622 maxClass = 20 /* the largest class number */ 623 hashBase = 257 /* hashing actually starts here */ 624 tokenNodeSize = 2 /* the number of words in a large token node */ 625 generalMacro = 0 /* preface to a macro defined with a parameter list */ 626 primaryMacro = 1 /* preface to a macro with a \&[primary] parameter */ 627 secondaryMacro = 2 /* preface to a macro with a \&[secondary] parameter */ 628 tertiaryMacro = 3 /* preface to a macro with a \&[tertiary] parameter */ 629 exprMacro = 4 /* preface to a macro with an undelimited \&[expr] parameter */ 630 ofMacro = 5 // preface to a macro with 631 // undelimited `\&[expr] |x| \&[of]~|y|' parameters 632 633 suffixMacro = 6 /* preface to a macro with an undelimited \&[suffix] parameter */ 634 textMacro = 7 /* preface to a macro with an undelimited \&[text] parameter */ 635 valueNodeSize = 2 /* the number of words in a value node */ 636 attrNodeSize = 3 /* the number of words in an attribute node */ 637 subscrNodeSize = 3 /* the number of words in a subscript node */ 638 collectiveSubscript = 0 /* code for the attribute `\.[[]]' */ 639 pairNodeSize = 4 /* the number of words in a pair node */ 640 transformNodeSize = 12 /* the number of words in a transform node */ 641 saveNodeSize = 2 /* number of words per non-boundary save-stack node */ 642 endpoint = 0 /* |left_type| at path beginning and |right_type| at path end */ 643 knotNodeSize = 7 /* number of words in a knot node */ 644 explicit = 1 /* |left_type| or |right_type| when control points are known */ 645 given = 2 /* |left_type| or |right_type| when a direction is given */ 646 curl = 3 /* |left_type| or |right_type| when a curl is desired */ 647 open = 4 /* |left_type| or |right_type| when \MF\ should choose the direction */ 648 endCycle = open + 1 649 moveIncrement = 11 /* number of items pushed by |make_moves| */ 650 zeroW = 4 651 rowNodeSize = 2 /* number of words in a row header node */ 652 zeroField = 4096 /* amount added to coordinates to make them positive */ 653 edgeHeaderSize = 6 /* number of words in an edge-structure header */ 654 fastCaseUp = 60 /* for octants 1 and 4 */ 655 fastCaseDown = 61 /* for octants 5 and 8 */ 656 slowCaseUp = 62 /* for octants 2 and 3 */ 657 slowCaseDown = 63 /* for octants 6 and 7 */ 658 axis = 0 /* a transition across the $x'$- or $y'$-axis */ 659 diagonal = 1 /* a transition where $y'=\pm x'$ */ 660 doublePathCode = 0 /* command modifier for `\&[doublepath]' */ 661 contourCode = 1 /* command modifier for `\&[contour]' */ 662 alsoCode = 2 /* command modifier for `\&[also]' */ 663 penNodeSize = 10 664 coordNodeSize = 3 665 intPackets = 20 /* number of words to represent $U_k$, $V_k$, $X_k$, and $Y_k$ */ 666 intIncrement = intPackets + intPackets + 5 /* number of stack words per level */ 667 maxPatience = 5000 668 white = 0 /* background pixels */ 669 black = 1 /* visible pixels */ 670 sScale = 64 /* the serial numbers are multiplied by this factor */ 671 depNodeSize = 2 /* the number of words per dependency node */ 672 independentNeedingFix = 0 673 fractionThreshold = 2685 /* a |fraction| coefficient less than this is zeroed */ 674 halfFractionThreshold = 1342 /* half of |fraction_threshold| */ 675 scaledThreshold = 8 /* a |scaled| coefficient less than this is zeroed */ 676 halfScaledThreshold = 4 /* half of |scaled_threshold| */ 677 independentBeingFixed = 1 /* this variable already appears in |s| */ 678 foreverText = maxInOpen + 1 /* |token_type| code for loop texts */ 679 loopText = maxInOpen + 2 /* |token_type| code for loop texts */ 680 parameter = maxInOpen + 3 /* |token_type| code for parameter texts */ 681 backedUp = maxInOpen + 4 /* |token_type| code for texts to be reread */ 682 inserted = maxInOpen + 5 /* |token_type| code for inserted texts */ 683 macro = maxInOpen + 6 /* |token_type| code for macro replacement texts */ 684 normal = 0 /* |scanner_status| at ``quiet times'' */ 685 skipping = 1 /* |scanner_status| when false conditional text is being skipped */ 686 flushing = 2 /* |scanner_status| when junk after a statement is being ignored */ 687 absorbing = 3 /* |scanner_status| when a \&[text] parameter is being scanned */ 688 varDefining = 4 /* |scanner_status| when a \&[vardef] is being scanned */ 689 opDefining = 5 /* |scanner_status| when a macro \&[def] is being scanned */ 690 loopDefining = 6 /* |scanner_status| when a \&[for] loop is being scanned */ 691 switch1 = 25 /* a label in |get_next| */ 692 startNumericToken = 85 /* another */ 693 startDecimalToken = 86 /* and another */ 694 finNumericToken = 87 695 /* and still another, although |goto| is considered harmful */ 696 startDef = 1 /* command modifier for \&[def] */ 697 varDef = 2 /* command modifier for \&[vardef] */ 698 endDef = 0 /* command modifier for \&[enddef] */ 699 startForever = 1 /* command modifier for \&[forever] */ 700 endFor = 0 /* command modifier for \&[endfor] */ 701 quote = 0 /* |macro_special| modifier for \&[quote] */ 702 macroPrefix = 1 /* |macro_special| modifier for \.[\#\AT!] */ 703 macroAt = 2 /* |macro_special| modifier for \.[\AT!] */ 704 macroSuffix = 3 /* |macro_special| modifier for \.[\AT!\#] */ 705 ifNodeSize = 2 /* number of words in stack entry for conditionals */ 706 ifCode = 1 /* code for \&[if] being evaluated */ 707 fiCode = 2 /* code for \&[fi] */ 708 elseCode = 3 /* code for \&[else] */ 709 elseIfCode = 4 /* code for \&[elseif] */ 710 loopNodeSize = 2 /* the number of words in a loop control node */ 711 progressionNodeSize = 4 /* the number of words in a progression node */ 712 baseDefaultLength = 18 /* length of the |MF_base_default| string */ 713 baseAreaLength = 8 /* length of its area part */ 714 baseExtLength = 5 /* length of its `\.[.base]' part */ 715 baseExtension = /* ".base" */ 742 /* the extension, as a \.[WEB] constant */ 716 continuePath = 25 /* a label inside of |scan_expression| */ 717 finishPath = 26 /* another */ 718 showTokenCode = 0 /* show the meaning of a single token */ 719 showStatsCode = 1 /* show current memory and string usage */ 720 showCode = 2 /* show a list of expressions */ 721 showVarCode = 3 /* show a variable and its descendents */ 722 showDependenciesCode = 4 /* show dependent variables in terms of independents */ 723 dropCode = 0 /* command modifier for `\&[dropping]' */ 724 keepCode = 1 /* command modifier for `\&[keeping]' */ 725 messageCode = 0 726 errMessageCode = 1 727 errHelpCode = 2 728 noTag = 0 /* vanilla character */ 729 ligTag = 1 /* character has a ligature/kerning program */ 730 listTag = 2 /* character has a successor in a charlist */ 731 extTag = 3 /* character is extensible */ 732 stopFlag = 128 + minQuarterword 733 /* value indicating `\.[STOP]' in a lig/kern program */ 734 kernFlag = 128 + minQuarterword /* op code for a kern step */ 735 slantCode = 1 736 spaceCode = 2 737 spaceStretchCode = 3 738 spaceShrinkCode = 4 739 xHeightCode = 5 740 quadCode = 6 741 extraSpaceCode = 7 742 charListCode = 0 743 ligTableCode = 1 744 extensibleCode = 2 745 headerByteCode = 3 746 fontDimenCode = 4 747 gfIdByte = 131 /* identifies the kind of \.[GF] files described here */ 748 paint0 = 0 /* beginning of the \\[paint] commands */ 749 paint1 = 64 // move right a given number of columns, then 750 // black$[]\swap[]$white 751 752 boc = 67 /* beginning of a character */ 753 boc1 = 68 /* short form of |boc| */ 754 eoc = 69 /* end of a character */ 755 skip0 = 70 /* skip no blank rows */ 756 skip1 = 71 /* skip over blank rows */ 757 newRow0 = 74 /* move down one row and then right */ 758 maxNewRow = 164 /* the largest \\[new\_row] command is |new_row_164| */ 759 xxx1 = 239 /* for \&[special] strings */ 760 xxx3 = 241 /* for long \&[special] strings */ 761 yyy = 243 /* for \&[numspecial] numbers */ 762 charLoc = 245 /* character locators in the postamble */ 763 pre = 247 /* preamble */ 764 post = 248 /* postamble beginning */ 765 postPost = 249 /* postamble ending */ 766 offBase = 6666 /* go here if the base file is unacceptable */ 767 breakpoint = 888 /* place where a breakpoint is desirable */ 768 769 // Constants in the outer block 770 memMax = 3000 // greatest index in \MF's internal |mem| array; 771 // must be strictly less than |max_halfword|; 772 // must be equal to |mem_top| in \.[INIMF], otherwise |>=mem_top| 773 774 maxInternal = 100 // maximum number of internal quantities 775 bufSize = 500 // maximum number of characters simultaneously present in 776 // current lines of open files; must not exceed |max_halfword| 777 778 errorLine = 64 // width of context lines on terminal error messages 779 halfErrorLine = 32 // width of first lines of contexts in terminal 780 // error messages; should be between 30 and |error_line-15| 781 782 maxPrintLine = 72 // width of longest text lines output; should be at least 60 783 screenWidth = 100 // number of pixels in each row of screen display 784 screenDepth = 200 // number of pixels in each column of screen display 785 stackSize = 30 // maximum number of simultaneous input sources 786 maxStrings = 2000 // maximum number of strings; must not exceed |max_halfword| 787 stringVacancies = 8000 // the minimum number of characters that should be 788 // available for the user's identifier names and strings, 789 // after \MF's own error messages are stored 790 791 poolSize = 32000 // maximum number of characters in strings, including all 792 // error messages and help texts, and the names of all identifiers; 793 // must exceed |string_vacancies| by the total 794 // length of \MF's own strings, which is currently about 22000 795 796 moveSize = 5000 // space for storing moves in a single octant 797 maxWiggle = 300 // number of autorounded points per cycle 798 gfBufSize = 8 // size of the output buffer, must be a multiple of 8 799 fileNameSize = 40 // file names shouldn't be longer than this 800 poolName = "MFbases:MF.POOL " 801 // string of length |file_name_size|; tells where the string pool appears 802 // \xref[MFbases] 803 pathSize = 300 // maximum number of knots between breakpoints of a path 804 bistackSize = 785 // size of stack for bisection algorithms; 805 // should probably be left at this value 806 807 headerSize = 100 // maximum number of \.[TFM] header words, times~4 808 ligTableSize = 5000 // maximum number of ligature/kern steps, must be 809 // at least 255 and at most 32510 810 811 maxKerns = 500 // maximum number of distinct kern amounts 812 maxFontDimen = 50 // maximum number of \&[fontdimen] parameters 813 ) 814 815 type ( 816 // Types in the outer block 817 asciiCode = /* 0..255 */ byte // eight-bit numbers 818 819 eightBits = /* 0..255 */ byte // unsigned one-byte quantity 820 alphaFile = knuth.File // files that contain textual data 821 byteFile = knuth.File // files that contain binary data 822 823 poolPointer = /* 0..poolSize */ uint16 // for variables that point into |str_pool| 824 strNumber = /* 0..maxStrings */ uint16 // for variables that point into |str_start| 825 packedAsciiCode = /* 0..255 */ byte // elements of |str_pool| array 826 827 scaled = int32 // this type is used for scaled integers 828 smallNumber = /* 0..63 */ byte // this type is self-explanatory 829 830 fraction = int32 // this type is used for scaled fractions 831 832 angle = int32 // this type is used for scaled angles 833 834 quarterword = /* minQuarterword..maxQuarterword */ byte // 1/4 of a word 835 halfword = /* 0..65535 */ uint16 // 1/2 of a word 836 twoChoices = /* 1..2 */ byte // used when there are two variants in a record 837 threeChoices = /* 1..3 */ byte // used when there are three variants in a record 838 twoHalves struct{ data uint32 } 839 fourQuarters = struct { 840 b0 quarterword 841 b1 quarterword 842 b2 quarterword 843 b3 quarterword 844 } 845 memoryWord struct{ data uint32 } 846 wordFile = knuth.File 847 848 commandCode = /* 1..maxCommandCode */ byte 849 850 screenRow = /* 0..screenDepth */ byte // a row number on the screen 851 screenCol = /* 0..screenWidth */ byte // a column number on the screen 852 transSpec [101]screenCol // a transition spec, see below 853 pixelColor = /* white..black */ byte // specifies one of the two pixel values 854 855 windowNumber = /* 0..15 */ byte 856 857 inStateRecord = struct { 858 indexField quarterword 859 startField, locField, limitField, nameField halfword 860 } 861 862 gfIndex = /* 0..gfBufSize */ byte // an index into the output buffer 863 ) 864 865 func (r *memoryWord) hh() *twoHalves { 866 return (*twoHalves)(unsafe.Add(unsafe.Pointer(&r.data), 0)) 867 } 868 869 func (r *memoryWord) int() *int32 { 870 return (*int32)(unsafe.Add(unsafe.Pointer(&r.data), 0)) 871 } 872 873 func (r *memoryWord) qqqq() *fourQuarters { 874 return (*fourQuarters)(unsafe.Add(unsafe.Pointer(&r.data), 0)) 875 } 876 877 func (r *twoHalves) b0() *quarterword { 878 return (*quarterword)(unsafe.Add(unsafe.Pointer(&r.data), 2)) 879 } 880 881 func (r *twoHalves) b1() *quarterword { 882 return (*quarterword)(unsafe.Add(unsafe.Pointer(&r.data), 3)) 883 } 884 885 func (r *twoHalves) lh() *halfword { 886 return (*halfword)(unsafe.Add(unsafe.Pointer(&r.data), 2)) 887 } 888 889 func (r *twoHalves) rh() *halfword { 890 return (*halfword)(unsafe.Add(unsafe.Pointer(&r.data), 0)) 891 } 892 893 type prg struct { 894 stdin, stdout, stderr knuth.File 895 // Global variables 896 bad int32 // is some ``constant'' wrong? 897 898 xord [256]asciiCode 899 // specifies conversion of input characters 900 xchr [256]char 901 // specifies conversion of output characters 902 903 nameOfFile [40]char 904 905 // on some systems this may be a \&[record] variable 906 nameLength/* 0..fileNameSize */ byte 907 // this many characters are actually 908 // relevant in |name_of_file| (the rest are blank) 909 910 buffer [501]asciiCode // lines of characters being read 911 first/* 0..bufSize */ uint16 // the first unused position in |buffer| 912 last/* 0..bufSize */ uint16 // end of the line just input to |buffer| 913 maxBufStack/* 0..bufSize */ uint16 // largest index used in |buffer| 914 915 termIn alphaFile // the terminal as an input file 916 termOut alphaFile // the terminal as an output file 917 918 strPool [32001]packedAsciiCode // the characters 919 strStart [2001]poolPointer // the starting pointers 920 poolPtr poolPointer // first unused position in |str_pool| 921 strPtr strNumber // number of the current string being created 922 initPoolPtr poolPointer // the starting value of |pool_ptr| 923 initStrPtr strNumber // the starting value of |str_ptr| 924 maxPoolPtr poolPointer // the maximum so far of |pool_ptr| 925 maxStrPtr strNumber // the maximum so far of |str_ptr| 926 927 strRef [2001] /* 0..maxStrRef */ byte 928 929 poolFile alphaFile // the string-pool file output by \.[TANGLE] 930 931 logFile alphaFile // transcript of \MF\ session 932 selector/* 0..maxSelector */ byte // where to print a message 933 dig [23] /* 0..15 */ byte // digits in a number being output 934 tally int32 // the number of characters recently printed 935 termOffset/* 0..maxPrintLine */ byte 936 // the number of characters on the current terminal line 937 fileOffset/* 0..maxPrintLine */ byte 938 // the number of characters on the current file line 939 trickBuf [65]asciiCode // circular buffer for 940 // pseudoprinting 941 942 trickCount int32 // threshold for pseudoprinting, explained later 943 firstCount int32 // another variable for pseudoprinting 944 945 interaction/* batchMode..errorStopMode */ byte // current level of interaction 946 947 deletionsAllowed bool // is it safe for |error| to call |get_next|? 948 history/* spotless..fatalErrorStop */ byte // has the source input been clean so far? 949 errorCount/* -1..100 */ int8 // the number of scrolled errors since the 950 // last statement ended 951 952 helpLine [6]strNumber // helps for the next |error| 953 helpPtr/* 0..6 */ byte // the number of help lines present 954 useErrHelp bool // should the |err_help| string be shown? 955 errHelp strNumber // a string set up by \&[errhelp] 956 957 interrupt int32 // should \MF\ pause for instructions? 958 okToInterrupt bool // should interrupts be observed? 959 960 arithError bool // has arithmetic overflow occurred recently? 961 962 twoToThe [31]int32 // powers of two 963 specLog [28]int32 // special logarithms 964 965 specAtan [26]angle // $\arctan2^[-k]$ times $2^[20]\cdot180/\pi$ 966 967 nSin, nCos fraction // results computed by |n_sin_cos| 968 969 randoms [55]fraction // the last 55 random values generated 970 jRandom/* 0..54 */ byte // the number of unused |randoms| 971 972 mem [3001]memoryWord // the big dynamic storage area 973 loMemMax halfword // the largest location of variable-size memory in use 974 hiMemMin halfword // the smallest location of one-word memory in use 975 976 varUsed, dynUsed int32 // how much memory is in use 977 978 avail halfword // head of the list of available one-word nodes 979 memEnd halfword // the last one-word node used in |mem| 980 981 rover halfword // points to some node in the list of empties 982 983 // free: packed array [mem_min..mem_max] of boolean; [free cells] 984 // [ \hskip1em ] was_free: packed array [mem_min..mem_max] of boolean; 985 // [previously free cells] 986 // [ \hskip1em ] was_mem_end, was_lo_max, was_hi_min: halfword ; 987 // [previous |mem_end|, |lo_mem_max|, and |hi_mem_min|] 988 // [ \hskip1em ] panicking:boolean; [do we want to check memory constantly?] 989 // [ ] 990 991 internal [100]scaled 992 // the values of internal quantities 993 intName [100]strNumber 994 // their names 995 intPtr/* maxGivenInternal..maxInternal */ byte 996 // the maximum internal quantity defined so far 997 998 oldSetting/* 0..maxSelector */ byte 999 sysTime, sysDay, sysMonth, sysYear int32 1000 // date and time supplied by external system 1001 1002 charClass [256] /* 0..maxClass */ byte // the class numbers 1003 1004 hashUsed halfword // allocation pointer for |hash| 1005 stCount int32 // total number of known identifiers 1006 1007 hash [2369]twoHalves // the hash table 1008 eqtb [2369]twoHalves // the equivalents 1009 1010 gPointer halfword // (global) parameter to the |forward| procedures 1011 1012 bigNodeSize [2]smallNumber 1013 1014 savePtr halfword // the most recently saved item 1015 1016 pathTail halfword // the node that links to the beginning of a path 1017 1018 deltaX, deltaY, delta [301]scaled // knot differences 1019 psi [300]angle // turning angles 1020 1021 theta [301]angle // values of $\theta_k$ 1022 uu [301]fraction // values of $u_k$ 1023 vv [301]angle // values of $v_k$ 1024 ww [301]fraction // values of $w_k$ 1025 1026 st, ct, sf, cf fraction // sines and cosines 1027 1028 move [5001]int32 // the recorded moves 1029 movePtr/* 0..moveSize */ uint16 // the number of items in the |move| list 1030 1031 bisectStack [786]int32 1032 bisectPtr/* 0..bistackSize */ uint16 1033 1034 curEdges halfword // the edge structure of current interest 1035 curWt int32 // the edge weight of current interest 1036 1037 traceX int32 // $x$~coordinate most recently shown in a trace 1038 traceY int32 // $y$~coordinate most recently shown in a trace 1039 traceYy int32 // $y$~coordinate most recently encountered 1040 1041 octant/* firstOctant..sixthOctant */ byte // the current octant of interest 1042 1043 curX, curY scaled 1044 // outputs of |skew|, |unskew|, and a few other routines 1045 1046 octantDir [8]strNumber 1047 1048 curSpec halfword // the principal output of |make_spec| 1049 turningNumber int32 // another output of |make_spec| 1050 curPen halfword // an implicit input of |make_spec|, used in autorounding 1051 curPathType/* doublePathCode..contourCode */ byte // likewise 1052 maxAllowed scaled // coordinates must be at most this big 1053 1054 before, after [301]scaled // data for |make_safe| 1055 nodeToRound [301]halfword // reference back to the path 1056 curRoundingPtr/* 0..maxWiggle */ uint16 // how many are being used 1057 maxRoundingPtr/* 0..maxWiggle */ uint16 // how many have been used 1058 1059 curGran scaled // the current granularity (which normally is |unity|) 1060 1061 octantNumber [8] /* 1..8 */ byte 1062 octantCode [8] /* firstOctant..sixthOctant */ byte 1063 1064 revTurns bool // should we make U-turns in the English manner? 1065 1066 yCorr, xyCorr, zCorr [8] /* 0..1 */ byte 1067 xCorr [8] /* -1..1 */ int8 1068 1069 m0, n0, m1, n1 int32 // lattice point coordinates 1070 d0, d1/* 0..1 */ byte // displacement corrections 1071 1072 envMove [5001]int32 1073 1074 tolStep/* 0..6 */ byte // either 0 or 3, usually 1075 1076 curT, curTt int32 // controls and results of |cubic_intersection| 1077 timeToGo int32 // this many backtracks before giving up 1078 maxT int32 // maximum of $2^[l+1]$ so far achieved 1079 1080 delx, dely int32 // the components of $\Delta=2^l(w_0-z_0)$ 1081 tol int32 // bound on the uncertainty in the overlap test 1082 uv, xy/* 0..bistackSize */ uint16 // pointers to the current packets of interest 1083 threeL int32 // |tol_step| times the bisection level 1084 apprT, apprTt int32 // best approximations known to the answers 1085 1086 // screen_pixel:array[screen_row,screen_col] of pixel_color[ ; ] 1087 1088 screenStarted bool // have the screen primitives been initialized? 1089 screenOk bool // is it legitimate to call |blank_rectangle|, 1090 // |paint_row|, and |update_screen|? 1091 1092 windowOpen [16]bool 1093 // has this window been opened? 1094 leftCol [16]screenCol 1095 // leftmost column position on screen 1096 rightCol [16]screenCol 1097 // rightmost column position, plus~1 1098 topRow [16]screenRow 1099 // topmost row position on screen 1100 botRow [16]screenRow 1101 // bottommost row position, plus~1 1102 mWindow [16]int32 1103 // offset between user and screen columns 1104 nWindow [16]int32 1105 // offset between user and screen rows 1106 windowTime [16]int32 1107 // it has been updated this often 1108 1109 rowTransition transSpec // an array of |black|/|white| transitions 1110 1111 serialNo int32 // the most recent serial number, times |s_scale| 1112 1113 fixNeeded bool // does at least one |independent| variable need scaling? 1114 watchCoefs bool // should we scale coefficients that exceed |coef_bound|? 1115 depFinal halfword // location of the constant term and final link 1116 1117 curCmd eightBits // current command set by |get_next| 1118 curMod int32 // operand of current command 1119 curSym halfword // hash address of current symbol 1120 1121 inputStack [31]inStateRecord 1122 inputPtr/* 0..stackSize */ byte // first unused location of |input_stack| 1123 maxInStack/* 0..stackSize */ byte // largest value of |input_ptr| when pushing 1124 curInput inStateRecord // the ``top'' input state 1125 1126 inOpen/* 0..maxInOpen */ byte // the number of lines in the buffer, less one 1127 openParens/* 0..maxInOpen */ byte // the number of open text files 1128 inputFile [6]alphaFile 1129 line int32 // current line number in the current source file 1130 lineStack [6]int32 1131 1132 paramStack [151]halfword 1133 // token list pointers for parameters 1134 paramPtr/* 0..paramSize */ byte // first unused entry in |param_stack| 1135 maxParamStack int32 1136 // largest value of |param_ptr| 1137 1138 filePtr/* 0..stackSize */ byte // shallowest level shown by |show_context| 1139 1140 scannerStatus/* normal..loopDefining */ byte // are we scanning at high speed? 1141 warningInfo int32 // if so, what else do we need to know, 1142 // in case an error occurs? 1143 1144 forceEof bool // should the next \&[input] be aborted early? 1145 1146 bgLoc, egLoc/* 1..hashBase+2112 */ uint16 1147 // hash addresses of `\.[begingroup]' and `\.[endgroup]' 1148 1149 condPtr halfword // top of the condition stack 1150 ifLimit/* normal..elseIfCode */ byte // upper bound on |fi_or_else| codes 1151 curIf smallNumber // type of conditional being worked on 1152 ifLine int32 // line where that conditional began 1153 1154 loopPtr halfword // top of the loop-control-node stack 1155 1156 curName strNumber // name of file just scanned 1157 curArea strNumber // file area just scanned, or \.[""] 1158 curExt strNumber // file extension just scanned, or \.[""] 1159 1160 areaDelimiter poolPointer // the most recent `\.>' or `\.:', if any 1161 extDelimiter poolPointer // the relevant `\..', if any 1162 1163 mfBaseDefault [18]char 1164 1165 jobName strNumber // principal file name 1166 logOpened bool // has the transcript file been opened? 1167 logName strNumber // full name of the log file 1168 1169 gfExt strNumber // default extension for the output file 1170 1171 gfFile byteFile // the generic font output goes here 1172 outputFileName strNumber // full name of the output file 1173 1174 curType smallNumber // the type of the expression just found 1175 curExp int32 // the value of the expression just found 1176 1177 maxC [2]int32 1178 // max coefficient magnitude 1179 maxPtr [2]halfword 1180 // where |p| occurs with |max_c| 1181 maxLink [2]halfword 1182 // other occurrences of |p| 1183 1184 varFlag/* 0..maxCommandCode */ byte // command that wants a variable 1185 1186 txx, txy, tyx, tyy, tx, ty scaled // current transform coefficients 1187 1188 startSym halfword // a symbolic token to insert at beginning of job 1189 1190 longHelpSeen bool // has the long \&[errmessage] help been used? 1191 1192 tfmFile byteFile // the font metric output goes here 1193 metricFileName strNumber // full name of the font metric file 1194 1195 bc, ec eightBits // smallest and largest character codes shipped out 1196 tfmWidth [256]scaled // \&[charwd] values 1197 tfmHeight [256]scaled // \&[charht] values 1198 tfmDepth [256]scaled // \&[chardp] values 1199 tfmItalCorr [256]scaled // \&[charic] values 1200 charExists [256]bool // has this code been shipped out? 1201 charTag [256] /* noTag..extTag */ byte // |remainder| category 1202 charRemainder [256] /* 0..ligTableSize */ uint16 // the |remainder| byte 1203 headerByte [100] /* -1..255 */ int16 1204 // bytes of the \.[TFM] header, or $-1$ if unset 1205 ligKern [5001]fourQuarters // the ligature/kern table 1206 nl/* 0..32767-256 */ uint16 // the number of ligature/kern steps so far 1207 kern [501]scaled // distinct kerning amounts 1208 nk/* 0..maxKerns */ uint16 // the number of distinct kerns so far 1209 exten [256]fourQuarters // extensible character recipes 1210 ne/* 0..256 */ uint16 // the number of extensible characters so far 1211 param [50]scaled // \&[fontdimen] parameters 1212 np/* 0..maxFontDimen */ byte // the largest \&[fontdimen] parameter specified so far 1213 nw, nh, nd, ni/* 0..256 */ uint16 // sizes of \.[TFM] subtables 1214 skipTable [256] /* 0..ligTableSize */ uint16 // local label status 1215 lkStarted bool // has there been a lig/kern step in this command yet? 1216 bchar int32 // right boundary character 1217 bchLabel/* 0..ligTableSize */ uint16 // left boundary starting location 1218 ll, lll/* 0..ligTableSize */ uint16 // registers used for lig/kern processing 1219 labelLoc [257] /* -1..ligTableSize */ int16 // lig/kern starting addresses 1220 labelChar [256]eightBits // characters for |label_loc| 1221 labelPtr/* 0..256 */ uint16 // highest position occupied in |label_loc| 1222 1223 perturbation scaled // quantity related to \.[TFM] rounding 1224 excess int32 // the list is this much too long 1225 1226 dimenHead [4]halfword // lists of \.[TFM] dimensions 1227 1228 maxTfmDimen scaled // bound on widths, heights, kerns, etc. 1229 tfmChanged int32 // the number of data entries that were out of bounds 1230 1231 gfMinM, gfMaxM, gfMinN, gfMaxN int32 // bounding rectangle 1232 gfPrevPtr int32 // where the present/next character started/starts 1233 totalChars int32 // the number of characters output so far 1234 charPtr [256]int32 // where individual characters started 1235 gfDx, gfDy [256]int32 // device escapements 1236 1237 gfBuf [9]eightBits // buffer for \.[GF] output 1238 halfBuf gfIndex // half of |gf_buf_size| 1239 gfLimit gfIndex // end of the current half buffer 1240 gfPtr gfIndex // the next available buffer address 1241 gfOffset int32 // |gf_buf_size| times the number of times the 1242 // output buffer has been fully emptied 1243 1244 bocC, bocP int32 // parameters of the next |boc| command 1245 1246 baseIdent strNumber 1247 1248 baseFile wordFile // for input or output of base information 1249 1250 readyAlready int32 // a sacrifice of purity for economy 1251 } 1252 1253 func (prg *prg) initialize() { // this procedure gets things started properly 1254 var ( 1255 // Local variables for initialization 1256 i int32 1257 1258 k int32 // all-purpose loop index 1259 ) 1260 prg.xchr[040] = ' ' 1261 prg.xchr[041] = '!' 1262 prg.xchr[042] = '"' 1263 prg.xchr[043] = '#' 1264 prg.xchr[044] = '$' 1265 prg.xchr[045] = '%' 1266 prg.xchr[046] = '&' 1267 prg.xchr[047] = '\'' 1268 1269 prg.xchr[050] = '(' 1270 prg.xchr[051] = ')' 1271 prg.xchr[052] = '*' 1272 prg.xchr[053] = '+' 1273 prg.xchr[054] = ',' 1274 prg.xchr[055] = '-' 1275 prg.xchr[056] = '.' 1276 prg.xchr[057] = '/' 1277 1278 prg.xchr[060] = '0' 1279 prg.xchr[061] = '1' 1280 prg.xchr[062] = '2' 1281 prg.xchr[063] = '3' 1282 prg.xchr[064] = '4' 1283 prg.xchr[065] = '5' 1284 prg.xchr[066] = '6' 1285 prg.xchr[067] = '7' 1286 1287 prg.xchr[070] = '8' 1288 prg.xchr[071] = '9' 1289 prg.xchr[072] = ':' 1290 prg.xchr[073] = ';' 1291 prg.xchr[074] = '<' 1292 prg.xchr[075] = '=' 1293 prg.xchr[076] = '>' 1294 prg.xchr[077] = '?' 1295 1296 prg.xchr[0100] = '@' 1297 prg.xchr[0101] = 'A' 1298 prg.xchr[0102] = 'B' 1299 prg.xchr[0103] = 'C' 1300 prg.xchr[0104] = 'D' 1301 prg.xchr[0105] = 'E' 1302 prg.xchr[0106] = 'F' 1303 prg.xchr[0107] = 'G' 1304 1305 prg.xchr[0110] = 'H' 1306 prg.xchr[0111] = 'I' 1307 prg.xchr[0112] = 'J' 1308 prg.xchr[0113] = 'K' 1309 prg.xchr[0114] = 'L' 1310 prg.xchr[0115] = 'M' 1311 prg.xchr[0116] = 'N' 1312 prg.xchr[0117] = 'O' 1313 1314 prg.xchr[0120] = 'P' 1315 prg.xchr[0121] = 'Q' 1316 prg.xchr[0122] = 'R' 1317 prg.xchr[0123] = 'S' 1318 prg.xchr[0124] = 'T' 1319 prg.xchr[0125] = 'U' 1320 prg.xchr[0126] = 'V' 1321 prg.xchr[0127] = 'W' 1322 1323 prg.xchr[0130] = 'X' 1324 prg.xchr[0131] = 'Y' 1325 prg.xchr[0132] = 'Z' 1326 prg.xchr[0133] = '[' 1327 prg.xchr[0134] = '\\' 1328 prg.xchr[0135] = ']' 1329 prg.xchr[0136] = '^' 1330 prg.xchr[0137] = '_' 1331 1332 prg.xchr[0140] = '`' 1333 prg.xchr[0141] = 'a' 1334 prg.xchr[0142] = 'b' 1335 prg.xchr[0143] = 'c' 1336 prg.xchr[0144] = 'd' 1337 prg.xchr[0145] = 'e' 1338 prg.xchr[0146] = 'f' 1339 prg.xchr[0147] = 'g' 1340 1341 prg.xchr[0150] = 'h' 1342 prg.xchr[0151] = 'i' 1343 prg.xchr[0152] = 'j' 1344 prg.xchr[0153] = 'k' 1345 prg.xchr[0154] = 'l' 1346 prg.xchr[0155] = 'm' 1347 prg.xchr[0156] = 'n' 1348 prg.xchr[0157] = 'o' 1349 1350 prg.xchr[0160] = 'p' 1351 prg.xchr[0161] = 'q' 1352 prg.xchr[0162] = 'r' 1353 prg.xchr[0163] = 's' 1354 prg.xchr[0164] = 't' 1355 prg.xchr[0165] = 'u' 1356 prg.xchr[0166] = 'v' 1357 prg.xchr[0167] = 'w' 1358 1359 prg.xchr[0170] = 'x' 1360 prg.xchr[0171] = 'y' 1361 prg.xchr[0172] = 'z' 1362 prg.xchr[0173] = '{' 1363 prg.xchr[0174] = '|' 1364 prg.xchr[0175] = '}' 1365 prg.xchr[0176] = '~' 1366 1367 for ii := int32(0); ii <= 037; ii++ { 1368 i = ii 1369 _ = i 1370 prg.xchr[i] = ' ' 1371 } 1372 for ii := int32(0177); ii <= 0377; ii++ { 1373 i = ii 1374 _ = i 1375 prg.xchr[i] = ' ' 1376 } 1377 1378 for ii := int32(firstTextChar); ii <= lastTextChar; ii++ { 1379 i = ii 1380 _ = i 1381 prg.xord[char(i)] = 0177 1382 } 1383 for ii := int32(0200); ii <= 0377; ii++ { 1384 i = ii 1385 _ = i 1386 prg.xord[prg.xchr[i]] = byte(i) 1387 } 1388 for ii := int32(0); ii <= 0176; ii++ { 1389 i = ii 1390 _ = i 1391 prg.xord[prg.xchr[i]] = byte(i) 1392 } 1393 1394 prg.interaction = byte(errorStopMode) 1395 1396 prg.deletionsAllowed = true 1397 prg.errorCount = 0 // |history| is initialized elsewhere 1398 1399 prg.helpPtr = 0 1400 prg.useErrHelp = false 1401 prg.errHelp = 0 1402 1403 prg.interrupt = 0 1404 prg.okToInterrupt = true 1405 1406 prg.arithError = false 1407 1408 prg.twoToThe[0] = 1 1409 for ii := int32(1); ii <= 30; ii++ { 1410 k = ii 1411 _ = k 1412 prg.twoToThe[k] = 2 * prg.twoToThe[k-1] 1413 } 1414 prg.specLog[1-1] = 93032640 1415 prg.specLog[2-1] = 38612034 1416 prg.specLog[3-1] = 17922280 1417 prg.specLog[4-1] = 8662214 1418 prg.specLog[5-1] = 4261238 1419 prg.specLog[6-1] = 2113709 1420 prg.specLog[7-1] = 1052693 1421 prg.specLog[8-1] = 525315 1422 prg.specLog[9-1] = 262400 1423 prg.specLog[10-1] = 131136 1424 prg.specLog[11-1] = 65552 1425 prg.specLog[12-1] = 32772 1426 prg.specLog[13-1] = 16385 1427 for ii := int32(14); ii <= 27; ii++ { 1428 k = ii 1429 _ = k 1430 prg.specLog[k-1] = prg.twoToThe[27-k] 1431 } 1432 prg.specLog[28-1] = 1 1433 1434 prg.specAtan[1-1] = 27855475 1435 prg.specAtan[2-1] = 14718068 1436 prg.specAtan[3-1] = 7471121 1437 prg.specAtan[4-1] = 3750058 1438 prg.specAtan[5-1] = 1876857 1439 prg.specAtan[6-1] = 938658 1440 prg.specAtan[7-1] = 469357 1441 prg.specAtan[8-1] = 234682 1442 prg.specAtan[9-1] = 117342 1443 prg.specAtan[10-1] = 58671 1444 prg.specAtan[11-1] = 29335 1445 prg.specAtan[12-1] = 14668 1446 prg.specAtan[13-1] = 7334 1447 prg.specAtan[14-1] = 3667 1448 prg.specAtan[15-1] = 1833 1449 prg.specAtan[16-1] = 917 1450 prg.specAtan[17-1] = 458 1451 prg.specAtan[18-1] = 229 1452 prg.specAtan[19-1] = 115 1453 prg.specAtan[20-1] = 57 1454 prg.specAtan[21-1] = 29 1455 prg.specAtan[22-1] = 14 1456 prg.specAtan[23-1] = 7 1457 prg.specAtan[24-1] = 4 1458 prg.specAtan[25-1] = 2 1459 prg.specAtan[26-1] = 1 1460 1461 // was_mem_end:=mem_min; [indicate that everything was previously free] 1462 // was_lo_max:=mem_min; was_hi_min:=mem_max; 1463 // panicking:=false; 1464 // [ ] 1465 1466 for ii := int32(1); ii <= maxGivenInternal; ii++ { 1467 k = ii 1468 _ = k 1469 prg.internal[k-1] = 0 1470 } 1471 prg.intPtr = byte(maxGivenInternal) 1472 1473 for ii := int32('0'); ii <= '9'; ii++ { 1474 k = ii 1475 _ = k 1476 prg.charClass[k] = byte(digitClass) 1477 } 1478 prg.charClass['.'] = byte(periodClass) 1479 prg.charClass[' '] = byte(spaceClass) 1480 prg.charClass['%'] = byte(percentClass) 1481 prg.charClass['"'] = byte(stringClass) 1482 1483 prg.charClass[','] = 5 1484 prg.charClass[';'] = 6 1485 prg.charClass['('] = 7 1486 prg.charClass[')'] = byte(rightParenClass) 1487 for ii := int32('A'); ii <= 'Z'; ii++ { 1488 k = ii 1489 _ = k 1490 prg.charClass[k] = byte(letterClass) 1491 } 1492 for ii := int32('a'); ii <= 'z'; ii++ { 1493 k = ii 1494 _ = k 1495 prg.charClass[k] = byte(letterClass) 1496 } 1497 prg.charClass['_'] = byte(letterClass) 1498 1499 prg.charClass['<'] = 10 1500 prg.charClass['='] = 10 1501 prg.charClass['>'] = 10 1502 prg.charClass[':'] = 10 1503 prg.charClass['|'] = 10 1504 1505 prg.charClass['`'] = 11 1506 prg.charClass['\''] = 11 1507 1508 prg.charClass['+'] = 12 1509 prg.charClass['-'] = 12 1510 1511 prg.charClass['/'] = 13 1512 prg.charClass['*'] = 13 1513 prg.charClass['\\'] = 13 1514 1515 prg.charClass['!'] = 14 1516 prg.charClass['?'] = 14 1517 1518 prg.charClass['#'] = 15 1519 prg.charClass['&'] = 15 1520 prg.charClass['@'] = 15 1521 prg.charClass['$'] = 15 1522 1523 prg.charClass['^'] = 16 1524 prg.charClass['~'] = 16 1525 1526 prg.charClass['['] = byte(leftBracketClass) 1527 prg.charClass[']'] = byte(rightBracketClass) 1528 1529 prg.charClass['{'] = 19 1530 prg.charClass['}'] = 19 1531 1532 for ii := int32(0); ii <= ' '-1; ii++ { 1533 k = ii 1534 _ = k 1535 prg.charClass[k] = byte(invalidClass) 1536 } 1537 for ii := int32(127); ii <= 255; ii++ { 1538 k = ii 1539 _ = k 1540 prg.charClass[k] = byte(invalidClass) 1541 } 1542 1543 *prg.hash[1-1].lh() = 0 1544 *prg.hash[1-1].rh() = 0 1545 *prg.eqtb[1-1].lh() = uint16(tagToken) 1546 *prg.eqtb[1-1].rh() = uint16(memMin) 1547 for ii := int32(2); ii <= hashBase+hashSize+12; ii++ { 1548 k = ii 1549 _ = k 1550 prg.hash[k-1] = prg.hash[1-1] 1551 prg.eqtb[k-1] = prg.eqtb[1-1] 1552 } 1553 1554 prg.bigNodeSize[transformType-13] = byte(transformNodeSize) 1555 prg.bigNodeSize[pairType-13] = byte(pairNodeSize) 1556 1557 prg.savePtr = uint16(memMin) 1558 1559 prg.octantDir[firstOctant-1] = /* "ENE" */ 548 1560 prg.octantDir[secondOctant-1] = /* "NNE" */ 549 1561 prg.octantDir[thirdOctant-1] = /* "NNW" */ 550 1562 prg.octantDir[fourthOctant-1] = /* "WNW" */ 551 1563 prg.octantDir[fifthOctant-1] = /* "WSW" */ 552 1564 prg.octantDir[sixthOctant-1] = /* "SSW" */ 553 1565 prg.octantDir[seventhOctant-1] = /* "SSE" */ 554 1566 prg.octantDir[eighthOctant-1] = /* "ESE" */ 555 1567 1568 prg.maxRoundingPtr = 0 1569 1570 prg.octantCode[1-1] = byte(firstOctant) 1571 prg.octantCode[2-1] = byte(secondOctant) 1572 prg.octantCode[3-1] = byte(thirdOctant) 1573 prg.octantCode[4-1] = byte(fourthOctant) 1574 prg.octantCode[5-1] = byte(fifthOctant) 1575 prg.octantCode[6-1] = byte(sixthOctant) 1576 prg.octantCode[7-1] = byte(seventhOctant) 1577 prg.octantCode[8-1] = byte(eighthOctant) 1578 for ii := int32(1); ii <= 8; ii++ { 1579 k = ii 1580 _ = k 1581 prg.octantNumber[prg.octantCode[k-1]-1] = byte(k) 1582 } 1583 1584 prg.revTurns = false 1585 1586 prg.xCorr[firstOctant-1] = 0 1587 prg.yCorr[firstOctant-1] = 0 1588 prg.xyCorr[firstOctant-1] = 0 1589 1590 prg.xCorr[secondOctant-1] = 0 1591 prg.yCorr[secondOctant-1] = 0 1592 prg.xyCorr[secondOctant-1] = 1 1593 1594 prg.xCorr[thirdOctant-1] = int8(-1) 1595 prg.yCorr[thirdOctant-1] = 1 1596 prg.xyCorr[thirdOctant-1] = 0 1597 1598 prg.xCorr[fourthOctant-1] = 1 1599 prg.yCorr[fourthOctant-1] = 0 1600 prg.xyCorr[fourthOctant-1] = 1 1601 1602 prg.xCorr[fifthOctant-1] = 0 1603 prg.yCorr[fifthOctant-1] = 1 1604 prg.xyCorr[fifthOctant-1] = 1 1605 1606 prg.xCorr[sixthOctant-1] = 0 1607 prg.yCorr[sixthOctant-1] = 1 1608 prg.xyCorr[sixthOctant-1] = 0 1609 1610 prg.xCorr[seventhOctant-1] = 1 1611 prg.yCorr[seventhOctant-1] = 0 1612 prg.xyCorr[seventhOctant-1] = 1 1613 1614 prg.xCorr[eighthOctant-1] = int8(-1) 1615 prg.yCorr[eighthOctant-1] = 1 1616 prg.xyCorr[eighthOctant-1] = 0 1617 1618 for ii := int32(1); ii <= 8; ii++ { 1619 k = ii 1620 _ = k 1621 prg.zCorr[k-1] = byte(int32(prg.xyCorr[k-1]) - int32(prg.xCorr[k-1])) 1622 } 1623 1624 prg.screenStarted = false 1625 prg.screenOk = false 1626 1627 for ii := int32(0); ii <= 15; ii++ { 1628 k = ii 1629 _ = k 1630 prg.windowOpen[k] = false 1631 prg.windowTime[k] = 0 1632 } 1633 1634 prg.fixNeeded = false 1635 prg.watchCoefs = true 1636 1637 prg.condPtr = uint16(memMin) 1638 prg.ifLimit = byte(normal) 1639 prg.curIf = 0 1640 prg.ifLine = 0 1641 1642 prg.loopPtr = uint16(memMin) 1643 1644 strcopy(prg.mfBaseDefault[:], "MFbases:plain.base") 1645 // \xref[MFbases] 1646 // \xref[plain] 1647 // \xref[system dependencies] 1648 1649 prg.curExp = 0 1650 1651 prg.varFlag = 0 1652 1653 prg.startSym = 0 1654 1655 prg.longHelpSeen = false 1656 1657 for ii := int32(0); ii <= 255; ii++ { 1658 k = ii 1659 _ = k 1660 prg.tfmWidth[k] = 0 1661 prg.tfmHeight[k] = 0 1662 prg.tfmDepth[k] = 0 1663 prg.tfmItalCorr[k] = 0 1664 prg.charExists[k] = false 1665 prg.charTag[k] = byte(noTag) 1666 prg.charRemainder[k] = 0 1667 prg.skipTable[k] = uint16(ligTableSize) 1668 } 1669 for ii := int32(1); ii <= headerSize; ii++ { 1670 k = ii 1671 _ = k 1672 prg.headerByte[k-1] = int16(-1) 1673 } 1674 prg.bc = 255 1675 prg.ec = 0 1676 prg.nl = 0 1677 prg.nk = 0 1678 prg.ne = 0 1679 prg.np = 0 1680 1681 prg.internal[boundaryChar-1] = -0200000 1682 prg.bchLabel = uint16(ligTableSize) 1683 1684 prg.labelLoc[0] = int16(-1) 1685 prg.labelPtr = 0 1686 1687 prg.gfPrevPtr = 0 1688 prg.totalChars = 0 1689 1690 prg.halfBuf = byte(gfBufSize / 2) 1691 prg.gfLimit = byte(gfBufSize) 1692 prg.gfPtr = 0 1693 prg.gfOffset = 0 1694 1695 prg.baseIdent = 0 1696 1697 } 1698 1699 // \4 1700 // Basic printing procedures 1701 func (prg *prg) printLn() { 1702 switch prg.selector { 1703 case termAndLog: 1704 prg.termOut.Writeln() 1705 prg.logFile.Writeln() 1706 prg.termOffset = 0 1707 prg.fileOffset = 0 1708 1709 case logOnly: 1710 prg.logFile.Writeln() 1711 prg.fileOffset = 0 1712 1713 case termOnly: 1714 prg.termOut.Writeln() 1715 prg.termOffset = 0 1716 1717 case noPrint, pseudo, newString: 1718 } // there are no other cases 1719 } // note that |tally| is not affected 1720 1721 func (prg *prg) printChar(s asciiCode) { 1722 switch prg.selector { 1723 case termAndLog: 1724 prg.termOut.Write(string(rune(prg.xchr[s]))) 1725 prg.logFile.Write(string(rune(prg.xchr[s]))) 1726 prg.termOffset = byte(int32(prg.termOffset) + 1) 1727 prg.fileOffset = byte(int32(prg.fileOffset) + 1) 1728 if int32(prg.termOffset) == maxPrintLine { 1729 prg.termOut.Writeln() 1730 prg.termOffset = 0 1731 } 1732 if int32(prg.fileOffset) == maxPrintLine { 1733 prg.logFile.Writeln() 1734 prg.fileOffset = 0 1735 } 1736 1737 case logOnly: 1738 prg.logFile.Write(string(rune(prg.xchr[s]))) 1739 prg.fileOffset = byte(int32(prg.fileOffset) + 1) 1740 if int32(prg.fileOffset) == maxPrintLine { 1741 prg.printLn() 1742 } 1743 1744 case termOnly: 1745 prg.termOut.Write(string(rune(prg.xchr[s]))) 1746 prg.termOffset = byte(int32(prg.termOffset) + 1) 1747 if int32(prg.termOffset) == maxPrintLine { 1748 prg.printLn() 1749 } 1750 1751 case noPrint: 1752 case pseudo: 1753 if prg.tally < prg.trickCount { 1754 prg.trickBuf[prg.tally%errorLine] = s 1755 } 1756 case newString: 1757 if int32(prg.poolPtr) < poolSize { 1758 prg.strPool[prg.poolPtr] = s 1759 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 1760 } 1761 // we drop characters if the string space is full 1762 } // there are no other cases 1763 prg.tally = prg.tally + 1 1764 } 1765 1766 func (prg *prg) print(s int32) { // prints string |s| 1767 var ( 1768 j poolPointer // current character code position 1769 ) 1770 if s < 0 || s >= int32(prg.strPtr) { 1771 s = /* "???" */ 259 1772 } // this can't happen 1773 // \xref[???] 1774 if s < 256 && int32(prg.selector) > pseudo { 1775 prg.printChar(asciiCode(s)) 1776 } else { 1777 j = prg.strStart[s] 1778 for int32(j) < int32(prg.strStart[s+1]) { 1779 prg.printChar(prg.strPool[j]) 1780 j = uint16(int32(j) + 1) 1781 } 1782 } 1783 } 1784 1785 func (prg *prg) slowPrint(s int32) { // prints string |s| 1786 var ( 1787 j poolPointer // current character code position 1788 ) 1789 if s < 0 || s >= int32(prg.strPtr) { 1790 s = /* "???" */ 259 1791 } // this can't happen 1792 // \xref[???] 1793 if s < 256 && int32(prg.selector) > pseudo { 1794 prg.printChar(asciiCode(s)) 1795 } else { 1796 j = prg.strStart[s] 1797 for int32(j) < int32(prg.strStart[s+1]) { 1798 prg.print(int32(prg.strPool[j])) 1799 j = uint16(int32(j) + 1) 1800 } 1801 } 1802 } 1803 1804 func (prg *prg) printNl(s strNumber) { 1805 if int32(prg.termOffset) > 0 && prg.selector&1 != 0 || int32(prg.fileOffset) > 0 && int32(prg.selector) >= logOnly { 1806 prg.printLn() 1807 } 1808 prg.print(int32(s)) 1809 } 1810 1811 func (prg *prg) printTheDigs(k eightBits) { 1812 for int32(k) > 0 { 1813 k = byte(int32(k) - 1) 1814 prg.printChar(asciiCode('0' + int32(prg.dig[k]))) 1815 } 1816 } 1817 1818 func (prg *prg) printInt(n int32) { // prints an integer in decimal form 1819 var ( 1820 k/* 0..23 */ byte // index to current digit; we assume that $\vert n\vert<10^[23]$ 1821 m int32 // used to negate |n| in possibly dangerous cases 1822 ) 1823 k = 0 1824 if n < 0 { 1825 prg.printChar(asciiCode('-')) 1826 if n > -100000000 { 1827 n = -n 1828 } else { 1829 m = -1 - n 1830 n = m / 10 1831 m = m%10 + 1 1832 k = 1 1833 if m < 10 { 1834 prg.dig[0] = byte(m) 1835 } else { 1836 prg.dig[0] = 0 1837 n = n + 1 1838 } 1839 } 1840 } 1841 for { 1842 prg.dig[k] = byte(n % 10) 1843 n = n / 10 1844 k = byte(int32(k) + 1) 1845 if n == 0 { 1846 break 1847 } 1848 } 1849 prg.printTheDigs(k) 1850 } 1851 1852 func (prg *prg) printScaled(s scaled) { // prints scaled real, rounded to five 1853 // digits 1854 1855 var ( 1856 delta scaled // amount of allowable inaccuracy 1857 ) 1858 if s < 0 { 1859 prg.printChar(asciiCode('-')) 1860 s = -s // print the sign, if negative 1861 } 1862 prg.printInt(s / 0200000) // print the integer part 1863 s = 10*(s%0200000) + 5 1864 if s != 5 { 1865 delta = 10 1866 prg.printChar(asciiCode('.')) 1867 for { 1868 if delta > 0200000 { 1869 s = s + 0100000 - delta/2 1870 } // round the final digit 1871 prg.printChar(asciiCode('0' + s/0200000)) 1872 s = 10 * (s % 0200000) 1873 delta = delta * 10 1874 if s <= delta { 1875 break 1876 } 1877 } 1878 } 1879 } 1880 1881 func (prg *prg) printTwo(x, y scaled) { 1882 prg.printChar(asciiCode('(')) 1883 prg.printScaled(x) 1884 prg.printChar(asciiCode(',')) 1885 prg.printScaled(y) 1886 prg.printChar(asciiCode(')')) 1887 } 1888 1889 func (prg *prg) printType(t smallNumber) { 1890 switch t { 1891 case vacuous: 1892 prg.print( /* "vacuous" */ 324) 1893 case booleanType: 1894 prg.print( /* "boolean" */ 325) 1895 case unknownBoolean: 1896 prg.print( /* "unknown boolean" */ 326) 1897 case stringType: 1898 prg.print( /* "string" */ 327) 1899 case unknownString: 1900 prg.print( /* "unknown string" */ 328) 1901 case penType: 1902 prg.print( /* "pen" */ 329) 1903 case unknownPen: 1904 prg.print( /* "unknown pen" */ 330) 1905 case futurePen: 1906 prg.print( /* "future pen" */ 331) 1907 case pathType: 1908 prg.print( /* "path" */ 332) 1909 case unknownPath: 1910 prg.print( /* "unknown path" */ 333) 1911 case pictureType: 1912 prg.print( /* "picture" */ 334) 1913 case unknownPicture: 1914 prg.print( /* "unknown picture" */ 335) 1915 case transformType: 1916 prg.print( /* "transform" */ 336) 1917 case pairType: 1918 prg.print( /* "pair" */ 337) 1919 case known: 1920 prg.print( /* "known numeric" */ 338) 1921 case dependent: 1922 prg.print( /* "dependent" */ 339) 1923 case protoDependent: 1924 prg.print( /* "proto-dependent" */ 340) 1925 case numericType: 1926 prg.print( /* "numeric" */ 341) 1927 case independent: 1928 prg.print( /* "independent" */ 342) 1929 case tokenList: 1930 prg.print( /* "token list" */ 343) 1931 case structured: 1932 prg.print( /* "structured" */ 344) 1933 case unsuffixedMacro: 1934 prg.print( /* "unsuffixed macro" */ 345) 1935 case suffixedMacro: 1936 prg.print( /* "suffixed macro" */ 346) 1937 1938 default: 1939 prg.print( /* "undefined" */ 347) 1940 } 1941 } 1942 1943 func (prg *prg) beginDiagnostic() { 1944 prg.oldSetting = prg.selector 1945 if prg.internal[tracingOnline-1] <= 0 && int32(prg.selector) == termAndLog { 1946 prg.selector = byte(int32(prg.selector) - 1) 1947 if int32(prg.history) == spotless { 1948 prg.history = byte(warningIssued) 1949 } 1950 } 1951 } 1952 1953 func (prg *prg) endDiagnostic(blankLine bool) { 1954 prg.printNl(strNumber( /* "" */ 285)) 1955 if blankLine { 1956 prg.printLn() 1957 } 1958 prg.selector = prg.oldSetting 1959 } 1960 1961 func (prg *prg) printDiagnostic(s, t strNumber, nuline bool) { 1962 prg.beginDiagnostic() 1963 if nuline { 1964 prg.printNl(s) 1965 } else { 1966 prg.print(int32(s)) 1967 } 1968 prg.print( /* " at line " */ 265) 1969 prg.printInt(prg.line) 1970 prg.print(int32(t)) 1971 prg.printChar(asciiCode(':')) 1972 } 1973 1974 func (prg *prg) printFileName(n, a, e int32) { 1975 prg.slowPrint(a) 1976 prg.slowPrint(n) 1977 prg.slowPrint(e) 1978 } // \2 1979 1980 // \4\hskip-\fontdimen2\font 1981 // procedure debug_help; 1982 // forward; [ ] 1983 1984 // \4 1985 // Declare the procedure called |flush_string| 1986 func (prg *prg) flushString(s strNumber) { 1987 if int32(s) < int32(prg.strPtr)-1 { 1988 prg.strRef[s] = 0 1989 } else { 1990 for { 1991 prg.strPtr = uint16(int32(prg.strPtr) - 1) 1992 if int32(prg.strRef[int32(prg.strPtr)-1]) != 0 { 1993 break 1994 } 1995 } 1996 } 1997 prg.poolPtr = prg.strStart[prg.strPtr] 1998 } 1999 2000 func (prg *prg) jumpOut() { 2001 panic(signal(endOfMf)) 2002 } 2003 2004 func (prg *prg) error1() { 2005 var ( 2006 c asciiCode // what the user types 2007 s1, s2, s3 int32 // used to save global variables when deleting tokens 2008 j poolPointer // character position being printed 2009 ) 2010 if int32(prg.history) < errorMessageIssued { 2011 prg.history = byte(errorMessageIssued) 2012 } 2013 prg.printChar(asciiCode('.')) 2014 prg.showContext() 2015 if int32(prg.interaction) == errorStopMode { 2016 for true { 2017 continue1: 2018 if int32(prg.interaction) != errorStopMode { 2019 goto exit 2020 } 2021 prg.clearForErrorPrompt() 2022 { 2023 prg.print( /* "? " */ 263) 2024 prg.termInput() 2025 } 2026 // \xref[?\relax] 2027 if int32(prg.last) == int32(prg.first) { 2028 goto exit 2029 } 2030 c = prg.buffer[prg.first] 2031 if int32(c) >= 'a' { 2032 c = byte(int32(c) + 'A' - 'a') 2033 } // convert to uppercase 2034 2035 // Interpret code |c| and |return| if done 2036 switch c { 2037 case '0', '1', '2', '3', 2038 '4', '5', '6', '7', 2039 '8', '9': 2040 if prg.deletionsAllowed { 2041 s1 = int32(prg.curCmd) 2042 s2 = prg.curMod 2043 s3 = int32(prg.curSym) 2044 prg.okToInterrupt = false 2045 if int32(prg.last) > int32(prg.first)+1 && int32(prg.buffer[int32(prg.first)+1]) >= '0' && int32(prg.buffer[int32(prg.first)+1]) <= '9' { 2046 c = byte(int32(c)*10 + int32(prg.buffer[int32(prg.first)+1]) - '0'*11) 2047 } else { 2048 c = byte(int32(c) - '0') 2049 } 2050 for int32(c) > 0 { 2051 prg.getNext() // one-level recursive call of |error| is possible 2052 2053 // Decrease the string reference count, if the current token is a string 2054 if int32(prg.curCmd) == stringToken { 2055 if int32(prg.strRef[prg.curMod]) < maxStrRef { 2056 if int32(prg.strRef[prg.curMod]) > 1 { 2057 prg.strRef[prg.curMod] = byte(int32(prg.strRef[prg.curMod]) - 1) 2058 } else { 2059 prg.flushString(strNumber(prg.curMod)) 2060 } 2061 } 2062 } 2063 c = byte(int32(c) - 1) 2064 } 2065 prg.curCmd = byte(s1) 2066 prg.curMod = s2 2067 prg.curSym = uint16(s3) 2068 prg.okToInterrupt = true 2069 { 2070 prg.helpPtr = 2 2071 prg.helpLine[1] = /* "I have just deleted some text, as you asked." */ 278 2072 prg.helpLine[0] = /* "You can now delete more, or insert, or whatever." */ 279 2073 } 2074 prg.showContext() 2075 goto continue1 2076 } 2077 2078 // \4\4 2079 // ["D"=]68:begin debug_help;goto continue; end; [ ] 2080 2081 // "E"= 2082 case 'E': 2083 if int32(prg.filePtr) > 0 { 2084 if int32(prg.inputStack[prg.filePtr].nameField) >= 256 { 2085 prg.printNl(strNumber( /* "You want to edit file " */ 264)) 2086 // \xref[You want to edit file x] 2087 prg.slowPrint(int32(prg.inputStack[prg.filePtr].nameField)) 2088 prg.print( /* " at line " */ 265) 2089 prg.printInt(prg.line) 2090 2091 prg.interaction = byte(scrollMode) 2092 prg.jumpOut() 2093 } 2094 } 2095 // "H"= 2096 case 'H': 2097 // Print the help information and |goto continue| 2098 if prg.useErrHelp { 2099 j = prg.strStart[prg.errHelp] 2100 for int32(j) < int32(prg.strStart[int32(prg.errHelp)+1]) { 2101 if int32(prg.strPool[j]) != '%' { 2102 prg.print(int32(prg.strPool[j])) 2103 } else if int32(j)+1 == int32(prg.strStart[int32(prg.errHelp)+1]) { 2104 prg.printLn() 2105 } else if int32(prg.strPool[int32(j)+1]) != '%' { 2106 prg.printLn() 2107 } else { 2108 j = uint16(int32(j) + 1) 2109 prg.printChar(asciiCode('%')) 2110 } 2111 j = uint16(int32(j) + 1) 2112 } 2113 prg.useErrHelp = false 2114 } else { 2115 if int32(prg.helpPtr) == 0 { 2116 prg.helpPtr = 2 2117 prg.helpLine[1] = /* "Sorry, I don't know how to help in this situation." */ 280 2118 prg.helpLine[0] = /* "Maybe you should try asking a human?" */ 281 2119 } 2120 for { 2121 prg.helpPtr = byte(int32(prg.helpPtr) - 1) 2122 prg.print(int32(prg.helpLine[prg.helpPtr])) 2123 prg.printLn() 2124 if int32(prg.helpPtr) == 0 { 2125 break 2126 } 2127 } 2128 } 2129 { 2130 prg.helpPtr = 4 2131 prg.helpLine[3] = /* "Sorry, I already gave what help I could..." */ 282 2132 prg.helpLine[2] = /* "Maybe you should try asking a human?" */ 281 2133 prg.helpLine[1] = /* "An error might have occurred before I noticed any problems." */ 283 2134 prg.helpLine[0] = /* "``If all else fails, read the instructions.''" */ 284 2135 } 2136 2137 goto continue1 2138 2139 // "I"= 2140 case 'I': 2141 // Introduce new material from the terminal and |return| 2142 prg.beginFileReading() // enter a new syntactic level for terminal input 2143 if int32(prg.last) > int32(prg.first)+1 { 2144 prg.curInput.locField = uint16(int32(prg.first) + 1) 2145 prg.buffer[prg.first] = ' ' 2146 } else { 2147 { 2148 prg.print( /* "insert>" */ 277) 2149 prg.termInput() 2150 } 2151 prg.curInput.locField = prg.first 2152 // \xref[insert>] 2153 } 2154 prg.first = uint16(int32(prg.last) + 1) 2155 prg.curInput.limitField = prg.last 2156 goto exit 2157 2158 // "Q"= 2159 case 'Q', 'R', 'S': 2160 // Change the interaction level and |return| 2161 prg.errorCount = 0 2162 prg.interaction = byte(batchMode + int32(c) - 'Q') 2163 prg.print( /* "OK, entering " */ 272) 2164 switch c { 2165 case 'Q': 2166 prg.print( /* "batchmode" */ 273) 2167 prg.selector = byte(int32(prg.selector) - 1) 2168 2169 // "R"= 2170 case 'R': 2171 prg.print( /* "nonstopmode" */ 274) 2172 // "S"= 2173 case 'S': 2174 prg.print( /* "scrollmode" */ 275) 2175 } // there are no other cases 2176 prg.print( /* "..." */ 276) 2177 prg.printLn() 2178 goto exit 2179 2180 // "X"= 2181 case 'X': 2182 prg.interaction = byte(scrollMode) 2183 prg.jumpOut() 2184 2185 default: 2186 } 2187 2188 // Print the menu of available options 2189 { 2190 prg.print( /* "Type <return> to proceed, S to scroll future error messages," */ 266) 2191 2192 // \xref[Type <return> to proceed...] 2193 prg.printNl(strNumber( /* "R to run without stopping, Q to run quietly," */ 267)) 2194 2195 prg.printNl(strNumber( /* "I to insert something, " */ 268)) 2196 if int32(prg.filePtr) > 0 { 2197 if int32(prg.inputStack[prg.filePtr].nameField) >= 256 { 2198 prg.print( /* "E to edit your file," */ 269) 2199 } 2200 } 2201 if prg.deletionsAllowed { 2202 prg.printNl(strNumber( /* "1 or ... or 9 to ignore the next 1 to 9 tokens of input," */ 270)) 2203 } 2204 prg.printNl(strNumber( /* "H for help, X to quit." */ 271)) 2205 } 2206 } 2207 } 2208 prg.errorCount = int8(int32(prg.errorCount) + 1) 2209 if int32(prg.errorCount) == 100 { 2210 prg.printNl(strNumber( /* "(That makes 100 errors; please try again.)" */ 262)) 2211 // \xref[That makes 100 errors...] 2212 prg.history = byte(fatalErrorStop) 2213 prg.jumpOut() 2214 } 2215 2216 // Put help message on the transcript file 2217 if int32(prg.interaction) > batchMode { 2218 prg.selector = byte(int32(prg.selector) - 1) 2219 } // avoid terminal output 2220 if prg.useErrHelp { 2221 prg.printNl(strNumber( /* "" */ 285)) 2222 2223 // Print the string |err_help|, possibly on several lines 2224 j = prg.strStart[prg.errHelp] 2225 for int32(j) < int32(prg.strStart[int32(prg.errHelp)+1]) { 2226 if int32(prg.strPool[j]) != '%' { 2227 prg.print(int32(prg.strPool[j])) 2228 } else if int32(j)+1 == int32(prg.strStart[int32(prg.errHelp)+1]) { 2229 prg.printLn() 2230 } else if int32(prg.strPool[int32(j)+1]) != '%' { 2231 prg.printLn() 2232 } else { 2233 j = uint16(int32(j) + 1) 2234 prg.printChar(asciiCode('%')) 2235 } 2236 j = uint16(int32(j) + 1) 2237 } 2238 } else { 2239 for int32(prg.helpPtr) > 0 { 2240 prg.helpPtr = byte(int32(prg.helpPtr) - 1) 2241 prg.printNl(prg.helpLine[prg.helpPtr]) 2242 } 2243 } 2244 prg.printLn() 2245 if int32(prg.interaction) > batchMode { 2246 prg.selector = byte(int32(prg.selector) + 1) 2247 } // re-enable terminal output 2248 prg.printLn() 2249 2250 exit: 2251 } 2252 2253 func (prg *prg) fatalError(s strNumber) { 2254 prg.normalizeSelector() 2255 2256 { 2257 if int32(prg.interaction) == errorStopMode { 2258 } 2259 prg.printNl(strNumber( /* "! " */ 261)) 2260 prg.print( /* "Emergency stop" */ 286) /* \xref[!\relax] */ 2261 } 2262 { 2263 prg.helpPtr = 1 2264 prg.helpLine[0] = s 2265 } 2266 { 2267 if int32(prg.interaction) == errorStopMode { 2268 prg.interaction = byte(scrollMode) 2269 } 2270 if prg.logOpened { 2271 prg.error1() 2272 } /* if interaction>batch_mode then debug_help; [ ] */ 2273 prg.history = byte(fatalErrorStop) 2274 prg.jumpOut() 2275 } 2276 // \xref[Emergency stop] 2277 } 2278 2279 func (prg *prg) overflow(s strNumber, n int32) { 2280 prg.normalizeSelector() 2281 { 2282 if int32(prg.interaction) == errorStopMode { 2283 } 2284 prg.printNl(strNumber( /* "! " */ 261)) 2285 prg.print( /* "METAFONT capacity exceeded, sorry [" */ 287) /* \xref[!\relax] */ 2286 } 2287 // \xref[METAFONT capacity exceeded ...] 2288 prg.print(int32(s)) 2289 prg.printChar(asciiCode('=')) 2290 prg.printInt(n) 2291 prg.printChar(asciiCode(']')) 2292 { 2293 prg.helpPtr = 2 2294 prg.helpLine[1] = /* "If you really absolutely need more capacity," */ 288 2295 prg.helpLine[0] = /* "you can ask a wizard to enlarge me." */ 289 2296 } 2297 { 2298 if int32(prg.interaction) == errorStopMode { 2299 prg.interaction = byte(scrollMode) 2300 } 2301 if prg.logOpened { 2302 prg.error1() 2303 } /* if interaction>batch_mode then debug_help; [ ] */ 2304 prg.history = byte(fatalErrorStop) 2305 prg.jumpOut() 2306 } 2307 } 2308 2309 func (prg *prg) confusion(s strNumber) { 2310 prg.normalizeSelector() 2311 if int32(prg.history) < errorMessageIssued { 2312 { 2313 if int32(prg.interaction) == errorStopMode { 2314 } 2315 prg.printNl(strNumber( /* "! " */ 261)) 2316 prg.print( /* "This can't happen (" */ 290) /* \xref[!\relax] */ 2317 } 2318 prg.print(int32(s)) 2319 prg.printChar(asciiCode(')')) 2320 // \xref[This can't happen] 2321 { 2322 prg.helpPtr = 1 2323 prg.helpLine[0] = /* "I'm broken. Please show this to someone who can fix can fix" */ 291 2324 } 2325 } else { 2326 { 2327 if int32(prg.interaction) == errorStopMode { 2328 } 2329 prg.printNl(strNumber( /* "! " */ 261)) 2330 prg.print( /* "I can't go on meeting you like this" */ 292) /* \xref[!\relax] */ 2331 } 2332 // \xref[I can't go on...] 2333 { 2334 prg.helpPtr = 2 2335 prg.helpLine[1] = /* "One of your faux pas seems to have wounded me deeply..." */ 293 2336 prg.helpLine[0] = /* "in fact, I'm barely conscious. Please fix it and try again." */ 294 2337 } 2338 } 2339 { 2340 if int32(prg.interaction) == errorStopMode { 2341 prg.interaction = byte(scrollMode) 2342 } 2343 if prg.logOpened { 2344 prg.error1() 2345 } /* if interaction>batch_mode then debug_help; [ ] */ 2346 prg.history = byte(fatalErrorStop) 2347 prg.jumpOut() 2348 } 2349 } 2350 2351 // 5. 2352 2353 // tangle:pos ../../mf.web:231:3: 2354 2355 // The overall \MF\ program begins with the heading just shown, after which 2356 // comes a bunch of procedure declarations and function declarations. 2357 // Finally we will get to the main program, which begins with the 2358 // comment `|start_here|'. If you want to skip down to the 2359 // main program now, you can look up `|start_here|' in the index. 2360 // But the author suggests that the best way to understand this program 2361 // is to follow pretty much the order of \MF's components as they appear in the 2362 // \.[WEB] description you are now reading, since the present ordering is 2363 // intended to combine the advantages of the ``bottom up'' and ``top down'' 2364 // approaches to the problem of understanding a somewhat complicated system. 2365 2366 // 7. 2367 2368 // tangle:pos ../../mf.web:253:3: 2369 2370 // Some of the code below is intended to be used only when diagnosing the 2371 // strange behavior that sometimes occurs when \MF\ is being installed or 2372 // when system wizards are fooling around with \MF\ without quite knowing 2373 // what they are doing. Such code will not normally be compiled; it is 2374 // delimited by the codewords `$|debug|\ldots|gubed|$', with apologies 2375 // to people who wish to preserve the purity of English. 2376 // 2377 // Similarly, there is some conditional code delimited by 2378 // `$|stat|\ldots|tats|$' that is intended for use when statistics are to be 2379 // kept about \MF's memory usage. The |stat| $\ldots$ |tats| code also 2380 // implements special diagnostic information that is printed when 2381 // $\\[tracingedges]>1$. 2382 // \xref[debugging] 2383 2384 // 8. 2385 2386 // tangle:pos ../../mf.web:279:3: 2387 2388 // This program has two important variations: (1) There is a long and slow 2389 // version called \.[INIMF], which does the extra calculations needed to 2390 // \xref[INIMF] 2391 // initialize \MF's internal tables; and (2)~there is a shorter and faster 2392 // production version, which cuts the initialization to a bare minimum. 2393 // Parts of the program that are needed in (1) but not in (2) are delimited by 2394 // the codewords `$|init|\ldots|tini|$'. 2395 2396 // 10. 2397 2398 // tangle:pos ../../mf.web:307:3: 2399 2400 // This \MF\ implementation conforms to the rules of the [\sl Pascal User 2401 // \xref[PASCAL][\PASCAL] 2402 // \xref[system dependencies] 2403 // Manual] published by Jensen and Wirth in 1975, except where system-dependent 2404 // \xref[Wirth, Niklaus] 2405 // \xref[Jensen, Kathleen] 2406 // code is necessary to make a useful system program, and except in another 2407 // respect where such conformity would unnecessarily obscure the meaning 2408 // and clutter up the code: We assume that |case| statements may include a 2409 // default case that applies if no matching label is found. Thus, we shall use 2410 // constructions like 2411 // $$\vbox[\halign[\ignorespaces#\hfil\cr 2412 // |case x of|\cr 2413 // 1: $\langle\,$code for $x=1\,\rangle$;\cr 2414 // 3: $\langle\,$code for $x=3\,\rangle$;\cr 2415 // |othercases| $\langle\,$code for |x<>1| and |x<>3|$\,\rangle$\cr 2416 // |endcases|\cr]]$$ 2417 // since most \PASCAL\ compilers have plugged this hole in the language by 2418 // incorporating some sort of default mechanism. For example, the \ph\ 2419 // compiler allows `|others|:' as a default label, and other \PASCAL s allow 2420 // syntaxes like `\&[else]' or `\&[otherwise]' or `\\[otherwise]:', etc. The 2421 // definitions of |othercases| and |endcases| should be changed to agree with 2422 // local conventions. Note that no semicolon appears before |endcases| in 2423 // this program, so the definition of |endcases| should include a semicolon 2424 // if the compiler wants one. (Of course, if no default mechanism is 2425 // available, the |case| statements of \MF\ will have to be laboriously 2426 // extended by listing all remaining cases. People who are stuck with such 2427 // \PASCAL s have, in fact, done this, successfully but not happily!) 2428 // \xref[PASCAL H][\ph] 2429 2430 // 12. 2431 2432 // tangle:pos ../../mf.web:386:3: 2433 2434 // Like the preceding parameters, the following quantities can be changed 2435 // at compile time to extend or reduce \MF's capacity. But if they are changed, 2436 // it is necessary to rerun the initialization program \.[INIMF] 2437 // \xref[INIMF] 2438 // to generate new tables for the production \MF\ program. 2439 // One can't simply make helter-skelter changes to the following constants, 2440 // since certain rather complex initialization 2441 // numbers are computed from them. They are defined here using 2442 // \.[WEB] macros, instead of being put into \PASCAL's |const| list, in order to 2443 // emphasize this distinction. 2444 2445 // 15. 2446 2447 // tangle:pos ../../mf.web:432:3: 2448 2449 // Labels are given symbolic names by the following definitions, so that 2450 // occasional |goto| statements will be meaningful. We insert the label 2451 // `|exit|' just before the `\ignorespaces|end|\unskip' of a procedure in 2452 // which we have used the `|return|' statement defined below; the label 2453 // `|restart|' is occasionally used at the very beginning of a procedure; and 2454 // the label `|reswitch|' is occasionally used just prior to a |case| 2455 // statement in which some cases change the conditions and we wish to branch 2456 // to the newly applicable case. Loops that are set up with the |loop| 2457 // construction defined below are commonly exited by going to `|done|' or to 2458 // `|found|' or to `|not_found|', and they are sometimes repeated by going to 2459 // `|continue|'. If two or more parts of a subroutine start differently but 2460 // end up the same, the shared code may be gathered together at 2461 // `|common_ending|'. 2462 // 2463 // Incidentally, this program never declares a label that isn't actually used, 2464 // because some fussy \PASCAL\ compilers will complain about redundant labels. 2465 2466 // 16. 2467 2468 // tangle:pos ../../mf.web:466:3: 2469 2470 // Here are some macros for common programming idioms. 2471 2472 // 17. \[2] The character set 2473 2474 // tangle:pos ../../mf.web:479:27: 2475 2476 // In order to make \MF\ readily portable to a wide variety of 2477 // computers, all of its input text is converted to an internal eight-bit 2478 // code that includes standard ASCII, the ``American Standard Code for 2479 // Information Interchange.'' This conversion is done immediately when each 2480 // character is read in. Conversely, characters are converted from ASCII to 2481 // the user's external representation just before they are output to a 2482 // text file. 2483 // \xref[ASCII code] 2484 // 2485 // Such an internal code is relevant to users of \MF\ only with respect to 2486 // the \&[char] and \&[ASCII] operations, and the comparison of strings. 2487 2488 // 26. 2489 2490 // tangle:pos ../../mf.web:742:3: 2491 2492 // The \ph\ compiler with which the present version of \MF\ was prepared has 2493 // extended the rules of \PASCAL\ in a very convenient way. To open file~|f|, 2494 // we can write 2495 // $$\vbox[\halign[#\hfil\qquad&#\hfil\cr 2496 // |reset(f,\\[name],'/O')|&for input;\cr 2497 // |rewrite(f,\\[name],'/O')|&for output.\cr]]$$ 2498 // The `\\[name]' parameter, which is of type `\ignorespaces|packed 2499 // array[\<\\[any]>] of text_char|', stands for the name of 2500 // the external file that is being opened for input or output. 2501 // Blank spaces that might appear in \\[name] are ignored. 2502 // 2503 // The `\.[/O]' parameter tells the operating system not to issue its own 2504 // error messages if something goes wrong. If a file of the specified name 2505 // cannot be found, or if such a file cannot be opened for some other reason 2506 // (e.g., someone may already be trying to write the same file), we will have 2507 // | erstat(f)<>0| after an unsuccessful |reset| or |rewrite|. This allows 2508 // \MF\ to undertake appropriate corrective action. 2509 // \xref[PASCAL H][\ph] 2510 // \xref[system dependencies] 2511 // 2512 // \MF's file-opening procedures return |false| if no file identified by 2513 // |name_of_file| could be opened. 2514 func (prg *prg) aOpenIn(f alphaFile) (r bool) { 2515 f.Reset(arraystr(prg.nameOfFile[:]), "/O") 2516 r = f.ErStat() == 0 2517 return r 2518 } 2519 2520 func (prg *prg) aOpenOut(f alphaFile) (r bool) { 2521 f.Rewrite(arraystr(prg.nameOfFile[:]), "/O") 2522 r = f.ErStat() == 0 2523 return r 2524 } 2525 2526 func (prg *prg) bOpenOut(f byteFile) (r bool) { 2527 f.Rewrite(arraystr(prg.nameOfFile[:]), "/O") 2528 r = f.ErStat() == 0 2529 return r 2530 } 2531 2532 func (prg *prg) wOpenIn(f wordFile) (r bool) { 2533 f.Reset(arraystr(prg.nameOfFile[:]), "/O") 2534 r = f.ErStat() == 0 2535 return r 2536 } 2537 2538 func (prg *prg) wOpenOut(f wordFile) (r bool) { 2539 f.Rewrite(arraystr(prg.nameOfFile[:]), "/O") 2540 r = f.ErStat() == 0 2541 return r 2542 } 2543 2544 // 27. 2545 2546 // tangle:pos ../../mf.web:793:3: 2547 2548 // Files can be closed with the \ph\ routine `|close(f)|', which 2549 // \xref[PASCAL H][\ph] 2550 // \xref[system dependencies] 2551 // should be used when all input or output with respect to |f| has been completed. 2552 // This makes |f| available to be opened again, if desired; and if |f| was used for 2553 // output, the |close| operation makes the corresponding external file appear 2554 // on the user's area, ready to be read. 2555 func (prg *prg) aClose(f alphaFile) { 2556 f.Close() 2557 } 2558 2559 func (prg *prg) bClose(f byteFile) { 2560 f.Close() 2561 } 2562 2563 func (prg *prg) wClose(f wordFile) { 2564 f.Close() 2565 } 2566 2567 // 28. 2568 2569 // tangle:pos ../../mf.web:813:3: 2570 2571 // Binary input and output are done with \PASCAL's ordinary |get| and |put| 2572 // procedures, so we don't have to make any other special arrangements for 2573 // binary~I/O. Text output is also easy to do with standard \PASCAL\ routines. 2574 // The treatment of text input is more difficult, however, because 2575 // of the necessary translation to |ASCII_code| values. 2576 // \MF's conventions should be efficient, and they should 2577 // blend nicely with the user's operating environment. 2578 2579 // 30. 2580 2581 // tangle:pos ../../mf.web:834:3: 2582 2583 // The |input_ln| function brings the next line of input from the specified 2584 // file into available positions of the buffer array and returns the value 2585 // |true|, unless the file has already been entirely read, in which case it 2586 // returns |false| and sets |last:=first|. In general, the |ASCII_code| 2587 // numbers that represent the next line of the file are input into 2588 // |buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the 2589 // global variable |last| is set equal to |first| plus the length of the 2590 // line. Trailing blanks are removed from the line; thus, either |last=first| 2591 // (in which case the line was entirely blank) or |buffer[last-1]<>" "|. 2592 // \xref[inner loop] 2593 // 2594 // An overflow error is given, however, if the normal actions of |input_ln| 2595 // would make |last>=buf_size|; this is done so that other parts of \MF\ 2596 // can safely look at the contents of |buffer[last+1]| without overstepping 2597 // the bounds of the |buffer| array. Upon entry to |input_ln|, the condition 2598 // |first<buf_size| will always hold, so that there is always room for an 2599 // ``empty'' line. 2600 // 2601 // The variable |max_buf_stack|, which is used to keep track of how large 2602 // the |buf_size| parameter must be to accommodate the present job, is 2603 // also kept up to date by |input_ln|. 2604 // 2605 // If the |bypass_eoln| parameter is |true|, |input_ln| will do a |get| 2606 // before looking at the first character of the line; this skips over 2607 // an |eoln| that was in |f^|. The procedure does not do a |get| when it 2608 // reaches the end of the line; therefore it can be used to acquire input 2609 // from the user's terminal as well as from ordinary text files. 2610 // 2611 // Standard \PASCAL\ says that a file should have |eoln| immediately 2612 // before |eof|, but \MF\ needs only a weaker restriction: If |eof| 2613 // occurs in the middle of a line, the system function |eoln| should return 2614 // a |true| result (even though |f^| will be undefined). 2615 func (prg *prg) inputLn(f alphaFile, bypassEoln bool) (r bool) { 2616 // inputs the next line or returns |false| 2617 var ( 2618 lastNonblank /* 0..bufSize */ uint16 // |last| with trailing blanks removed 2619 ) 2620 if bypassEoln { 2621 if !f.EOF() { 2622 f.Get() 2623 } 2624 } 2625 // input the first character of the line into |f^| 2626 prg.last = prg.first // cf.\ Matthew 19\thinspace:\thinspace30 2627 if f.EOF() { 2628 r = false 2629 } else { 2630 lastNonblank = prg.first 2631 for !f.EOLN() { 2632 if int32(prg.last) >= int32(prg.maxBufStack) { 2633 prg.maxBufStack = uint16(int32(prg.last) + 1) 2634 if int32(prg.maxBufStack) == bufSize { 2635 if int32(prg.baseIdent) == 0 { 2636 prg.termOut.Writeln("Buffer size exceeded!") 2637 panic(signal(finalEnd)) 2638 // \xref[Buffer size exceeded] 2639 } else { 2640 prg.curInput.locField = prg.first 2641 prg.curInput.limitField = uint16(int32(prg.last) - 1) 2642 prg.overflow(strNumber( /* "buffer size" */ 256), bufSize) 2643 // \xref[METAFONT capacity exceeded buffer size][\quad buffer size] 2644 } 2645 } 2646 } 2647 prg.buffer[prg.last] = prg.xord[*f.ByteP()] 2648 f.Get() 2649 prg.last = uint16(int32(prg.last) + 1) 2650 if int32(prg.buffer[int32(prg.last)-1]) != ' ' { 2651 lastNonblank = prg.last 2652 } 2653 } 2654 prg.last = lastNonblank 2655 r = true 2656 } 2657 return r 2658 } 2659 2660 // 32. 2661 2662 // tangle:pos ../../mf.web:898:3: 2663 2664 // Here is how to open the terminal files 2665 // in \ph. The `\.[/I]' switch suppresses the first |get|. 2666 // \xref[PASCAL H][\ph] 2667 // \xref[system dependencies] 2668 2669 // 33. 2670 2671 // tangle:pos ../../mf.web:907:3: 2672 2673 // Sometimes it is necessary to synchronize the input/output mixture that 2674 // happens on the user's terminal, and three system-dependent 2675 // procedures are used for this 2676 // purpose. The first of these, |update_terminal|, is called when we want 2677 // to make sure that everything we have output to the terminal so far has 2678 // actually left the computer's internal buffers and been sent. 2679 // The second, |clear_terminal|, is called when we wish to cancel any 2680 // input that the user may have typed ahead (since we are about to 2681 // issue an unexpected error message). The third, |wake_up_terminal|, 2682 // is supposed to revive the terminal if the user has disabled it by 2683 // some instruction to the operating system. The following macros show how 2684 // these operations can be specified in \ph: 2685 // \xref[PASCAL H][\ph] 2686 // \xref[system dependencies] 2687 2688 // 35. 2689 2690 // tangle:pos ../../mf.web:963:3: 2691 2692 // Different systems have different ways to get started. But regardless of 2693 // what conventions are adopted, the routine that initializes the terminal 2694 // should satisfy the following specifications: 2695 // 2696 // \yskip\textindent[1)]It should open file |term_in| for input from the 2697 // terminal. (The file |term_out| will already be open for output to the 2698 // terminal.) 2699 // 2700 // \textindent[2)]If the user has given a command line, this line should be 2701 // considered the first line of terminal input. Otherwise the 2702 // user should be prompted with `\.[**]', and the first line of input 2703 // should be whatever is typed in response. 2704 // 2705 // \textindent[3)]The first line of input, which might or might not be a 2706 // command line, should appear in locations |first| to |last-1| of the 2707 // |buffer| array. 2708 // 2709 // \textindent[4)]The global variable |loc| should be set so that the 2710 // character to be read next by \MF\ is in |buffer[loc]|. This 2711 // character should not be blank, and we should have |loc<last|. 2712 // 2713 // \yskip\noindent(It may be necessary to prompt the user several times 2714 // before a non-blank line comes in. The prompt is `\.[**]' instead of the 2715 // later `\.*' because the meaning is slightly different: `\.[input]' need 2716 // not be typed immediately after~`\.[**]'.) 2717 2718 // 36. 2719 2720 // tangle:pos ../../mf.web:991:3: 2721 2722 // The following program does the required initialization 2723 // without retrieving a possible command line. 2724 // It should be clear how to modify this routine to deal with command lines, 2725 // if the system permits them. 2726 // \xref[system dependencies] 2727 func (prg *prg) initTerminal() (r bool) { 2728 prg.termIn.Reset("TTY:", "/O/I") 2729 for true { 2730 prg.termOut.Write("**") 2731 // \xref[**] 2732 if !prg.inputLn(prg.termIn, false) { 2733 prg.termOut.Writeln() 2734 prg.termOut.Write("! End of file on the terminal... why?") 2735 // \xref[End of file on the terminal] 2736 r = false 2737 goto exit 2738 } 2739 prg.curInput.locField = prg.first 2740 for int32(prg.curInput.locField) < int32(prg.last) && int32(prg.buffer[prg.curInput.locField]) == ' ' { 2741 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 2742 } 2743 if int32(prg.curInput.locField) < int32(prg.last) { 2744 r = true 2745 2746 goto exit // return unless the line was all blank 2747 } 2748 prg.termOut.Writeln("Please type the name of your input file.") 2749 } 2750 2751 exit: 2752 ; 2753 return r 2754 } 2755 2756 // 39. 2757 2758 // tangle:pos ../../mf.web:1077:3: 2759 2760 // Several of the elementary string operations are performed using \.[WEB] 2761 // macros instead of \PASCAL\ procedures, because many of the 2762 // operations are done quite frequently and we want to avoid the 2763 // overhead of procedure calls. For example, here is 2764 // a simple macro that computes the length of a string. 2765 // \xref[WEB] 2766 2767 // 40. 2768 2769 // tangle:pos ../../mf.web:1087:3: 2770 2771 // The length of the current string is called |cur_length|: 2772 2773 // 41. 2774 2775 // tangle:pos ../../mf.web:1091:3: 2776 2777 // Strings are created by appending character codes to |str_pool|. 2778 // The |append_char| macro, defined here, does not check to see if the 2779 // value of |pool_ptr| has gotten too high; this test is supposed to be 2780 // made before |append_char| is used. 2781 // 2782 // To test if there is room to append |l| more characters to |str_pool|, 2783 // we shall write |str_room(l)|, which aborts \MF\ and gives an 2784 // apologetic error message if there isn't enough room. 2785 2786 // 44. 2787 2788 // tangle:pos ../../mf.web:1153:3: 2789 2790 // Once a sequence of characters has been appended to |str_pool|, it 2791 // officially becomes a string when the function |make_string| is called. 2792 // This function returns the identification number of the new string as its 2793 // value. 2794 func (prg *prg) makeString() (r strNumber) { 2795 if int32(prg.strPtr) == int32(prg.maxStrPtr) { 2796 if int32(prg.strPtr) == maxStrings { 2797 prg.overflow(strNumber( /* "number of strings" */ 258), maxStrings-int32(prg.initStrPtr)) 2798 } 2799 // \xref[METAFONT capacity exceeded number of strings][\quad number of strings] 2800 prg.maxStrPtr = uint16(int32(prg.maxStrPtr) + 1) 2801 } 2802 prg.strRef[prg.strPtr] = 1 2803 prg.strPtr = uint16(int32(prg.strPtr) + 1) 2804 prg.strStart[prg.strPtr] = prg.poolPtr 2805 r = uint16(int32(prg.strPtr) - 1) 2806 return r 2807 } 2808 2809 // 45. 2810 2811 // tangle:pos ../../mf.web:1169:3: 2812 2813 // The following subroutine compares string |s| with another string of the 2814 // same length that appears in |buffer| starting at position |k|; 2815 // the result is |true| if and only if the strings are equal. 2816 func (prg *prg) strEqBuf(s strNumber, k int32) (r bool) { // loop exit 2817 var ( 2818 j poolPointer // running index 2819 result bool // result of comparison 2820 ) 2821 j = prg.strStart[s] 2822 for int32(j) < int32(prg.strStart[int32(s)+1]) { 2823 if int32(prg.strPool[j]) != int32(prg.buffer[k]) { 2824 result = false 2825 goto notFound 2826 } 2827 j = uint16(int32(j) + 1) 2828 k = k + 1 2829 } 2830 result = true 2831 2832 notFound: 2833 r = result 2834 return r 2835 } 2836 2837 // 46. 2838 2839 // tangle:pos ../../mf.web:1189:3: 2840 2841 // Here is a similar routine, but it compares two strings in the string pool, 2842 // and it does not assume that they have the same length. If the first string 2843 // is lexicographically greater than, less than, or equal to the second, 2844 // the result is respectively positive, negative, or zero. 2845 func (prg *prg) strVsStr(s, t strNumber) (r int32) { 2846 var ( 2847 j, k poolPointer // running indices 2848 ls, lt int32 // lengths 2849 l int32 // length remaining to test 2850 ) 2851 ls = int32(prg.strStart[int32(s)+1]) - int32(prg.strStart[s]) 2852 lt = int32(prg.strStart[int32(t)+1]) - int32(prg.strStart[t]) 2853 if ls <= lt { 2854 l = ls 2855 } else { 2856 l = lt 2857 } 2858 j = prg.strStart[s] 2859 k = prg.strStart[t] 2860 for l > 0 { 2861 if int32(prg.strPool[j]) != int32(prg.strPool[k]) { 2862 r = int32(prg.strPool[j]) - int32(prg.strPool[k]) 2863 goto exit 2864 } 2865 j = uint16(int32(j) + 1) 2866 k = uint16(int32(k) + 1) 2867 l = l - 1 2868 } 2869 r = ls - lt 2870 2871 exit: 2872 ; 2873 return r 2874 } 2875 2876 // 47. 2877 2878 // tangle:pos ../../mf.web:1212:3: 2879 2880 // The initial values of |str_pool|, |str_start|, |pool_ptr|, 2881 // and |str_ptr| are computed by the \.[INIMF] program, based in part 2882 // on the information that \.[WEB] has output while processing \MF. 2883 // \xref[INIMF] 2884 // \xref[string pool] 2885 func (prg *prg) getStringsStarted() (r bool) { 2886 var ( 2887 k, l/* 0..255 */ byte // small indices or counters 2888 m, n char // characters input from |pool_file| 2889 g strNumber // the string just created 2890 a int32 // accumulator for check sum 2891 c bool // check sum has been checked 2892 ) 2893 prg.poolPtr = 0 2894 prg.strPtr = 0 2895 prg.maxPoolPtr = 0 2896 prg.maxStrPtr = 0 2897 prg.strStart[0] = 0 2898 2899 // Make the first 256 strings 2900 for ii := int32(0); ii <= 255; ii++ { 2901 k = byte(ii) 2902 _ = k 2903 if int32(k) < ' ' || int32(k) > '~' { 2904 { 2905 prg.strPool[prg.poolPtr] = '^' 2906 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2907 } 2908 { 2909 prg.strPool[prg.poolPtr] = '^' 2910 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2911 } 2912 if int32(k) < 0100 { 2913 prg.strPool[prg.poolPtr] = byte(int32(k) + 0100) 2914 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2915 } else if int32(k) < 0200 { 2916 prg.strPool[prg.poolPtr] = byte(int32(k) - 0100) 2917 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2918 } else { 2919 l = byte(int32(k) / 16) 2920 if int32(l) < 10 { 2921 prg.strPool[prg.poolPtr] = byte(int32(l) + '0') 2922 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2923 } else { 2924 prg.strPool[prg.poolPtr] = byte(int32(l) - 10 + 'a') 2925 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2926 } 2927 l = byte(int32(k) % 16) 2928 if int32(l) < 10 { 2929 prg.strPool[prg.poolPtr] = byte(int32(l) + '0') 2930 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2931 } else { 2932 prg.strPool[prg.poolPtr] = byte(int32(l) - 10 + 'a') 2933 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2934 } 2935 } 2936 } else { 2937 prg.strPool[prg.poolPtr] = k 2938 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 2939 } 2940 g = prg.makeString() 2941 prg.strRef[g] = byte(maxStrRef) 2942 } 2943 2944 // Read the other strings from the \.[MF.POOL] file and return |true|, or give an error message and return |false| 2945 strcopy(prg.nameOfFile[:], "MFbases:MF.POOL ") // we needn't set |name_length| 2946 if prg.aOpenIn(prg.poolFile) { 2947 c = false 2948 for { 2949 // Read one string, but return |false| if the string memory space is getting too tight for comfort 2950 { 2951 if prg.poolFile.EOF() { 2952 prg.termOut.Writeln("! MF.POOL has no check sum.") 2953 prg.aClose(prg.poolFile) 2954 r = false 2955 goto exit 2956 } 2957 // \xref[MF.POOL has no check sum] 2958 prg.poolFile.Read(&m, &n) // read two digits of string length 2959 if int32(m) == '*' { 2960 a = 0 2961 k = 1 2962 for true { 2963 if int32(prg.xord[n]) < '0' || int32(prg.xord[n]) > '9' { 2964 prg.termOut.Writeln("! MF.POOL check sum doesn't have nine digits.") 2965 prg.aClose(prg.poolFile) 2966 r = false 2967 goto exit 2968 } 2969 // \xref[MF.POOL check sum...] 2970 a = 10*a + int32(prg.xord[n]) - '0' 2971 if int32(k) == 9 { 2972 goto done 2973 } 2974 k = byte(int32(k) + 1) 2975 prg.poolFile.Read(&n) 2976 } 2977 2978 done: 2979 if a != 461259239 { 2980 prg.termOut.Writeln("! MF.POOL doesn't match; TANGLE me again.") 2981 prg.aClose(prg.poolFile) 2982 r = false 2983 goto exit 2984 } 2985 // \xref[MF.POOL doesn't match] 2986 c = true 2987 } else { 2988 if int32(prg.xord[m]) < '0' || int32(prg.xord[m]) > '9' || int32(prg.xord[n]) < '0' || int32(prg.xord[n]) > '9' { 2989 prg.termOut.Writeln("! MF.POOL line doesn't begin with two digits.") 2990 prg.aClose(prg.poolFile) 2991 r = false 2992 goto exit 2993 } 2994 // \xref[MF.POOL line doesn't...] 2995 l = byte(int32(prg.xord[m])*10 + int32(prg.xord[n]) - '0'*11) // compute the length 2996 if int32(prg.poolPtr)+int32(l)+stringVacancies > poolSize { 2997 prg.termOut.Writeln("! You have to increase POOLSIZE.") 2998 prg.aClose(prg.poolFile) 2999 r = false 3000 goto exit 3001 } 3002 // \xref[You have to increase POOLSIZE] 3003 for ii := int32(1); ii <= int32(l); ii++ { 3004 k = byte(ii) 3005 _ = k 3006 if prg.poolFile.EOLN() { 3007 m = ' ' 3008 } else { 3009 prg.poolFile.Read(&m) 3010 } 3011 { 3012 prg.strPool[prg.poolPtr] = prg.xord[m] 3013 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 3014 } 3015 } 3016 prg.poolFile.Readln() 3017 g = prg.makeString() 3018 prg.strRef[g] = byte(maxStrRef) 3019 } 3020 } 3021 if c { 3022 break 3023 } 3024 } 3025 prg.aClose(prg.poolFile) 3026 r = true 3027 } else { 3028 prg.termOut.Writeln("! I can't read MF.POOL.") 3029 prg.aClose(prg.poolFile) 3030 r = false 3031 goto exit 3032 } 3033 3034 exit: 3035 ; 3036 return r 3037 } 3038 3039 // 56. 3040 3041 // tangle:pos ../../mf.web:1406:3: 3042 3043 // Macro abbreviations for output to the terminal and to the log file are 3044 // defined here for convenience. Some systems need special conventions 3045 // for terminal output, and it is possible to adhere to those conventions 3046 // by changing |wterm|, |wterm_ln|, and |wterm_cr| here. 3047 // \xref[system dependencies] 3048 3049 // 65. 3050 3051 // tangle:pos ../../mf.web:1560:3: 3052 3053 // \MF\ also makes use of a trivial procedure to print two digits. The 3054 // following subroutine is usually called with a parameter in the range |0<=n<=99|. 3055 func (prg *prg) printDd(n int32) { 3056 n = abs(n) % 100 3057 prg.printChar(asciiCode('0' + n/10)) 3058 prg.printChar(asciiCode('0' + n%10)) 3059 } // \2 3060 3061 func (prg *prg) termInput() { // gets a line from the terminal 3062 var ( 3063 k /* 0..bufSize */ uint16 // index into |buffer| 3064 ) // now the user sees the prompt for sure 3065 if !prg.inputLn(prg.termIn, true) { 3066 prg.fatalError(strNumber( /* "End of file on the terminal!" */ 260)) 3067 } 3068 // \xref[End of file on the terminal] 3069 prg.termOffset = 0 // the user's line ended with \<\rm return> 3070 prg.selector = byte(int32(prg.selector) - 1) // prepare to echo the input 3071 if int32(prg.last) != int32(prg.first) { 3072 for ii := int32(prg.first); ii <= int32(prg.last)-1; ii++ { 3073 k = uint16(ii) 3074 _ = k 3075 prg.print(int32(prg.buffer[k])) 3076 } 3077 } 3078 prg.printLn() 3079 prg.buffer[prg.last] = '%' 3080 prg.selector = byte(int32(prg.selector) + 1) // restore previous status 3081 } 3082 3083 // \4 3084 // Error handling procedures 3085 func (prg *prg) normalizeSelector() { 3086 if prg.logOpened { 3087 prg.selector = byte(termAndLog) 3088 } else { 3089 prg.selector = byte(termOnly) 3090 } 3091 if int32(prg.jobName) == 0 { 3092 prg.openLogFile() 3093 } 3094 if int32(prg.interaction) == batchMode { 3095 prg.selector = byte(int32(prg.selector) - 1) 3096 } 3097 } 3098 3099 // 93. 3100 3101 // tangle:pos ../../mf.web:1993:3: 3102 3103 // When an interrupt has been detected, the program goes into its 3104 // highest interaction level and lets the user have the full flexibility of 3105 // the |error| routine. \MF\ checks for interrupts only at times when it is 3106 // safe to do this. 3107 func (prg *prg) pauseForInstructions() { 3108 if prg.okToInterrupt { 3109 prg.interaction = byte(errorStopMode) 3110 if int32(prg.selector) == logOnly || int32(prg.selector) == noPrint { 3111 prg.selector = byte(int32(prg.selector) + 1) 3112 } 3113 { 3114 if int32(prg.interaction) == errorStopMode { 3115 } 3116 prg.printNl(strNumber( /* "! " */ 261)) 3117 prg.print( /* "Interruption" */ 295) /* \xref[!\relax] */ 3118 } 3119 // \xref[Interruption] 3120 { 3121 prg.helpPtr = 3 3122 prg.helpLine[2] = /* "You rang?" */ 296 3123 prg.helpLine[1] = /* "Try to insert an instruction for me (e.g., `I show x;')," */ 297 3124 prg.helpLine[0] = /* "unless you just want to quit by typing `X'." */ 298 3125 } 3126 prg.deletionsAllowed = false 3127 prg.error1() 3128 prg.deletionsAllowed = true 3129 prg.interrupt = 0 3130 } 3131 } 3132 3133 // 94. 3134 3135 // tangle:pos ../../mf.web:2013:3: 3136 3137 // Many of \MF's error messages state that a missing token has been 3138 // inserted behind the scenes. We can save string space and program space 3139 // by putting this common code into a subroutine. 3140 func (prg *prg) missingErr(s strNumber) { 3141 { 3142 if int32(prg.interaction) == errorStopMode { 3143 } 3144 prg.printNl(strNumber( /* "! " */ 261)) 3145 prg.print( /* "Missing `" */ 299) /* \xref[!\relax] */ 3146 } 3147 prg.print(int32(s)) 3148 prg.print( /* "' has been inserted" */ 300) 3149 // \xref[Missing...inserted] 3150 } 3151 3152 // 95. \[7] Arithmetic with scaled numbers 3153 3154 // tangle:pos ../../mf.web:2022:40: 3155 3156 // The principal computations performed by \MF\ are done entirely in terms of 3157 // integers less than $2^[31]$ in magnitude; thus, the arithmetic specified in this 3158 // program can be carried out in exactly the same way on a wide variety of 3159 // computers, including some small ones. 3160 // \xref[small computers] 3161 // 3162 // But \PASCAL\ does not define the |div| 3163 // operation in the case of negative dividends; for example, the result of 3164 // |(-2*n-1) div 2| is |-(n+1)| on some computers and |-n| on others. 3165 // There are two principal types of arithmetic: ``translation-preserving,'' 3166 // in which the identity |(a+q*b)div b=(a div b)+q| is valid; and 3167 // ``negation-preserving,'' in which |(-a)div b=-(a div b)|. This leads to 3168 // two \MF s, which can produce different results, although the differences 3169 // should be negligible when the language is being used properly. 3170 // The \TeX\ processor has been defined carefully so that both varieties 3171 // of arithmetic will produce identical output, but it would be too 3172 // inefficient to constrain \MF\ in a similar way. 3173 3174 // 96. 3175 3176 // tangle:pos ../../mf.web:2043:3: 3177 3178 // One of \MF's most common operations is the calculation of 3179 // $\lfloor[a+b\over2]\rfloor$, 3180 // the midpoint of two given integers |a| and~|b|. The only decent way to do 3181 // this in \PASCAL\ is to write `|(a+b) div 2|'; but on most machines it is 3182 // far more efficient to calculate `|(a+b)| right shifted one bit'. 3183 // 3184 // Therefore the midpoint operation will always be denoted by `|half(a+b)|' 3185 // in this program. If \MF\ is being implemented with languages that permit 3186 // binary shifting, the |half| macro should be changed to make this operation 3187 // as efficient as possible. 3188 3189 // 99. 3190 3191 // tangle:pos ../../mf.web:2068:3: 3192 3193 // At crucial points the program will say |check_arith|, to test if 3194 // an arithmetic error has been detected. 3195 func (prg *prg) clearArith() { 3196 { 3197 if int32(prg.interaction) == errorStopMode { 3198 } 3199 prg.printNl(strNumber( /* "! " */ 261)) 3200 prg.print( /* "Arithmetic overflow" */ 301) /* \xref[!\relax] */ 3201 } 3202 // \xref[Arithmetic overflow] 3203 { 3204 prg.helpPtr = 4 3205 prg.helpLine[3] = /* "Uh, oh. A little while ago one of the quantities that I was" */ 302 3206 prg.helpLine[2] = /* "computing got too large, so I'm afraid your answers will be" */ 303 3207 prg.helpLine[1] = /* "somewhat askew. You'll probably have to adopt different" */ 304 3208 prg.helpLine[0] = /* "tactics next time. But I shall try to carry on anyway." */ 305 3209 } 3210 prg.error1() 3211 prg.arithError = false 3212 } 3213 3214 // 100. 3215 3216 // tangle:pos ../../mf.web:2083:3: 3217 3218 // Addition is not always checked to make sure that it doesn't overflow, 3219 // but in places where overflow isn't too unlikely the |slow_add| routine 3220 // is used. 3221 func (prg *prg) slowAdd(x, y int32) (r int32) { 3222 if x >= 0 { 3223 if y <= 017777777777-x { 3224 r = x + y 3225 } else { 3226 prg.arithError = true 3227 r = 017777777777 3228 } 3229 } else if -y <= 017777777777+x { 3230 r = x + y 3231 } else { 3232 prg.arithError = true 3233 r = -017777777777 3234 } 3235 return r 3236 } 3237 3238 // 102. 3239 3240 // tangle:pos ../../mf.web:2112:3: 3241 3242 // The following function is used to create a scaled integer from a given decimal 3243 // fraction $(.d_0d_1\ldots d_[k-1])$, where |0<=k<=17|. The digit $d_i$ is 3244 // given in |dig[i]|, and the calculation produces a correctly rounded result. 3245 func (prg *prg) roundDecimals(k smallNumber) (r scaled) { 3246 // converts a decimal fraction 3247 var ( 3248 a int32 // the accumulator 3249 ) 3250 a = 0 3251 for int32(k) > 0 { 3252 k = byte(int32(k) - 1) 3253 a = (a + int32(prg.dig[k])*0400000) / 10 3254 } 3255 r = (a + 1) / 2 3256 return r 3257 } 3258 3259 // 107. 3260 3261 // tangle:pos ../../mf.web:2194:3: 3262 3263 // The |make_fraction| routine produces the |fraction| equivalent of 3264 // |p/q|, given integers |p| and~|q|; it computes the integer 3265 // $f=\lfloor2^[28]p/q+[1\over2]\rfloor$, when $p$ and $q$ are 3266 // positive. If |p| and |q| are both of the same scaled type |t|, 3267 // the ``type relation'' |make_fraction(t,t)=fraction| is valid; 3268 // and it's also possible to use the subroutine ``backwards,'' using 3269 // the relation |make_fraction(t,fraction)=t| between scaled types. 3270 // 3271 // If the result would have magnitude $2^[31]$ or more, |make_fraction| 3272 // sets |arith_error:=true|. Most of \MF's internal computations have 3273 // been designed to avoid this sort of error. 3274 // 3275 // Notice that if 64-bit integer arithmetic were available, 3276 // we could simply compute |$(2^[29]$*p+q)div (2*q)|. 3277 // But when we are restricted to \PASCAL's 32-bit arithmetic we 3278 // must either resort to multiple-precision maneuvering 3279 // or use a simple but slow iteration. The multiple-precision technique 3280 // would be about three times faster than the code adopted here, but it 3281 // would be comparatively long and tricky, involving about sixteen 3282 // additional multiplications and divisions. 3283 // 3284 // This operation is part of \MF's ``inner loop''; indeed, it will 3285 // consume nearly 10\pct! of the running time (exclusive of input and output) 3286 // if the code below is left unchanged. A machine-dependent recoding 3287 // will therefore make \MF\ run faster. The present implementation 3288 // is highly portable, but slow; it avoids multiplication and division 3289 // except in the initial stage. System wizards should be careful to 3290 // replace it with a routine that is guaranteed to produce identical 3291 // results in all cases. 3292 // \xref[system dependencies] 3293 // 3294 // As noted below, a few more routines should also be replaced by machine-dependent 3295 // code, for efficiency. But when a procedure is not part of the ``inner loop,'' 3296 // such changes aren't advisable; simplicity and robustness are 3297 // preferable to trickery, unless the cost is too high. 3298 // \xref[inner loop] 3299 func (prg *prg) makeFraction(p, q int32) (r fraction) { 3300 var ( 3301 f int32 // the fraction bits, with a leading 1 bit 3302 n int32 // the integer part of $\vert p/q\vert$ 3303 negative bool // should the result be negated? 3304 beCareful int32 // disables certain compiler optimizations 3305 ) 3306 if p >= 0 { 3307 negative = false 3308 } else { 3309 p = -p 3310 negative = true 3311 } 3312 if q <= 0 { 3313 q = -q 3314 negative = !negative 3315 } 3316 n = p / q 3317 p = p % q 3318 if n >= 8 { 3319 prg.arithError = true 3320 if negative { 3321 r = -017777777777 3322 } else { 3323 r = 017777777777 3324 } 3325 } else { 3326 n = (n - 1) * 02000000000 3327 3328 // Compute $f=\lfloor 2^[28](1+p/q)+[1\over2]\rfloor$ 3329 f = 1 3330 for { 3331 beCareful = p - q 3332 p = beCareful + p 3333 if p >= 0 { 3334 f = f + f + 1 3335 } else { 3336 f = f + f 3337 p = p + q 3338 } 3339 if f >= 02000000000 { 3340 break 3341 } 3342 } 3343 beCareful = p - q 3344 if beCareful+p >= 0 { 3345 f = f + 1 3346 } 3347 if negative { 3348 r = -(f + n) 3349 } else { 3350 r = f + n 3351 } 3352 } 3353 return r 3354 } 3355 3356 // 109. 3357 3358 // tangle:pos ../../mf.web:2278:3: 3359 3360 // The dual of |make_fraction| is |take_fraction|, which multiplies a 3361 // given integer~|q| by a fraction~|f|. When the operands are positive, it 3362 // computes $p=\lfloor qf/2^[28]+[1\over2]\rfloor$, a symmetric function 3363 // of |q| and~|f|. 3364 // 3365 // This routine is even more ``inner loopy'' than |make_fraction|; 3366 // the present implementation consumes almost 20\pct! of \MF's computation 3367 // time during typical jobs, so a machine-language or 64-bit 3368 // substitute is advisable. 3369 // \xref[inner loop] \xref[system dependencies] 3370 func (prg *prg) takeFraction(q int32, f fraction) (r int32) { 3371 var ( 3372 p int32 // the fraction so far 3373 negative bool // should the result be negated? 3374 n int32 // additional multiple of $q$ 3375 beCareful int32 // disables certain compiler optimizations 3376 ) 3377 if f >= 0 { 3378 negative = false 3379 } else { 3380 f = -f 3381 negative = true 3382 } 3383 if q < 0 { 3384 q = -q 3385 negative = !negative 3386 } 3387 3388 if f < 02000000000 { 3389 n = 0 3390 } else { 3391 n = f / 02000000000 3392 f = f % 02000000000 3393 if q <= 017777777777/n { 3394 n = n * q 3395 } else { 3396 prg.arithError = true 3397 n = 017777777777 3398 } 3399 } 3400 f = f + 02000000000 3401 3402 // Compute $p=\lfloor qf/2^[28]+[1\over2]\rfloor-q$ 3403 p = 01000000000 // that's $2^[27]$; the invariants hold now with $k=28$ 3404 if q < 010000000000 { 3405 for { 3406 if f&1 != 0 { 3407 p = (p + q) / 2 3408 } else { 3409 p = p / 2 3410 } 3411 f = f / 2 3412 if f == 1 { 3413 break 3414 } 3415 } 3416 } else { 3417 for { 3418 if f&1 != 0 { 3419 p = p + (q-p)/2 3420 } else { 3421 p = p / 2 3422 } 3423 f = f / 2 3424 if f == 1 { 3425 break 3426 } 3427 } 3428 } 3429 beCareful = n - 017777777777 3430 if beCareful+p > 0 { 3431 prg.arithError = true 3432 n = 017777777777 - p 3433 } 3434 if negative { 3435 r = -(n + p) 3436 } else { 3437 r = n + p 3438 } 3439 return r 3440 } 3441 3442 // 112. 3443 3444 // tangle:pos ../../mf.web:2335:3: 3445 3446 // When we want to multiply something by a |scaled| quantity, we use a scheme 3447 // analogous to |take_fraction| but with a different scaling. 3448 // Given positive operands, |take_scaled| 3449 // computes the quantity $p=\lfloor qf/2^[16]+[1\over2]\rfloor$. 3450 // 3451 // Once again it is a good idea to use 64-bit arithmetic if 3452 // possible; otherwise |take_scaled| will use more than 2\pct! of the running time 3453 // when the Computer Modern fonts are being generated. 3454 // \xref[inner loop] 3455 func (prg *prg) takeScaled(q int32, f scaled) (r int32) { 3456 var ( 3457 p int32 // the fraction so far 3458 negative bool // should the result be negated? 3459 n int32 // additional multiple of $q$ 3460 beCareful int32 // disables certain compiler optimizations 3461 ) 3462 if f >= 0 { 3463 negative = false 3464 } else { 3465 f = -f 3466 negative = true 3467 } 3468 if q < 0 { 3469 q = -q 3470 negative = !negative 3471 } 3472 3473 if f < 0200000 { 3474 n = 0 3475 } else { 3476 n = f / 0200000 3477 f = f % 0200000 3478 if q <= 017777777777/n { 3479 n = n * q 3480 } else { 3481 prg.arithError = true 3482 n = 017777777777 3483 } 3484 } 3485 f = f + 0200000 3486 3487 // Compute $p=\lfloor qf/2^[16]+[1\over2]\rfloor-q$ 3488 p = 0100000 // that's $2^[15]$; the invariants hold now with $k=16$ 3489 // \xref[inner loop] 3490 if q < 010000000000 { 3491 for { 3492 if f&1 != 0 { 3493 p = (p + q) / 2 3494 } else { 3495 p = p / 2 3496 } 3497 f = f / 2 3498 if f == 1 { 3499 break 3500 } 3501 } 3502 } else { 3503 for { 3504 if f&1 != 0 { 3505 p = p + (q-p)/2 3506 } else { 3507 p = p / 2 3508 } 3509 f = f / 2 3510 if f == 1 { 3511 break 3512 } 3513 } 3514 } 3515 beCareful = n - 017777777777 3516 if beCareful+p > 0 { 3517 prg.arithError = true 3518 n = 017777777777 - p 3519 } 3520 if negative { 3521 r = -(n + p) 3522 } else { 3523 r = n + p 3524 } 3525 return r 3526 } 3527 3528 // 114. 3529 3530 // tangle:pos ../../mf.web:2378:3: 3531 3532 // For completeness, there's also |make_scaled|, which computes a 3533 // quotient as a |scaled| number instead of as a |fraction|. 3534 // In other words, the result is $\lfloor2^[16]p/q+[1\over2]\rfloor$, if the 3535 // operands are positive. \ (This procedure is not used especially often, 3536 // so it is not part of \MF's inner loop.) 3537 func (prg *prg) makeScaled(p, q int32) (r scaled) { 3538 var ( 3539 f int32 // the fraction bits, with a leading 1 bit 3540 n int32 // the integer part of $\vert p/q\vert$ 3541 negative bool // should the result be negated? 3542 beCareful int32 // disables certain compiler optimizations 3543 ) 3544 if p >= 0 { 3545 negative = false 3546 } else { 3547 p = -p 3548 negative = true 3549 } 3550 if q <= 0 { 3551 q = -q 3552 negative = !negative 3553 } 3554 n = p / q 3555 p = p % q 3556 if n >= 0100000 { 3557 prg.arithError = true 3558 if negative { 3559 r = -017777777777 3560 } else { 3561 r = 017777777777 3562 } 3563 } else { 3564 n = (n - 1) * 0200000 3565 3566 // Compute $f=\lfloor 2^[16](1+p/q)+[1\over2]\rfloor$ 3567 f = 1 3568 for { 3569 beCareful = p - q 3570 p = beCareful + p 3571 if p >= 0 { 3572 f = f + f + 1 3573 } else { 3574 f = f + f 3575 p = p + q 3576 } 3577 if f >= 0200000 { 3578 break 3579 } 3580 } 3581 beCareful = p - q 3582 if beCareful+p >= 0 { 3583 f = f + 1 3584 } 3585 if negative { 3586 r = -(f + n) 3587 } else { 3588 r = f + n 3589 } 3590 } 3591 return r 3592 } 3593 3594 // 116. 3595 3596 // tangle:pos ../../mf.web:2418:3: 3597 3598 // Here is a typical example of how the routines above can be used. 3599 // It computes the function 3600 // $$[1\over3\tau]f(\theta,\phi)= 3601 // [\tau^[-1]\bigl(2+\sqrt2\,(\sin\theta-[1\over16]\sin\phi) 3602 // (\sin\phi-[1\over16]\sin\theta)(\cos\theta-\cos\phi)\bigr)\over 3603 // 3\,\bigl(1+[1\over2](\sqrt5-1)\cos\theta+[1\over2](3-\sqrt5\,)\cos\phi\bigr)],$$ 3604 // where $\tau$ is a |scaled| ``tension'' parameter. This is \MF's magic 3605 // fudge factor for placing the first control point of a curve that starts 3606 // at an angle $\theta$ and ends at an angle $\phi$ from the straight path. 3607 // (Actually, if the stated quantity exceeds 4, \MF\ reduces it to~4.) 3608 // 3609 // The trigonometric quantity to be multiplied by $\sqrt2$ is less than $\sqrt2$. 3610 // (It's a sum of eight terms whose absolute values can be bounded using 3611 // relations such as $\sin\theta\cos\theta\L[1\over2]$.) Thus the numerator 3612 // is positive; and since the tension $\tau$ is constrained to be at least 3613 // $3\over4$, the numerator is less than $16\over3$. The denominator is 3614 // nonnegative and at most~6. Hence the fixed-point calculations below 3615 // are guaranteed to stay within the bounds of a 32-bit computer word. 3616 // 3617 // The angles $\theta$ and $\phi$ are given implicitly in terms of |fraction| 3618 // arguments |st|, |ct|, |sf|, and |cf|, representing $\sin\theta$, $\cos\theta$, 3619 // $\sin\phi$, and $\cos\phi$, respectively. 3620 func (prg *prg) velocity(st, ct, sf, cf fraction, t scaled) (r fraction) { 3621 var ( 3622 acc, num, denom int32 // registers for intermediate calculations 3623 ) 3624 acc = prg.takeFraction(st-sf/16, sf-st/16) 3625 acc = prg.takeFraction(acc, ct-cf) 3626 num = 04000000000 + prg.takeFraction(acc, fraction(379625062)) 3627 // $2^[28]\sqrt2\approx379625062.497$ 3628 denom = 06000000000 + prg.takeFraction(ct, fraction(497706707)) + prg.takeFraction(cf, fraction(307599661)) 3629 // $3\cdot2^[27]\cdot(\sqrt5-1)\approx497706706.78$ and 3630 // $3\cdot2^[27]\cdot(3-\sqrt5\,)\approx307599661.22$ 3631 3632 if t != 0200000 { 3633 num = prg.makeScaled(num, t) 3634 } 3635 // |make_scaled(fraction,scaled)=fraction| 3636 if num/4 >= denom { 3637 r = 010000000000 3638 } else { 3639 r = prg.makeFraction(num, denom) 3640 } 3641 return r 3642 } 3643 3644 // 117. 3645 3646 // tangle:pos ../../mf.web:2456:3: 3647 3648 // The following somewhat different subroutine tests rigorously if $ab$ is 3649 // greater than, equal to, or less than~$cd$, 3650 // given integers $(a,b,c,d)$. In most cases a quick decision is reached. 3651 // The result is $+1$, 0, or~$-1$ in the three respective cases. 3652 func (prg *prg) abVsCd(a, b, c, d int32) (r int32) { 3653 var ( 3654 q, r1 int32 // temporary registers 3655 ) 3656 if a < 0 { 3657 a = -a 3658 b = -b 3659 } 3660 if c < 0 { 3661 c = -c 3662 d = -d 3663 } 3664 if d <= 0 { 3665 if b >= 0 { 3666 if (a == 0 || b == 0) && (c == 0 || d == 0) { 3667 r = 0 3668 goto exit 3669 } else { 3670 r = 1 3671 goto exit 3672 } 3673 } 3674 if d == 0 { 3675 if a == 0 { 3676 r = 0 3677 goto exit 3678 } else { 3679 r = -1 3680 goto exit 3681 } 3682 } 3683 q = a 3684 a = c 3685 c = q 3686 q = -b 3687 b = -d 3688 d = q 3689 } else if b <= 0 { 3690 if b < 0 { 3691 if a > 0 { 3692 r = -1 3693 goto exit 3694 } 3695 } 3696 if c == 0 { 3697 r = 0 3698 goto exit 3699 } else { 3700 r = -1 3701 goto exit 3702 } 3703 } 3704 for true { 3705 q = a / d 3706 r1 = c / b 3707 if q != r1 { 3708 if q > r1 { 3709 r = 1 3710 goto exit 3711 } else { 3712 r = -1 3713 goto exit 3714 } 3715 } 3716 q = a % d 3717 r1 = c % b 3718 if r1 == 0 { 3719 if q == 0 { 3720 r = 0 3721 goto exit 3722 } else { 3723 r = 1 3724 goto exit 3725 } 3726 } 3727 if q == 0 { 3728 r = -1 3729 goto exit 3730 } 3731 a = b 3732 b = q 3733 c = d 3734 d = r1 3735 } // now |a>d>0| and |c>b>0| 3736 // now |a>d>0| and |c>b>0| 3737 exit: 3738 ; 3739 return r 3740 } 3741 3742 // 119. 3743 3744 // tangle:pos ../../mf.web:2499:3: 3745 3746 // We conclude this set of elementary routines with some simple rounding 3747 // and truncation operations that are coded in a machine-independent fashion. 3748 // The routines are slightly complicated because we want them to work 3749 // without overflow whenever $-2^[31]\L x<2^[31]$. 3750 func (prg *prg) floorScaled(x scaled) (r scaled) { 3751 // $2^[16]\lfloor x/2^[16]\rfloor$ 3752 var ( 3753 beCareful int32 // temporary register 3754 ) 3755 if x >= 0 { 3756 r = x - x%0200000 3757 } else { 3758 beCareful = x + 1 3759 r = x + -beCareful%0200000 + 1 - 0200000 3760 } 3761 return r 3762 } 3763 3764 func (prg *prg) floorUnscaled(x scaled) (r int32) { 3765 // $\lfloor x/2^[16]\rfloor$ 3766 var ( 3767 beCareful int32 // temporary register 3768 ) 3769 if x >= 0 { 3770 r = x / 0200000 3771 } else { 3772 beCareful = x + 1 3773 r = -(1 + -beCareful/0200000) 3774 } 3775 return r 3776 } 3777 3778 func (prg *prg) roundUnscaled(x scaled) (r int32) { 3779 // $\lfloor x/2^[16]+.5\rfloor$ 3780 var ( 3781 beCareful int32 // temporary register 3782 ) 3783 if x >= 0100000 { 3784 r = 1 + (x-0100000)/0200000 3785 } else if x >= -0100000 { 3786 r = 0 3787 } else { 3788 beCareful = x + 1 3789 r = -(1 + (-beCareful-0100000)/0200000) 3790 } 3791 return r 3792 } 3793 3794 func (prg *prg) roundFraction(x fraction) (r scaled) { 3795 // $\lfloor x/2^[12]+.5\rfloor$ 3796 var ( 3797 beCareful int32 // temporary register 3798 ) 3799 if x >= 2048 { 3800 r = 1 + (x-2048)/4096 3801 } else if x >= -2048 { 3802 r = 0 3803 } else { 3804 beCareful = x + 1 3805 r = -(1 + (-beCareful-2048)/4096) 3806 } 3807 return r 3808 } 3809 3810 // 120. \[8] Algebraic and transcendental functions 3811 3812 // tangle:pos ../../mf.web:2541:48: 3813 3814 // \MF\ computes all of the necessary special functions from scratch, without 3815 // relying on |real| arithmetic or system subroutines for sines, cosines, etc. 3816 3817 // 121. 3818 3819 // tangle:pos ../../mf.web:2545:3: 3820 3821 // To get the square root of a |scaled| number |x|, we want to calculate 3822 // $s=\lfloor 2^8\!\sqrt x +[1\over2]\rfloor$. If $x>0$, this is the unique 3823 // integer such that $2^[16]x-s\L s^2<2^[16]x+s$. The following subroutine 3824 // determines $s$ by an iterative method that maintains the invariant 3825 // relations $x=2^[46-2k]x_0\bmod 2^[30]$, $0<y=\lfloor 2^[16-2k]x_0\rfloor 3826 // -s^2+s\L q=2s$, where $x_0$ is the initial value of $x$. The value of~$y$ 3827 // might, however, be zero at the start of the first iteration. 3828 func (prg *prg) squareRt(x scaled) (r scaled) { 3829 var ( 3830 k smallNumber // iteration control counter 3831 y, q int32 // registers for intermediate calculations 3832 ) 3833 if x <= 0 { 3834 if x < 0 { 3835 { 3836 if int32(prg.interaction) == errorStopMode { 3837 } 3838 prg.printNl(strNumber( /* "! " */ 261)) 3839 prg.print( /* "Square root of " */ 306) /* \xref[!\relax] */ 3840 } 3841 // \xref[Square root...replaced by 0] 3842 prg.printScaled(x) 3843 prg.print( /* " has been replaced by 0" */ 307) 3844 { 3845 prg.helpPtr = 2 3846 prg.helpLine[1] = /* "Since I don't take square roots of negative numbers," */ 308 3847 prg.helpLine[0] = /* "I'm zeroing this one. Proceed, with fingers crossed." */ 309 3848 } 3849 prg.error1() 3850 } 3851 r = 0 3852 } else { 3853 k = 23 3854 q = 2 3855 for x < 04000000000 { // i.e., |while x<$2^[29]$|\unskip 3856 k = byte(int32(k) - 1) 3857 x = x + x + x + x 3858 } 3859 if x < 010000000000 { 3860 y = 0 3861 } else { 3862 x = x - 010000000000 3863 y = 1 3864 } 3865 for { 3866 // Decrease |k| by 1, maintaining the invariant relations between |x|, |y|, and~|q| 3867 x = x + x 3868 y = y + y 3869 if x >= 010000000000 { 3870 x = x - 010000000000 3871 y = y + 1 3872 } 3873 x = x + x 3874 y = y + y - q 3875 q = q + q 3876 if x >= 010000000000 { 3877 x = x - 010000000000 3878 y = y + 1 3879 } 3880 if y > q { 3881 y = y - q 3882 q = q + 2 3883 } else if y <= 0 { 3884 q = q - 2 3885 y = y + q 3886 } 3887 k = byte(int32(k) - 1) 3888 if int32(k) == 0 { 3889 break 3890 } 3891 } 3892 r = q / 2 3893 } 3894 return r 3895 } 3896 3897 // 124. 3898 3899 // tangle:pos ../../mf.web:2600:3: 3900 3901 // Pythagorean addition $\psqrt[a^2+b^2]$ is implemented by an elegant 3902 // iterative scheme due to Cleve Moler and Donald Morrison [[\sl IBM Journal 3903 // \xref[Moler, Cleve Barry] 3904 // \xref[Morrison, Donald Ross] 3905 // of Research and Development\/ \bf27] (1983), 577--581]. It modifies |a| and~|b| 3906 // in such a way that their Pythagorean sum remains invariant, while the 3907 // smaller argument decreases. 3908 func (prg *prg) pythAdd(a, b int32) (r int32) { 3909 var ( 3910 r1 fraction // register used to transform |a| and |b| 3911 big bool // is the result dangerously near $2^[31]$? 3912 ) 3913 a = abs(a) 3914 b = abs(b) 3915 if a < b { 3916 r1 = b 3917 b = a 3918 a = r1 3919 } // now |0<=b<=a| 3920 if b > 0 { 3921 if a < 04000000000 { 3922 big = false 3923 } else { 3924 a = a / 4 3925 b = b / 4 3926 big = true 3927 } // we reduced the precision to avoid arithmetic overflow 3928 3929 // Replace |a| by an approximation to $\psqrt[a^2+b^2]$ 3930 for true { 3931 r1 = prg.makeFraction(b, a) 3932 r1 = prg.takeFraction(r1, r1) // now $r\approx b^2/a^2$ 3933 if r1 == 0 { 3934 goto done 3935 } 3936 r1 = prg.makeFraction(r1, 010000000000+r1) 3937 a = a + prg.takeFraction(a+a, r1) 3938 b = prg.takeFraction(b, r1) 3939 } 3940 3941 done: 3942 ; 3943 if big { 3944 if a < 04000000000 { 3945 a = a + a + a + a 3946 } else { 3947 prg.arithError = true 3948 a = 017777777777 3949 } 3950 } 3951 } 3952 r = a 3953 return r 3954 } 3955 3956 // 126. 3957 3958 // tangle:pos ../../mf.web:2641:3: 3959 3960 // Here is a similar algorithm for $\psqrt[a^2-b^2]$. 3961 // It converges slowly when $b$ is near $a$, but otherwise it works fine. 3962 func (prg *prg) pythSub(a, b int32) (r int32) { 3963 var ( 3964 r1 fraction // register used to transform |a| and |b| 3965 big bool // is the input dangerously near $2^[31]$? 3966 ) 3967 a = abs(a) 3968 b = abs(b) 3969 if a <= b { 3970 if a < b { 3971 { 3972 if int32(prg.interaction) == errorStopMode { 3973 } 3974 prg.printNl(strNumber( /* "! " */ 261)) 3975 prg.print( /* "Pythagorean subtraction " */ 310) /* \xref[!\relax] */ 3976 } 3977 prg.printScaled(a) 3978 prg.print( /* "+-+" */ 311) 3979 prg.printScaled(b) 3980 prg.print( /* " has been replaced by 0" */ 307) 3981 // \xref[Pythagorean...] 3982 { 3983 prg.helpPtr = 2 3984 prg.helpLine[1] = /* "Since I don't take square roots of negative numbers," */ 308 3985 prg.helpLine[0] = /* "I'm zeroing this one. Proceed, with fingers crossed." */ 309 3986 } 3987 prg.error1() 3988 } 3989 a = 0 3990 } else { 3991 if a < 010000000000 { 3992 big = false 3993 } else { 3994 a = a / 2 3995 b = b / 2 3996 big = true 3997 } 3998 3999 // Replace |a| by an approximation to $\psqrt[a^2-b^2]$ 4000 for true { 4001 r1 = prg.makeFraction(b, a) 4002 r1 = prg.takeFraction(r1, r1) // now $r\approx b^2/a^2$ 4003 if r1 == 0 { 4004 goto done 4005 } 4006 r1 = prg.makeFraction(r1, 010000000000-r1) 4007 a = a - prg.takeFraction(a+a, r1) 4008 b = prg.takeFraction(b, r1) 4009 } 4010 4011 done: 4012 ; 4013 if big { 4014 a = a + a 4015 } 4016 } 4017 r = a 4018 return r 4019 } 4020 4021 // 132. 4022 4023 // tangle:pos ../../mf.web:2713:3: 4024 4025 // Here is the routine that calculates $2^8$ times the natural logarithm 4026 // of a |scaled| quantity; it is an integer approximation to $2^[24]\ln(x/2^[16])$, 4027 // when |x| is a given positive integer. 4028 // 4029 // The method is based on exercise 1.2.2--25 in [\sl The Art of Computer 4030 // Programming\/]: During the main iteration we have $1\L 2^[-30]x<1/(1-2^[1-k])$, 4031 // and the logarithm of $2^[30]x$ remains to be added to an accumulator 4032 // register called~$y$. Three auxiliary bits of accuracy are retained in~$y$ 4033 // during the calculation, and sixteen auxiliary bits to extend |y| are 4034 // kept in~|z| during the initial argument reduction. (We add 4035 // $100\cdot2^[16]=6553600$ to~|z| and subtract 100 from~|y| so that |z| will 4036 // not become negative; also, the actual amount subtracted from~|y| is~96, 4037 // not~100, because we want to add~4 for rounding before the final division by~8.) 4038 func (prg *prg) mLog(x scaled) (r scaled) { 4039 var ( 4040 y, z int32 // auxiliary registers 4041 k int32 // iteration counter 4042 ) 4043 if x <= 0 { 4044 { 4045 if int32(prg.interaction) == errorStopMode { 4046 } 4047 prg.printNl(strNumber( /* "! " */ 261)) 4048 prg.print( /* "Logarithm of " */ 312) /* \xref[!\relax] */ 4049 } 4050 // \xref[Logarithm...replaced by 0] 4051 prg.printScaled(x) 4052 prg.print( /* " has been replaced by 0" */ 307) 4053 { 4054 prg.helpPtr = 2 4055 prg.helpLine[1] = /* "Since I don't take logs of non-positive numbers," */ 313 4056 prg.helpLine[0] = /* "I'm zeroing this one. Proceed, with fingers crossed." */ 309 4057 } 4058 prg.error1() 4059 r = 0 4060 } else { 4061 y = 1302456956 + 4 - 100 // $14\times2^[27]\ln2\approx1302456956.421063$ 4062 z = 27595 + 6553600 // and $2^[16]\times .421063\approx 27595$ 4063 for x < 010000000000 { 4064 x = x + x 4065 y = y - 93032639 4066 z = z - 48782 4067 } // $2^[27]\ln2\approx 93032639.74436163$ 4068 // and $2^[16]\times.74436163\approx 48782$ 4069 4070 y = y + z/0200000 4071 k = 2 4072 for x > 010000000000+4 { 4073 4074 // Increase |k| until |x| can be multiplied by a factor of $2^[-k]$, and adjust $y$ accordingly 4075 z = (x-1)/prg.twoToThe[k] + 1 // $z=\lceil x/2^k\rceil$ 4076 for x < 010000000000+z { 4077 z = (z + 1) / 2 4078 k = k + 1 4079 } 4080 y = y + prg.specLog[k-1] 4081 x = x - z 4082 } 4083 r = y / 8 4084 } 4085 return r 4086 } 4087 4088 // 135. 4089 4090 // tangle:pos ../../mf.web:2762:3: 4091 4092 // Conversely, the exponential routine calculates $\exp(x/2^8)$, 4093 // when |x| is |scaled|. The result is an integer approximation to 4094 // $2^[16]\exp(x/2^[24])$, when |x| is regarded as an integer. 4095 func (prg *prg) mExp(x scaled) (r scaled) { 4096 var ( 4097 k smallNumber // loop control index 4098 y, z int32 // auxiliary registers 4099 ) 4100 if x > 174436200 { 4101 prg.arithError = true 4102 r = 017777777777 4103 } else if x < -197694359 { 4104 r = 0 4105 } else { 4106 if x <= 0 { 4107 z = -(8 * x) 4108 y = 04000000 // $y=2^[20]$ 4109 } else { 4110 if x <= 127919879 { 4111 z = 1023359037 - 8*x 4112 } else { 4113 z = 8 * (174436200 - x) 4114 } // |z| is always nonnegative 4115 y = 017777777777 4116 } 4117 4118 // Multiply |y| by $\exp(-z/2^[27])$ 4119 k = 1 4120 for z > 0 { 4121 for z >= prg.specLog[k-1] { 4122 z = z - prg.specLog[k-1] 4123 y = y - 1 - (y-prg.twoToThe[int32(k)-1])/prg.twoToThe[k] 4124 } 4125 k = byte(int32(k) + 1) 4126 } 4127 if x <= 127919879 { 4128 r = (y + 8) / 16 4129 } else { 4130 r = y 4131 } 4132 } 4133 return r 4134 } 4135 4136 // 139. 4137 4138 // tangle:pos ../../mf.web:2841:3: 4139 4140 // Given integers |x| and |y|, not both zero, the |n_arg| function 4141 // returns the |angle| whose tangent points in the direction $(x,y)$. 4142 // This subroutine first determines the correct octant, then solves the 4143 // problem for |0<=y<=x|, then converts the result appropriately to 4144 // return an answer in the range |-one_eighty_deg<=$\theta$<=one_eighty_deg|. 4145 // (The answer is |+one_eighty_deg| if |y=0| and |x<0|, but an answer of 4146 // |-one_eighty_deg| is possible if, for example, |y=-1| and $x=-2^[30]$.) 4147 // 4148 // The octants are represented in a ``Gray code,'' since that turns out 4149 // to be computationally simplest. 4150 func (prg *prg) nArg(x, y int32) (r angle) { 4151 var ( 4152 z angle // auxiliary register 4153 t int32 // temporary storage 4154 k smallNumber // loop counter 4155 octant/* firstOctant..sixthOctant */ byte // octant code 4156 ) 4157 if x >= 0 { 4158 octant = byte(firstOctant) 4159 } else { 4160 x = -x 4161 octant = byte(firstOctant + negateX) 4162 } 4163 if y < 0 { 4164 y = -y 4165 octant = byte(int32(octant) + negateY) 4166 } 4167 if x < y { 4168 t = y 4169 y = x 4170 x = t 4171 octant = byte(int32(octant) + switchXAndY) 4172 } 4173 if x == 0 { 4174 { 4175 if int32(prg.interaction) == errorStopMode { 4176 } 4177 prg.printNl(strNumber( /* "! " */ 261)) 4178 prg.print( /* "angle(0,0) is taken as zero" */ 314) /* \xref[!\relax] */ 4179 } 4180 // \xref[angle(0,0)...zero] 4181 { 4182 prg.helpPtr = 2 4183 prg.helpLine[1] = /* "The `angle' between two identical points is undefined." */ 315 4184 prg.helpLine[0] = /* "I'm zeroing this one. Proceed, with fingers crossed." */ 309 4185 } 4186 prg.error1() 4187 r = 0 4188 } else { 4189 for x >= 04000000000 { 4190 x = x / 2 4191 y = y / 2 4192 } 4193 z = 0 4194 if y > 0 { 4195 for x < 02000000000 { 4196 x = x + x 4197 y = y + y 4198 } 4199 4200 // Increase |z| to the arg of $(x,y)$ 4201 k = 0 4202 for { 4203 y = y + y 4204 k = byte(int32(k) + 1) 4205 if y > x { 4206 z = z + prg.specAtan[k-1] 4207 t = x 4208 x = x + y/prg.twoToThe[int32(k)+int32(k)] 4209 y = y - t 4210 } 4211 if int32(k) == 15 { 4212 break 4213 } 4214 } 4215 for { 4216 y = y + y 4217 k = byte(int32(k) + 1) 4218 if y > x { 4219 z = z + prg.specAtan[k-1] 4220 y = y - x 4221 } 4222 if int32(k) == 26 { 4223 break 4224 } 4225 } 4226 } 4227 4228 // Return an appropriate answer based on |z| and |octant| 4229 switch octant { 4230 case firstOctant: 4231 r = z 4232 case secondOctant: 4233 r = 0550000000 - z 4234 case thirdOctant: 4235 r = 0550000000 + z 4236 case fourthOctant: 4237 r = 01320000000 - z 4238 case fifthOctant: 4239 r = z - 01320000000 4240 case sixthOctant: 4241 r = -z - 0550000000 4242 case seventhOctant: 4243 r = z - 0550000000 4244 case eighthOctant: 4245 r = -z 4246 } 4247 } 4248 return r 4249 } 4250 4251 // 145. 4252 4253 // tangle:pos ../../mf.web:2955:3: 4254 4255 // Given an integer |z| that is $2^[20]$ times an angle $\theta$ in degrees, 4256 // the purpose of |n_sin_cos(z)| is to set 4257 // |x=$r\cos\theta$| and |y=$r\sin\theta$| (approximately), 4258 // for some rather large number~|r|. The maximum of |x| and |y| 4259 // will be between $2^[28]$ and $2^[30]$, so that there will be hardly 4260 // any loss of accuracy. Then |x| and~|y| are divided by~|r|. 4261 func (prg *prg) nSinCos(z angle) { // computes a multiple of the sine and cosine 4262 var ( 4263 k smallNumber // loop control variable 4264 q/* 0..7 */ byte // specifies the quadrant 4265 r1 fraction // magnitude of |(x,y)| 4266 x, y, t int32 // temporary registers 4267 ) 4268 for z < 0 { 4269 z = z + 02640000000 4270 } 4271 z = z % 02640000000 // now |0<=z<three_sixty_deg| 4272 q = byte(z / 0264000000) 4273 z = z % 0264000000 4274 x = 02000000000 4275 y = x 4276 if !(q&1 != 0) { 4277 z = 0264000000 - z 4278 } 4279 4280 // Subtract angle |z| from |(x,y)| 4281 k = 1 4282 for z > 0 { 4283 if z >= prg.specAtan[k-1] { 4284 z = z - prg.specAtan[k-1] 4285 t = x 4286 4287 x = t + y/prg.twoToThe[k] 4288 y = y - t/prg.twoToThe[k] 4289 } 4290 k = byte(int32(k) + 1) 4291 } 4292 if y < 0 { 4293 y = 0 4294 } 4295 4296 // Convert |(x,y)| to the octant determined by~|q| 4297 switch q { 4298 case 0: 4299 case 1: 4300 t = x 4301 x = y 4302 y = t 4303 4304 case 2: 4305 t = x 4306 x = -y 4307 y = t 4308 4309 case 3: 4310 x = -x 4311 case 4: 4312 x = -x 4313 y = -y 4314 4315 case 5: 4316 t = x 4317 x = -y 4318 y = -t 4319 4320 case 6: 4321 t = x 4322 x = y 4323 y = -t 4324 4325 case 7: 4326 y = -y 4327 } 4328 r1 = prg.pythAdd(x, y) 4329 prg.nCos = prg.makeFraction(x, r1) 4330 prg.nSin = prg.makeFraction(y, r1) 4331 } 4332 4333 // 149. 4334 4335 // tangle:pos ../../mf.web:3029:3: 4336 4337 // To consume a random fraction, the program below will say `|next_random|' 4338 // and then it will fetch |randoms[j_random]|. The |next_random| macro 4339 // actually accesses the numbers backwards; blocks of 55~$x$'s are 4340 // essentially being ``flipped.'' But that doesn't make them less random. 4341 func (prg *prg) newRandoms() { 4342 var ( 4343 k/* 0..54 */ byte // index into |randoms| 4344 x fraction // accumulator 4345 ) 4346 for ii := int32(0); ii <= 23; ii++ { 4347 k = byte(ii) 4348 _ = k 4349 x = prg.randoms[k] - prg.randoms[int32(k)+31] 4350 if x < 0 { 4351 x = x + 02000000000 4352 } 4353 prg.randoms[k] = x 4354 } 4355 for ii := int32(24); ii <= 54; ii++ { 4356 k = byte(ii) 4357 _ = k 4358 x = prg.randoms[k] - prg.randoms[int32(k)-24] 4359 if x < 0 { 4360 x = x + 02000000000 4361 } 4362 prg.randoms[k] = x 4363 } 4364 prg.jRandom = 54 4365 } 4366 4367 // 150. 4368 4369 // tangle:pos ../../mf.web:3053:3: 4370 4371 // To initialize the |randoms| table, we call the following routine. 4372 func (prg *prg) initRandoms(seed scaled) { 4373 var ( 4374 j, jj, k fraction // more or less random integers 4375 i/* 0..54 */ byte // index into |randoms| 4376 ) 4377 j = abs(seed) 4378 for j >= 02000000000 { 4379 j = j / 2 4380 } 4381 k = 1 4382 for ii := int32(0); ii <= 54; ii++ { 4383 i = byte(ii) 4384 _ = i 4385 jj = k 4386 k = j - k 4387 j = jj 4388 if k < 0 { 4389 k = k + 02000000000 4390 } 4391 prg.randoms[int32(i)*21%55] = j 4392 } 4393 prg.newRandoms() 4394 prg.newRandoms() 4395 prg.newRandoms() // ``warm up'' the array 4396 } 4397 4398 // 151. 4399 4400 // tangle:pos ../../mf.web:3069:3: 4401 4402 // To produce a uniform random number in the range |0<=u<x| or |0>=u>x| 4403 // or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here. 4404 // 4405 // Note that the call of |take_fraction| will produce the values 0 and~|x| 4406 // with about half the probability that it will produce any other particular 4407 // values between 0 and~|x|, because it rounds its answers. 4408 func (prg *prg) unifRand(x scaled) (r scaled) { 4409 var ( 4410 y scaled // trial value 4411 ) 4412 if int32(prg.jRandom) == 0 { 4413 prg.newRandoms() 4414 } else { 4415 prg.jRandom = byte(int32(prg.jRandom) - 1) 4416 } 4417 y = prg.takeFraction(abs(x), prg.randoms[prg.jRandom]) 4418 if y == abs(x) { 4419 r = 0 4420 } else if x > 0 { 4421 r = y 4422 } else { 4423 r = -y 4424 } 4425 return r 4426 } 4427 4428 // 152. 4429 4430 // tangle:pos ../../mf.web:3084:3: 4431 4432 // Finally, a normal deviate with mean zero and unit standard deviation 4433 // can readily be obtained with the ratio method (Algorithm 3.4.1R in 4434 // [\sl The Art of Computer Programming\/]). 4435 func (prg *prg) normRand() (r scaled) { 4436 var ( 4437 x, u, l int32 // what the book would call $2^[16]X$, $2^[28]U$, 4438 // and $-2^[24]\ln U$ 4439 ) 4440 for { 4441 for { 4442 if int32(prg.jRandom) == 0 { 4443 prg.newRandoms() 4444 } else { 4445 prg.jRandom = byte(int32(prg.jRandom) - 1) 4446 } 4447 x = prg.takeFraction(112429, prg.randoms[prg.jRandom]-01000000000) 4448 // $2^[16]\sqrt[8/e]\approx 112428.82793$ 4449 if int32(prg.jRandom) == 0 { 4450 prg.newRandoms() 4451 } else { 4452 prg.jRandom = byte(int32(prg.jRandom) - 1) 4453 } 4454 u = prg.randoms[prg.jRandom] 4455 if abs(x) < u { 4456 break 4457 } 4458 } 4459 x = prg.makeFraction(x, u) 4460 l = 139548960 - prg.mLog(u) // $2^[24]\cdot12\ln2\approx139548959.6165$ 4461 if prg.abVsCd(1024, l, x, x) >= 0 { 4462 break 4463 } 4464 } 4465 r = x 4466 return r 4467 } // \2 4468 4469 func (prg *prg) showTokenList(p, q int32, l, nullTally int32) { 4470 var ( 4471 class, c smallNumber // the |char_class| of previous and new tokens 4472 r1, v int32 // temporary registers 4473 ) 4474 class = byte(percentClass) 4475 prg.tally = nullTally 4476 for p != memMin && prg.tally < l { 4477 if p == q { 4478 prg.firstCount = prg.tally 4479 prg.trickCount = prg.tally + 1 + errorLine - halfErrorLine 4480 if prg.trickCount < errorLine { 4481 prg.trickCount = errorLine 4482 } 4483 } 4484 4485 // Display token |p| and set |c| to its class; but |return| if there are problems 4486 c = byte(letterClass) // the default 4487 if p < memMin || p > int32(prg.memEnd) { 4488 prg.print( /* " CLOBBERED" */ 493) 4489 goto exit 4490 // \xref[CLOBBERED] 4491 } 4492 if p < int32(prg.hiMemMin) { 4493 if int32(*(*prg.mem[p].hh()).b1()) == token { 4494 if int32(*(*prg.mem[p].hh()).b0()) == known { 4495 if int32(class) == digitClass { 4496 prg.printChar(asciiCode(' ')) 4497 } 4498 v = *prg.mem[p+1].int() 4499 if v < 0 { 4500 if int32(class) == leftBracketClass { 4501 prg.printChar(asciiCode(' ')) 4502 } 4503 prg.printChar(asciiCode('[')) 4504 prg.printScaled(v) 4505 prg.printChar(asciiCode(']')) 4506 c = byte(rightBracketClass) 4507 } else { 4508 prg.printScaled(v) 4509 c = byte(digitClass) 4510 } 4511 } else if int32(*(*prg.mem[p].hh()).b0()) != stringType { 4512 prg.print( /* " BAD" */ 496) 4513 } else { 4514 prg.printChar(asciiCode('"')) 4515 prg.slowPrint(*prg.mem[p+1].int()) 4516 prg.printChar(asciiCode('"')) 4517 c = byte(stringClass) 4518 } 4519 } else if int32(*(*prg.mem[p].hh()).b1()) != capsule || int32(*(*prg.mem[p].hh()).b0()) < vacuous || int32(*(*prg.mem[p].hh()).b0()) > independent { 4520 prg.print( /* " BAD" */ 496) 4521 } else { 4522 prg.gPointer = uint16(p) 4523 prg.printCapsule() 4524 c = byte(rightParenClass) 4525 } 4526 } else { 4527 r1 = int32(*(*prg.mem[p].hh()).lh()) 4528 if r1 >= hashBase+hashSize+12+1 { 4529 if r1 < hashBase+hashSize+12+1+paramSize { 4530 prg.print( /* "(EXPR" */ 498) 4531 r1 = r1 - (hashBase + hashSize + 12 + 1) 4532 // \xref[EXPR] 4533 } else if r1 < hashBase+hashSize+12+1+paramSize+paramSize { 4534 prg.print( /* "(SUFFIX" */ 499) 4535 r1 = r1 - (hashBase + hashSize + 12 + 1 + paramSize) 4536 // \xref[SUFFIX] 4537 } else { 4538 prg.print( /* "(TEXT" */ 500) 4539 r1 = r1 - (hashBase + hashSize + 12 + 1 + paramSize + paramSize) 4540 // \xref[TEXT] 4541 } 4542 prg.printInt(r1) 4543 prg.printChar(asciiCode(')')) 4544 c = byte(rightParenClass) 4545 } else if r1 < 1 { 4546 if r1 == 0 { 4547 if int32(class) == leftBracketClass { 4548 prg.printChar(asciiCode(' ')) 4549 } 4550 prg.print( /* "[]" */ 497) 4551 c = byte(rightBracketClass) 4552 } else { 4553 prg.print( /* " IMPOSSIBLE" */ 494) 4554 } 4555 } else { 4556 r1 = int32(*prg.hash[r1-1].rh()) 4557 if r1 < 0 || r1 >= int32(prg.strPtr) { 4558 prg.print( /* " NONEXISTENT" */ 495) 4559 } else { 4560 // Print string |r| as a symbolic token and set |c| to its class 4561 c = prg.charClass[prg.strPool[prg.strStart[r1]]] 4562 if int32(c) == int32(class) { 4563 switch c { 4564 case letterClass: 4565 prg.printChar(asciiCode('.')) 4566 case 5, 6, 7, 8: 4567 4568 default: 4569 prg.printChar(asciiCode(' ')) 4570 } 4571 } 4572 prg.slowPrint(r1) 4573 } 4574 } 4575 } 4576 class = c 4577 p = int32(*(*prg.mem[p].hh()).rh()) 4578 } 4579 if p != memMin { 4580 prg.print( /* " ETC." */ 492) 4581 } 4582 // \xref[ETC] 4583 4584 // \xref[ETC] 4585 exit: 4586 } 4587 4588 // \4 4589 // Declare the procedure called |runaway| 4590 func (prg *prg) runaway() { 4591 if int32(prg.scannerStatus) > flushing { 4592 prg.printNl(strNumber( /* "Runaway " */ 637)) 4593 switch prg.scannerStatus { 4594 case absorbing: 4595 prg.print( /* "text?" */ 638) 4596 case varDefining, opDefining: 4597 prg.print( /* "definition?" */ 639) 4598 case loopDefining: 4599 prg.print( /* "loop?" */ 640) 4600 } // there are no other cases 4601 prg.printLn() 4602 prg.showTokenList(int32(*(*prg.mem[3000-2].hh()).rh()), memMin, errorLine-10, 0) 4603 } 4604 } 4605 4606 // 163. 4607 4608 // tangle:pos ../../mf.web:3304:3: 4609 4610 // The function |get_avail| returns a pointer to a new one-word node whose 4611 // |link| field is null. However, \MF\ will halt if there is no more room left. 4612 // \xref[inner loop] 4613 func (prg *prg) getAvail() (r halfword) { // single-word node allocation 4614 var ( 4615 p halfword // the new node being got 4616 ) 4617 p = prg.avail // get top location in the |avail| stack 4618 if int32(p) != memMin { 4619 prg.avail = *(*prg.mem[prg.avail].hh()).rh() 4620 } else if int32(prg.memEnd) < memMax { 4621 prg.memEnd = uint16(int32(prg.memEnd) + 1) 4622 p = prg.memEnd 4623 } else { 4624 prg.hiMemMin = uint16(int32(prg.hiMemMin) - 1) 4625 p = prg.hiMemMin 4626 if int32(prg.hiMemMin) <= int32(prg.loMemMax) { 4627 prg.runaway() // if memory is exhausted, display possible runaway text 4628 prg.overflow(strNumber( /* "main memory size" */ 316), memMax+1-memMin) 4629 // quit; all one-word nodes are busy 4630 // \xref[METAFONT capacity exceeded main memory size][\quad main memory size] 4631 } 4632 } 4633 *(*prg.mem[p].hh()).rh() = uint16(memMin) // provide an oft-desired initialization of the new node 4634 prg.dynUsed = prg.dynUsed + 1 // maintain statistics 4635 r = p 4636 return r 4637 } 4638 4639 // 164. 4640 4641 // tangle:pos ../../mf.web:3328:3: 4642 4643 // Conversely, a one-word node is recycled by calling |free_avail|. 4644 4645 // 165. 4646 4647 // tangle:pos ../../mf.web:3335:3: 4648 4649 // There's also a |fast_get_avail| routine, which saves the procedure-call 4650 // overhead at the expense of extra programming. This macro is used in 4651 // the places that would otherwise account for the most calls of |get_avail|. 4652 // \xref[inner loop] 4653 4654 // 167. 4655 4656 // tangle:pos ../../mf.web:3373:3: 4657 4658 // A call to |get_node| with argument |s| returns a pointer to a new node 4659 // of size~|s|, which must be 2~or more. The |link| field of the first word 4660 // of this new node is set to null. An overflow stop occurs if no suitable 4661 // space exists. 4662 // 4663 // If |get_node| is called with $s=2^[30]$, it simply merges adjacent free 4664 // areas and returns the value |max_halfword|. 4665 func (prg *prg) getNode(s int32) (r halfword) { 4666 var ( 4667 p halfword // the node currently under inspection 4668 q halfword // the node physically after node |p| 4669 r1 int32 // the newly allocated node, or a candidate for this honor 4670 t, tt int32 // temporary registers 4671 // \xref[inner loop] 4672 ) 4673 restart: 4674 p = prg.rover // start at some free node in the ring 4675 for { 4676 // Try to allocate within node |p| and its physical successors, and |goto found| if allocation was possible 4677 q = uint16(int32(p) + int32(*(*prg.mem[p].hh()).lh())) // find the physical successor 4678 for int32(*(*prg.mem[q].hh()).rh()) == 65535 { // merge node |p| with node |q| 4679 t = int32(*(*prg.mem[int32(q)+1].hh()).rh()) 4680 tt = int32(*(*prg.mem[int32(q)+1].hh()).lh()) 4681 // \xref[inner loop] 4682 if int32(q) == int32(prg.rover) { 4683 prg.rover = uint16(t) 4684 } 4685 *(*prg.mem[t+1].hh()).lh() = uint16(tt) 4686 *(*prg.mem[tt+1].hh()).rh() = uint16(t) 4687 4688 q = uint16(int32(q) + int32(*(*prg.mem[q].hh()).lh())) 4689 } 4690 r1 = int32(q) - s 4691 if r1 > int32(p)+1 { 4692 *(*prg.mem[p].hh()).lh() = uint16(r1 - int32(p)) // store the remaining size 4693 prg.rover = p // start searching here next time 4694 // start searching here next time 4695 goto found 4696 } 4697 if r1 == int32(p) { 4698 if int32(*(*prg.mem[int32(p)+1].hh()).rh()) != int32(p) { 4699 prg.rover = *(*prg.mem[int32(p)+1].hh()).rh() 4700 t = int32(*(*prg.mem[int32(p)+1].hh()).lh()) 4701 *(*prg.mem[int32(prg.rover)+1].hh()).lh() = uint16(t) 4702 *(*prg.mem[t+1].hh()).rh() = prg.rover 4703 4704 goto found 4705 } 4706 } 4707 *(*prg.mem[p].hh()).lh() = uint16(int32(q) - int32(p)) 4708 p = *(*prg.mem[int32(p)+1].hh()).rh() // move to the next node in the ring 4709 if int32(p) == int32(prg.rover) { 4710 break 4711 } 4712 } // repeat until the whole list has been traversed 4713 if s == 010000000000 { 4714 r = 65535 4715 goto exit 4716 } 4717 if int32(prg.loMemMax)+2 < int32(prg.hiMemMin) { 4718 if int32(prg.loMemMax)+2 <= memMin+65535 { 4719 if int32(prg.hiMemMin)-int32(prg.loMemMax) >= 1998 { 4720 t = int32(prg.loMemMax) + 1000 4721 } else { 4722 t = int32(prg.loMemMax) + 1 + (int32(prg.hiMemMin)-int32(prg.loMemMax))/2 4723 } 4724 // |lo_mem_max+2<=t<hi_mem_min| 4725 if t > memMin+65535 { 4726 t = memMin + 65535 4727 } 4728 p = *(*prg.mem[int32(prg.rover)+1].hh()).lh() 4729 q = prg.loMemMax 4730 *(*prg.mem[int32(p)+1].hh()).rh() = q 4731 *(*prg.mem[int32(prg.rover)+1].hh()).lh() = q 4732 4733 *(*prg.mem[int32(q)+1].hh()).rh() = prg.rover 4734 *(*prg.mem[int32(q)+1].hh()).lh() = p 4735 *(*prg.mem[q].hh()).rh() = 65535 4736 *(*prg.mem[q].hh()).lh() = uint16(t - int32(prg.loMemMax)) 4737 4738 prg.loMemMax = uint16(t) 4739 *(*prg.mem[prg.loMemMax].hh()).rh() = uint16(memMin) 4740 *(*prg.mem[prg.loMemMax].hh()).lh() = uint16(memMin) 4741 prg.rover = q 4742 goto restart 4743 } 4744 } 4745 prg.overflow(strNumber( /* "main memory size" */ 316), memMax+1-memMin) 4746 // sorry, nothing satisfactory is left 4747 // \xref[METAFONT capacity exceeded main memory size][\quad main memory size] 4748 4749 // sorry, nothing satisfactory is left 4750 // \xref[METAFONT capacity exceeded main memory size][\quad main memory size] 4751 found: 4752 *(*prg.mem[r1].hh()).rh() = uint16(memMin) // this node is now nonempty 4753 prg.varUsed = prg.varUsed + s // maintain usage statistics 4754 4755 r = uint16(r1) 4756 4757 exit: 4758 ; 4759 return r 4760 } 4761 4762 // 172. 4763 4764 // tangle:pos ../../mf.web:3454:3: 4765 4766 // Conversely, when some variable-size node |p| of size |s| is no longer needed, 4767 // the operation |free_node(p,s)| will make its words available, by inserting 4768 // |p| as a new empty node just before where |rover| now points. 4769 func (prg *prg) freeNode(p halfword, s halfword) { // variable-size node 4770 // liberation 4771 4772 var ( 4773 q halfword // |llink(rover)| 4774 ) 4775 *(*prg.mem[p].hh()).lh() = s 4776 *(*prg.mem[p].hh()).rh() = 65535 4777 // \xref[inner loop] 4778 q = *(*prg.mem[int32(prg.rover)+1].hh()).lh() 4779 *(*prg.mem[int32(p)+1].hh()).lh() = q 4780 *(*prg.mem[int32(p)+1].hh()).rh() = prg.rover // set both links 4781 *(*prg.mem[int32(prg.rover)+1].hh()).lh() = p 4782 *(*prg.mem[int32(q)+1].hh()).rh() = p // insert |p| into the ring 4783 prg.varUsed = prg.varUsed - int32(s) // maintain statistics 4784 } 4785 4786 // 173. 4787 4788 // tangle:pos ../../mf.web:3468:3: 4789 4790 // Just before \.[INIMF] writes out the memory, it sorts the doubly linked 4791 // available space list. The list is probably very short at such times, so a 4792 // simple insertion sort is used. The smallest available location will be 4793 // pointed to by |rover|, the next-smallest by |rlink(rover)|, etc. 4794 func (prg *prg) sortAvail() { // sorts the available variable-size nodes 4795 // by location 4796 4797 var ( 4798 p, q, r1 halfword // indices into |mem| 4799 oldRover halfword // initial |rover| setting 4800 ) 4801 p = prg.getNode(010000000000) // merge adjacent free areas 4802 p = *(*prg.mem[int32(prg.rover)+1].hh()).rh() 4803 *(*prg.mem[int32(prg.rover)+1].hh()).rh() = 65535 4804 oldRover = prg.rover 4805 for int32(p) != int32(oldRover) { 4806 // Sort |p| into the list starting at |rover| and advance |p| to |rlink(p)| 4807 if int32(p) < int32(prg.rover) { 4808 q = p 4809 p = *(*prg.mem[int32(q)+1].hh()).rh() 4810 *(*prg.mem[int32(q)+1].hh()).rh() = prg.rover 4811 prg.rover = q 4812 } else { 4813 q = prg.rover 4814 for int32(*(*prg.mem[int32(q)+1].hh()).rh()) < int32(p) { 4815 q = *(*prg.mem[int32(q)+1].hh()).rh() 4816 } 4817 r1 = *(*prg.mem[int32(p)+1].hh()).rh() 4818 *(*prg.mem[int32(p)+1].hh()).rh() = *(*prg.mem[int32(q)+1].hh()).rh() 4819 *(*prg.mem[int32(q)+1].hh()).rh() = p 4820 p = r1 4821 } 4822 } 4823 p = prg.rover 4824 for int32(*(*prg.mem[int32(p)+1].hh()).rh()) != 65535 { 4825 *(*prg.mem[int32(*(*prg.mem[int32(p)+1].hh()).rh())+1].hh()).lh() = p 4826 p = *(*prg.mem[int32(p)+1].hh()).rh() 4827 } 4828 *(*prg.mem[int32(p)+1].hh()).rh() = prg.rover 4829 *(*prg.mem[int32(prg.rover)+1].hh()).lh() = p 4830 } 4831 4832 // 175. \[11] Memory layout 4833 4834 // tangle:pos ../../mf.web:3502:24: 4835 4836 // Some areas of |mem| are dedicated to fixed usage, since static allocation is 4837 // more efficient than dynamic allocation when we can get away with it. For 4838 // example, locations |mem_min| to |mem_min+2| are always used to store the 4839 // specification for null pen coordinates that are `$(0,0)$'. The 4840 // following macro definitions accomplish the static allocation by giving 4841 // symbolic names to the fixed positions. Static variable-size nodes appear 4842 // in locations |mem_min| through |lo_mem_stat_max|, and static single-word nodes 4843 // appear in locations |hi_mem_stat_min| through |mem_top|, inclusive. 4844 4845 // 177. 4846 4847 // tangle:pos ../../mf.web:3545:3: 4848 4849 // The procedure |flush_list(p)| frees an entire linked list of one-word 4850 // nodes that starts at a given position, until coming to |sentinel| or a 4851 // pointer that is not in the one-word region. Another procedure, 4852 // |flush_node_list|, frees an entire linked list of one-word and two-word 4853 // nodes, until coming to a |null| pointer. 4854 // \xref[inner loop] 4855 func (prg *prg) flushList(p halfword) { 4856 var ( 4857 q, r1 halfword // list traversers 4858 ) 4859 if int32(p) >= int32(prg.hiMemMin) { 4860 if int32(p) != 3000 { 4861 r1 = p 4862 for { 4863 q = r1 4864 r1 = *(*prg.mem[r1].hh()).rh() 4865 prg.dynUsed = prg.dynUsed - 1 4866 4867 if int32(r1) < int32(prg.hiMemMin) { 4868 goto done 4869 } 4870 if int32(r1) == 3000 { 4871 break 4872 } 4873 } 4874 4875 done: 4876 *(*prg.mem[q].hh()).rh() = prg.avail 4877 prg.avail = p 4878 } 4879 } 4880 } 4881 4882 func (prg *prg) flushNodeList(p halfword) { 4883 var ( 4884 q halfword // the node being recycled 4885 ) 4886 for int32(p) != memMin { 4887 q = p 4888 p = *(*prg.mem[p].hh()).rh() 4889 if int32(q) < int32(prg.hiMemMin) { 4890 prg.freeNode(q, halfword(2)) 4891 } else { 4892 *(*prg.mem[q].hh()).rh() = prg.avail 4893 prg.avail = q 4894 prg.dynUsed = prg.dynUsed - 1 4895 } 4896 } 4897 } 4898 4899 // 180. 4900 4901 // tangle:pos ../../mf.web:3599:3: 4902 4903 // Procedure |check_mem| makes sure that the available space lists of 4904 // |mem| are well formed, and it optionally prints out all locations 4905 // that are reserved now but were free the last time this procedure was called. 4906 // procedure check_mem( print_locs : boolean); 4907 // label done1,done2; [loop exits] 4908 // var p, q, r:halfword ; [current locations of interest in |mem|] 4909 // clobbered:boolean; [is something amiss?] 4910 // begin for p:=mem_min to lo_mem_max do free[p]:=false; [you can probably 4911 // do this faster] 4912 // for p:=hi_mem_min to mem_end do free[p]:=false; [ditto] 4913 // 4914 // [ Check single-word |avail| list ] 4915 // p:=avail; q:=mem_min ; clobbered:=false; 4916 // while p<>mem_min do 4917 // begin if (p>mem_end)or(p<hi_mem_min) then clobbered:=true 4918 // else if free[p] then clobbered:=true; 4919 // if clobbered then 4920 // begin print_nl(["AVAIL list clobbered at "=]317); 4921 // [ \xref[AVAIL list clobbered...] ] 4922 // print_int(q); goto done1; 4923 // end; 4924 // free[p]:=true; q:=p; p:= mem[ q].hh.rh ; 4925 // end; 4926 // done1: 4927 // 4928 // ; 4929 // 4930 // [ Check variable-size |avail| list ] 4931 // p:=rover; q:=mem_min ; clobbered:=false; 4932 // repeat if (p>=lo_mem_max)or(p<mem_min) then clobbered:=true 4933 // else if ( mem[ p+ 1].hh.rh >=lo_mem_max)or( mem[ p+ 1].hh.rh <mem_min) then clobbered:=true 4934 // else if not( ( mem[ p].hh.rh = 65535 ) )or( mem[ p].hh.lh <2)or 4935 // (p+ mem[ p].hh.lh >lo_mem_max)or ( mem[ mem[ p+ 1].hh.rh + 1].hh.lh <>p) then clobbered:=true; 4936 // if clobbered then 4937 // begin print_nl(["Double-AVAIL list clobbered at "=]318); 4938 // [ \xref[Double-AVAIL list clobbered...] ] 4939 // print_int(q); goto done2; 4940 // end; 4941 // for q:=p to p+ mem[ p].hh.lh -1 do [mark all locations free] 4942 // begin if free[q] then 4943 // begin print_nl(["Doubly free location at "=]319); 4944 // [ \xref[Doubly free location...] ] 4945 // print_int(q); goto done2; 4946 // end; 4947 // free[q]:=true; 4948 // end; 4949 // q:=p; p:= mem[ p+ 1].hh.rh ; 4950 // until p=rover; 4951 // done2: 4952 // 4953 // ; 4954 // 4955 // [ Check flags of unavailable nodes ] 4956 // p:=mem_min; 4957 // while p<=lo_mem_max do [node |p| should not be empty] 4958 // begin if ( mem[ p].hh.rh = 65535 ) then 4959 // begin print_nl(["Bad flag at "=]320); print_int(p); 4960 // [ \xref[Bad flag...] ] 4961 // end; 4962 // while (p<=lo_mem_max) and not free[p] do p:= p+1 ; 4963 // while (p<=lo_mem_max) and free[p] do p:= p+1 ; 4964 // end 4965 // 4966 // ; 4967 // 4968 // [ Check the list of linear dependencies ] 4969 // q:=mem_min +3 +10 ; p:= mem[ q].hh.rh ; 4970 // while p<>mem_min +3 +10 do 4971 // begin if mem[ p+1 ].hh.lh <>q then 4972 // begin print_nl(["Bad PREVDEP at "=]597); print_int(p); 4973 // [ \xref[Bad PREVDEP...] ] 4974 // end; 4975 // p:= mem[ p+1 ].hh.rh ; r:=mem_min +3 +10 +2 +2 +2 ; 4976 // repeat if mem[ mem[ p].hh.lh +1 ].int >=mem[ r+1 ].int then 4977 // begin print_nl(["Out of order at "=]598); print_int(p); 4978 // [ \xref[Out of order...] ] 4979 // end; 4980 // r:= mem[ p].hh.lh ; q:=p; p:= mem[ q].hh.rh ; 4981 // until r=mem_min ; 4982 // end 4983 // 4984 // ; 4985 // if print_locs then 4986 // [ Print newly busy locations ] 4987 // begin print_nl(["New busy locs:"=]321); 4988 // [ \xref[New busy locs] ] 4989 // for p:=mem_min to lo_mem_max do 4990 // if not free[p] and ((p>was_lo_max) or was_free[p]) then 4991 // begin print_char([" "=]32); print_int(p); 4992 // end; 4993 // for p:=hi_mem_min to mem_end do 4994 // if not free[p] and 4995 // ((p<was_hi_min) or (p>was_mem_end) or was_free[p]) then 4996 // begin print_char([" "=]32); print_int(p); 4997 // end; 4998 // end 4999 // 5000 // ; 5001 // for p:=mem_min to lo_mem_max do was_free[p]:=free[p]; 5002 // for p:=hi_mem_min to mem_end do was_free[p]:=free[p]; 5003 // [|was_free:=free| might be faster] 5004 // was_mem_end:=mem_end; was_lo_max:=lo_mem_max; was_hi_min:=hi_mem_min; 5005 // end; 5006 // [ ] 5007 5008 // 185. 5009 5010 // tangle:pos ../../mf.web:3684:3: 5011 5012 // The |search_mem| procedure attempts to answer the question ``Who points 5013 // to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem| 5014 // that might not be of type |two_halves|. Strictly speaking, this is 5015 // \xref[dirty \PASCAL] 5016 // undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to 5017 // point to |p| purely by coincidence). But for debugging purposes, we want 5018 // to rule out the places that do [\sl not\/] point to |p|, so a few false 5019 // drops are tolerable. 5020 // procedure search_mem( p:halfword ); [look for pointers to |p|] 5021 // var q:integer; [current position being searched] 5022 // begin for q:=mem_min to lo_mem_max do 5023 // begin if mem[ q].hh.rh =p then 5024 // begin print_nl(["LINK("=]322); print_int(q); print_char([")"=]41); 5025 // end; 5026 // if mem[ q].hh.lh =p then 5027 // begin print_nl(["INFO("=]323); print_int(q); print_char([")"=]41); 5028 // end; 5029 // end; 5030 // for q:=hi_mem_min to mem_end do 5031 // begin if mem[ q].hh.rh =p then 5032 // begin print_nl(["LINK("=]322); print_int(q); print_char([")"=]41); 5033 // end; 5034 // if mem[ q].hh.lh =p then 5035 // begin print_nl(["INFO("=]323); print_int(q); print_char([")"=]41); 5036 // end; 5037 // end; 5038 // 5039 // [ Search |eqtb| for equivalents equal to |p| ] 5040 // for q:=1 to hash_base+hash_size +12 do 5041 // begin if eqtb[ q].rh =p then 5042 // begin print_nl(["EQUIV("=]458); print_int(q); print_char([")"=]41); 5043 // end; 5044 // end 5045 // 5046 // ; 5047 // end; 5048 // [ ] 5049 5050 // 188. 5051 5052 // tangle:pos ../../mf.web:3900:3: 5053 5054 // Values inside \MF\ are stored in two-word nodes that have a |name_type| 5055 // as well as a |type|. The possibilities for |name_type| are defined 5056 // here; they will be explained in more detail later. 5057 5058 // 189. 5059 5060 // tangle:pos ../../mf.web:3918:3: 5061 5062 // Primitive operations that produce values have a secondary identification 5063 // code in addition to their command code; it's something like genera and species. 5064 // For example, `\.*' has the command code |primary_binary|, and its 5065 // secondary identification is |times|. The secondary codes start at 30 so that 5066 // they don't overlap with the type codes; some type codes (e.g., |string_type|) 5067 // are used as operators as well as type identifications. 5068 func (prg *prg) printOp(c quarterword) { 5069 if int32(c) <= numericType { 5070 prg.printType(c) 5071 } else { 5072 switch c { 5073 case trueCode: 5074 prg.print( /* "true" */ 348) 5075 case falseCode: 5076 prg.print( /* "false" */ 349) 5077 case nullPictureCode: 5078 prg.print( /* "nullpicture" */ 350) 5079 case nullPenCode: 5080 prg.print( /* "nullpen" */ 351) 5081 case jobNameOp: 5082 prg.print( /* "jobname" */ 352) 5083 case readStringOp: 5084 prg.print( /* "readstring" */ 353) 5085 case penCircle: 5086 prg.print( /* "pencircle" */ 354) 5087 case normalDeviate: 5088 prg.print( /* "normaldeviate" */ 355) 5089 case oddOp: 5090 prg.print( /* "odd" */ 356) 5091 case knownOp: 5092 prg.print( /* "known" */ 357) 5093 case unknownOp: 5094 prg.print( /* "unknown" */ 358) 5095 case notOp: 5096 prg.print( /* "not" */ 359) 5097 case decimal: 5098 prg.print( /* "decimal" */ 360) 5099 case reverse: 5100 prg.print( /* "reverse" */ 361) 5101 case makePathOp: 5102 prg.print( /* "makepath" */ 362) 5103 case makePenOp: 5104 prg.print( /* "makepen" */ 363) 5105 case totalWeightOp: 5106 prg.print( /* "totalweight" */ 364) 5107 case octOp: 5108 prg.print( /* "oct" */ 365) 5109 case hexOp: 5110 prg.print( /* "hex" */ 366) 5111 case asciiOp: 5112 prg.print( /* "ASCII" */ 367) 5113 case charOp: 5114 prg.print( /* "char" */ 368) 5115 case lengthOp: 5116 prg.print( /* "length" */ 369) 5117 case turningOp: 5118 prg.print( /* "turningnumber" */ 370) 5119 case xPart: 5120 prg.print( /* "xpart" */ 371) 5121 case yPart: 5122 prg.print( /* "ypart" */ 372) 5123 case xxPart: 5124 prg.print( /* "xxpart" */ 373) 5125 case xyPart: 5126 prg.print( /* "xypart" */ 374) 5127 case yxPart: 5128 prg.print( /* "yxpart" */ 375) 5129 case yyPart: 5130 prg.print( /* "yypart" */ 376) 5131 case sqrtOp: 5132 prg.print( /* "sqrt" */ 377) 5133 case mExpOp: 5134 prg.print( /* "mexp" */ 378) 5135 case mLogOp: 5136 prg.print( /* "mlog" */ 379) 5137 case sinDOp: 5138 prg.print( /* "sind" */ 380) 5139 case cosDOp: 5140 prg.print( /* "cosd" */ 381) 5141 case floorOp: 5142 prg.print( /* "floor" */ 382) 5143 case uniformDeviate: 5144 prg.print( /* "uniformdeviate" */ 383) 5145 case charExistsOp: 5146 prg.print( /* "charexists" */ 384) 5147 case angleOp: 5148 prg.print( /* "angle" */ 385) 5149 case cycleOp: 5150 prg.print( /* "cycle" */ 386) 5151 case plus: 5152 prg.printChar(asciiCode('+')) 5153 case minus: 5154 prg.printChar(asciiCode('-')) 5155 case times: 5156 prg.printChar(asciiCode('*')) 5157 case over: 5158 prg.printChar(asciiCode('/')) 5159 case pythagAdd: 5160 prg.print( /* "++" */ 387) 5161 case pythagSub: 5162 prg.print( /* "+-+" */ 311) 5163 case orOp: 5164 prg.print( /* "or" */ 388) 5165 case andOp: 5166 prg.print( /* "and" */ 389) 5167 case lessThan: 5168 prg.printChar(asciiCode('<')) 5169 case lessOrEqual: 5170 prg.print( /* "<=" */ 390) 5171 case greaterThan: 5172 prg.printChar(asciiCode('>')) 5173 case greaterOrEqual: 5174 prg.print( /* ">=" */ 391) 5175 case equalTo: 5176 prg.printChar(asciiCode('=')) 5177 case unequalTo: 5178 prg.print( /* "<>" */ 392) 5179 case concatenate: 5180 prg.print('&') 5181 case rotatedBy: 5182 prg.print( /* "rotated" */ 393) 5183 case slantedBy: 5184 prg.print( /* "slanted" */ 394) 5185 case scaledBy: 5186 prg.print( /* "scaled" */ 395) 5187 case shiftedBy: 5188 prg.print( /* "shifted" */ 396) 5189 case transformedBy: 5190 prg.print( /* "transformed" */ 397) 5191 case xScaled: 5192 prg.print( /* "xscaled" */ 398) 5193 case yScaled: 5194 prg.print( /* "yscaled" */ 399) 5195 case zScaled: 5196 prg.print( /* "zscaled" */ 400) 5197 case intersect: 5198 prg.print( /* "intersectiontimes" */ 401) 5199 case substringOf: 5200 prg.print( /* "substring" */ 402) 5201 case subpathOf: 5202 prg.print( /* "subpath" */ 403) 5203 case directionTimeOf: 5204 prg.print( /* "directiontime" */ 404) 5205 case pointOf: 5206 prg.print( /* "point" */ 405) 5207 case precontrolOf: 5208 prg.print( /* "precontrol" */ 406) 5209 case postcontrolOf: 5210 prg.print( /* "postcontrol" */ 407) 5211 case penOffsetOf: 5212 prg.print( /* "penoffset" */ 408) 5213 5214 default: 5215 prg.print( /* ".." */ 409) 5216 } 5217 } 5218 } 5219 5220 // 194. 5221 5222 // tangle:pos ../../mf.web:4268:3: 5223 5224 // The following procedure, which is called just before \MF\ initializes its 5225 // input and output, establishes the initial values of the date and time. 5226 // \xref[system dependencies] 5227 // Since standard \PASCAL\ cannot provide such information, something special 5228 // is needed. The program here simply assumes that suitable values appear in 5229 // the global variables \\[sys\_time], \\[sys\_day], \\[sys\_month], and 5230 // \\[sys\_year] (which are initialized to noon on 4 July 1776, 5231 // in case the implementor is careless). 5232 // 5233 // Note that the values are |scaled| integers. Hence \MF\ can no longer 5234 // be used after the year 32767. 5235 func (prg *prg) fixDateAndTime() { 5236 prg.sysTime = 12 * 60 5237 prg.sysDay = 4 5238 prg.sysMonth = 7 5239 prg.sysYear = 1776 // self-evident truths 5240 prg.internal[time-1] = prg.sysTime * 0200000 // minutes since midnight 5241 prg.internal[day-1] = prg.sysDay * 0200000 // day of the month 5242 prg.internal[month-1] = prg.sysMonth * 0200000 // month of the year 5243 prg.internal[year-1] = prg.sysYear * 0200000 // Anno Domini 5244 } 5245 5246 // 205. 5247 5248 // tangle:pos ../../mf.web:4485:3: 5249 5250 // Here is the subroutine that searches the hash table for an identifier 5251 // that matches a given string of length~|l| appearing in |buffer[j.. 5252 // (j+l-1)]|. If the identifier is not found, it is inserted; hence it 5253 // will always be found, and the corresponding hash table address 5254 // will be returned. 5255 func (prg *prg) idLookup(j, l int32) (r halfword) { // go here when you've found it 5256 var ( 5257 h int32 // hash code 5258 p halfword // index in |hash| array 5259 k halfword // index in |buffer| array 5260 ) 5261 if l == 1 { 5262 p = uint16(int32(prg.buffer[j]) + 1) 5263 *prg.hash[p-1].rh() = uint16(int32(p) - 1) 5264 goto found 5265 } 5266 5267 // Compute the hash code |h| 5268 h = int32(prg.buffer[j]) 5269 for ii := j + 1; ii <= j+l-1; ii++ { 5270 k = halfword(ii) 5271 _ = k 5272 h = h + h + int32(prg.buffer[k]) 5273 for h >= hashPrime { 5274 h = h - hashPrime 5275 } 5276 } 5277 p = uint16(h + hashBase) // we start searching here; note that |0<=h<hash_prime| 5278 for true { 5279 if int32(*prg.hash[p-1].rh()) > 0 { 5280 if int32(prg.strStart[int32(*prg.hash[p-1].rh())+1])-int32(prg.strStart[*prg.hash[p-1].rh()]) == l { 5281 if prg.strEqBuf(*prg.hash[p-1].rh(), j) { 5282 goto found 5283 } 5284 } 5285 } 5286 if int32(*prg.hash[p-1].lh()) == 0 { 5287 if int32(*prg.hash[p-1].rh()) > 0 { 5288 for { 5289 if int32(prg.hashUsed) == hashBase { 5290 prg.overflow(strNumber( /* "hash size" */ 457), hashSize) 5291 } 5292 // \xref[METAFONT capacity exceeded hash size][\quad hash size] 5293 prg.hashUsed = uint16(int32(prg.hashUsed) - 1) 5294 if int32(*prg.hash[prg.hashUsed-1].rh()) == 0 { 5295 break 5296 } 5297 } // search for an empty location in |hash| 5298 *prg.hash[p-1].lh() = prg.hashUsed 5299 p = prg.hashUsed 5300 } 5301 { 5302 if int32(prg.poolPtr)+l > int32(prg.maxPoolPtr) { 5303 if int32(prg.poolPtr)+l > poolSize { 5304 prg.overflow(strNumber( /* "pool size" */ 257), poolSize-int32(prg.initPoolPtr)) 5305 } /* \xref[METAFONT capacity exceeded pool size][\quad pool size] */ 5306 prg.maxPoolPtr = uint16(int32(prg.poolPtr) + l) 5307 } 5308 } 5309 for ii := j; ii <= j+l-1; ii++ { 5310 k = halfword(ii) 5311 _ = k 5312 prg.strPool[prg.poolPtr] = prg.buffer[k] 5313 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 5314 } 5315 *prg.hash[p-1].rh() = prg.makeString() 5316 prg.strRef[*prg.hash[p-1].rh()] = byte(maxStrRef) 5317 prg.stCount = prg.stCount + 1 5318 5319 goto found 5320 } 5321 p = *prg.hash[p-1].lh() 5322 } 5323 5324 found: 5325 r = p 5326 return r 5327 } 5328 5329 // 210. 5330 5331 // tangle:pos ../../mf.web:4549:3: 5332 5333 // We need to put \MF's ``primitive'' symbolic tokens into the hash 5334 // table, together with their command code (which will be the |eq_type|) 5335 // and an operand (which will be the |equiv|). The |primitive| procedure 5336 // does this, in a way that no \MF\ user can. The global value |cur_sym| 5337 // contains the new |eqtb| pointer after |primitive| has acted. 5338 func (prg *prg) primitive(s strNumber, c halfword, o halfword) { 5339 var ( 5340 k poolPointer // index into |str_pool| 5341 j smallNumber // index into |buffer| 5342 l smallNumber // length of the string 5343 ) 5344 k = prg.strStart[s] 5345 l = byte(int32(prg.strStart[int32(s)+1]) - int32(k)) 5346 // we will move |s| into the (empty) |buffer| 5347 for ii := int32(0); ii <= int32(l)-1; ii++ { 5348 j = smallNumber(ii) 5349 _ = j 5350 prg.buffer[j] = prg.strPool[int32(k)+int32(j)] 5351 } 5352 prg.curSym = prg.idLookup(0, int32(l)) 5353 5354 if int32(s) >= 256 { 5355 prg.flushString(strNumber(int32(prg.strPtr) - 1)) 5356 *prg.hash[prg.curSym-1].rh() = s 5357 } 5358 *prg.eqtb[prg.curSym-1].lh() = c 5359 *prg.eqtb[prg.curSym-1].rh() = o 5360 } 5361 5362 // 213. 5363 5364 // tangle:pos ../../mf.web:4712:3: 5365 5366 // We will deal with the other primitives later, at some point in the program 5367 // where their |eq_type| and |equiv| values are more meaningful. For example, 5368 // the primitives for macro definitions will be loaded when we consider the 5369 // routines that define macros. 5370 // It is easy to find where each particular 5371 // primitive was treated by looking in the index at the end; for example, the 5372 // section where |"def"| entered |eqtb| is listed under `\&[def] primitive'. 5373 5374 // 215. 5375 5376 // tangle:pos ../../mf.web:4764:3: 5377 5378 // A numeric token is created by the following trivial routine. 5379 func (prg *prg) newNumTok(v scaled) (r halfword) { 5380 var ( 5381 p halfword // the new node 5382 ) 5383 p = prg.getNode(tokenNodeSize) 5384 *prg.mem[int32(p)+1].int() = v 5385 *(*prg.mem[p].hh()).b0() = byte(known) 5386 *(*prg.mem[p].hh()).b1() = byte(token) 5387 r = p 5388 return r 5389 } // \2 5390 5391 func (prg *prg) flushTokenList(p halfword) { 5392 var ( 5393 q halfword // the node being recycled 5394 ) 5395 for int32(p) != memMin { 5396 q = p 5397 p = *(*prg.mem[p].hh()).rh() 5398 if int32(q) >= int32(prg.hiMemMin) { 5399 *(*prg.mem[q].hh()).rh() = prg.avail 5400 prg.avail = q 5401 prg.dynUsed = prg.dynUsed - 1 5402 } else { 5403 switch *(*prg.mem[q].hh()).b0() { 5404 case vacuous, booleanType, known: 5405 case stringType: 5406 if int32(prg.strRef[*prg.mem[int32(q)+1].int()]) < maxStrRef { 5407 if int32(prg.strRef[*prg.mem[int32(q)+1].int()]) > 1 { 5408 prg.strRef[*prg.mem[int32(q)+1].int()] = byte(int32(prg.strRef[*prg.mem[int32(q)+1].int()]) - 1) 5409 } else { 5410 prg.flushString(strNumber(*prg.mem[int32(q)+1].int())) 5411 } 5412 } 5413 case unknownBoolean, unknownString, unknownPen, unknownPicture, 5414 unknownPath, penType, pathType, futurePen, 5415 pictureType, pairType, transformType, dependent, 5416 protoDependent, independent: 5417 prg.gPointer = q 5418 prg.tokenRecycle() 5419 5420 default: 5421 prg.confusion(strNumber( /* "token" */ 491)) 5422 // \xref[this can't happen token][\quad token] 5423 } 5424 5425 prg.freeNode(q, halfword(tokenNodeSize)) 5426 } 5427 } 5428 } 5429 5430 // 226. 5431 5432 // tangle:pos ../../mf.web:4940:3: 5433 5434 // Macro definitions are kept in \MF's memory in the form of token lists 5435 // that have a few extra one-word nodes at the beginning. 5436 // 5437 // The first node contains a reference count that is used to tell when the 5438 // list is no longer needed. To emphasize the fact that a reference count is 5439 // present, we shall refer to the |info| field of this special node as the 5440 // |ref_count| field. 5441 // \xref[reference counts] 5442 // 5443 // The next node or nodes after the reference count serve to describe the 5444 // formal parameters. They consist of zero or more parameter tokens followed 5445 // by a code for the type of macro. 5446 func (prg *prg) deleteMacRef(p halfword) { 5447 if int32(*(*prg.mem[p].hh()).lh()) == memMin { 5448 prg.flushTokenList(p) 5449 } else { 5450 *(*prg.mem[p].hh()).lh() = uint16(int32(*(*prg.mem[p].hh()).lh()) - 1) 5451 } 5452 } 5453 5454 // 227. 5455 5456 // tangle:pos ../../mf.web:4972:3: 5457 5458 // The following subroutine displays a macro, given a pointer to its 5459 // reference count. 5460 // \4 5461 // Declare the procedure called |print_cmd_mod| 5462 func (prg *prg) printCmdMod(c, m int32) { 5463 switch c { 5464 case addToCommand: 5465 prg.print( /* "addto" */ 462) 5466 case assignment: 5467 prg.print( /* ":=" */ 461) 5468 case atLeast: 5469 prg.print( /* "atleast" */ 464) 5470 case atToken: 5471 prg.print( /* "at" */ 463) 5472 case bcharLabel: 5473 prg.print( /* "||:" */ 460) 5474 case beginGroup: 5475 prg.print( /* "begingroup" */ 465) 5476 case colon: 5477 prg.print(':') 5478 case comma: 5479 prg.print(',') 5480 case controls: 5481 prg.print( /* "controls" */ 466) 5482 case cullCommand: 5483 prg.print( /* "cull" */ 467) 5484 case curlCommand: 5485 prg.print( /* "curl" */ 468) 5486 case delimiters: 5487 prg.print( /* "delimiters" */ 469) 5488 case displayCommand: 5489 prg.print( /* "display" */ 470) 5490 case doubleColon: 5491 prg.print( /* "::" */ 459) 5492 case endGroup: 5493 prg.print( /* "endgroup" */ 453) 5494 case everyJobCommand: 5495 prg.print( /* "everyjob" */ 471) 5496 case exitTest: 5497 prg.print( /* "exitif" */ 472) 5498 case expandAfter: 5499 prg.print( /* "expandafter" */ 473) 5500 case fromToken: 5501 prg.print( /* "from" */ 474) 5502 case inWindow: 5503 prg.print( /* "inwindow" */ 475) 5504 case interimCommand: 5505 prg.print( /* "interim" */ 476) 5506 case leftBrace: 5507 prg.print('{') 5508 case leftBracket: 5509 prg.print('[') 5510 case letCommand: 5511 prg.print( /* "let" */ 477) 5512 case newInternal: 5513 prg.print( /* "newinternal" */ 478) 5514 case ofToken: 5515 prg.print( /* "of" */ 479) 5516 case openWindow: 5517 prg.print( /* "openwindow" */ 480) 5518 case pathJoin: 5519 prg.print( /* ".." */ 409) 5520 case randomSeed: 5521 prg.print( /* "randomseed" */ 481) 5522 case relax: 5523 prg.printChar(asciiCode('\\')) 5524 case rightBrace: 5525 prg.print('}') 5526 case rightBracket: 5527 prg.print(']') 5528 case saveCommand: 5529 prg.print( /* "save" */ 482) 5530 case scanTokens: 5531 prg.print( /* "scantokens" */ 483) 5532 case semicolon: 5533 prg.print(';') 5534 case shipOutCommand: 5535 prg.print( /* "shipout" */ 484) 5536 case skipTo: 5537 prg.print( /* "skipto" */ 485) 5538 case stepToken: 5539 prg.print( /* "step" */ 486) 5540 case strOp: 5541 prg.print( /* "str" */ 487) 5542 case tension: 5543 prg.print( /* "tension" */ 488) 5544 case toToken: 5545 prg.print( /* "to" */ 489) 5546 case untilToken: 5547 prg.print( /* "until" */ 490) 5548 5549 case macroDef: 5550 if m <= varDef { 5551 if m == startDef { 5552 prg.print( /* "def" */ 654) 5553 } else if m < startDef { 5554 prg.print( /* "enddef" */ 454) 5555 } else { 5556 prg.print( /* "vardef" */ 655) 5557 } 5558 } else if m == secondaryPrimaryMacro { 5559 prg.print( /* "primarydef" */ 656) 5560 } else if m == tertiarySecondaryMacro { 5561 prg.print( /* "secondarydef" */ 657) 5562 } else { 5563 prg.print( /* "tertiarydef" */ 658) 5564 } 5565 case iteration: 5566 if m <= startForever { 5567 if m == startForever { 5568 prg.print( /* "forever" */ 661) 5569 } else { 5570 prg.print( /* "endfor" */ 455) 5571 } 5572 } else if m == hashBase+hashSize+12+1 { 5573 prg.print( /* "for" */ 659) 5574 } else { 5575 prg.print( /* "forsuffixes" */ 660) 5576 } 5577 5578 case macroSpecial: 5579 switch m { 5580 case macroPrefix: 5581 prg.print( /* "#@" */ 663) 5582 case macroAt: 5583 prg.printChar(asciiCode('@')) 5584 case macroSuffix: 5585 prg.print( /* "@#" */ 664) 5586 5587 default: 5588 prg.print( /* "quote" */ 662) 5589 } 5590 5591 case paramType: 5592 if m >= hashBase+hashSize+12+1 { 5593 if m == hashBase+hashSize+12+1 { 5594 prg.print( /* "expr" */ 675) 5595 } else if m == hashBase+hashSize+12+1+paramSize { 5596 prg.print( /* "suffix" */ 676) 5597 } else { 5598 prg.print( /* "text" */ 677) 5599 } 5600 } else if m < secondaryMacro { 5601 prg.print( /* "primary" */ 678) 5602 } else if m == secondaryMacro { 5603 prg.print( /* "secondary" */ 679) 5604 } else { 5605 prg.print( /* "tertiary" */ 680) 5606 } 5607 5608 case input: 5609 if m == 0 { 5610 prg.print( /* "input" */ 690) 5611 } else { 5612 prg.print( /* "endinput" */ 616) 5613 } 5614 5615 case ifTest, fiOrElse: 5616 switch m { 5617 case ifCode: 5618 prg.print( /* "if" */ 717) 5619 case fiCode: 5620 prg.print( /* "fi" */ 452) 5621 case elseCode: 5622 prg.print( /* "else" */ 718) 5623 5624 default: 5625 prg.print( /* "elseif" */ 719) 5626 } 5627 5628 case nullary, unary, primaryBinary, secondaryBinary, 5629 tertiaryBinary, expressionBinary, cycle, plusOrMinus, 5630 slash, ampersand, equals, andCommand: 5631 prg.printOp(quarterword(m)) 5632 5633 case typeName: 5634 prg.printType(smallNumber(m)) 5635 5636 case stop: 5637 if m == 0 { 5638 prg.print( /* "end" */ 912) 5639 } else { 5640 prg.print( /* "dump" */ 913) 5641 } 5642 5643 case modeCommand: 5644 switch m { 5645 case batchMode: 5646 prg.print( /* "batchmode" */ 273) 5647 case nonstopMode: 5648 prg.print( /* "nonstopmode" */ 274) 5649 case scrollMode: 5650 prg.print( /* "scrollmode" */ 275) 5651 5652 default: 5653 prg.print( /* "errorstopmode" */ 919) 5654 } 5655 5656 case protectionCommand: 5657 if m == 0 { 5658 prg.print( /* "inner" */ 920) 5659 } else { 5660 prg.print( /* "outer" */ 921) 5661 } 5662 5663 case showCommand: 5664 switch m { 5665 case showTokenCode: 5666 prg.print( /* "showtoken" */ 935) 5667 case showStatsCode: 5668 prg.print( /* "showstats" */ 936) 5669 case showCode: 5670 prg.print( /* "show" */ 937) 5671 case showVarCode: 5672 prg.print( /* "showvariable" */ 938) 5673 5674 default: 5675 prg.print( /* "showdependencies" */ 939) 5676 } 5677 5678 case leftDelimiter, rightDelimiter: 5679 if c == leftDelimiter { 5680 prg.print( /* "lef" */ 942) 5681 } else { 5682 prg.print( /* "righ" */ 943) 5683 } 5684 prg.print( /* "t delimiter that matches " */ 944) 5685 prg.slowPrint(int32(*prg.hash[m-1].rh())) 5686 5687 case tagToken: 5688 if m == memMin { 5689 prg.print( /* "tag" */ 945) 5690 } else { 5691 prg.print( /* "variable" */ 946) 5692 } 5693 case definedMacro: 5694 prg.print( /* "macro:" */ 947) 5695 case secondaryPrimaryMacro, tertiarySecondaryMacro, expressionTertiaryMacro: 5696 prg.printCmdMod(macroDef, c) 5697 prg.print( /* "'d macro:" */ 948) 5698 prg.printLn() 5699 prg.showTokenList(int32(*(*prg.mem[*(*prg.mem[m].hh()).rh()].hh()).rh()), memMin, 1000, 0) 5700 5701 case repeatLoop: 5702 prg.print( /* "[repeat the loop]" */ 949) 5703 case internalQuantity: 5704 prg.slowPrint(int32(prg.intName[m-1])) 5705 5706 case thingToAdd: 5707 if m == contourCode { 5708 prg.print( /* "contour" */ 956) 5709 } else if m == doublePathCode { 5710 prg.print( /* "doublepath" */ 957) 5711 } else { 5712 prg.print( /* "also" */ 958) 5713 } 5714 case withOption: 5715 if m == penType { 5716 prg.print( /* "withpen" */ 959) 5717 } else { 5718 prg.print( /* "withweight" */ 960) 5719 } 5720 case cullOp: 5721 if m == dropCode { 5722 prg.print( /* "dropping" */ 961) 5723 } else { 5724 prg.print( /* "keeping" */ 962) 5725 } 5726 5727 case messageCommand: 5728 if m < errMessageCode { 5729 prg.print( /* "message" */ 992) 5730 } else if m == errMessageCode { 5731 prg.print( /* "errmessage" */ 993) 5732 } else { 5733 prg.print( /* "errhelp" */ 994) 5734 } 5735 5736 case tfmCommand: 5737 switch m { 5738 case charListCode: 5739 prg.print( /* "charlist" */ 1004) 5740 case ligTableCode: 5741 prg.print( /* "ligtable" */ 1005) 5742 case extensibleCode: 5743 prg.print( /* "extensible" */ 1006) 5744 case headerByteCode: 5745 prg.print( /* "headerbyte" */ 1007) 5746 5747 default: 5748 prg.print( /* "fontdimen" */ 1008) 5749 } 5750 5751 case ligKernToken: 5752 switch m { 5753 case 0: 5754 prg.print( /* "=:" */ 1026) 5755 case 1: 5756 prg.print( /* "=:|" */ 1027) 5757 case 2: 5758 prg.print( /* "|=:" */ 1029) 5759 case 3: 5760 prg.print( /* "|=:|" */ 1031) 5761 case 5: 5762 prg.print( /* "=:|>" */ 1028) 5763 case 6: 5764 prg.print( /* "|=:>" */ 1030) 5765 case 7: 5766 prg.print( /* "|=:|>" */ 1032) 5767 case 11: 5768 prg.print( /* "|=:|>>" */ 1033) 5769 5770 default: 5771 prg.print( /* "kern" */ 1034) 5772 } 5773 5774 case specialCommand: 5775 if m == known { 5776 prg.print( /* "numspecial" */ 1059) 5777 } else { 5778 prg.print( /* "special" */ 1058) 5779 } 5780 5781 default: 5782 prg.print( /* "[unknown command code!]" */ 602) 5783 } 5784 } 5785 5786 func (prg *prg) showMacro(p halfword, q, l int32) { 5787 var ( 5788 r1 halfword // temporary storage 5789 ) 5790 p = *(*prg.mem[p].hh()).rh() // bypass the reference count 5791 for int32(*(*prg.mem[p].hh()).lh()) > textMacro { 5792 r1 = *(*prg.mem[p].hh()).rh() 5793 *(*prg.mem[p].hh()).rh() = uint16(memMin) 5794 prg.showTokenList(int32(p), memMin, l, 0) 5795 *(*prg.mem[p].hh()).rh() = r1 5796 p = r1 5797 if l > 0 { 5798 l = l - prg.tally 5799 } else { 5800 goto exit 5801 } 5802 } // control printing of `\.[ETC.]' 5803 // \xref[ETC] 5804 prg.tally = 0 5805 switch *(*prg.mem[p].hh()).lh() { 5806 case generalMacro: 5807 prg.print( /* "->" */ 501) 5808 // \xref[->] 5809 case primaryMacro, secondaryMacro, tertiaryMacro: 5810 prg.printChar(asciiCode('<')) 5811 prg.printCmdMod(paramType, int32(*(*prg.mem[p].hh()).lh())) 5812 prg.print( /* ">->" */ 502) 5813 5814 case exprMacro: 5815 prg.print( /* "<expr>->" */ 503) 5816 case ofMacro: 5817 prg.print( /* "<expr>of<primary>->" */ 504) 5818 case suffixMacro: 5819 prg.print( /* "<suffix>->" */ 505) 5820 case textMacro: 5821 prg.print( /* "<text>->" */ 506) 5822 } // there are no other cases 5823 prg.showTokenList(int32(*(*prg.mem[p].hh()).rh()), q, l-prg.tally, 0) 5824 5825 exit: 5826 } 5827 5828 // 228. \[15] Data structures for variables 5829 5830 // tangle:pos ../../mf.web:5001:40: 5831 5832 // The variables of \MF\ programs can be simple, like `\.x', or they can 5833 // combine the structural properties of arrays and records, like `\.[x20a.b]'. 5834 // A \MF\ user assigns a type to a variable like \.[x20a.b] by saying, for 5835 // example, `\.[boolean] \.[x[]a.b]'. It's time for us to study how such 5836 // things are represented inside of the computer. 5837 // 5838 // Each variable value occupies two consecutive words, either in a two-word 5839 // node called a value node, or as a two-word subfield of a larger node. One 5840 // of those two words is called the |value| field; it is an integer, 5841 // containing either a |scaled| numeric value or the representation of some 5842 // other type of quantity. (It might also be subdivided into halfwords, in 5843 // which case it is referred to by other names instead of |value|.) The other 5844 // word is broken into subfields called |type|, |name_type|, and |link|. The 5845 // |type| field is a quarterword that specifies the variable's type, and 5846 // |name_type| is a quarterword from which \MF\ can reconstruct the 5847 // variable's name (sometimes by using the |link| field as well). Thus, only 5848 // 1.25 words are actually devoted to the value itself; the other 5849 // three-quarters of a word are overhead, but they aren't wasted because they 5850 // allow \MF\ to deal with sparse arrays and to provide meaningful diagnostics. 5851 // 5852 // In this section we shall be concerned only with the structural aspects of 5853 // variables, not their values. Later parts of the program will change the 5854 // |type| and |value| fields, but we shall treat those fields as black boxes 5855 // whose contents should not be touched. 5856 // 5857 // However, if the |type| field is |structured|, there is no |value| field, 5858 // and the second word is broken into two pointer fields called |attr_head| 5859 // and |subscr_head|. Those fields point to additional nodes that 5860 // contain structural information, as we shall see. 5861 5862 // 232. 5863 5864 // tangle:pos ../../mf.web:5177:3: 5865 5866 // If |type(p)=pair_type| or |transform_type| and if |value(p)=null|, the 5867 // procedure call |init_big_node(p)| will allocate a pair or transform node 5868 // for~|p|. The individual parts of such nodes are initially of type 5869 // |independent|. 5870 func (prg *prg) initBigNode(p halfword) { 5871 var ( 5872 q halfword // the new node 5873 s smallNumber // its size 5874 ) 5875 s = prg.bigNodeSize[*(*prg.mem[p].hh()).b0()-13] 5876 q = prg.getNode(int32(s)) 5877 for { 5878 s = byte(int32(s) - 2) 5879 /* Make variable |q+s| newly independent */ { 5880 if prg.serialNo > 017777777777-sScale { 5881 prg.overflow(strNumber( /* "independent variables" */ 587), prg.serialNo/sScale) 5882 } /* \xref[METAFONT capacity exceeded independent variables][\quad independent variables] */ 5883 *(*prg.mem[int32(q)+int32(s)].hh()).b0() = byte(independent) 5884 prg.serialNo = prg.serialNo + sScale 5885 *prg.mem[int32(q)+int32(s)+1].int() = prg.serialNo 5886 } 5887 *(*prg.mem[int32(q)+int32(s)].hh()).b1() = byte(int32(s)/2 + xPartSector) 5888 *(*prg.mem[int32(q)+int32(s)].hh()).rh() = uint16(memMin) 5889 if int32(s) == 0 { 5890 break 5891 } 5892 } 5893 *(*prg.mem[q].hh()).rh() = p 5894 *prg.mem[int32(p)+1].int() = int32(q) 5895 } 5896 5897 // 233. 5898 5899 // tangle:pos ../../mf.web:5192:3: 5900 5901 // The |id_transform| function creates a capsule for the 5902 // identity transformation. 5903 func (prg *prg) idTransform() (r halfword) { 5904 var ( 5905 p, q, r1 halfword // list manipulation registers 5906 ) 5907 p = prg.getNode(valueNodeSize) 5908 *(*prg.mem[p].hh()).b0() = byte(transformType) 5909 *(*prg.mem[p].hh()).b1() = byte(capsule) 5910 *prg.mem[int32(p)+1].int() = memMin 5911 prg.initBigNode(p) 5912 q = uint16(*prg.mem[int32(p)+1].int()) 5913 r1 = uint16(int32(q) + transformNodeSize) 5914 for { 5915 r1 = uint16(int32(r1) - 2) 5916 *(*prg.mem[r1].hh()).b0() = byte(known) 5917 *prg.mem[int32(r1)+1].int() = 0 5918 if int32(r1) == int32(q) { 5919 break 5920 } 5921 } 5922 *prg.mem[int32(q)+4+1].int() = 0200000 5923 *prg.mem[int32(q)+10+1].int() = 0200000 5924 r = p 5925 return r 5926 } 5927 5928 // 234. 5929 5930 // tangle:pos ../../mf.web:5207:3: 5931 5932 // Tokens are of type |tag_token| when they first appear, but they point 5933 // to |null| until they are first used as the root of a variable. 5934 // The following subroutine establishes the root node on such grand occasions. 5935 func (prg *prg) newRoot(x halfword) { 5936 var ( 5937 p halfword // the new node 5938 ) 5939 p = prg.getNode(valueNodeSize) 5940 *(*prg.mem[p].hh()).b0() = byte(undefined) 5941 *(*prg.mem[p].hh()).b1() = byte(root) 5942 *(*prg.mem[p].hh()).rh() = x 5943 *prg.eqtb[x-1].rh() = p 5944 } 5945 5946 // 235. 5947 5948 // tangle:pos ../../mf.web:5217:3: 5949 5950 // These conventions for variable representation are illustrated by the 5951 // |print_variable_name| routine, which displays the full name of a 5952 // variable given only a pointer to its two-word value packet. 5953 func (prg *prg) printVariableName(p halfword) { 5954 var ( 5955 q halfword // a token list that will name the variable's suffix 5956 r1 halfword // temporary for token list creation 5957 ) 5958 for int32(*(*prg.mem[p].hh()).b1()) >= xPartSector { 5959 5960 // Preface the output with a part specifier; |return| in the case of a capsule 5961 switch *(*prg.mem[p].hh()).b1() { 5962 case xPartSector: 5963 prg.printChar(asciiCode('x')) 5964 case yPartSector: 5965 prg.printChar(asciiCode('y')) 5966 case xxPartSector: 5967 prg.print( /* "xx" */ 509) 5968 case xyPartSector: 5969 prg.print( /* "xy" */ 510) 5970 case yxPartSector: 5971 prg.print( /* "yx" */ 511) 5972 case yyPartSector: 5973 prg.print( /* "yy" */ 512) 5974 case capsule: 5975 prg.print( /* "%CAPSULE" */ 513) 5976 prg.printInt(int32(p) - memMin) 5977 goto exit 5978 // \xref[CAPSULE] 5979 5980 } // there are no other cases 5981 prg.print( /* "part " */ 514) 5982 p = *(*prg.mem[int32(p)-2*(int32(*(*prg.mem[p].hh()).b1())-xPartSector)].hh()).rh() 5983 } 5984 q = uint16(memMin) 5985 for int32(*(*prg.mem[p].hh()).b1()) > savedRoot { 5986 5987 // Ascend one level, pushing a token onto list |q| and replacing |p| by its parent 5988 if int32(*(*prg.mem[p].hh()).b1()) == subscr { 5989 r1 = prg.newNumTok(*prg.mem[int32(p)+2].int()) 5990 for { 5991 p = *(*prg.mem[p].hh()).rh() 5992 if int32(*(*prg.mem[p].hh()).b1()) == attr { 5993 break 5994 } 5995 } 5996 } else if int32(*(*prg.mem[p].hh()).b1()) == structuredRoot { 5997 p = *(*prg.mem[p].hh()).rh() 5998 goto found 5999 } else { 6000 if int32(*(*prg.mem[p].hh()).b1()) != attr { 6001 prg.confusion(strNumber( /* "var" */ 508)) 6002 } 6003 // \xref[this can't happen var][\quad var] 6004 r1 = prg.getAvail() 6005 *(*prg.mem[r1].hh()).lh() = *(*prg.mem[int32(p)+2].hh()).lh() 6006 } 6007 *(*prg.mem[r1].hh()).rh() = q 6008 q = r1 6009 6010 found: 6011 p = *(*prg.mem[int32(p)+2].hh()).rh() 6012 } 6013 r1 = prg.getAvail() 6014 *(*prg.mem[r1].hh()).lh() = *(*prg.mem[p].hh()).rh() 6015 *(*prg.mem[r1].hh()).rh() = q 6016 if int32(*(*prg.mem[p].hh()).b1()) == savedRoot { 6017 prg.print( /* "(SAVED)" */ 507) 6018 } 6019 // \xref[SAVED] 6020 prg.showTokenList(int32(r1), memMin, 017777777777, prg.tally) 6021 prg.flushTokenList(r1) 6022 6023 exit: 6024 } 6025 6026 // 238. 6027 6028 // tangle:pos ../../mf.web:5270:3: 6029 6030 // The |interesting| function returns |true| if a given variable is not 6031 // in a capsule, or if the user wants to trace capsules. 6032 func (prg *prg) interesting(p halfword) (r bool) { 6033 var ( 6034 t smallNumber // a |name_type| 6035 ) 6036 if prg.internal[tracingCapsules-1] > 0 { 6037 r = true 6038 } else { 6039 t = *(*prg.mem[p].hh()).b1() 6040 if int32(t) >= xPartSector { 6041 if int32(t) != capsule { 6042 t = *(*prg.mem[*(*prg.mem[int32(p)-2*(int32(t)-xPartSector)].hh()).rh()].hh()).b1() 6043 } 6044 } 6045 r = int32(t) != capsule 6046 } 6047 return r 6048 } 6049 6050 // 239. 6051 6052 // tangle:pos ../../mf.web:5283:3: 6053 6054 // Now here is a subroutine that converts an unstructured type into an 6055 // equivalent structured type, by inserting a |structured| node that is 6056 // capable of growing. This operation is done only when |name_type(p)=root|, 6057 // |subscr|, or |attr|. 6058 // 6059 // The procedure returns a pointer to the new node that has taken node~|p|'s 6060 // place in the structure. Node~|p| itself does not move, nor are its 6061 // |value| or |type| fields changed in any way. 6062 func (prg *prg) newStructure(p halfword) (r halfword) { 6063 var ( 6064 q, r1 halfword // list manipulation registers 6065 ) 6066 switch *(*prg.mem[p].hh()).b1() { 6067 case root: 6068 q = *(*prg.mem[p].hh()).rh() 6069 r1 = prg.getNode(valueNodeSize) 6070 *prg.eqtb[q-1].rh() = r1 6071 6072 case subscr: 6073 // Link a new subscript node |r| in place of node |p| 6074 q = p 6075 for { 6076 q = *(*prg.mem[q].hh()).rh() 6077 if int32(*(*prg.mem[q].hh()).b1()) == attr { 6078 break 6079 } 6080 } 6081 q = *(*prg.mem[int32(q)+2].hh()).rh() 6082 r1 = uint16(int32(q) + 1) // |link(r)=subscr_head(q)| 6083 for { 6084 q = r1 6085 r1 = *(*prg.mem[r1].hh()).rh() 6086 if int32(r1) == int32(p) { 6087 break 6088 } 6089 } 6090 r1 = prg.getNode(subscrNodeSize) 6091 *(*prg.mem[q].hh()).rh() = r1 6092 *prg.mem[int32(r1)+2].int() = *prg.mem[int32(p)+2].int() 6093 6094 case attr: 6095 // Link a new attribute node |r| in place of node |p| 6096 q = *(*prg.mem[int32(p)+2].hh()).rh() 6097 r1 = *(*prg.mem[int32(q)+1].hh()).lh() 6098 for { 6099 q = r1 6100 r1 = *(*prg.mem[r1].hh()).rh() 6101 if int32(r1) == int32(p) { 6102 break 6103 } 6104 } 6105 r1 = prg.getNode(attrNodeSize) 6106 *(*prg.mem[q].hh()).rh() = r1 6107 6108 prg.mem[int32(r1)+2] = prg.mem[int32(p)+2] // copy |attr_loc| and |parent| 6109 if int32(*(*prg.mem[int32(p)+2].hh()).lh()) == collectiveSubscript { 6110 q = uint16(int32(*(*prg.mem[int32(p)+2].hh()).rh()) + 1) 6111 for int32(*(*prg.mem[q].hh()).rh()) != int32(p) { 6112 q = *(*prg.mem[q].hh()).rh() 6113 } 6114 *(*prg.mem[q].hh()).rh() = r1 6115 } 6116 6117 default: 6118 prg.confusion(strNumber( /* "struct" */ 515)) 6119 // \xref[this can't happen struct][\quad struct] 6120 } 6121 6122 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[p].hh()).rh() 6123 *(*prg.mem[r1].hh()).b0() = byte(structured) 6124 *(*prg.mem[r1].hh()).b1() = *(*prg.mem[p].hh()).b1() 6125 *(*prg.mem[int32(r1)+1].hh()).lh() = p 6126 *(*prg.mem[p].hh()).b1() = byte(structuredRoot) 6127 6128 q = prg.getNode(attrNodeSize) 6129 *(*prg.mem[p].hh()).rh() = q 6130 *(*prg.mem[int32(r1)+1].hh()).rh() = q 6131 *(*prg.mem[int32(q)+2].hh()).rh() = r1 6132 *(*prg.mem[q].hh()).b0() = byte(undefined) 6133 *(*prg.mem[q].hh()).b1() = byte(attr) 6134 *(*prg.mem[q].hh()).rh() = uint16(memMin + 3 + 10 + 2 + 2) 6135 *(*prg.mem[int32(q)+2].hh()).lh() = uint16(collectiveSubscript) 6136 r = r1 6137 return r 6138 } 6139 6140 // 242. 6141 6142 // tangle:pos ../../mf.web:5336:3: 6143 6144 // The |find_variable| routine is given a pointer~|t| to a nonempty token 6145 // list of suffixes; it returns a pointer to the corresponding two-word 6146 // value. For example, if |t| points to token \.x followed by a numeric 6147 // token containing the value~7, |find_variable| finds where the value of 6148 // \.[x7] is stored in memory. This may seem a simple task, and it 6149 // usually is, except when \.[x7] has never been referenced before. 6150 // Indeed, \.x may never have even been subscripted before; complexities 6151 // arise with respect to updating the collective subscript information. 6152 // 6153 // If a macro type is detected anywhere along path~|t|, or if the first 6154 // item on |t| isn't a |tag_token|, the value |null| is returned. 6155 // Otherwise |p| will be a non-null pointer to a node such that 6156 // |undefined<type(p)<structured|. 6157 func (prg *prg) findVariable(t halfword) (r halfword) { 6158 var ( 6159 p, q, r1, s halfword // nodes in the ``value'' line 6160 pp, qq, rr, ss halfword // nodes in the ``collective'' line 6161 n int32 // subscript or attribute 6162 saveWord memoryWord // temporary storage for a word of |mem| 6163 // \xref[inner loop] 6164 ) 6165 p = *(*prg.mem[t].hh()).lh() 6166 t = *(*prg.mem[t].hh()).rh() 6167 if int32(*prg.eqtb[p-1].lh())%outerTag != tagToken { 6168 r = uint16(memMin) 6169 goto exit 6170 } 6171 if int32(*prg.eqtb[p-1].rh()) == memMin { 6172 prg.newRoot(p) 6173 } 6174 p = *prg.eqtb[p-1].rh() 6175 pp = p 6176 for int32(t) != memMin { 6177 if int32(*(*prg.mem[pp].hh()).b0()) != structured { 6178 if int32(*(*prg.mem[pp].hh()).b0()) > structured { 6179 r = uint16(memMin) 6180 goto exit 6181 } 6182 ss = prg.newStructure(pp) 6183 if int32(p) == int32(pp) { 6184 p = ss 6185 } 6186 pp = ss 6187 } // now |type(pp)=structured| 6188 if int32(*(*prg.mem[p].hh()).b0()) != structured { 6189 p = prg.newStructure(p) 6190 } 6191 if int32(t) < int32(prg.hiMemMin) { 6192 n = *prg.mem[int32(t)+1].int() 6193 pp = *(*prg.mem[*(*prg.mem[int32(pp)+1].hh()).lh()].hh()).rh() // now |attr_loc(pp)=collective_subscript| 6194 q = *(*prg.mem[*(*prg.mem[int32(p)+1].hh()).lh()].hh()).rh() 6195 saveWord = prg.mem[int32(q)+2] 6196 *prg.mem[int32(q)+2].int() = 017777777777 6197 s = uint16(int32(p) + 1) // |link(s)=subscr_head(p)| 6198 for { 6199 r1 = s 6200 s = *(*prg.mem[s].hh()).rh() 6201 if n <= *prg.mem[int32(s)+2].int() { 6202 break 6203 } 6204 } 6205 if n == *prg.mem[int32(s)+2].int() { 6206 p = s 6207 } else { 6208 p = prg.getNode(subscrNodeSize) 6209 *(*prg.mem[r1].hh()).rh() = p 6210 *(*prg.mem[p].hh()).rh() = s 6211 *prg.mem[int32(p)+2].int() = n 6212 *(*prg.mem[p].hh()).b1() = byte(subscr) 6213 *(*prg.mem[p].hh()).b0() = byte(undefined) 6214 } 6215 prg.mem[int32(q)+2] = saveWord 6216 } else { 6217 // Descend one level for the attribute |info(t)| 6218 n = int32(*(*prg.mem[t].hh()).lh()) 6219 ss = *(*prg.mem[int32(pp)+1].hh()).lh() 6220 for { 6221 rr = ss 6222 ss = *(*prg.mem[ss].hh()).rh() 6223 if n <= int32(*(*prg.mem[int32(ss)+2].hh()).lh()) { 6224 break 6225 } 6226 } 6227 if n < int32(*(*prg.mem[int32(ss)+2].hh()).lh()) { 6228 qq = prg.getNode(attrNodeSize) 6229 *(*prg.mem[rr].hh()).rh() = qq 6230 *(*prg.mem[qq].hh()).rh() = ss 6231 *(*prg.mem[int32(qq)+2].hh()).lh() = uint16(n) 6232 *(*prg.mem[qq].hh()).b1() = byte(attr) 6233 *(*prg.mem[qq].hh()).b0() = byte(undefined) 6234 *(*prg.mem[int32(qq)+2].hh()).rh() = pp 6235 ss = qq 6236 } 6237 if int32(p) == int32(pp) { 6238 p = ss 6239 pp = ss 6240 } else { 6241 pp = ss 6242 s = *(*prg.mem[int32(p)+1].hh()).lh() 6243 for { 6244 r1 = s 6245 s = *(*prg.mem[s].hh()).rh() 6246 if n <= int32(*(*prg.mem[int32(s)+2].hh()).lh()) { 6247 break 6248 } 6249 } 6250 if n == int32(*(*prg.mem[int32(s)+2].hh()).lh()) { 6251 p = s 6252 } else { 6253 q = prg.getNode(attrNodeSize) 6254 *(*prg.mem[r1].hh()).rh() = q 6255 *(*prg.mem[q].hh()).rh() = s 6256 *(*prg.mem[int32(q)+2].hh()).lh() = uint16(n) 6257 *(*prg.mem[q].hh()).b1() = byte(attr) 6258 *(*prg.mem[q].hh()).b0() = byte(undefined) 6259 *(*prg.mem[int32(q)+2].hh()).rh() = p 6260 p = q 6261 } 6262 } 6263 } 6264 t = *(*prg.mem[t].hh()).rh() 6265 } 6266 if int32(*(*prg.mem[pp].hh()).b0()) >= structured { 6267 if int32(*(*prg.mem[pp].hh()).b0()) == structured { 6268 pp = *(*prg.mem[int32(pp)+1].hh()).lh() 6269 } else { 6270 r = uint16(memMin) 6271 goto exit 6272 } 6273 } 6274 if int32(*(*prg.mem[p].hh()).b0()) == structured { 6275 p = *(*prg.mem[int32(p)+1].hh()).lh() 6276 } 6277 if int32(*(*prg.mem[p].hh()).b0()) == undefined { 6278 if int32(*(*prg.mem[pp].hh()).b0()) == undefined { 6279 *(*prg.mem[pp].hh()).b0() = byte(numericType) 6280 *prg.mem[int32(pp)+1].int() = memMin 6281 } 6282 *(*prg.mem[p].hh()).b0() = *(*prg.mem[pp].hh()).b0() 6283 *prg.mem[int32(p)+1].int() = memMin 6284 } 6285 r = p 6286 6287 exit: 6288 ; 6289 return r 6290 } 6291 6292 // 246. 6293 6294 // tangle:pos ../../mf.web:5440:3: 6295 6296 // Variables lose their former values when they appear in a type declaration, 6297 // or when they are defined to be macros or \&[let] equal to something else. 6298 // A subroutine will be defined later that recycles the storage associated 6299 // with any particular |type| or |value|; our goal now is to study a higher 6300 // level process called |flush_variable|, which selectively frees parts of a 6301 // variable structure. 6302 // 6303 // This routine has some complexity because of examples such as 6304 // `\hbox[\tt numeric x[]a[]b]', 6305 // which recycles all variables of the form \.[x[i]a[j]b] (and no others), while 6306 // `\hbox[\tt vardef x[]a[]=...]' 6307 // discards all variables of the form \.[x[i]a[j]] followed by an arbitrary 6308 // suffix, except for the collective node \.[x[]a[]] itself. The obvious way 6309 // to handle such examples is to use recursion; so that's what we~do. 6310 // \xref[recursion] 6311 // 6312 // Parameter |p| points to the root information of the variable; 6313 // parameter |t| points to a list of one-word nodes that represent 6314 // suffixes, with |info=collective_subscript| for subscripts. 6315 // \4 6316 // Declare subroutines for printing expressions 6317 func (prg *prg) printPath(h halfword, s strNumber, nuline bool) { 6318 var ( 6319 p, q halfword // for list traversal 6320 ) 6321 prg.printDiagnostic(strNumber( /* "Path" */ 517), s, nuline) 6322 prg.printLn() 6323 // \xref[Path at line...] 6324 p = h 6325 for { 6326 q = *(*prg.mem[p].hh()).rh() 6327 if int32(p) == memMin || int32(q) == memMin { 6328 prg.printNl(strNumber( /* "???" */ 259)) 6329 goto done // this won't happen 6330 // \xref[???] 6331 } 6332 6333 // Print information for adjacent knots |p| and |q| 6334 prg.printTwo(*prg.mem[int32(p)+1].int(), *prg.mem[int32(p)+2].int()) 6335 switch *(*prg.mem[p].hh()).b1() { 6336 case endpoint: 6337 if int32(*(*prg.mem[p].hh()).b0()) == open { 6338 prg.print( /* "[open?]" */ 518) 6339 } // can't happen 6340 // \xref[open?] 6341 if int32(*(*prg.mem[q].hh()).b0()) != endpoint || int32(q) != int32(h) { 6342 q = uint16(memMin) 6343 } // force an error 6344 // force an error 6345 goto done1 6346 6347 case explicit: 6348 // Print control points between |p| and |q|, then |goto done1| 6349 prg.print( /* "..controls " */ 524) 6350 prg.printTwo(*prg.mem[int32(p)+5].int(), *prg.mem[int32(p)+6].int()) 6351 prg.print( /* " and " */ 523) 6352 if int32(*(*prg.mem[q].hh()).b0()) != explicit { 6353 prg.print( /* "??" */ 525) 6354 } else { 6355 prg.printTwo(*prg.mem[int32(q)+3].int(), *prg.mem[int32(q)+4].int()) 6356 } 6357 6358 goto done1 6359 6360 case open: 6361 // Print information for a curve that begins |open| 6362 if int32(*(*prg.mem[p].hh()).b0()) != explicit && int32(*(*prg.mem[p].hh()).b0()) != open { 6363 prg.print( /* "[open?]" */ 518) 6364 } // can't happen 6365 // \xref[open?] 6366 6367 case curl, given: 6368 // Print information for a curve that begins |curl| or |given| 6369 if int32(*(*prg.mem[p].hh()).b0()) == open { 6370 prg.print( /* "??" */ 525) 6371 } // can't happen 6372 // \xref[??] 6373 if int32(*(*prg.mem[p].hh()).b1()) == curl { 6374 prg.print( /* "[curl " */ 521) 6375 prg.printScaled(*prg.mem[int32(p)+5].int()) 6376 } else { 6377 prg.nSinCos(*prg.mem[int32(p)+5].int()) 6378 prg.printChar(asciiCode('{')) 6379 prg.printScaled(prg.nCos) 6380 prg.printChar(asciiCode(',')) 6381 prg.printScaled(prg.nSin) 6382 } 6383 prg.printChar(asciiCode('}')) 6384 6385 default: 6386 prg.print( /* "???" */ 259) // can't happen 6387 // \xref[???] 6388 } 6389 6390 if int32(*(*prg.mem[q].hh()).b0()) <= explicit { 6391 prg.print( /* "..control?" */ 519) 6392 } else if *prg.mem[int32(p)+6].int() != 0200000 || *prg.mem[int32(q)+4].int() != 0200000 { 6393 prg.print( /* "..tension " */ 522) 6394 if *prg.mem[int32(p)+6].int() < 0 { 6395 prg.print( /* "atleast" */ 464) 6396 } 6397 prg.printScaled(abs(*prg.mem[int32(p)+6].int())) 6398 if *prg.mem[int32(p)+6].int() != *prg.mem[int32(q)+4].int() { 6399 prg.print( /* " and " */ 523) 6400 if *prg.mem[int32(q)+4].int() < 0 { 6401 prg.print( /* "atleast" */ 464) 6402 } 6403 prg.printScaled(abs(*prg.mem[int32(q)+4].int())) 6404 } 6405 } 6406 6407 done1: 6408 ; 6409 p = q 6410 if int32(p) != int32(h) || int32(*(*prg.mem[h].hh()).b0()) != endpoint { 6411 prg.printNl(strNumber( /* " .." */ 520)) 6412 if int32(*(*prg.mem[p].hh()).b0()) == given { 6413 prg.nSinCos(*prg.mem[int32(p)+3].int()) 6414 prg.printChar(asciiCode('{')) 6415 prg.printScaled(prg.nCos) 6416 prg.printChar(asciiCode(',')) 6417 prg.printScaled(prg.nSin) 6418 prg.printChar(asciiCode('}')) 6419 } else if int32(*(*prg.mem[p].hh()).b0()) == curl { 6420 prg.print( /* "[curl " */ 521) 6421 prg.printScaled(*prg.mem[int32(p)+3].int()) 6422 prg.printChar(asciiCode('}')) 6423 } 6424 } 6425 if int32(p) == int32(h) { 6426 break 6427 } 6428 } 6429 if int32(*(*prg.mem[h].hh()).b0()) != endpoint { 6430 prg.print( /* "cycle" */ 386) 6431 } 6432 6433 done: 6434 prg.endDiagnostic(true) 6435 } 6436 6437 // \4 6438 // Declare the procedure called |print_weight| 6439 func (prg *prg) printWeight(q halfword, xOff int32) { 6440 var ( 6441 w, m int32 // unpacked weight and coordinate 6442 d int32 // temporary data register 6443 ) 6444 d = int32(*(*prg.mem[q].hh()).lh()) - 0 6445 w = d % 8 6446 m = d/8 - int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) 6447 if int32(prg.fileOffset) > maxPrintLine-9 { 6448 prg.printNl(strNumber(' ')) 6449 } else { 6450 prg.printChar(asciiCode(' ')) 6451 } 6452 prg.printInt(m + xOff) 6453 for w > zeroW { 6454 prg.printChar(asciiCode('+')) 6455 w = w - 1 6456 } 6457 for w < zeroW { 6458 prg.printChar(asciiCode('-')) 6459 w = w + 1 6460 } 6461 } 6462 6463 func (prg *prg) printEdges(s strNumber, nuline bool, xOff, yOff int32) { 6464 var ( 6465 p, q, r1 halfword // for list traversal 6466 n int32 // row number 6467 ) 6468 prg.printDiagnostic(strNumber( /* "Edge structure" */ 532), s, nuline) 6469 p = *(*prg.mem[prg.curEdges].hh()).lh() 6470 n = int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh()) - zeroField 6471 for int32(p) != int32(prg.curEdges) { 6472 q = *(*prg.mem[int32(p)+1].hh()).lh() 6473 r1 = *(*prg.mem[int32(p)+1].hh()).rh() 6474 if int32(q) > memMin+1 || int32(r1) != 3000 { 6475 prg.printNl(strNumber( /* "row " */ 533)) 6476 prg.printInt(n + yOff) 6477 prg.printChar(asciiCode(':')) 6478 for int32(q) > memMin+1 { 6479 prg.printWeight(q, xOff) 6480 q = *(*prg.mem[q].hh()).rh() 6481 } 6482 prg.print( /* " |" */ 534) 6483 for int32(r1) != 3000 { 6484 prg.printWeight(r1, xOff) 6485 r1 = *(*prg.mem[r1].hh()).rh() 6486 } 6487 } 6488 p = *(*prg.mem[p].hh()).lh() 6489 n = n - 1 6490 } 6491 prg.endDiagnostic(true) 6492 } 6493 6494 func (prg *prg) unskew(x, y scaled, octant smallNumber) { 6495 switch octant { 6496 case firstOctant: 6497 prg.curX = x + y 6498 prg.curY = y 6499 case secondOctant: 6500 prg.curX = y 6501 prg.curY = x + y 6502 case thirdOctant: 6503 prg.curX = -y 6504 prg.curY = x + y 6505 case fourthOctant: 6506 prg.curX = -x - y 6507 prg.curY = y 6508 case fifthOctant: 6509 prg.curX = -x - y 6510 prg.curY = -y 6511 case sixthOctant: 6512 prg.curX = -y 6513 prg.curY = -x - y 6514 case seventhOctant: 6515 prg.curX = y 6516 prg.curY = -x - y 6517 case eighthOctant: 6518 prg.curX = x + y 6519 prg.curY = -y 6520 } // there are no other cases 6521 } 6522 6523 func (prg *prg) printPen(p halfword, s strNumber, nuline bool) { 6524 var ( 6525 nothingPrinted bool // has there been any action yet? 6526 k/* 1..8 */ byte // octant number 6527 h halfword // offset list head 6528 m, n int32 // offset indices 6529 w, ww halfword // pointers that traverse the offset list 6530 ) 6531 prg.printDiagnostic(strNumber( /* "Pen polygon" */ 569), s, nuline) 6532 nothingPrinted = true 6533 prg.printLn() 6534 for ii := int32(1); ii <= 8; ii++ { 6535 k = byte(ii) 6536 _ = k 6537 prg.octant = prg.octantCode[k-1] 6538 h = uint16(int32(p) + int32(prg.octant)) 6539 n = int32(*(*prg.mem[h].hh()).lh()) 6540 w = *(*prg.mem[h].hh()).rh() 6541 if !(k&1 != 0) { 6542 w = *(*prg.mem[w].hh()).lh() 6543 } // in even octants, start at $w_[n+1]$ 6544 for ii := int32(1); ii <= n+1; ii++ { 6545 m = ii 6546 _ = m 6547 if k&1 != 0 { 6548 ww = *(*prg.mem[w].hh()).rh() 6549 } else { 6550 ww = *(*prg.mem[w].hh()).lh() 6551 } 6552 if *prg.mem[int32(ww)+1].int() != *prg.mem[int32(w)+1].int() || *prg.mem[int32(ww)+2].int() != *prg.mem[int32(w)+2].int() { 6553 if nothingPrinted { 6554 nothingPrinted = false 6555 } else { 6556 prg.printNl(strNumber( /* " .. " */ 571)) 6557 } 6558 prg.unskew(*prg.mem[int32(ww)+1].int(), *prg.mem[int32(ww)+2].int(), prg.octant) 6559 prg.printTwo(prg.curX, prg.curY) 6560 } 6561 w = ww 6562 } 6563 } 6564 if nothingPrinted { 6565 w = *(*prg.mem[int32(p)+firstOctant].hh()).rh() 6566 prg.printTwo(*prg.mem[int32(w)+1].int()+*prg.mem[int32(w)+2].int(), *prg.mem[int32(w)+2].int()) 6567 } 6568 prg.printNl(strNumber( /* " .. cycle" */ 570)) 6569 prg.endDiagnostic(true) 6570 } 6571 6572 func (prg *prg) printDependency(p halfword, t smallNumber) { 6573 var ( 6574 v int32 // a coefficient 6575 pp, q halfword // for list manipulation 6576 ) 6577 pp = p 6578 for true { 6579 v = abs(*prg.mem[int32(p)+1].int()) 6580 q = *(*prg.mem[p].hh()).lh() 6581 if int32(q) == memMin { 6582 if v != 0 || int32(p) == int32(pp) { 6583 if *prg.mem[int32(p)+1].int() > 0 { 6584 if int32(p) != int32(pp) { 6585 prg.printChar(asciiCode('+')) 6586 } 6587 } 6588 prg.printScaled(*prg.mem[int32(p)+1].int()) 6589 } 6590 6591 goto exit 6592 } 6593 6594 // Print the coefficient, unless it's $\pm1.0$ 6595 if *prg.mem[int32(p)+1].int() < 0 { 6596 prg.printChar(asciiCode('-')) 6597 } else if int32(p) != int32(pp) { 6598 prg.printChar(asciiCode('+')) 6599 } 6600 if int32(t) == dependent { 6601 v = prg.roundFraction(v) 6602 } 6603 if v != 0200000 { 6604 prg.printScaled(v) 6605 } 6606 if int32(*(*prg.mem[q].hh()).b0()) != independent { 6607 prg.confusion(strNumber( /* "dep" */ 588)) 6608 } 6609 // \xref[this can't happen dep][\quad dep] 6610 prg.printVariableName(q) 6611 v = *prg.mem[int32(q)+1].int() % sScale 6612 for v > 0 { 6613 prg.print( /* "*4" */ 589) 6614 v = v - 2 6615 } 6616 p = *(*prg.mem[p].hh()).rh() 6617 } 6618 6619 exit: 6620 } 6621 6622 // \4 6623 // Declare the procedure called |print_dp| 6624 func (prg *prg) printDp(t smallNumber, p halfword, verbosity smallNumber) { 6625 var ( 6626 q halfword // the node following |p| 6627 ) 6628 q = *(*prg.mem[p].hh()).rh() 6629 if int32(*(*prg.mem[q].hh()).lh()) == memMin || int32(verbosity) > 0 { 6630 prg.printDependency(p, t) 6631 } else { 6632 prg.print( /* "linearform" */ 764) 6633 } 6634 // \xref[linearform] 6635 } 6636 6637 // \4 6638 // Declare the stashing/unstashing routines 6639 func (prg *prg) stashCurExp() (r halfword) { 6640 var ( 6641 p halfword // the capsule that will be returned 6642 ) 6643 switch prg.curType { 6644 case unknownBoolean, unknownString, unknownPen, unknownPicture, 6645 unknownPath, transformType, pairType, dependent, 6646 protoDependent, independent: 6647 p = uint16(prg.curExp) 6648 6649 default: 6650 p = prg.getNode(valueNodeSize) 6651 *(*prg.mem[p].hh()).b1() = byte(capsule) 6652 *(*prg.mem[p].hh()).b0() = prg.curType 6653 *prg.mem[int32(p)+1].int() = prg.curExp 6654 6655 } 6656 6657 prg.curType = byte(vacuous) 6658 *(*prg.mem[p].hh()).rh() = uint16(memMin + 1) 6659 r = p 6660 return r 6661 } 6662 6663 func (prg *prg) unstashCurExp(p halfword) { 6664 prg.curType = *(*prg.mem[p].hh()).b0() 6665 switch prg.curType { 6666 case unknownBoolean, unknownString, unknownPen, unknownPicture, 6667 unknownPath, transformType, pairType, dependent, 6668 protoDependent, independent: 6669 prg.curExp = int32(p) 6670 6671 default: 6672 prg.curExp = *prg.mem[int32(p)+1].int() 6673 prg.freeNode(p, halfword(valueNodeSize)) 6674 6675 } 6676 6677 } 6678 6679 func (prg *prg) printExp(p halfword, verbosity smallNumber) { 6680 var ( 6681 restoreCurExp bool // should |cur_exp| be restored? 6682 t smallNumber // the type of the expression 6683 v int32 // the value of the expression 6684 q halfword // a big node being displayed 6685 ) 6686 if int32(p) != memMin { 6687 restoreCurExp = false 6688 } else { 6689 p = prg.stashCurExp() 6690 restoreCurExp = true 6691 } 6692 t = *(*prg.mem[p].hh()).b0() 6693 if int32(t) < dependent { 6694 v = *prg.mem[int32(p)+1].int() 6695 } else if int32(t) < independent { 6696 v = int32(*(*prg.mem[int32(p)+1].hh()).rh()) 6697 } 6698 6699 // Print an abbreviated value of |v| with format depending on |t| 6700 switch t { 6701 case vacuous: 6702 prg.print( /* "vacuous" */ 324) 6703 case booleanType: 6704 if v == trueCode { 6705 prg.print( /* "true" */ 348) 6706 } else { 6707 prg.print( /* "false" */ 349) 6708 } 6709 case unknownBoolean, unknownString, unknownPen, unknownPicture, 6710 unknownPath, numericType: 6711 // Display a variable that's been declared but not defined 6712 prg.printType(t) 6713 if v != memMin { 6714 prg.printChar(asciiCode(' ')) 6715 for int32(*(*prg.mem[v].hh()).b1()) == capsule && v != int32(p) { 6716 v = *prg.mem[v+1].int() 6717 } 6718 prg.printVariableName(halfword(v)) 6719 } 6720 6721 case stringType: 6722 prg.printChar(asciiCode('"')) 6723 prg.slowPrint(v) 6724 prg.printChar(asciiCode('"')) 6725 6726 case penType, futurePen, pathType, pictureType: 6727 // Display a complex type 6728 if int32(verbosity) <= 1 { 6729 prg.printType(t) 6730 } else { 6731 if int32(prg.selector) == termAndLog { 6732 if prg.internal[tracingOnline-1] <= 0 { 6733 prg.selector = byte(termOnly) 6734 prg.printType(t) 6735 prg.print( /* " (see the transcript file)" */ 762) 6736 prg.selector = byte(termAndLog) 6737 } 6738 } 6739 switch t { 6740 case penType: 6741 prg.printPen(halfword(v), strNumber( /* "" */ 285), false) 6742 case futurePen: 6743 prg.printPath(halfword(v), strNumber( /* " (future pen)" */ 763), false) 6744 case pathType: 6745 prg.printPath(halfword(v), strNumber( /* "" */ 285), false) 6746 case pictureType: 6747 prg.curEdges = uint16(v) 6748 prg.printEdges(strNumber( /* "" */ 285), false, 0, 0) 6749 6750 } // there are no other cases 6751 } 6752 6753 case transformType, pairType: 6754 if v == memMin { 6755 prg.printType(t) 6756 } else { 6757 // Display a big node 6758 prg.printChar(asciiCode('(')) 6759 q = uint16(v + int32(prg.bigNodeSize[t-13])) 6760 for { 6761 if int32(*(*prg.mem[v].hh()).b0()) == known { 6762 prg.printScaled(*prg.mem[v+1].int()) 6763 } else if int32(*(*prg.mem[v].hh()).b0()) == independent { 6764 prg.printVariableName(halfword(v)) 6765 } else { 6766 prg.printDp(*(*prg.mem[v].hh()).b0(), *(*prg.mem[v+1].hh()).rh(), verbosity) 6767 } 6768 v = v + 2 6769 if v != int32(q) { 6770 prg.printChar(asciiCode(',')) 6771 } 6772 if v == int32(q) { 6773 break 6774 } 6775 } 6776 prg.printChar(asciiCode(')')) 6777 } 6778 6779 case known: 6780 prg.printScaled(v) 6781 case dependent, protoDependent: 6782 prg.printDp(t, halfword(v), verbosity) 6783 case independent: 6784 prg.printVariableName(p) 6785 6786 default: 6787 prg.confusion(strNumber( /* "exp" */ 761)) 6788 // \xref[this can't happen exp][\quad exp] 6789 } 6790 if restoreCurExp { 6791 prg.unstashCurExp(p) 6792 } 6793 } 6794 6795 func (prg *prg) dispErr(p halfword, s strNumber) { 6796 if int32(prg.interaction) == errorStopMode { 6797 } 6798 prg.printNl(strNumber( /* ">> " */ 765)) 6799 // \xref[>>] 6800 prg.printExp(p, smallNumber(1)) // ``medium verbose'' printing of the expression 6801 if int32(s) != 285 { 6802 prg.printNl(strNumber( /* "! " */ 261)) 6803 prg.print(int32(s)) 6804 // \xref[!\relax] 6805 } 6806 } 6807 6808 // \4 6809 // Declare basic dependency-list subroutines 6810 func (prg *prg) pPlusFq(p halfword, f int32, q halfword, 6811 t, tt smallNumber) (r halfword) { 6812 var ( 6813 pp, qq halfword // |info(p)| and |info(q)|, respectively 6814 r1, s halfword // for list manipulation 6815 threshold int32 // defines a neighborhood of zero 6816 v int32 // temporary register 6817 ) 6818 if int32(t) == dependent { 6819 threshold = fractionThreshold 6820 } else { 6821 threshold = scaledThreshold 6822 } 6823 r1 = uint16(3000 - 1) 6824 pp = *(*prg.mem[p].hh()).lh() 6825 qq = *(*prg.mem[q].hh()).lh() 6826 for true { 6827 if int32(pp) == int32(qq) { 6828 if int32(pp) == memMin { 6829 goto done 6830 } else { 6831 // Contribute a term from |p|, plus |f| times the corresponding term from |q| 6832 if int32(tt) == dependent { 6833 v = *prg.mem[int32(p)+1].int() + prg.takeFraction(f, *prg.mem[int32(q)+1].int()) 6834 } else { 6835 v = *prg.mem[int32(p)+1].int() + prg.takeScaled(f, *prg.mem[int32(q)+1].int()) 6836 } 6837 *prg.mem[int32(p)+1].int() = v 6838 s = p 6839 p = *(*prg.mem[p].hh()).rh() 6840 if abs(v) < threshold { 6841 prg.freeNode(s, halfword(depNodeSize)) 6842 } else { 6843 if abs(v) >= 04525252525 { 6844 if prg.watchCoefs { 6845 *(*prg.mem[qq].hh()).b0() = byte(independentNeedingFix) 6846 prg.fixNeeded = true 6847 } 6848 } 6849 *(*prg.mem[r1].hh()).rh() = s 6850 r1 = s 6851 } 6852 pp = *(*prg.mem[p].hh()).lh() 6853 q = *(*prg.mem[q].hh()).rh() 6854 qq = *(*prg.mem[q].hh()).lh() 6855 } 6856 } else if *prg.mem[int32(pp)+1].int() < *prg.mem[int32(qq)+1].int() { 6857 if int32(tt) == dependent { 6858 v = prg.takeFraction(f, *prg.mem[int32(q)+1].int()) 6859 } else { 6860 v = prg.takeScaled(f, *prg.mem[int32(q)+1].int()) 6861 } 6862 if abs(v) > threshold/2 { 6863 s = prg.getNode(depNodeSize) 6864 *(*prg.mem[s].hh()).lh() = qq 6865 *prg.mem[int32(s)+1].int() = v 6866 if abs(v) >= 04525252525 { 6867 if prg.watchCoefs { 6868 *(*prg.mem[qq].hh()).b0() = byte(independentNeedingFix) 6869 prg.fixNeeded = true 6870 } 6871 } 6872 *(*prg.mem[r1].hh()).rh() = s 6873 r1 = s 6874 } 6875 q = *(*prg.mem[q].hh()).rh() 6876 qq = *(*prg.mem[q].hh()).lh() 6877 } else { 6878 *(*prg.mem[r1].hh()).rh() = p 6879 r1 = p 6880 p = *(*prg.mem[p].hh()).rh() 6881 pp = *(*prg.mem[p].hh()).lh() 6882 } 6883 } 6884 6885 done: 6886 if int32(t) == dependent { 6887 *prg.mem[int32(p)+1].int() = prg.slowAdd(*prg.mem[int32(p)+1].int(), prg.takeFraction(*prg.mem[int32(q)+1].int(), f)) 6888 } else { 6889 *prg.mem[int32(p)+1].int() = prg.slowAdd(*prg.mem[int32(p)+1].int(), prg.takeScaled(*prg.mem[int32(q)+1].int(), f)) 6890 } 6891 *(*prg.mem[r1].hh()).rh() = p 6892 prg.depFinal = p 6893 r = *(*prg.mem[3000-1].hh()).rh() 6894 return r 6895 } 6896 6897 func (prg *prg) pOverV(p halfword, v scaled, 6898 t0, t1 smallNumber) (r halfword) { 6899 var ( 6900 r1, s halfword // for list manipulation 6901 w int32 // tentative coefficient 6902 threshold int32 6903 scalingDown bool 6904 ) 6905 if int32(t0) != int32(t1) { 6906 scalingDown = true 6907 } else { 6908 scalingDown = false 6909 } 6910 if int32(t1) == dependent { 6911 threshold = halfFractionThreshold 6912 } else { 6913 threshold = halfScaledThreshold 6914 } 6915 r1 = uint16(3000 - 1) 6916 for int32(*(*prg.mem[p].hh()).lh()) != memMin { 6917 if scalingDown { 6918 if abs(v) < 02000000 { 6919 w = prg.makeScaled(*prg.mem[int32(p)+1].int(), v*010000) 6920 } else { 6921 w = prg.makeScaled(prg.roundFraction(*prg.mem[int32(p)+1].int()), v) 6922 } 6923 } else { 6924 w = prg.makeScaled(*prg.mem[int32(p)+1].int(), v) 6925 } 6926 if abs(w) <= threshold { 6927 s = *(*prg.mem[p].hh()).rh() 6928 prg.freeNode(p, halfword(depNodeSize)) 6929 p = s 6930 } else { 6931 if abs(w) >= 04525252525 { 6932 prg.fixNeeded = true 6933 *(*prg.mem[*(*prg.mem[p].hh()).lh()].hh()).b0() = byte(independentNeedingFix) 6934 } 6935 *(*prg.mem[r1].hh()).rh() = p 6936 r1 = p 6937 *prg.mem[int32(p)+1].int() = w 6938 p = *(*prg.mem[p].hh()).rh() 6939 } 6940 } 6941 *(*prg.mem[r1].hh()).rh() = p 6942 *prg.mem[int32(p)+1].int() = prg.makeScaled(*prg.mem[int32(p)+1].int(), v) 6943 r = *(*prg.mem[3000-1].hh()).rh() 6944 return r 6945 } 6946 6947 func (prg *prg) valTooBig(x scaled) { 6948 if prg.internal[warningCheck-1] > 0 { 6949 { 6950 if int32(prg.interaction) == errorStopMode { 6951 } 6952 prg.printNl(strNumber( /* "! " */ 261)) 6953 prg.print( /* "Value is too large (" */ 590) /* \xref[!\relax] */ 6954 } 6955 prg.printScaled(x) 6956 prg.printChar(asciiCode(')')) 6957 // \xref[Value is too large] 6958 { 6959 prg.helpPtr = 4 6960 prg.helpLine[3] = /* "The equation I just processed has given some variable" */ 591 6961 prg.helpLine[2] = /* "a value of 4096 or more. Continue and I'll try to cope" */ 592 6962 prg.helpLine[1] = /* "with that big value; but it might be dangerous." */ 593 6963 prg.helpLine[0] = /* "(Set warningcheck:=0 to suppress this message.)" */ 594 6964 } 6965 prg.error1() 6966 } 6967 } 6968 6969 func (prg *prg) makeKnown(p, q halfword) { 6970 var ( 6971 t /* dependent..protoDependent */ byte // the previous type 6972 ) 6973 *(*prg.mem[int32(*(*prg.mem[q].hh()).rh())+1].hh()).lh() = *(*prg.mem[int32(p)+1].hh()).lh() 6974 *(*prg.mem[*(*prg.mem[int32(p)+1].hh()).lh()].hh()).rh() = *(*prg.mem[q].hh()).rh() 6975 t = *(*prg.mem[p].hh()).b0() 6976 *(*prg.mem[p].hh()).b0() = byte(known) 6977 *prg.mem[int32(p)+1].int() = *prg.mem[int32(q)+1].int() 6978 prg.freeNode(q, halfword(depNodeSize)) 6979 if abs(*prg.mem[int32(p)+1].int()) >= 02000000000 { 6980 prg.valTooBig(*prg.mem[int32(p)+1].int()) 6981 } 6982 if prg.internal[tracingEquations-1] > 0 { 6983 if prg.interesting(p) { 6984 prg.beginDiagnostic() 6985 prg.printNl(strNumber( /* "#### " */ 595)) 6986 // \xref[]]]\#\#\#\#_][\.[\#\#\#\#]] 6987 prg.printVariableName(p) 6988 prg.printChar(asciiCode('=')) 6989 prg.printScaled(*prg.mem[int32(p)+1].int()) 6990 prg.endDiagnostic(false) 6991 } 6992 } 6993 if prg.curExp == int32(p) { 6994 if int32(prg.curType) == int32(t) { 6995 prg.curType = byte(known) 6996 prg.curExp = *prg.mem[int32(p)+1].int() 6997 prg.freeNode(p, halfword(valueNodeSize)) 6998 } 6999 } 7000 } 7001 7002 func (prg *prg) fixDependencies() { 7003 var ( 7004 p, q, r1, s, t halfword // list manipulation registers 7005 x halfword // an independent variable 7006 ) 7007 r1 = *(*prg.mem[memMin+3+10].hh()).rh() 7008 s = uint16(memMin) 7009 for int32(r1) != memMin+3+10 { 7010 t = r1 7011 7012 // Run through the dependency list for variable |t|, fixing all nodes, and ending with final link~|q| 7013 r1 = uint16(int32(t) + 1) // |link(r)=dep_list(t)| 7014 for true { 7015 q = *(*prg.mem[r1].hh()).rh() 7016 x = *(*prg.mem[q].hh()).lh() 7017 if int32(x) == memMin { 7018 goto done 7019 } 7020 if int32(*(*prg.mem[x].hh()).b0()) <= independentBeingFixed { 7021 if int32(*(*prg.mem[x].hh()).b0()) < independentBeingFixed { 7022 p = prg.getAvail() 7023 *(*prg.mem[p].hh()).rh() = s 7024 s = p 7025 *(*prg.mem[s].hh()).lh() = x 7026 *(*prg.mem[x].hh()).b0() = byte(independentBeingFixed) 7027 } 7028 *prg.mem[int32(q)+1].int() = *prg.mem[int32(q)+1].int() / 4 7029 if *prg.mem[int32(q)+1].int() == 0 { 7030 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[q].hh()).rh() 7031 prg.freeNode(q, halfword(depNodeSize)) 7032 q = r1 7033 } 7034 } 7035 r1 = q 7036 } 7037 7038 done: 7039 ; 7040 r1 = *(*prg.mem[q].hh()).rh() 7041 if int32(q) == int32(*(*prg.mem[int32(t)+1].hh()).rh()) { 7042 prg.makeKnown(t, q) 7043 } 7044 } 7045 for int32(s) != memMin { 7046 p = *(*prg.mem[s].hh()).rh() 7047 x = *(*prg.mem[s].hh()).lh() 7048 { 7049 *(*prg.mem[s].hh()).rh() = prg.avail 7050 prg.avail = s 7051 prg.dynUsed = prg.dynUsed - 1 7052 } 7053 s = p 7054 *(*prg.mem[x].hh()).b0() = byte(independent) 7055 *prg.mem[int32(x)+1].int() = *prg.mem[int32(x)+1].int() + 2 7056 } 7057 prg.fixNeeded = false 7058 } 7059 7060 // \4 7061 // Declare the recycling subroutines 7062 func (prg *prg) tossKnotList(p halfword) { 7063 var ( 7064 q halfword // the node being freed 7065 r1 halfword // the next node 7066 ) 7067 q = p 7068 for { 7069 r1 = *(*prg.mem[q].hh()).rh() 7070 prg.freeNode(q, halfword(knotNodeSize)) 7071 q = r1 7072 if int32(q) == int32(p) { 7073 break 7074 } 7075 } 7076 } 7077 7078 func (prg *prg) tossEdges(h halfword) { 7079 var ( 7080 p, q halfword // for list manipulation 7081 ) 7082 q = *(*prg.mem[h].hh()).rh() 7083 for int32(q) != int32(h) { 7084 prg.flushList(*(*prg.mem[int32(q)+1].hh()).rh()) 7085 if int32(*(*prg.mem[int32(q)+1].hh()).lh()) > memMin+1 { 7086 prg.flushList(*(*prg.mem[int32(q)+1].hh()).lh()) 7087 } 7088 p = q 7089 q = *(*prg.mem[q].hh()).rh() 7090 prg.freeNode(p, halfword(rowNodeSize)) 7091 } 7092 prg.freeNode(h, halfword(edgeHeaderSize)) 7093 } 7094 7095 func (prg *prg) tossPen(p halfword) { 7096 var ( 7097 k/* 1..8 */ byte // relative header locations 7098 w, ww halfword // pointers to offset nodes 7099 ) 7100 if int32(p) != memMin+3 { 7101 for ii := int32(1); ii <= 8; ii++ { 7102 k = byte(ii) 7103 _ = k 7104 w = *(*prg.mem[int32(p)+int32(k)].hh()).rh() 7105 for { 7106 ww = *(*prg.mem[w].hh()).rh() 7107 prg.freeNode(w, halfword(coordNodeSize)) 7108 w = ww 7109 if int32(w) == int32(*(*prg.mem[int32(p)+int32(k)].hh()).rh()) { 7110 break 7111 } 7112 } 7113 } 7114 prg.freeNode(p, halfword(penNodeSize)) 7115 } 7116 } 7117 7118 func (prg *prg) ringDelete(p halfword) { 7119 var ( 7120 q halfword 7121 ) 7122 q = uint16(*prg.mem[int32(p)+1].int()) 7123 if int32(q) != memMin { 7124 if int32(q) != int32(p) { 7125 for *prg.mem[int32(q)+1].int() != int32(p) { 7126 q = uint16(*prg.mem[int32(q)+1].int()) 7127 } 7128 *prg.mem[int32(q)+1].int() = *prg.mem[int32(p)+1].int() 7129 } 7130 } 7131 } 7132 7133 func (prg *prg) recycleValue(p halfword) { 7134 var ( 7135 t smallNumber // a type code 7136 v int32 // a value 7137 vv int32 // another value 7138 q, r1, s, pp halfword // link manipulation registers 7139 ) 7140 t = *(*prg.mem[p].hh()).b0() 7141 if int32(t) < dependent { 7142 v = *prg.mem[int32(p)+1].int() 7143 } 7144 switch t { 7145 case undefined, vacuous, booleanType, known, 7146 numericType: 7147 case unknownBoolean, unknownString, unknownPen, unknownPicture, 7148 unknownPath: 7149 prg.ringDelete(p) 7150 case stringType: 7151 if int32(prg.strRef[v]) < maxStrRef { 7152 if int32(prg.strRef[v]) > 1 { 7153 prg.strRef[v] = byte(int32(prg.strRef[v]) - 1) 7154 } else { 7155 prg.flushString(strNumber(v)) 7156 } 7157 } 7158 case penType: 7159 if int32(*(*prg.mem[v].hh()).lh()) == memMin { 7160 prg.tossPen(halfword(v)) 7161 } else { 7162 *(*prg.mem[v].hh()).lh() = uint16(int32(*(*prg.mem[v].hh()).lh()) - 1) 7163 } 7164 case pathType, futurePen: 7165 prg.tossKnotList(halfword(v)) 7166 case pictureType: 7167 prg.tossEdges(halfword(v)) 7168 case pairType, transformType: 7169 // Recycle a big node 7170 if v != memMin { 7171 q = uint16(v + int32(prg.bigNodeSize[t-13])) 7172 for { 7173 q = uint16(int32(q) - 2) 7174 prg.recycleValue(q) 7175 if int32(q) == v { 7176 break 7177 } 7178 } 7179 prg.freeNode(halfword(v), halfword(prg.bigNodeSize[t-13])) 7180 } 7181 7182 case dependent, protoDependent: 7183 // Recycle a dependency list 7184 q = *(*prg.mem[int32(p)+1].hh()).rh() 7185 for int32(*(*prg.mem[q].hh()).lh()) != memMin { 7186 q = *(*prg.mem[q].hh()).rh() 7187 } 7188 *(*prg.mem[*(*prg.mem[int32(p)+1].hh()).lh()].hh()).rh() = *(*prg.mem[q].hh()).rh() 7189 *(*prg.mem[int32(*(*prg.mem[q].hh()).rh())+1].hh()).lh() = *(*prg.mem[int32(p)+1].hh()).lh() 7190 *(*prg.mem[q].hh()).rh() = uint16(memMin) 7191 prg.flushNodeList(*(*prg.mem[int32(p)+1].hh()).rh()) 7192 7193 case independent: 7194 // Recycle an independent variable 7195 prg.maxC[dependent-17] = 0 7196 prg.maxC[protoDependent-17] = 0 7197 7198 prg.maxLink[dependent-17] = uint16(memMin) 7199 prg.maxLink[protoDependent-17] = uint16(memMin) 7200 7201 q = *(*prg.mem[memMin+3+10].hh()).rh() 7202 for int32(q) != memMin+3+10 { 7203 s = uint16(int32(q) + 1) // now |link(s)=dep_list(q)| 7204 for true { 7205 r1 = *(*prg.mem[s].hh()).rh() 7206 if int32(*(*prg.mem[r1].hh()).lh()) == memMin { 7207 goto done 7208 } 7209 if int32(*(*prg.mem[r1].hh()).lh()) != int32(p) { 7210 s = r1 7211 } else { 7212 t = *(*prg.mem[q].hh()).b0() 7213 *(*prg.mem[s].hh()).rh() = *(*prg.mem[r1].hh()).rh() 7214 *(*prg.mem[r1].hh()).lh() = q 7215 if abs(*prg.mem[int32(r1)+1].int()) > prg.maxC[t-17] { 7216 if prg.maxC[t-17] > 0 { 7217 *(*prg.mem[prg.maxPtr[t-17]].hh()).rh() = prg.maxLink[t-17] 7218 prg.maxLink[t-17] = prg.maxPtr[t-17] 7219 } 7220 prg.maxC[t-17] = abs(*prg.mem[int32(r1)+1].int()) 7221 prg.maxPtr[t-17] = r1 7222 } else { 7223 *(*prg.mem[r1].hh()).rh() = prg.maxLink[t-17] 7224 prg.maxLink[t-17] = r1 7225 } 7226 } 7227 } 7228 7229 done: 7230 q = *(*prg.mem[r1].hh()).rh() 7231 } 7232 if prg.maxC[dependent-17] > 0 || prg.maxC[protoDependent-17] > 0 { 7233 if prg.maxC[dependent-17]/010000 >= prg.maxC[protoDependent-17] { 7234 t = byte(dependent) 7235 } else { 7236 t = byte(protoDependent) 7237 } 7238 7239 // Determine the dependency list |s| to substitute for the independent variable~|p| 7240 s = prg.maxPtr[t-17] 7241 pp = *(*prg.mem[s].hh()).lh() 7242 v = *prg.mem[int32(s)+1].int() 7243 if int32(t) == dependent { 7244 *prg.mem[int32(s)+1].int() = -02000000000 7245 } else { 7246 *prg.mem[int32(s)+1].int() = -0200000 7247 } 7248 r1 = *(*prg.mem[int32(pp)+1].hh()).rh() 7249 *(*prg.mem[s].hh()).rh() = r1 7250 for int32(*(*prg.mem[r1].hh()).lh()) != memMin { 7251 r1 = *(*prg.mem[r1].hh()).rh() 7252 } 7253 q = *(*prg.mem[r1].hh()).rh() 7254 *(*prg.mem[r1].hh()).rh() = uint16(memMin) 7255 *(*prg.mem[int32(q)+1].hh()).lh() = *(*prg.mem[int32(pp)+1].hh()).lh() 7256 *(*prg.mem[*(*prg.mem[int32(pp)+1].hh()).lh()].hh()).rh() = q 7257 { 7258 if prg.serialNo > 017777777777-sScale { 7259 prg.overflow(strNumber( /* "independent variables" */ 587), prg.serialNo/sScale) 7260 } /* \xref[METAFONT capacity exceeded independent variables][\quad independent variables] */ 7261 *(*prg.mem[pp].hh()).b0() = byte(independent) 7262 prg.serialNo = prg.serialNo + sScale 7263 *prg.mem[int32(pp)+1].int() = prg.serialNo 7264 } 7265 if prg.curExp == int32(pp) { 7266 if int32(prg.curType) == int32(t) { 7267 prg.curType = byte(independent) 7268 } 7269 } 7270 if prg.internal[tracingEquations-1] > 0 { 7271 if prg.interesting(p) { 7272 prg.beginDiagnostic() 7273 prg.printNl(strNumber( /* "### " */ 767)) 7274 // \xref[]]]\#\#\#_][\.[\#\#\#]] 7275 if v > 0 { 7276 prg.printChar(asciiCode('-')) 7277 } 7278 if int32(t) == dependent { 7279 vv = prg.roundFraction(prg.maxC[dependent-17]) 7280 } else { 7281 vv = prg.maxC[protoDependent-17] 7282 } 7283 if vv != 0200000 { 7284 prg.printScaled(vv) 7285 } 7286 prg.printVariableName(p) 7287 for *prg.mem[int32(p)+1].int()%sScale > 0 { 7288 prg.print( /* "*4" */ 589) 7289 *prg.mem[int32(p)+1].int() = *prg.mem[int32(p)+1].int() - 2 7290 } 7291 if int32(t) == dependent { 7292 prg.printChar(asciiCode('=')) 7293 } else { 7294 prg.print( /* " = " */ 768) 7295 } 7296 prg.printDependency(s, t) 7297 prg.endDiagnostic(false) 7298 } 7299 } 7300 t = byte(dependent + protoDependent - int32(t)) // complement |t| 7301 if prg.maxC[t-17] > 0 { 7302 *(*prg.mem[prg.maxPtr[t-17]].hh()).rh() = prg.maxLink[t-17] 7303 prg.maxLink[t-17] = prg.maxPtr[t-17] 7304 } 7305 if int32(t) != dependent { 7306 for ii := int32(dependent); ii <= protoDependent; ii++ { 7307 t = smallNumber(ii) 7308 _ = t 7309 r1 = prg.maxLink[t-17] 7310 for int32(r1) != memMin { 7311 q = *(*prg.mem[r1].hh()).lh() 7312 *(*prg.mem[int32(q)+1].hh()).rh() = prg.pPlusFq(*(*prg.mem[int32(q)+1].hh()).rh(), prg.makeFraction(*prg.mem[int32(r1)+1].int(), -v), s, t, smallNumber(dependent)) 7313 if int32(*(*prg.mem[int32(q)+1].hh()).rh()) == int32(prg.depFinal) { 7314 prg.makeKnown(q, prg.depFinal) 7315 } 7316 q = r1 7317 r1 = *(*prg.mem[r1].hh()).rh() 7318 prg.freeNode(q, halfword(depNodeSize)) 7319 } 7320 } 7321 } else { 7322 // Substitute new proto-dependencies in place of |p| 7323 for ii := int32(dependent); ii <= protoDependent; ii++ { 7324 t = smallNumber(ii) 7325 _ = t 7326 r1 = prg.maxLink[t-17] 7327 for int32(r1) != memMin { 7328 q = *(*prg.mem[r1].hh()).lh() 7329 if int32(t) == dependent { 7330 if prg.curExp == int32(q) { 7331 if int32(prg.curType) == dependent { 7332 prg.curType = byte(protoDependent) 7333 } 7334 } 7335 *(*prg.mem[int32(q)+1].hh()).rh() = prg.pOverV(*(*prg.mem[int32(q)+1].hh()).rh(), scaled(0200000), smallNumber(dependent), smallNumber(protoDependent)) 7336 *(*prg.mem[q].hh()).b0() = byte(protoDependent) 7337 *prg.mem[int32(r1)+1].int() = prg.roundFraction(*prg.mem[int32(r1)+1].int()) 7338 } 7339 *(*prg.mem[int32(q)+1].hh()).rh() = prg.pPlusFq(*(*prg.mem[int32(q)+1].hh()).rh(), prg.makeScaled(*prg.mem[int32(r1)+1].int(), -v), s, smallNumber(protoDependent), smallNumber(protoDependent)) 7340 if int32(*(*prg.mem[int32(q)+1].hh()).rh()) == int32(prg.depFinal) { 7341 prg.makeKnown(q, prg.depFinal) 7342 } 7343 q = r1 7344 r1 = *(*prg.mem[r1].hh()).rh() 7345 prg.freeNode(q, halfword(depNodeSize)) 7346 } 7347 } 7348 } 7349 prg.flushNodeList(s) 7350 if prg.fixNeeded { 7351 prg.fixDependencies() 7352 } 7353 { 7354 if prg.arithError { 7355 prg.clearArith() 7356 } 7357 } 7358 } 7359 7360 case tokenList, structured: 7361 prg.confusion(strNumber( /* "recycle" */ 766)) 7362 // \xref[this can't happen recycle][\quad recycle] 7363 case unsuffixedMacro, suffixedMacro: 7364 prg.deleteMacRef(halfword(*prg.mem[int32(p)+1].int())) 7365 } // there are no other cases 7366 *(*prg.mem[p].hh()).b0() = byte(undefined) 7367 } 7368 7369 // \4 7370 // Declare the procedure called |flush_cur_exp| 7371 func (prg *prg) flushCurExp(v scaled) { 7372 switch prg.curType { 7373 case unknownBoolean, unknownString, unknownPen, unknownPicture, 7374 unknownPath, transformType, pairType, dependent, 7375 protoDependent, independent: 7376 prg.recycleValue(halfword(prg.curExp)) 7377 prg.freeNode(halfword(prg.curExp), halfword(valueNodeSize)) 7378 7379 case penType: 7380 if int32(*(*prg.mem[prg.curExp].hh()).lh()) == memMin { 7381 prg.tossPen(halfword(prg.curExp)) 7382 } else { 7383 *(*prg.mem[prg.curExp].hh()).lh() = uint16(int32(*(*prg.mem[prg.curExp].hh()).lh()) - 1) 7384 } 7385 case stringType: 7386 if int32(prg.strRef[prg.curExp]) < maxStrRef { 7387 if int32(prg.strRef[prg.curExp]) > 1 { 7388 prg.strRef[prg.curExp] = byte(int32(prg.strRef[prg.curExp]) - 1) 7389 } else { 7390 prg.flushString(strNumber(prg.curExp)) 7391 } 7392 } 7393 case futurePen, pathType: 7394 prg.tossKnotList(halfword(prg.curExp)) 7395 case pictureType: 7396 prg.tossEdges(halfword(prg.curExp)) 7397 7398 default: 7399 } 7400 7401 prg.curType = byte(known) 7402 prg.curExp = v 7403 } 7404 7405 func (prg *prg) flushError(v scaled) { prg.error1(); prg.flushCurExp(v) } // \2 7406 7407 func (prg *prg) putGetError() { prg.backError(); prg.getXNext() } 7408 7409 func (prg *prg) putGetFlushError(v scaled) { 7410 prg.putGetError() 7411 prg.flushCurExp(v) 7412 } 7413 7414 // \4 7415 // Declare the procedure called |flush_below_variable| 7416 func (prg *prg) flushBelowVariable(p halfword) { 7417 var ( 7418 q, r1 halfword // list manipulation registers 7419 ) 7420 if int32(*(*prg.mem[p].hh()).b0()) != structured { 7421 prg.recycleValue(p) 7422 } else { 7423 q = *(*prg.mem[int32(p)+1].hh()).rh() 7424 for int32(*(*prg.mem[q].hh()).b1()) == subscr { 7425 prg.flushBelowVariable(q) 7426 r1 = q 7427 q = *(*prg.mem[q].hh()).rh() 7428 prg.freeNode(r1, halfword(subscrNodeSize)) 7429 } 7430 r1 = *(*prg.mem[int32(p)+1].hh()).lh() 7431 q = *(*prg.mem[r1].hh()).rh() 7432 prg.recycleValue(r1) 7433 if int32(*(*prg.mem[p].hh()).b1()) <= savedRoot { 7434 prg.freeNode(r1, halfword(valueNodeSize)) 7435 } else { 7436 prg.freeNode(r1, halfword(subscrNodeSize)) 7437 } 7438 // we assume that |subscr_node_size=attr_node_size| 7439 for { 7440 prg.flushBelowVariable(q) 7441 r1 = q 7442 q = *(*prg.mem[q].hh()).rh() 7443 prg.freeNode(r1, halfword(attrNodeSize)) 7444 if int32(q) == memMin+3+10+2+2 { 7445 break 7446 } 7447 } 7448 *(*prg.mem[p].hh()).b0() = byte(undefined) 7449 } 7450 } 7451 7452 func (prg *prg) flushVariable(p, t halfword, discardSuffixes bool) { 7453 var ( 7454 q, r1 halfword // list manipulation 7455 n halfword // attribute to match 7456 ) 7457 for int32(t) != memMin { 7458 if int32(*(*prg.mem[p].hh()).b0()) != structured { 7459 goto exit 7460 } 7461 n = *(*prg.mem[t].hh()).lh() 7462 t = *(*prg.mem[t].hh()).rh() 7463 if int32(n) == collectiveSubscript { 7464 r1 = uint16(int32(p) + 1) 7465 q = *(*prg.mem[r1].hh()).rh() // |q=subscr_head(p)| 7466 for int32(*(*prg.mem[q].hh()).b1()) == subscr { 7467 prg.flushVariable(q, t, discardSuffixes) 7468 if int32(t) == memMin { 7469 if int32(*(*prg.mem[q].hh()).b0()) == structured { 7470 r1 = q 7471 } else { 7472 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[q].hh()).rh() 7473 prg.freeNode(q, halfword(subscrNodeSize)) 7474 } 7475 } else { 7476 r1 = q 7477 } 7478 q = *(*prg.mem[r1].hh()).rh() 7479 } 7480 } 7481 p = *(*prg.mem[int32(p)+1].hh()).lh() 7482 for { 7483 r1 = p 7484 p = *(*prg.mem[p].hh()).rh() 7485 if int32(*(*prg.mem[int32(p)+2].hh()).lh()) >= int32(n) { 7486 break 7487 } 7488 } 7489 if int32(*(*prg.mem[int32(p)+2].hh()).lh()) != int32(n) { 7490 goto exit 7491 } 7492 } 7493 if discardSuffixes { 7494 prg.flushBelowVariable(p) 7495 } else { 7496 if int32(*(*prg.mem[p].hh()).b0()) == structured { 7497 p = *(*prg.mem[int32(p)+1].hh()).lh() 7498 } 7499 prg.recycleValue(p) 7500 } 7501 7502 exit: 7503 } 7504 7505 // 248. 7506 7507 // tangle:pos ../../mf.web:5518:3: 7508 7509 // Just before assigning a new value to a variable, we will recycle the 7510 // old value and make the old value undefined. The |und_type| routine 7511 // determines what type of undefined value should be given, based on 7512 // the current type before recycling. 7513 func (prg *prg) undType(p halfword) (r smallNumber) { 7514 switch *(*prg.mem[p].hh()).b0() { 7515 case undefined, vacuous: 7516 r = byte(undefined) 7517 case booleanType, unknownBoolean: 7518 r = byte(unknownBoolean) 7519 case stringType, unknownString: 7520 r = byte(unknownString) 7521 case penType, unknownPen, futurePen: 7522 r = byte(unknownPen) 7523 case pathType, unknownPath: 7524 r = byte(unknownPath) 7525 case pictureType, unknownPicture: 7526 r = byte(unknownPicture) 7527 case transformType, pairType, numericType: 7528 r = *(*prg.mem[p].hh()).b0() 7529 case known, dependent, protoDependent, independent: 7530 r = byte(numericType) 7531 } // there are no other cases 7532 return r 7533 } 7534 7535 // 249. 7536 7537 // tangle:pos ../../mf.web:5536:3: 7538 7539 // The |clear_symbol| routine is used when we want to redefine the equivalent 7540 // of a symbolic token. It must remove any variable structure or macro 7541 // definition that is currently attached to that symbol. If the |saving| 7542 // parameter is true, a subsidiary structure is saved instead of destroyed. 7543 func (prg *prg) clearSymbol(p halfword, saving bool) { 7544 var ( 7545 q halfword // |equiv(p)| 7546 ) 7547 q = *prg.eqtb[p-1].rh() 7548 switch int32(*prg.eqtb[p-1].lh()) % outerTag { 7549 case definedMacro, secondaryPrimaryMacro, tertiarySecondaryMacro, expressionTertiaryMacro: 7550 if !saving { 7551 prg.deleteMacRef(q) 7552 } 7553 case tagToken: 7554 if int32(q) != memMin { 7555 if saving { 7556 *(*prg.mem[q].hh()).b1() = byte(savedRoot) 7557 } else { 7558 prg.flushBelowVariable(q) 7559 prg.freeNode(q, halfword(valueNodeSize)) 7560 } 7561 } 7562 7563 default: 7564 } 7565 7566 prg.eqtb[p-1] = prg.eqtb[hashBase+hashSize+12-1] 7567 } 7568 7569 // 252. 7570 7571 // tangle:pos ../../mf.web:5596:3: 7572 7573 // The |save_variable| routine is given a hash address |q|; it salts this 7574 // address away in the save stack, together with its current equivalent, 7575 // then makes token~|q| behave as though it were brand new. 7576 // 7577 // Nothing is stacked when |save_ptr=null|, however; there's no way to remove 7578 // things from the stack when the program is not inside a group, so there's 7579 // no point in wasting the space. 7580 func (prg *prg) saveVariable(q halfword) { 7581 var ( 7582 p halfword // temporary register 7583 ) 7584 if int32(prg.savePtr) != memMin { 7585 p = prg.getNode(saveNodeSize) 7586 *(*prg.mem[p].hh()).lh() = q 7587 *(*prg.mem[p].hh()).rh() = prg.savePtr 7588 *prg.mem[int32(p)+1].hh() = prg.eqtb[q-1] 7589 prg.savePtr = p 7590 } 7591 prg.clearSymbol(q, int32(prg.savePtr) != memMin) 7592 } 7593 7594 // 253. 7595 7596 // tangle:pos ../../mf.web:5613:3: 7597 7598 // Similarly, |save_internal| is given the location |q| of an internal 7599 // quantity like |tracing_pens|. It creates a save stack entry of the 7600 // third kind. 7601 func (prg *prg) saveInternal(q halfword) { 7602 var ( 7603 p halfword // new item for the save stack 7604 ) 7605 if int32(prg.savePtr) != memMin { 7606 p = prg.getNode(saveNodeSize) 7607 *(*prg.mem[p].hh()).lh() = uint16(hashBase + hashSize + 12 + int32(q)) 7608 *(*prg.mem[p].hh()).rh() = prg.savePtr 7609 *prg.mem[int32(p)+1].int() = prg.internal[q-1] 7610 prg.savePtr = p 7611 } 7612 } 7613 7614 // 254. 7615 7616 // tangle:pos ../../mf.web:5625:3: 7617 7618 // At the end of a group, the |unsave| routine restores all of the saved 7619 // equivalents in reverse order. This routine will be called only when there 7620 // is at least one boundary item on the save stack. 7621 func (prg *prg) unsave() { 7622 var ( 7623 q halfword // index to saved item 7624 p halfword // temporary register 7625 ) 7626 for int32(*(*prg.mem[prg.savePtr].hh()).lh()) != 0 { 7627 q = *(*prg.mem[prg.savePtr].hh()).lh() 7628 if int32(q) > hashBase+hashSize+12 { 7629 if prg.internal[tracingRestores-1] > 0 { 7630 prg.beginDiagnostic() 7631 prg.printNl(strNumber( /* "[restoring " */ 516)) 7632 prg.slowPrint(int32(prg.intName[int32(q)-(hashBase+hashSize+12)-1])) 7633 prg.printChar(asciiCode('=')) 7634 prg.printScaled(*prg.mem[int32(prg.savePtr)+1].int()) 7635 prg.printChar(asciiCode('}')) 7636 prg.endDiagnostic(false) 7637 } 7638 prg.internal[int32(q)-(hashBase+hashSize+12)-1] = *prg.mem[int32(prg.savePtr)+1].int() 7639 } else { 7640 if prg.internal[tracingRestores-1] > 0 { 7641 prg.beginDiagnostic() 7642 prg.printNl(strNumber( /* "[restoring " */ 516)) 7643 prg.slowPrint(int32(*prg.hash[q-1].rh())) 7644 prg.printChar(asciiCode('}')) 7645 prg.endDiagnostic(false) 7646 } 7647 prg.clearSymbol(q, false) 7648 prg.eqtb[q-1] = *prg.mem[int32(prg.savePtr)+1].hh() 7649 if int32(*prg.eqtb[q-1].lh())%outerTag == tagToken { 7650 p = *prg.eqtb[q-1].rh() 7651 if int32(p) != memMin { 7652 *(*prg.mem[p].hh()).b1() = byte(root) 7653 } 7654 } 7655 } 7656 p = *(*prg.mem[prg.savePtr].hh()).rh() 7657 prg.freeNode(prg.savePtr, halfword(saveNodeSize)) 7658 prg.savePtr = p 7659 } 7660 p = *(*prg.mem[prg.savePtr].hh()).rh() 7661 { 7662 *(*prg.mem[prg.savePtr].hh()).rh() = prg.avail 7663 prg.avail = prg.savePtr 7664 prg.dynUsed = prg.dynUsed - 1 7665 } 7666 prg.savePtr = p 7667 } 7668 7669 // 255. \[17] Data structures for paths 7670 7671 // tangle:pos ../../mf.web:5660:36: 7672 7673 // When a \MF\ user specifies a path, \MF\ will create a list of knots 7674 // and control points for the associated cubic spline curves. If the 7675 // knots are $z_0$, $z_1$, \dots, $z_n$, there are control points 7676 // $z_k^+$ and $z_[k+1]^-$ such that the cubic splines between knots 7677 // $z_k$ and $z_[k+1]$ are defined by B\'ezier's formula 7678 // \xref[Bezier][B\'ezier, Pierre Etienne] 7679 // $$\eqalign[z(t)&=B(z_k,z_k^+,z_[k+1]^-,z_[k+1];t)\cr 7680 // &=(1-t)^3z_k+3(1-t)^2tz_k^++3(1-t)t^2z_[k+1]^-+t^3z_[k+1]\cr]$$ 7681 // for |0<=t<=1|. 7682 // 7683 // There is a 7-word node for each knot $z_k$, containing one word of 7684 // control information and six words for the |x| and |y| coordinates 7685 // of $z_k^-$ and $z_k$ and~$z_k^+$. The control information appears 7686 // in the |left_type| and |right_type| fields, which each occupy 7687 // a quarter of the first word in the node; they specify properties 7688 // of the curve as it enters and leaves the knot. There's also a 7689 // halfword |link| field, which points to the following knot. 7690 // 7691 // If the path is a closed contour, knots 0 and |n| are identical; 7692 // i.e., the |link| in knot |n-1| points to knot~0. But if the path 7693 // is not closed, the |left_type| of knot~0 and the |right_type| of knot~|n| 7694 // are equal to |endpoint|. In the latter case the |link| in knot~|n| points 7695 // to knot~0, and the control points $z_0^-$ and $z_n^+$ are not used. 7696 7697 // 256. 7698 7699 // tangle:pos ../../mf.web:5696:3: 7700 7701 // Before the B\'ezier control points have been calculated, the memory 7702 // space they will ultimately occupy is taken up by information that can be 7703 // used to compute them. There are four cases: 7704 // 7705 // \yskip 7706 // \textindent[$\bullet$] If |right_type=open|, the curve should leave 7707 // the knot in the same direction it entered; \MF\ will figure out a 7708 // suitable direction. 7709 // 7710 // \yskip 7711 // \textindent[$\bullet$] If |right_type=curl|, the curve should leave the 7712 // knot in a direction depending on the angle at which it enters the next 7713 // knot and on the curl parameter stored in |right_curl|. 7714 // 7715 // \yskip 7716 // \textindent[$\bullet$] If |right_type=given|, the curve should leave the 7717 // knot in a nonzero direction stored as an |angle| in |right_given|. 7718 // 7719 // \yskip 7720 // \textindent[$\bullet$] If |right_type=explicit|, the B\'ezier control 7721 // point for leaving this knot has already been computed; it is in the 7722 // |right_x| and |right_y| fields. 7723 // 7724 // \yskip\noindent 7725 // The rules for |left_type| are similar, but they refer to the curve entering 7726 // the knot, and to \\[left] fields instead of \\[right] fields. 7727 // 7728 // Non-|explicit| control points will be chosen based on ``tension'' parameters 7729 // in the |left_tension| and |right_tension| fields. The 7730 // `\&[atleast]' option is represented by negative tension values. 7731 // \xref[at_least_][\&[atleast] primitive] 7732 // 7733 // For example, the \MF\ path specification 7734 // $$\.[z0..z1..tension atleast 1..\[curl 2\]z2..z3\[-1,-2\]..tension 7735 // 3 and 4..p],$$ 7736 // where \.p is the path `\.[z4..controls z45 and z54..z5]', will be represented 7737 // by the six knots 7738 // \def\lodash[\hbox to 1.1em[\thinspace\hrulefill\thinspace]] 7739 // $$\vbox[\halign[#\hfil&&\qquad#\hfil\cr 7740 // |left_type|&\\[left] info&|x_coord,y_coord|&|right_type|&\\[right] info\cr 7741 // \noalign[\yskip] 7742 // |endpoint|&\lodash$,\,$\lodash&$x_0,y_0$&|curl|&$1.0,1.0$\cr 7743 // |open|&\lodash$,1.0$&$x_1,y_1$&|open|&\lodash$,-1.0$\cr 7744 // |curl|&$2.0,-1.0$&$x_2,y_2$&|curl|&$2.0,1.0$\cr 7745 // |given|&$d,1.0$&$x_3,y_3$&|given|&$d,3.0$\cr 7746 // |open|&\lodash$,4.0$&$x_4,y_4$&|explicit|&$x_[45],y_[45]$\cr 7747 // |explicit|&$x_[54],y_[54]$&$x_5,y_5$&|endpoint|&\lodash$,\,$\lodash\cr]]$$ 7748 // Here |d| is the |angle| obtained by calling |n_arg(-unity,-two)|. 7749 // Of course, this example is more complicated than anything a normal user 7750 // would ever write. 7751 // 7752 // These types must satisfy certain restrictions because of the form of \MF's 7753 // path syntax: 7754 // (i)~|open| type never appears in the same node together with |endpoint|, 7755 // |given|, or |curl|. 7756 // (ii)~The |right_type| of a node is |explicit| if and only if the 7757 // |left_type| of the following node is |explicit|. 7758 // (iii)~|endpoint| types occur only at the ends, as mentioned above. 7759 7760 // 264. 7761 7762 // tangle:pos ../../mf.web:5865:3: 7763 7764 // If we want to duplicate a knot node, we can say |copy_knot|: 7765 func (prg *prg) copyKnot(p halfword) (r halfword) { 7766 var ( 7767 q halfword // the copy 7768 k/* 0..knotNodeSize-1 */ byte // runs through the words of a knot node 7769 ) 7770 q = prg.getNode(knotNodeSize) 7771 for ii := int32(0); ii <= knotNodeSize-1; ii++ { 7772 k = byte(ii) 7773 _ = k 7774 prg.mem[int32(q)+int32(k)] = prg.mem[int32(p)+int32(k)] 7775 } 7776 r = q 7777 return r 7778 } 7779 7780 // 265. 7781 7782 // tangle:pos ../../mf.web:5875:3: 7783 7784 // The |copy_path| routine makes a clone of a given path. 7785 func (prg *prg) copyPath(p halfword) (r halfword) { 7786 var ( 7787 q, pp, qq halfword // for list manipulation 7788 ) 7789 q = prg.getNode(knotNodeSize) // this will correspond to |p| 7790 qq = q 7791 pp = p 7792 for true { 7793 *(*prg.mem[qq].hh()).b0() = *(*prg.mem[pp].hh()).b0() 7794 *(*prg.mem[qq].hh()).b1() = *(*prg.mem[pp].hh()).b1() 7795 7796 *prg.mem[int32(qq)+1].int() = *prg.mem[int32(pp)+1].int() 7797 *prg.mem[int32(qq)+2].int() = *prg.mem[int32(pp)+2].int() 7798 7799 *prg.mem[int32(qq)+3].int() = *prg.mem[int32(pp)+3].int() 7800 *prg.mem[int32(qq)+4].int() = *prg.mem[int32(pp)+4].int() 7801 7802 *prg.mem[int32(qq)+5].int() = *prg.mem[int32(pp)+5].int() 7803 *prg.mem[int32(qq)+6].int() = *prg.mem[int32(pp)+6].int() 7804 7805 if int32(*(*prg.mem[pp].hh()).rh()) == int32(p) { 7806 *(*prg.mem[qq].hh()).rh() = q 7807 r = q 7808 goto exit 7809 } 7810 *(*prg.mem[qq].hh()).rh() = prg.getNode(knotNodeSize) 7811 qq = *(*prg.mem[qq].hh()).rh() 7812 pp = *(*prg.mem[pp].hh()).rh() 7813 } 7814 7815 exit: 7816 ; 7817 return r 7818 } 7819 7820 // 266. 7821 7822 // tangle:pos ../../mf.web:5894:3: 7823 7824 // Similarly, there's a way to copy the [\sl reverse\/] of a path. This procedure 7825 // returns a pointer to the first node of the copy, if the path is a cycle, 7826 // but to the final node of a non-cyclic copy. The global 7827 // variable |path_tail| will point to the final node of the original path; 7828 // this trick makes it easier to implement `\&[doublepath]'. 7829 // 7830 // All node types are assumed to be |endpoint| or |explicit| only. 7831 func (prg *prg) htapYpoc(p halfword) (r halfword) { 7832 var ( 7833 q, pp, qq, rr halfword // for list manipulation 7834 ) 7835 q = prg.getNode(knotNodeSize) // this will correspond to |p| 7836 qq = q 7837 pp = p 7838 for true { 7839 *(*prg.mem[qq].hh()).b1() = *(*prg.mem[pp].hh()).b0() 7840 *(*prg.mem[qq].hh()).b0() = *(*prg.mem[pp].hh()).b1() 7841 7842 *prg.mem[int32(qq)+1].int() = *prg.mem[int32(pp)+1].int() 7843 *prg.mem[int32(qq)+2].int() = *prg.mem[int32(pp)+2].int() 7844 7845 *prg.mem[int32(qq)+5].int() = *prg.mem[int32(pp)+3].int() 7846 *prg.mem[int32(qq)+6].int() = *prg.mem[int32(pp)+4].int() 7847 7848 *prg.mem[int32(qq)+3].int() = *prg.mem[int32(pp)+5].int() 7849 *prg.mem[int32(qq)+4].int() = *prg.mem[int32(pp)+6].int() 7850 7851 if int32(*(*prg.mem[pp].hh()).rh()) == int32(p) { 7852 *(*prg.mem[q].hh()).rh() = qq 7853 prg.pathTail = pp 7854 r = q 7855 goto exit 7856 } 7857 rr = prg.getNode(knotNodeSize) 7858 *(*prg.mem[rr].hh()).rh() = qq 7859 qq = rr 7860 pp = *(*prg.mem[pp].hh()).rh() 7861 } 7862 7863 exit: 7864 ; 7865 return r 7866 } 7867 7868 // 269. \[18] Choosing control points 7869 7870 // tangle:pos ../../mf.web:5933:34: 7871 7872 // Now we must actually delve into one of \MF's more difficult routines, 7873 // the |make_choices| procedure that chooses angles and control points for 7874 // the splines of a curve when the user has not specified them explicitly. 7875 // The parameter to |make_choices| points to a list of knots and 7876 // path information, as described above. 7877 // 7878 // A path decomposes into independent segments at “breakpoint” knots, 7879 // which are knots whose left and right angles are both prespecified in 7880 // some way (i.e., their |left_type| and |right_type| aren't both open). 7881 // \4 7882 // Declare the procedure called |solve_choices| 7883 // \4 7884 // Declare subroutines needed by |solve_choices| 7885 func (prg *prg) curlRatio(gamma, aTension, bTension scaled) (r fraction) { 7886 var ( 7887 alpha, beta, num, denom, ff fraction // registers 7888 ) 7889 alpha = prg.makeFraction(0200000, aTension) 7890 beta = prg.makeFraction(0200000, bTension) 7891 7892 if alpha <= beta { 7893 ff = prg.makeFraction(alpha, beta) 7894 ff = prg.takeFraction(ff, ff) 7895 gamma = prg.takeFraction(gamma, ff) 7896 7897 beta = beta / 010000 // convert |fraction| to |scaled| 7898 denom = prg.takeFraction(gamma, alpha) + 0600000 - beta 7899 num = prg.takeFraction(gamma, 06000000000-alpha) + beta 7900 } else { 7901 ff = prg.makeFraction(beta, alpha) 7902 ff = prg.takeFraction(ff, ff) 7903 beta = prg.takeFraction(beta, ff) / 010000 // convert |fraction| to |scaled| 7904 denom = prg.takeFraction(gamma, alpha) + ff/1365 - beta 7905 // $1365\approx 2^[12]/3$ 7906 num = prg.takeFraction(gamma, 06000000000-alpha) + beta 7907 } 7908 if num >= denom+denom+denom+denom { 7909 r = 010000000000 7910 } else { 7911 r = prg.makeFraction(num, denom) 7912 } 7913 return r 7914 } 7915 7916 func (prg *prg) setControls(p, q halfword, k int32) { 7917 var ( 7918 rr, ss fraction // velocities, divided by thrice the tension 7919 lt, rt scaled // tensions 7920 sine fraction // $\sin(\theta+\phi)$ 7921 ) 7922 lt = abs(*prg.mem[int32(q)+4].int()) 7923 rt = abs(*prg.mem[int32(p)+6].int()) 7924 rr = prg.velocity(prg.st, prg.ct, prg.sf, prg.cf, rt) 7925 ss = prg.velocity(prg.sf, prg.cf, prg.st, prg.ct, lt) 7926 if *prg.mem[int32(p)+6].int() < 0 || *prg.mem[int32(q)+4].int() < 0 { 7927 if prg.st >= 0 && prg.sf >= 0 || prg.st <= 0 && prg.sf <= 0 { 7928 sine = prg.takeFraction(abs(prg.st), prg.cf) + prg.takeFraction(abs(prg.sf), prg.ct) 7929 if sine > 0 { 7930 sine = prg.takeFraction(sine, 02000000000+0200000) // safety factor 7931 if *prg.mem[int32(p)+6].int() < 0 { 7932 if prg.abVsCd(abs(prg.sf), 02000000000, rr, sine) < 0 { 7933 rr = prg.makeFraction(abs(prg.sf), sine) 7934 } 7935 } 7936 if *prg.mem[int32(q)+4].int() < 0 { 7937 if prg.abVsCd(abs(prg.st), 02000000000, ss, sine) < 0 { 7938 ss = prg.makeFraction(abs(prg.st), sine) 7939 } 7940 } 7941 } 7942 } 7943 } 7944 *prg.mem[int32(p)+5].int() = *prg.mem[int32(p)+1].int() + prg.takeFraction(prg.takeFraction(prg.deltaX[k], prg.ct)-prg.takeFraction(prg.deltaY[k], prg.st), rr) 7945 *prg.mem[int32(p)+6].int() = *prg.mem[int32(p)+2].int() + prg.takeFraction(prg.takeFraction(prg.deltaY[k], prg.ct)+prg.takeFraction(prg.deltaX[k], prg.st), rr) 7946 *prg.mem[int32(q)+3].int() = *prg.mem[int32(q)+1].int() - prg.takeFraction(prg.takeFraction(prg.deltaX[k], prg.cf)+prg.takeFraction(prg.deltaY[k], prg.sf), ss) 7947 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+2].int() - prg.takeFraction(prg.takeFraction(prg.deltaY[k], prg.cf)-prg.takeFraction(prg.deltaX[k], prg.sf), ss) 7948 *(*prg.mem[p].hh()).b1() = byte(explicit) 7949 *(*prg.mem[q].hh()).b0() = byte(explicit) 7950 } 7951 7952 func (prg *prg) solveChoices(p, q halfword, n halfword) { 7953 var ( 7954 k/* 0..pathSize */ uint16 // current knot number 7955 r1, s, t halfword // registers for list traversal 7956 7957 // Other local variables for |solve_choices| 7958 aa, bb, cc, ff, acc fraction // temporary registers 7959 dd, ee scaled // likewise, but |scaled| 7960 lt, rt scaled // tension values 7961 ) 7962 k = 0 7963 s = p 7964 for true { 7965 t = *(*prg.mem[s].hh()).rh() 7966 if int32(k) == 0 { 7967 switch *(*prg.mem[s].hh()).b1() { 7968 case given: 7969 if int32(*(*prg.mem[t].hh()).b0()) == given { 7970 aa = prg.nArg(prg.deltaX[0], prg.deltaY[0]) 7971 7972 prg.nSinCos(*prg.mem[int32(p)+5].int() - aa) 7973 prg.ct = prg.nCos 7974 prg.st = prg.nSin 7975 7976 prg.nSinCos(*prg.mem[int32(q)+3].int() - aa) 7977 prg.cf = prg.nCos 7978 prg.sf = -prg.nSin 7979 7980 prg.setControls(p, q, 0) 7981 goto exit 7982 } else { 7983 // Set up the equation for a given value of $\theta_0$ 7984 prg.vv[0] = *prg.mem[int32(s)+5].int() - prg.nArg(prg.deltaX[0], prg.deltaY[0]) 7985 if abs(prg.vv[0]) > 01320000000 { 7986 if prg.vv[0] > 0 { 7987 prg.vv[0] = prg.vv[0] - 02640000000 7988 } else { 7989 prg.vv[0] = prg.vv[0] + 02640000000 7990 } 7991 } 7992 prg.uu[0] = 0 7993 prg.ww[0] = 0 7994 } 7995 7996 case curl: 7997 if int32(*(*prg.mem[t].hh()).b0()) == curl { 7998 *(*prg.mem[p].hh()).b1() = byte(explicit) 7999 *(*prg.mem[q].hh()).b0() = byte(explicit) 8000 lt = abs(*prg.mem[int32(q)+4].int()) 8001 rt = abs(*prg.mem[int32(p)+6].int()) 8002 if rt == 0200000 { 8003 if prg.deltaX[0] >= 0 { 8004 *prg.mem[int32(p)+5].int() = *prg.mem[int32(p)+1].int() + (prg.deltaX[0]+1)/3 8005 } else { 8006 *prg.mem[int32(p)+5].int() = *prg.mem[int32(p)+1].int() + (prg.deltaX[0]-1)/3 8007 } 8008 if prg.deltaY[0] >= 0 { 8009 *prg.mem[int32(p)+6].int() = *prg.mem[int32(p)+2].int() + (prg.deltaY[0]+1)/3 8010 } else { 8011 *prg.mem[int32(p)+6].int() = *prg.mem[int32(p)+2].int() + (prg.deltaY[0]-1)/3 8012 } 8013 } else { 8014 ff = prg.makeFraction(0200000, 3*rt) // $\alpha/3$ 8015 *prg.mem[int32(p)+5].int() = *prg.mem[int32(p)+1].int() + prg.takeFraction(prg.deltaX[0], ff) 8016 *prg.mem[int32(p)+6].int() = *prg.mem[int32(p)+2].int() + prg.takeFraction(prg.deltaY[0], ff) 8017 } 8018 if lt == 0200000 { 8019 if prg.deltaX[0] >= 0 { 8020 *prg.mem[int32(q)+3].int() = *prg.mem[int32(q)+1].int() - (prg.deltaX[0]+1)/3 8021 } else { 8022 *prg.mem[int32(q)+3].int() = *prg.mem[int32(q)+1].int() - (prg.deltaX[0]-1)/3 8023 } 8024 if prg.deltaY[0] >= 0 { 8025 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+2].int() - (prg.deltaY[0]+1)/3 8026 } else { 8027 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+2].int() - (prg.deltaY[0]-1)/3 8028 } 8029 } else { 8030 ff = prg.makeFraction(0200000, 3*lt) // $\beta/3$ 8031 *prg.mem[int32(q)+3].int() = *prg.mem[int32(q)+1].int() - prg.takeFraction(prg.deltaX[0], ff) 8032 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+2].int() - prg.takeFraction(prg.deltaY[0], ff) 8033 } 8034 8035 goto exit 8036 } else { 8037 // Set up the equation for a curl at $\theta_0$ 8038 cc = *prg.mem[int32(s)+5].int() 8039 lt = abs(*prg.mem[int32(t)+4].int()) 8040 rt = abs(*prg.mem[int32(s)+6].int()) 8041 if rt == 0200000 && lt == 0200000 { 8042 prg.uu[0] = prg.makeFraction(cc+cc+0200000, cc+0400000) 8043 } else { 8044 prg.uu[0] = prg.curlRatio(cc, rt, lt) 8045 } 8046 prg.vv[0] = -prg.takeFraction(prg.psi[1-1], prg.uu[0]) 8047 prg.ww[0] = 0 8048 } 8049 8050 case open: 8051 prg.uu[0] = 0 8052 prg.vv[0] = 0 8053 prg.ww[0] = 02000000000 8054 // this begins a cycle 8055 } 8056 } else { 8057 switch *(*prg.mem[s].hh()).b0() { 8058 case endCycle, open: 8059 // Set up equation to match mock curvatures at $z_k$; then |goto found| with $\theta_n$ adjusted to equal $\theta_0$, if a cycle has ended 8060 if abs(*prg.mem[int32(r1)+6].int()) == 0200000 { 8061 aa = 01000000000 8062 dd = 2 * prg.delta[k] 8063 } else { 8064 aa = prg.makeFraction(0200000, 3*abs(*prg.mem[int32(r1)+6].int())-0200000) 8065 dd = prg.takeFraction(prg.delta[k], 8066 06000000000-prg.makeFraction(0200000, abs(*prg.mem[int32(r1)+6].int()))) 8067 } 8068 if abs(*prg.mem[int32(t)+4].int()) == 0200000 { 8069 bb = 01000000000 8070 ee = 2 * prg.delta[int32(k)-1] 8071 } else { 8072 bb = prg.makeFraction(0200000, 3*abs(*prg.mem[int32(t)+4].int())-0200000) 8073 ee = prg.takeFraction(prg.delta[int32(k)-1], 8074 06000000000-prg.makeFraction(0200000, abs(*prg.mem[int32(t)+4].int()))) 8075 } 8076 cc = 02000000000 - prg.takeFraction(prg.uu[int32(k)-1], aa) 8077 8078 // Calculate the ratio $\\[ff]=C_k/(C_k+B_k-u_[k-1]A_k)$ 8079 dd = prg.takeFraction(dd, cc) 8080 lt = abs(*prg.mem[int32(s)+4].int()) 8081 rt = abs(*prg.mem[int32(s)+6].int()) 8082 if lt != rt { 8083 if lt < rt { 8084 ff = prg.makeFraction(lt, rt) 8085 ff = prg.takeFraction(ff, ff) // $\alpha_k^2/\beta_k^2$ 8086 dd = prg.takeFraction(dd, ff) 8087 } else { 8088 ff = prg.makeFraction(rt, lt) 8089 ff = prg.takeFraction(ff, ff) // $\beta_k^2/\alpha_k^2$ 8090 ee = prg.takeFraction(ee, ff) 8091 } 8092 } 8093 ff = prg.makeFraction(ee, ee+dd) 8094 prg.uu[k] = prg.takeFraction(ff, bb) 8095 8096 // Calculate the values of $v_k$ and $w_k$ 8097 acc = -prg.takeFraction(prg.psi[int32(k)+1-1], prg.uu[k]) 8098 if int32(*(*prg.mem[r1].hh()).b1()) == curl { 8099 prg.ww[k] = 0 8100 prg.vv[k] = acc - prg.takeFraction(prg.psi[1-1], 02000000000-ff) 8101 } else { 8102 ff = prg.makeFraction(02000000000-ff, cc) // this is 8103 // $B_k/(C_k+B_k-u_[k-1]A_k)<5$ 8104 8105 acc = acc - prg.takeFraction(prg.psi[k-1], ff) 8106 ff = prg.takeFraction(ff, aa) // this is $A_k/(C_k+B_k-u_[k-1]A_k)$ 8107 prg.vv[k] = acc - prg.takeFraction(prg.vv[int32(k)-1], ff) 8108 if prg.ww[int32(k)-1] == 0 { 8109 prg.ww[k] = 0 8110 } else { 8111 prg.ww[k] = -prg.takeFraction(prg.ww[int32(k)-1], ff) 8112 } 8113 } 8114 if int32(*(*prg.mem[s].hh()).b0()) == endCycle { 8115 aa = 0 8116 bb = 02000000000 // we have |k=n| 8117 for { 8118 k = uint16(int32(k) - 1) 8119 if int32(k) == 0 { 8120 k = n 8121 } 8122 aa = prg.vv[k] - prg.takeFraction(aa, prg.uu[k]) 8123 bb = prg.ww[k] - prg.takeFraction(bb, prg.uu[k]) 8124 if int32(k) == int32(n) { 8125 break 8126 } 8127 } // now $\theta_n=\\[aa]+\\[bb]\cdot\theta_n$ 8128 aa = prg.makeFraction(aa, 02000000000-bb) 8129 prg.theta[n] = aa 8130 prg.vv[0] = aa 8131 for ii := int32(1); ii <= int32(n)-1; ii++ { 8132 k = uint16(ii) 8133 _ = k 8134 prg.vv[k] = prg.vv[k] + prg.takeFraction(aa, prg.ww[k]) 8135 } 8136 8137 goto found 8138 } 8139 8140 case curl: 8141 // Set up equation for a curl at $\theta_n$ and |goto found| 8142 cc = *prg.mem[int32(s)+3].int() 8143 lt = abs(*prg.mem[int32(s)+4].int()) 8144 rt = abs(*prg.mem[int32(r1)+6].int()) 8145 if rt == 0200000 && lt == 0200000 { 8146 ff = prg.makeFraction(cc+cc+0200000, cc+0400000) 8147 } else { 8148 ff = prg.curlRatio(cc, lt, rt) 8149 } 8150 prg.theta[n] = -prg.makeFraction(prg.takeFraction(prg.vv[int32(n)-1], ff), 8151 02000000000-prg.takeFraction(ff, prg.uu[int32(n)-1])) 8152 8153 goto found 8154 8155 case given: 8156 // Calculate the given value of $\theta_n$ and |goto found| 8157 prg.theta[n] = *prg.mem[int32(s)+3].int() - prg.nArg(prg.deltaX[int32(n)-1], prg.deltaY[int32(n)-1]) 8158 if abs(prg.theta[n]) > 01320000000 { 8159 if prg.theta[n] > 0 { 8160 prg.theta[n] = prg.theta[n] - 02640000000 8161 } else { 8162 prg.theta[n] = prg.theta[n] + 02640000000 8163 } 8164 } 8165 8166 goto found 8167 8168 } 8169 } // there are no other cases 8170 r1 = s 8171 s = t 8172 k = uint16(int32(k) + 1) 8173 } 8174 8175 found: 8176 for ii := int32(n) - 1; ii >= 0; ii-- { 8177 k = uint16(ii) 8178 _ = k 8179 prg.theta[k] = prg.vv[k] - prg.takeFraction(prg.theta[int32(k)+1], prg.uu[k]) 8180 } 8181 s = p 8182 k = 0 8183 for { 8184 t = *(*prg.mem[s].hh()).rh() 8185 8186 prg.nSinCos(prg.theta[k]) 8187 prg.st = prg.nSin 8188 prg.ct = prg.nCos 8189 8190 prg.nSinCos(-prg.psi[int32(k)+1-1] - prg.theta[int32(k)+1]) 8191 prg.sf = prg.nSin 8192 prg.cf = prg.nCos 8193 8194 prg.setControls(s, t, int32(k)) 8195 8196 k = uint16(int32(k) + 1) 8197 s = t 8198 if int32(k) == int32(n) { 8199 break 8200 } 8201 } 8202 8203 exit: 8204 } 8205 8206 func (prg *prg) makeChoices(knots halfword) { 8207 var ( 8208 h halfword // the first breakpoint 8209 p, q halfword // consecutive breakpoints being processed 8210 8211 // Other local variables for |make_choices| 8212 k, n/* 0..pathSize */ uint16 // current and final knot numbers 8213 s, t halfword // registers for list traversal 8214 delx, dely scaled // directions where |open| meets |explicit| 8215 sine, cosine fraction // trig functions of various angles 8216 ) 8217 { 8218 if prg.arithError { 8219 prg.clearArith() 8220 } 8221 } // make sure that |arith_error=false| 8222 if prg.internal[tracingChoices-1] > 0 { 8223 prg.printPath(knots, strNumber( /* ", before choices" */ 526), true) 8224 } 8225 8226 // If consecutive knots are equal, join them explicitly 8227 p = knots 8228 for { 8229 q = *(*prg.mem[p].hh()).rh() 8230 if *prg.mem[int32(p)+1].int() == *prg.mem[int32(q)+1].int() { 8231 if *prg.mem[int32(p)+2].int() == *prg.mem[int32(q)+2].int() { 8232 if int32(*(*prg.mem[p].hh()).b1()) > explicit { 8233 *(*prg.mem[p].hh()).b1() = byte(explicit) 8234 if int32(*(*prg.mem[p].hh()).b0()) == open { 8235 *(*prg.mem[p].hh()).b0() = byte(curl) 8236 *prg.mem[int32(p)+3].int() = 0200000 8237 } 8238 *(*prg.mem[q].hh()).b0() = byte(explicit) 8239 if int32(*(*prg.mem[q].hh()).b1()) == open { 8240 *(*prg.mem[q].hh()).b1() = byte(curl) 8241 *prg.mem[int32(q)+5].int() = 0200000 8242 } 8243 *prg.mem[int32(p)+5].int() = *prg.mem[int32(p)+1].int() 8244 *prg.mem[int32(q)+3].int() = *prg.mem[int32(p)+1].int() 8245 8246 *prg.mem[int32(p)+6].int() = *prg.mem[int32(p)+2].int() 8247 *prg.mem[int32(q)+4].int() = *prg.mem[int32(p)+2].int() 8248 } 8249 } 8250 } 8251 p = q 8252 if int32(p) == int32(knots) { 8253 break 8254 } 8255 } 8256 8257 // Find the first breakpoint, |h|, on the path; insert an artificial breakpoint if the path is an unbroken cycle 8258 h = knots 8259 for true { 8260 if int32(*(*prg.mem[h].hh()).b0()) != open { 8261 goto done 8262 } 8263 if int32(*(*prg.mem[h].hh()).b1()) != open { 8264 goto done 8265 } 8266 h = *(*prg.mem[h].hh()).rh() 8267 if int32(h) == int32(knots) { 8268 *(*prg.mem[h].hh()).b0() = byte(endCycle) 8269 goto done 8270 } 8271 } 8272 8273 done: 8274 ; 8275 p = h 8276 for { 8277 // Fill in the control points between |p| and the next breakpoint, then advance |p| to that breakpoint 8278 q = *(*prg.mem[p].hh()).rh() 8279 if int32(*(*prg.mem[p].hh()).b1()) >= given { 8280 for int32(*(*prg.mem[q].hh()).b0()) == open && int32(*(*prg.mem[q].hh()).b1()) == open { 8281 q = *(*prg.mem[q].hh()).rh() 8282 } 8283 8284 // Fill in the control information between consecutive breakpoints |p| and |q| 8285 8286 // Calculate the turning angles $\psi_k$ and the distances $d_[k,k+1]$; set $n$ to the length of the path 8287 k = 0 8288 s = p 8289 n = uint16(pathSize) 8290 for { 8291 t = *(*prg.mem[s].hh()).rh() 8292 prg.deltaX[k] = *prg.mem[int32(t)+1].int() - *prg.mem[int32(s)+1].int() 8293 prg.deltaY[k] = *prg.mem[int32(t)+2].int() - *prg.mem[int32(s)+2].int() 8294 prg.delta[k] = prg.pythAdd(prg.deltaX[k], prg.deltaY[k]) 8295 if int32(k) > 0 { 8296 sine = prg.makeFraction(prg.deltaY[int32(k)-1], prg.delta[int32(k)-1]) 8297 cosine = prg.makeFraction(prg.deltaX[int32(k)-1], prg.delta[int32(k)-1]) 8298 prg.psi[k-1] = prg.nArg(prg.takeFraction(prg.deltaX[k], cosine)+prg.takeFraction(prg.deltaY[k], sine), prg.takeFraction(prg.deltaY[k], cosine)-prg.takeFraction(prg.deltaX[k], sine)) 8299 } 8300 // \xref[METAFONT capacity exceeded path size][\quad path size] 8301 k = uint16(int32(k) + 1) 8302 s = t 8303 if int32(k) == pathSize { 8304 prg.overflow(strNumber( /* "path size" */ 531), pathSize) 8305 } 8306 if int32(s) == int32(q) { 8307 n = k 8308 } 8309 if int32(k) >= int32(n) && int32(*(*prg.mem[s].hh()).b0()) != endCycle { 8310 break 8311 } 8312 } 8313 if int32(k) == int32(n) { 8314 prg.psi[n-1] = 0 8315 } else { 8316 prg.psi[k-1] = prg.psi[1-1] 8317 } 8318 8319 // Remove |open| types at the breakpoints 8320 if int32(*(*prg.mem[q].hh()).b0()) == open { 8321 delx = *prg.mem[int32(q)+5].int() - *prg.mem[int32(q)+1].int() 8322 dely = *prg.mem[int32(q)+6].int() - *prg.mem[int32(q)+2].int() 8323 if delx == 0 && dely == 0 { 8324 *(*prg.mem[q].hh()).b0() = byte(curl) 8325 *prg.mem[int32(q)+3].int() = 0200000 8326 } else { 8327 *(*prg.mem[q].hh()).b0() = byte(given) 8328 *prg.mem[int32(q)+3].int() = prg.nArg(delx, dely) 8329 } 8330 } 8331 if int32(*(*prg.mem[p].hh()).b1()) == open && int32(*(*prg.mem[p].hh()).b0()) == explicit { 8332 delx = *prg.mem[int32(p)+1].int() - *prg.mem[int32(p)+3].int() 8333 dely = *prg.mem[int32(p)+2].int() - *prg.mem[int32(p)+4].int() 8334 if delx == 0 && dely == 0 { 8335 *(*prg.mem[p].hh()).b1() = byte(curl) 8336 *prg.mem[int32(p)+5].int() = 0200000 8337 } else { 8338 *(*prg.mem[p].hh()).b1() = byte(given) 8339 *prg.mem[int32(p)+5].int() = prg.nArg(delx, dely) 8340 } 8341 } 8342 prg.solveChoices(p, q, n) 8343 } 8344 p = q 8345 if int32(p) == int32(h) { 8346 break 8347 } 8348 } 8349 if prg.internal[tracingChoices-1] > 0 { 8350 prg.printPath(knots, strNumber( /* ", after choices" */ 527), true) 8351 } 8352 if prg.arithError { 8353 { 8354 if int32(prg.interaction) == errorStopMode { 8355 } 8356 prg.printNl(strNumber( /* "! " */ 261)) 8357 prg.print( /* "Some number got too big" */ 528) /* \xref[!\relax] */ 8358 } 8359 // \xref[Some number got too big] 8360 { 8361 prg.helpPtr = 2 8362 prg.helpLine[1] = /* "The path that I just computed is out of range." */ 529 8363 prg.helpLine[0] = /* "So it will probably look funny. Proceed, for a laugh." */ 530 8364 } 8365 prg.putGetError() 8366 prg.arithError = false 8367 } 8368 } 8369 8370 // 274. 8371 8372 // tangle:pos ../../mf.web:6025:3: 8373 8374 // Before we can go further into the way choices are made, we need to 8375 // consider the underlying theory. The basic ideas implemented in |make_choices| 8376 // are due to John Hobby, who introduced the notion of ``mock curvature'' 8377 // \xref[Hobby, John Douglas] 8378 // at a knot. Angles are chosen so that they preserve mock curvature when 8379 // a knot is passed, and this has been found to produce excellent results. 8380 // 8381 // It is convenient to introduce some notations that simplify the necessary 8382 // formulas. Let $d_[k,k+1]=\vert z\k-z_k\vert$ be the (nonzero) distance 8383 // between knots |k| and |k+1|; and let 8384 // $$[z\k-z_k\over z_k-z_[k-1]]=[d_[k,k+1]\over d_[k-1,k]]e^[i\psi_k]$$ 8385 // so that a polygonal line from $z_[k-1]$ to $z_k$ to $z\k$ turns left 8386 // through an angle of~$\psi_k$. We assume that $\vert\psi_k\vert\L180^\circ$. 8387 // The control points for the spline from $z_k$ to $z\k$ will be denoted by 8388 // $$\eqalign[z_k^+&=z_k+ 8389 // \textstyle[1\over3]\rho_k e^[i\theta_k](z\k-z_k),\cr 8390 // z\k^-&=z\k- 8391 // \textstyle[1\over3]\sigma\k e^[-i\phi\k](z\k-z_k),\cr]$$ 8392 // where $\rho_k$ and $\sigma\k$ are nonnegative ``velocity ratios'' at the 8393 // beginning and end of the curve, while $\theta_k$ and $\phi\k$ are the 8394 // corresponding ``offset angles.'' These angles satisfy the condition 8395 // $$\theta_k+\phi_k+\psi_k=0,\eqno(*)$$ 8396 // whenever the curve leaves an intermediate knot~|k| in the direction that 8397 // it enters. 8398 8399 // 275. 8400 8401 // tangle:pos ../../mf.web:6050:3: 8402 8403 // Let $\alpha_k$ and $\beta\k$ be the reciprocals of the ``tension'' of 8404 // the curve at its beginning and ending points. This means that 8405 // $\rho_k=\alpha_k f(\theta_k,\phi\k)$ and $\sigma\k=\beta\k f(\phi\k,\theta_k)$, 8406 // where $f(\theta,\phi)$ is \MF's standard velocity function defined in 8407 // the |velocity| subroutine. The cubic spline $B(z_k^[\phantom+],z_k^+, 8408 // z\k^-,z\k^[\phantom+];t)$ 8409 // has curvature 8410 // \xref[curvature] 8411 // $$[2\sigma\k\sin(\theta_k+\phi\k)-6\sin\theta_k\over\rho_k^2d_[k,k+1]] 8412 // \qquad[\rm and]\qquad 8413 // [2\rho_k\sin(\theta_k+\phi\k)-6\sin\phi\k\over\sigma\k^2d_[k,k+1]]$$ 8414 // at |t=0| and |t=1|, respectively. The mock curvature is the linear 8415 // \xref[mock curvature] 8416 // approximation to this true curvature that arises in the limit for 8417 // small $\theta_k$ and~$\phi\k$, if second-order terms are discarded. 8418 // The standard velocity function satisfies 8419 // $$f(\theta,\phi)=1+O(\theta^2+\theta\phi+\phi^2);$$ 8420 // hence the mock curvatures are respectively 8421 // $$[2\beta\k(\theta_k+\phi\k)-6\theta_k\over\alpha_k^2d_[k,k+1]] 8422 // \qquad[\rm and]\qquad 8423 // [2\alpha_k(\theta_k+\phi\k)-6\phi\k\over\beta\k^2d_[k,k+1]].\eqno(**)$$ 8424 8425 // 276. 8426 8427 // tangle:pos ../../mf.web:6072:3: 8428 8429 // The turning angles $\psi_k$ are given, and equation $(*)$ above 8430 // determines $\phi_k$ when $\theta_k$ is known, so the task of 8431 // angle selection is essentially to choose appropriate values for each 8432 // $\theta_k$. When equation~$(*)$ is used to eliminate $\phi$~variables 8433 // from $(**)$, we obtain a system of linear equations of the form 8434 // $$A_k\theta_[k-1]+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$ 8435 // where 8436 // $$A_k=[\alpha_[k-1]\over\beta_k^2d_[k-1,k]], 8437 // \qquad B_k=[3-\alpha_[k-1]\over\beta_k^2d_[k-1,k]], 8438 // \qquad C_k=[3-\beta\k\over\alpha_k^2d_[k,k+1]], 8439 // \qquad D_k=[\beta\k\over\alpha_k^2d_[k,k+1]].$$ 8440 // The tensions are always $3\over4$ or more, hence each $\alpha$ and~$\beta$ 8441 // will be at most $4\over3$. It follows that $B_k\G[5\over4]A_k$ and 8442 // $C_k\G[5\over4]D_k$; hence the equations are diagonally dominant; 8443 // hence they have a unique solution. Moreover, in most cases the tensions 8444 // are equal to~1, so that $B_k=2A_k$ and $C_k=2D_k$. This makes the 8445 // solution numerically stable, and there is an exponential damping 8446 // effect: The data at knot $k\pm j$ affects the angle at knot~$k$ by 8447 // a factor of~$O(2^[-j])$. 8448 8449 // 277. 8450 8451 // tangle:pos ../../mf.web:6092:3: 8452 8453 // However, we still must consider the angles at the starting and ending 8454 // knots of a non-cyclic path. These angles might be given explicitly, or 8455 // they might be specified implicitly in terms of an amount of ``curl.'' 8456 // 8457 // Let's assume that angles need to be determined for a non-cyclic path 8458 // starting at $z_0$ and ending at~$z_n$. Then equations of the form 8459 // $$A_k\theta_[k-1]+(B_k+C_k)\theta_k+D_k\theta_[k+1]=R_k$$ 8460 // have been given for $0<k<n$, and it will be convenient to introduce 8461 // equations of the same form for $k=0$ and $k=n$, where 8462 // $$A_0=B_0=C_n=D_n=0.$$ 8463 // If $\theta_0$ is supposed to have a given value $E_0$, we simply 8464 // define $C_0=1$, $D_0=0$, and $R_0=E_0$. Otherwise a curl 8465 // parameter, $\gamma_0$, has been specified at~$z_0$; this means 8466 // that the mock curvature at $z_0$ should be $\gamma_0$ times the 8467 // mock curvature at $z_1$; i.e., 8468 // $$[2\beta_1(\theta_0+\phi_1)-6\theta_0\over\alpha_0^2d_[01]] 8469 // =\gamma_0[2\alpha_0(\theta_0+\phi_1)-6\phi_1\over\beta_1^2d_[01]].$$ 8470 // This equation simplifies to 8471 // $$(\alpha_0\chi_0+3-\beta_1)\theta_0+ 8472 // \bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\theta_1= 8473 // -\bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\psi_1,$$ 8474 // where $\chi_0=\alpha_0^2\gamma_0/\beta_1^2$; so we can set $C_0= 8475 // \chi_0\alpha_0+3-\beta_1$, $D_0=(3-\alpha_0)\chi_0+\beta_1$, $R_0=-D_0\psi_1$. 8476 // It can be shown that $C_0>0$ and $C_0B_1-A_1D_0>0$ when $\gamma_0\G0$, 8477 // hence the linear equations remain nonsingular. 8478 // 8479 // Similar considerations apply at the right end, when the final angle $\phi_n$ 8480 // may or may not need to be determined. It is convenient to let $\psi_n=0$, 8481 // hence $\theta_n=-\phi_n$. We either have an explicit equation $\theta_n=E_n$, 8482 // or we have 8483 // $$\bigl((3-\beta_n)\chi_n+\alpha_[n-1]\bigr)\theta_[n-1]+ 8484 // (\beta_n\chi_n+3-\alpha_[n-1])\theta_n=0,\qquad 8485 // \chi_n=[\beta_n^2\gamma_n\over\alpha_[n-1]^2].$$ 8486 // 8487 // When |make_choices| chooses angles, it must compute the coefficients of 8488 // these linear equations, then solve the equations. To compute the coefficients, 8489 // it is necessary to compute arctangents of the given turning angles~$\psi_k$. 8490 // When the equations are solved, the chosen directions $\theta_k$ are put 8491 // back into the form of control points by essentially computing sines and 8492 // cosines. 8493 8494 // 303. \[19] Generating discrete moves 8495 8496 // tangle:pos ../../mf.web:6573:36: 8497 8498 // The purpose of the next part of \MF\ is to compute discrete approximations 8499 // to curves described as parametric polynomial functions $z(t)$. 8500 // We shall start with the low level first, because an efficient ``engine'' 8501 // is needed to support the high-level constructions. 8502 // 8503 // Most of the subroutines are based on variations of a single theme, 8504 // namely the idea of [\sl bisection]. Given a Bernshte[\u\i]n polynomial 8505 // \xref[Bernshte[\u\i]n, Serge[\u\i] Natanovich] 8506 // $$B(z_0,z_1,\ldots,z_n;t)=\sum_k[n\choose k]t^k(1-t)^[n-k]z_k,$$ 8507 // we can conveniently bisect its range as follows: 8508 // 8509 // \smallskip 8510 // \textindent[1)] Let $z_k^[(0)]=z_k$, for |0<=k<=n|. 8511 // 8512 // \smallskip 8513 // \textindent[2)] Let $z_k^[(j+1)]=[1\over2](z_k^[(j)]+z\k^[(j)])$, for 8514 // |0<=k<n-j|, for |0<=j<n|. 8515 // 8516 // \smallskip\noindent 8517 // Then 8518 // $$B(z_0,z_1,\ldots,z_n;t)=B(z_0^[(0)],z_0^[(1)],\ldots,z_0^[(n)];2t) 8519 // =B(z_0^[(n)],z_1^[(n-1)],\ldots,z_n^[(0)];2t-1).$$ 8520 // This formula gives us the coefficients of polynomials to use over the ranges 8521 // $0\L t\L[1\over2]$ and $[1\over2]\L t\L1$. 8522 // 8523 // In our applications it will usually be possible to work indirectly with 8524 // numbers that allow us to deduce relevant properties of the polynomials 8525 // without actually computing the polynomial values. We will deal with 8526 // coefficients $Z_k=2^l(z_k-z_[k-1])$ for |1<=k<=n|, instead of 8527 // the actual numbers $z_0$, $z_1$, \dots,~$z_n$, and the value of~|l| will 8528 // increase by~1 at each bisection step. This technique reduces the 8529 // amount of calculation needed for bisection and also increases the 8530 // accuracy of evaluation (since one bit of precision is gained at each 8531 // bisection). Indeed, the bisection process now becomes one level shorter: 8532 // 8533 // \smallskip 8534 // \textindent[$1'$)] Let $Z_k^[(1)]=Z_k$, for |1<=k<=n|. 8535 // 8536 // \smallskip 8537 // \textindent[$2'$)] Let $Z_k^[(j+1)]=[1\over2](Z_k^[(j)]+Z\k^[(j)])$, for 8538 // |1<=k<=n-j|, for |1<=j<n|. 8539 // 8540 // \smallskip\noindent 8541 // The relevant coefficients $(Z'_1,\ldots,Z'_n)$ and $(Z''_1,\ldots,Z''_n)$ 8542 // for the two subintervals after bisection are respectively 8543 // $(Z_1^[(1)],Z_1^[(2)],\ldots,Z_1^[(n)])$ and 8544 // $(Z_1^[(n)],Z_2^[(n-1)],\ldots,Z_n^[(1)])$. 8545 // And the values of $z_0$ appropriate for the bisected interval are $z'_0=z_0$ 8546 // and $z''_0=z_0+(Z'_1+Z'_2+\cdots+Z'_n)/2^[l+1]$. 8547 // 8548 // Step $2'$ involves division by~2, which introduces computational errors 8549 // of at most $1\over2$ at each step; thus after $l$~levels of bisection the 8550 // integers $Z_k$ will differ from their true values by at most $(n-1)l/2$. 8551 // This error rate is quite acceptable, considering that we have $l$~more 8552 // bits of precision in the $Z$'s by comparison with the~$z$'s. Note also 8553 // that the $Z$'s remain bounded; there's no danger of integer overflow, even 8554 // though we have the identity $Z_k=2^l(z_k-z_[k-1])$ for arbitrarily large~$l$. 8555 // 8556 // In fact, we can show not only that the $Z$'s remain bounded, but also that 8557 // they become nearly equal, since they are control points for a polynomial 8558 // of one less degree. If $\vert Z\k-Z_k\vert\L M$ initially, it is possible 8559 // to prove that $\vert Z\k-Z_k\vert\L\lceil M/2^l\rceil$ after $l$~levels 8560 // of bisection, even in the presence of rounding errors. Here's the 8561 // proof [cf.~Lane and Riesenfeld, [\sl IEEE Trans.\ on Pattern Analysis 8562 // \xref[Lane, Jeffrey Michael] 8563 // \xref[Riesenfeld, Richard Franklin] 8564 // and Machine Intelligence\/ \bf PAMI-2] (1980), 35--46]: Assuming that 8565 // $\vert Z\k-Z_k\vert\L M$ before bisection, we want to prove that 8566 // $\vert Z\k-Z_k\vert\L\lceil M/2\rceil$ afterward. First we show that 8567 // $\vert Z\k^[(j)]-Z_k^[(j)]\vert\L M$ for all $j$ and~$k$, by induction 8568 // on~$j$; this follows from the fact that 8569 // $$\bigl\vert\\[half](a+b)-\\[half](b+c)\bigr\vert\L 8570 // \max\bigl(\vert a-b\vert,\vert b-c\vert\bigr)$$ 8571 // holds for both of the rounding rules $\\[half](x)=\lfloor x/2\rfloor$ 8572 // and $\\[half](x)=[\rm sign](x)\lfloor\vert x/2\vert\rfloor$. 8573 // (If $\vert a-b\vert$ and $\vert b-c\vert$ are equal, then 8574 // $a+b$ and $b+c$ are both even or both odd. The rounding errors either 8575 // cancel or round the numbers toward each other; hence 8576 // $$\eqalign[\bigl\vert\\[half](a+b)-\\[half](b+c)\bigr\vert 8577 // &\L\textstyle\bigl\vert[1\over2](a+b)-[1\over2](b+c)\bigr\vert\cr 8578 // &=\textstyle\bigl\vert[1\over2](a-b)+[1\over2](b-c)\bigr\vert 8579 // \L\max\bigl(\vert a-b\vert,\vert b-c\vert\bigr),\cr]$$ 8580 // as required. A simpler argument applies if $\vert a-b\vert$ and 8581 // $\vert b-c\vert$ are unequal.) Now it is easy to see that 8582 // $\vert Z_1^[(j+1)]-Z_1^[(j)]\vert\L\bigl\lfloor[1\over2] 8583 // \vert Z_2^[(j)]-Z_1^[(j)]\vert+[1\over2]\bigr\rfloor 8584 // \L\bigl\lfloor[1\over2](M+1)\bigr\rfloor=\lceil M/2\rceil$. 8585 // 8586 // Another interesting fact about bisection is the identity 8587 // $$Z_1'+\cdots+Z_n'+Z_1''+\cdots+Z_n''=2(Z_1+\cdots+Z_n+E),$$ 8588 // where $E$ is the sum of the rounding errors in all of the halving 8589 // operations ($\vert E\vert\L n(n-1)/4$). 8590 8591 // 304. 8592 8593 // tangle:pos ../../mf.web:6667:3: 8594 8595 // We will later reduce the problem of digitizing a complex cubic 8596 // $z(t)=B(z_0,z_1,z_2,z_3;t)$ to the following simpler problem: 8597 // Given two real cubics 8598 // $x(t)=B(x_0,x_1,x_2,x_3;t)$ 8599 // and $y(t)=B(y_0,y_1,y_2,y_3;t)$ that are monotone nondecreasing, 8600 // determine the set of integer points 8601 // $$P=\bigl\[\bigl(\lfloor x(t)\rfloor,\lfloor y(t)\rfloor\bigr) 8602 // \bigm\vert 0\L t\L 1\bigr\].$$ 8603 // Well, the problem isn't actually quite so clean as this; when the path 8604 // goes very near an integer point $(a,b)$, computational errors may 8605 // make us think that $P$ contains $(a-1,b)$ while in reality it should 8606 // contain $(a,b-1)$. Furthermore, if the path goes [\sl exactly\/] 8607 // through the integer points $(a-1,b-1)$ and 8608 // $(a,b)$, we will want $P$ to contain one 8609 // of the two points $(a-1,b)$ or $(a,b-1)$, so that $P$ can be described 8610 // entirely by ``rook moves'' upwards or to the right; no diagonal 8611 // moves from $(a-1,b-1)$ to~$(a,b)$ will be allowed. 8612 // 8613 // Thus, the set $P$ we wish to compute will merely be an approximation 8614 // to the set described in the formula above. It will consist of 8615 // $\lfloor x(1)\rfloor-\lfloor x(0)\rfloor$ rightward moves and 8616 // $\lfloor y(1)\rfloor-\lfloor y(0)\rfloor$ upward moves, intermixed 8617 // in some order. Our job will be to figure out a suitable order. 8618 // 8619 // The following recursive strategy suggests itself, when we recall that 8620 // $x(0)=x_0$, $x(1)=x_3$, $y(0)=y_0$, and $y(1)=y_3$: 8621 // 8622 // \smallskip 8623 // If $\lfloor x_0\rfloor=\lfloor x_3\rfloor$ then take 8624 // $\lfloor y_3\rfloor-\lfloor y_0\rfloor$ steps up. 8625 // 8626 // Otherwise if $\lfloor y_0\rfloor=\lfloor y_3\rfloor$ then take 8627 // $\lfloor x_3\rfloor-\lfloor x_0\rfloor$ steps to the right. 8628 // 8629 // Otherwise bisect the current cubics and repeat the process on both halves. 8630 // 8631 // \yskip\noindent 8632 // This intuitively appealing formulation does not quite solve the problem, 8633 // because it may never terminate. For example, it's not hard to see that 8634 // no steps will [\sl ever\/] be taken if $(x_0,x_1,x_2,x_3)=(y_0,y_1,y_2,y_3)$! 8635 // However, we can surmount this difficulty with a bit of care; so let's 8636 // proceed to flesh out the algorithm as stated, before worrying about 8637 // such details. 8638 // 8639 // The bisect-and-double strategy discussed above suggests that we represent 8640 // $(x_0,x_1,x_2,x_3)$ by $(X_1,X_2,X_3)$, where $X_k=2^l(x_k-x_[k-1])$ 8641 // for some~$l$. Initially $l=16$, since the $x$'s are |scaled|. 8642 // In order to deal with other aspects of the algorithm we will want to 8643 // maintain also the quantities $m=\lfloor x_3\rfloor-\lfloor x_0\rfloor$ 8644 // and $R=2^l(x_0\bmod 1)$. Similarly, 8645 // $(y_0,y_1,y_2,y_3)$ will be represented by $(Y_1,Y_2,Y_3)$, 8646 // $n=\lfloor y_3\rfloor-\lfloor y_0\rfloor$, 8647 // and $S=2^l(y_0\bmod 1)$. The algorithm now takes the following form: 8648 // 8649 // \smallskip 8650 // If $m=0$ then take $n$ steps up. 8651 // 8652 // Otherwise if $n=0$ then take $m$ steps to the right. 8653 // 8654 // Otherwise bisect the current cubics and repeat the process on both halves. 8655 // 8656 // \smallskip\noindent 8657 // The bisection process for $(X_1,X_2,X_3,m,R,l)$ reduces, in essence, 8658 // to the following formulas: 8659 // $$\vbox[\halign[$#\hfil$\cr 8660 // X_2'=\\[half](X_1+X_2),\quad 8661 // X_2''=\\[half](X_2+X_3),\quad 8662 // X_3'=\\[half](X_2'+X_2''),\cr 8663 // X_1'=X_1,\quad 8664 // X_1''=X_3',\quad 8665 // X_3''=X_3,\cr 8666 // R'=2R,\quad 8667 // T=X_1'+X_2'+X_3'+R',\quad 8668 // R''=T\bmod 2^[l+1],\cr 8669 // m'=\lfloor T/2^[l+1]\rfloor,\quad 8670 // m''=m-m'.\cr]]$$ 8671 8672 // 305. 8673 8674 // tangle:pos ../../mf.web:6744:3: 8675 8676 // When $m=n=1$, the computation can be speeded up because we simply 8677 // need to decide between two alternatives, (up,\thinspace right) 8678 // versus (right,\thinspace up). There appears to be no simple, direct 8679 // way to make the correct decision by looking at the values of 8680 // $(X_1,X_2,X_3,R)$ and 8681 // $(Y_1,Y_2,Y_3,S)$; but we can streamline the bisection process, and 8682 // we can use the fact that only one of the two descendants needs to 8683 // be examined after each bisection. Furthermore, we observed earlier 8684 // that after several levels of bisection the $X$'s and $Y$'s will be nearly 8685 // equal; so we will be justified in assuming that the curve is essentially a 8686 // straight line. (This, incidentally, solves the problem of infinite 8687 // recursion mentioned earlier.) 8688 // 8689 // It is possible to show that 8690 // $$m=\bigl\lfloor(X_1+X_2+X_3+R+E)\,/\,2^l\bigr\rfloor,$$ 8691 // where $E$ is an accumulated rounding error that is at most 8692 // $3\cdot(2^[l-16]-1)$ in absolute value. We will make sure that 8693 // the $X$'s are less than $2^[28]$; hence when $l=30$ we must 8694 // have |m<=1|. This proves that the special case $m=n=1$ is 8695 // bound to be reached by the time $l=30$. Furthermore $l=30$ is 8696 // a suitable time to make the straight line approximation, 8697 // if the recursion hasn't already died out, because the maximum 8698 // difference between $X$'s will then be $<2^[14]$; this corresponds 8699 // to an error of $<1$ with respect to the original scaling. 8700 // (Stating this another way, each bisection makes the curve two bits 8701 // closer to a straight line, hence 14 bisections are sufficient for 8702 // 28-bit accuracy.) 8703 // 8704 // In the case of a straight line, the curve goes first right, then up, 8705 // if and only if $(T-2^l)(2^l-S)>(U-2^l)(2^l-R)$, where 8706 // $T=X_1+X_2+X_3+R$ and $U=Y_1+Y_2+Y_3+S$. For the actual curve 8707 // essentially runs from $(R/2^l,S/2^l)$ to $(T/2^l,U/2^l)$, and 8708 // we are testing whether or not $(1,1)$ is above the straight 8709 // line connecting these two points. (This formula assumes that $(1,1)$ 8710 // is not exactly on the line.) 8711 8712 // 306. 8713 8714 // tangle:pos ../../mf.web:6780:3: 8715 8716 // We have glossed over the problem of tie-breaking in ambiguous 8717 // cases when the cubic curve passes exactly through integer points. 8718 // \MF\ finesses this problem by assuming that coordinates 8719 // $(x,y)$ actually stand for slightly perturbed values $(x+\xi,y+\eta)$, 8720 // where $\xi$ and~$\eta$ are infinitesimals whose signs will determine 8721 // what to do when $x$ and/or~$y$ are exact integers. The quantities 8722 // $\lfloor x\rfloor$ and~$\lfloor y\rfloor$ in the formulas above 8723 // should actually read $\lfloor x+\xi\rfloor$ and $\lfloor y+\eta\rfloor$. 8724 // 8725 // If $x$ is a |scaled| value, we have $\lfloor x+\xi\rfloor=\lfloor x\rfloor$ 8726 // if $\xi>0$, and $\lfloor x+\xi\rfloor=\lfloor x-2^[-16]\rfloor$ if 8727 // $\xi<0$. It is convenient to represent $\xi$ by the integer |xi_corr|, 8728 // defined to be 0~if $\xi>0$ and 1~if $\xi<0$; then, for example, the 8729 // integer $\lfloor x+\xi\rfloor$ can be computed as 8730 // |floor_unscaled(x-xi_corr)|. Similarly, $\eta$ is conveniently 8731 // represented by~|eta_corr|. 8732 // 8733 // In our applications the sign of $\xi-\eta$ will always be the same as 8734 // the sign of $\xi$. Therefore it turns out that the rule for straight 8735 // lines, as stated above, should be modified as follows in the case of 8736 // ties: The line goes first right, then up, if and only if 8737 // $(T-2^l)(2^l-S)+\xi>(U-2^l)(2^l-R)$. And this relation holds iff 8738 // $|ab_vs_cd|(T-2^l,2^l-S,U-2^l,2^l-R)-|xi_corr|\ge0$. 8739 // 8740 // These conventions for rounding are symmetrical, in the sense that the 8741 // digitized moves obtained from $(x_0,x_1,x_2,x_3,y_0,y_1,y_2,y_3,\xi,\eta)$ 8742 // will be exactly complementary to the moves that would be obtained from 8743 // $(-x_3,-x_2,-x_1,-x_0,-y_3,-y_2,-y_1,-y_0,-\xi,-\eta)$, if arithmetic 8744 // is exact. However, truncation errors in the bisection process might 8745 // upset the symmetry. We can restore much of the lost symmetry by adding 8746 // |xi_corr| or |eta_corr| when halving the data. 8747 8748 // 307. 8749 8750 // tangle:pos ../../mf.web:6812:3: 8751 8752 // One further possibility needs to be mentioned: The algorithm 8753 // will be applied only to cubic polynomials $B(x_0,x_1,x_2,x_3;t)$ that 8754 // are nondecreasing as $t$~varies from 0 to~1; this condition turns 8755 // out to hold if and only if $x_0\L x_1$ and $x_2\L x_3$, and either 8756 // $x_1\L x_2$ or $(x_1-x_2)^2\L(x_1-x_0)(x_3-x_2)$. If bisection were 8757 // carried out with perfect accuracy, these relations would remain 8758 // invariant. But rounding errors can creep in, hence the bisection 8759 // algorithm can produce non-monotonic subproblems from monotonic 8760 // initial conditions. This leads to the potential danger that $m$ or~$n$ 8761 // could become negative in the algorithm described above. 8762 // 8763 // For example, if we start with $(x_1-x_0,x_2-x_1,x_3-x_2)= 8764 // (X_1,X_2,X_3)=(7,-16,39)$, the corresponding polynomial is 8765 // monotonic, because $16^2<7\cdot39$. But the bisection algorithm 8766 // produces the left descendant $(7,-5,3)$, which is nonmonotonic; 8767 // its right descendant is~$(0,-1,3)$. 8768 // 8769 // \def\xt[[\tilde x]] 8770 // Fortunately we can prove that such rounding errors will never cause 8771 // the algorithm to make a tragic mistake. At every stage we are working 8772 // with numbers corresponding to a cubic polynomial $B(\xt_0, 8773 // \xt_1,\xt_2,\xt_3)$ that approximates some 8774 // monotonic polynomial $B(x_0,x_1,x_2,x_3)$. The accumulated errors are 8775 // controlled so that $\vert x_k-\xt_k\vert<\epsilon=3\cdot2^[-16]$. 8776 // If bisection is done at some stage of the recursion, we have 8777 // $m=\lfloor\xt_3\rfloor-\lfloor\xt_0\rfloor>0$, and the algorithm 8778 // computes a bisection value $\bar x$ such that $m'=\lfloor\bar x\rfloor- 8779 // \lfloor\xt_0\rfloor$ 8780 // and $m''=\lfloor\xt_3\rfloor-\lfloor\bar x\rfloor$. We want to prove 8781 // that neither $m'$ nor $m''$ can be negative. Since $\bar x$ is an 8782 // approximation to a value in the interval $[x_0,x_3]$, we have 8783 // $\bar x>x_0-\epsilon$ and $\bar x<x_3+\epsilon$, hence $\bar x> 8784 // \xt_0-2\epsilon$ and $\bar x<\xt_3+2\epsilon$. 8785 // If $m'$ is negative we must have $\xt_0\bmod 1<2\epsilon$; 8786 // if $m''$ is negative we must have $\xt_3\bmod 1>1-2\epsilon$. 8787 // In either case the condition $\lfloor\xt_3\rfloor-\lfloor\xt_0\rfloor>0$ 8788 // implies that $\xt_3-\xt_0>1-2\epsilon$, hence $x_3-x_0>1-4\epsilon$. 8789 // But it can be shown that if $B(x_0,x_1,x_2,x_3;t)$ is a monotonic 8790 // cubic, then $B(x_0,x_1,x_2,x_3;[1\over2])$ is always between 8791 // $.06[x_0,x_3]$ and $.94[x_0,x_3]$; and it is impossible for $\bar x$ 8792 // to be within~$\epsilon$ of such a number. Contradiction! 8793 // (The constant .06 is actually $(2-\sqrt3\,)/4$; the worst case 8794 // occurs for polynomials like $B(0,2-\sqrt3,1-\sqrt3,3;t)$.) 8795 8796 // 311. 8797 8798 // tangle:pos ../../mf.web:6907:3: 8799 8800 // The |make_moves| subroutine is given |scaled| values $(x_0,x_1,x_2,x_3)$ 8801 // and $(y_0,y_1,y_2,y_3)$ that represent monotone-nondecreasing polynomials; 8802 // it makes $\lfloor x_3+\xi\rfloor-\lfloor x_0+\xi\rfloor$ rightward moves 8803 // and $\lfloor y_3+\eta\rfloor-\lfloor y_0+\eta\rfloor$ upward moves, as 8804 // explained earlier. (Here $\lfloor x+\xi\rfloor$ actually stands for 8805 // $\lfloor x/2^[16]-|xi_corr|\rfloor$, if $x$ is regarded as an integer 8806 // without scaling.) The unscaled integers $x_k$ and~$y_k$ should be less 8807 // than $2^[28]$ in magnitude. 8808 // 8809 // It is assumed that $|move_ptr| + \lfloor y_3+\eta\rfloor - 8810 // \lfloor y_0+\eta\rfloor < |move_size|$ when this procedure is called, 8811 // so that the capacity of the |move| array will not be exceeded. 8812 // 8813 // The variables |r| and |s| in this procedure stand respectively for 8814 // $R-|xi_corr|$ and $S-|eta_corr|$ in the theory discussed above. 8815 func (prg *prg) makeMoves(xx0, xx1, xx2, xx3, yy0, yy1, yy2, yy3 scaled, xiCorr, etaCorr smallNumber) { 8816 var ( 8817 x1, x2, x3, m, r1, y1, y2, y3, n, s, l int32 8818 // bisection variables explained above 8819 q, t, u, x2a, x3a, y2a, y3a int32 // additional temporary registers 8820 ) 8821 if xx3 < xx0 || yy3 < yy0 { 8822 prg.confusion(strNumber('m')) 8823 } 8824 // \xref[this can't happen m][\quad m] 8825 l = 16 8826 prg.bisectPtr = 0 8827 8828 x1 = xx1 - xx0 8829 x2 = xx2 - xx1 8830 x3 = xx3 - xx2 8831 if xx0 >= int32(xiCorr) { 8832 r1 = (xx0 - int32(xiCorr)) % 0200000 8833 } else { 8834 r1 = 0200000 - 1 - (-xx0+int32(xiCorr)-1)%0200000 8835 } 8836 m = (xx3 - xx0 + r1) / 0200000 8837 8838 y1 = yy1 - yy0 8839 y2 = yy2 - yy1 8840 y3 = yy3 - yy2 8841 if yy0 >= int32(etaCorr) { 8842 s = (yy0 - int32(etaCorr)) % 0200000 8843 } else { 8844 s = 0200000 - 1 - (-yy0+int32(etaCorr)-1)%0200000 8845 } 8846 n = (yy3 - yy0 + s) / 0200000 8847 8848 if xx3-xx0 >= 02000000000 || yy3-yy0 >= 02000000000 { 8849 x1 = (x1 + int32(xiCorr)) / 2 8850 x2 = (x2 + int32(xiCorr)) / 2 8851 x3 = (x3 + int32(xiCorr)) / 2 8852 r1 = (r1 + int32(xiCorr)) / 2 8853 8854 y1 = (y1 + int32(etaCorr)) / 2 8855 y2 = (y2 + int32(etaCorr)) / 2 8856 y3 = (y3 + int32(etaCorr)) / 2 8857 s = (s + int32(etaCorr)) / 2 8858 8859 l = 15 8860 } 8861 for true { 8862 continue1: 8863 if m == 0 { 8864 for n > 0 { 8865 prg.movePtr = uint16(int32(prg.movePtr) + 1) 8866 prg.move[prg.movePtr] = 1 8867 n = n - 1 8868 } 8869 } else if n == 0 { 8870 prg.move[prg.movePtr] = prg.move[prg.movePtr] + m 8871 } else if m+n == 2 { 8872 r1 = prg.twoToThe[l] - r1 8873 s = prg.twoToThe[l] - s 8874 8875 for l < 30 { 8876 x3a = x3 8877 x2a = (x2 + x3 + int32(xiCorr)) / 2 8878 x2 = (x1 + x2 + int32(xiCorr)) / 2 8879 x3 = (x2 + x2a + int32(xiCorr)) / 2 8880 t = x1 + x2 + x3 8881 r1 = r1 + r1 - int32(xiCorr) 8882 8883 y3a = y3 8884 y2a = (y2 + y3 + int32(etaCorr)) / 2 8885 y2 = (y1 + y2 + int32(etaCorr)) / 2 8886 y3 = (y2 + y2a + int32(etaCorr)) / 2 8887 u = y1 + y2 + y3 8888 s = s + s - int32(etaCorr) 8889 8890 if t < r1 { 8891 if u < s { 8892 x1 = x3 8893 x2 = x2a 8894 x3 = x3a 8895 r1 = r1 - t 8896 y1 = y3 8897 y2 = y2a 8898 y3 = y3a 8899 s = s - u 8900 } else { 8901 { 8902 prg.movePtr = uint16(int32(prg.movePtr) + 1) 8903 prg.move[prg.movePtr] = 2 8904 } 8905 goto done 8906 } 8907 } else if u < s { 8908 { 8909 prg.move[prg.movePtr] = prg.move[prg.movePtr] + 1 8910 prg.movePtr = uint16(int32(prg.movePtr) + 1) 8911 prg.move[prg.movePtr] = 1 8912 } 8913 goto done 8914 } 8915 l = l + 1 8916 } 8917 r1 = r1 - int32(xiCorr) 8918 s = s - int32(etaCorr) 8919 if prg.abVsCd(x1+x2+x3, s, y1+y2+y3, r1)-int32(xiCorr) >= 0 { 8920 prg.move[prg.movePtr] = prg.move[prg.movePtr] + 1 8921 prg.movePtr = uint16(int32(prg.movePtr) + 1) 8922 prg.move[prg.movePtr] = 1 8923 } else { 8924 // Move up then right 8925 prg.movePtr = uint16(int32(prg.movePtr) + 1) 8926 prg.move[prg.movePtr] = 2 8927 } 8928 8929 done: 8930 } else { 8931 l = l + 1 8932 prg.bisectStack[int32(prg.bisectPtr)+10] = l 8933 8934 prg.bisectStack[int32(prg.bisectPtr)+2] = x3 8935 prg.bisectStack[int32(prg.bisectPtr)+1] = (x2 + x3 + int32(xiCorr)) / 2 8936 x2 = (x1 + x2 + int32(xiCorr)) / 2 8937 x3 = (x2 + prg.bisectStack[int32(prg.bisectPtr)+1] + int32(xiCorr)) / 2 8938 prg.bisectStack[prg.bisectPtr] = x3 8939 8940 r1 = r1 + r1 + int32(xiCorr) 8941 t = x1 + x2 + x3 + r1 8942 8943 q = t / prg.twoToThe[l] 8944 prg.bisectStack[int32(prg.bisectPtr)+3] = t % prg.twoToThe[l] 8945 8946 prg.bisectStack[int32(prg.bisectPtr)+4] = m - q 8947 m = q 8948 8949 prg.bisectStack[int32(prg.bisectPtr)+7] = y3 8950 prg.bisectStack[int32(prg.bisectPtr)+6] = (y2 + y3 + int32(etaCorr)) / 2 8951 y2 = (y1 + y2 + int32(etaCorr)) / 2 8952 y3 = (y2 + prg.bisectStack[int32(prg.bisectPtr)+6] + int32(etaCorr)) / 2 8953 prg.bisectStack[int32(prg.bisectPtr)+5] = y3 8954 8955 s = s + s + int32(etaCorr) 8956 u = y1 + y2 + y3 + s 8957 8958 q = u / prg.twoToThe[l] 8959 prg.bisectStack[int32(prg.bisectPtr)+8] = u % prg.twoToThe[l] 8960 8961 prg.bisectStack[int32(prg.bisectPtr)+9] = n - q 8962 n = q 8963 8964 prg.bisectPtr = uint16(int32(prg.bisectPtr) + moveIncrement) 8965 goto continue1 8966 } 8967 if int32(prg.bisectPtr) == 0 { 8968 goto exit 8969 } 8970 8971 // Remove a subproblem for |make_moves| from the stack 8972 prg.bisectPtr = uint16(int32(prg.bisectPtr) - moveIncrement) 8973 8974 x1 = prg.bisectStack[prg.bisectPtr] 8975 x2 = prg.bisectStack[int32(prg.bisectPtr)+1] 8976 x3 = prg.bisectStack[int32(prg.bisectPtr)+2] 8977 r1 = prg.bisectStack[int32(prg.bisectPtr)+3] 8978 m = prg.bisectStack[int32(prg.bisectPtr)+4] 8979 8980 y1 = prg.bisectStack[int32(prg.bisectPtr)+5] 8981 y2 = prg.bisectStack[int32(prg.bisectPtr)+6] 8982 y3 = prg.bisectStack[int32(prg.bisectPtr)+7] 8983 s = prg.bisectStack[int32(prg.bisectPtr)+8] 8984 n = prg.bisectStack[int32(prg.bisectPtr)+9] 8985 8986 l = prg.bisectStack[int32(prg.bisectPtr)+10] 8987 } 8988 8989 exit: 8990 } 8991 8992 // 321. 8993 8994 // tangle:pos ../../mf.web:7034:3: 8995 8996 // After |make_moves| has acted, possibly for several curves that move toward 8997 // the same octant, a ``smoothing'' operation might be done on the |move| array. 8998 // This removes optical glitches that can arise even when the curve has been 8999 // digitized without rounding errors. 9000 // 9001 // The smoothing process replaces the integers $a_0\ldots a_n$ in 9002 // |move[b..t]| by ``smoothed'' integers $a_0'\ldots a_n'$ defined as 9003 // follows: 9004 // $$a_k'=a_k+\delta\k-\delta_k;\qquad 9005 // \delta_k=\cases[+1,&if $1<k<n$ and $a_[k-2]\G a_[k-1]\ll a_k\G a\k$;\cr 9006 // -1,&if $1<k<n$ and $a_[k-2]\L a_[k-1]\gg a_k\L a\k$;\cr 9007 // 0,&otherwise.\cr]$$ 9008 // Here $a\ll b$ means that $a\L b-2$, and $a\gg b$ means that $a\G b+2$. 9009 // 9010 // The smoothing operation is symmetric in the sense that, if $a_0\ldots a_n$ 9011 // smooths to $a_0'\ldots a_n'$, then the reverse sequence $a_n\ldots a_0$ 9012 // smooths to $a_n'\ldots a_0'$; also the complementary sequence 9013 // $(m-a_0)\ldots(m-a_n)$ smooths to $(m-a_0')\ldots(m-a_n')$. 9014 // We have $a_0'+\cdots+a_n'=a_0+\cdots+a_n$ because $\delta_0=\delta_[n+1]=0$. 9015 func (prg *prg) smoothMoves(b, t int32) { 9016 var ( 9017 k/* 1..moveSize */ uint16 // index into |move| 9018 a, aa, aaa int32 // original values of |move[k],move[k-1],move[k-2]| 9019 ) 9020 if t-b >= 3 { 9021 k = uint16(b + 2) 9022 aa = prg.move[int32(k)-1] 9023 aaa = prg.move[int32(k)-2] 9024 for { 9025 a = prg.move[k] 9026 if abs(a-aa) > 1 { 9027 if a > aa { 9028 if aaa >= aa { 9029 if a >= prg.move[int32(k)+1] { 9030 prg.move[int32(k)-1] = prg.move[int32(k)-1] + 1 9031 prg.move[k] = a - 1 9032 } 9033 } 9034 } else { 9035 if aaa <= aa { 9036 if a <= prg.move[int32(k)+1] { 9037 prg.move[int32(k)-1] = prg.move[int32(k)-1] - 1 9038 prg.move[k] = a + 1 9039 } 9040 } 9041 } 9042 } 9043 k = uint16(int32(k) + 1) 9044 aaa = aa 9045 aa = a 9046 if int32(k) == t { 9047 break 9048 } 9049 } 9050 } 9051 } 9052 9053 // 323. \[20] Edge structures 9054 9055 // tangle:pos ../../mf.web:7078:26: 9056 9057 // Now we come to \MF's internal scheme for representing what the user can 9058 // actually ``see,'' the edges between pixels. Each pixel has an integer 9059 // weight, obtained by summing the weights on all edges to its left. \MF\ 9060 // represents only the nonzero edge weights, since most of the edges are 9061 // weightless; in this way, the data storage requirements grow only linearly 9062 // with respect to the number of pixels per point, even though two-dimensional 9063 // data is being represented. (Well, the actual dependence on the underlying 9064 // resolution is order $n\log n$, but the $\log n$ factor is buried in our 9065 // implicit restriction on the maximum raster size.) The sum of all edge 9066 // weights in each row should be zero. 9067 // 9068 // The data structure for edge weights must be compact and flexible, 9069 // yet it should support efficient updating and display operations. We 9070 // want to be able to have many different edge structures in memory at 9071 // once, and we want the computer to be able to translate them, reflect them, 9072 // and/or merge them together with relative ease. 9073 // 9074 // \MF's solution to this problem requires one single-word node per 9075 // nonzero edge weight, plus one two-word node for each row in a contiguous 9076 // set of rows. There's also a header node that provides global information 9077 // about the entire structure. 9078 9079 // 325. 9080 9081 // tangle:pos ../../mf.web:7144:3: 9082 9083 // The rows themselves are represented by row header nodes that 9084 // contain four link fields. Two of these four, |sorted| and |unsorted|, 9085 // point to the first items of the edge-weight lists just mentioned. 9086 // The other two, |link| and |knil|, point to the headers of the two 9087 // adjacent rows. If |p| points to the header for row number~|n|, then 9088 // |link(p)| points up to the header for row~|n+1|, and |knil(p)| points 9089 // down to the header for row~|n-1|. This double linking makes it 9090 // convenient to move through consecutive rows either upward or downward; 9091 // as usual, we have |link(knil(p))=knil(link(p))=p| for all row headers~|p|. 9092 // 9093 // The row associated with a given value of |n| contains weights for 9094 // edges that run between the lattice points |(m,n)| and |(m,n+1)|. 9095 9096 // 326. 9097 9098 // tangle:pos ../../mf.web:7163:3: 9099 9100 // The main header node |h| for an edge structure has |link| and |knil| 9101 // fields that link it above the topmost row and below the bottommost row. 9102 // It also has fields called |m_min|, |m_max|, |n_min|, and |n_max| that 9103 // bound the current extent of the edge data: All |m| values in edge-weight 9104 // nodes should lie between |m_min(h)-4096| and |m_max(h)-4096|, inclusive. 9105 // Furthermore the topmost row header, pointed to by |knil(h)|, 9106 // is for row number |n_max(h)-4096|; the bottommost row header, pointed to by 9107 // |link(h)|, is for row number |n_min(h)-4096|. 9108 // 9109 // The offset constant |c| that's used in all of the edge-weight data is 9110 // represented implicitly in |m_offset(h)|; its actual value is 9111 // $$\hbox[|c=min_halfword+zero_w+8*m_offset(h)|.]$$ 9112 // Notice that it's possible to shift an entire edge structure by an 9113 // amount $(\Delta m,\Delta n)$ by adding $\Delta n$ to |n_min(h)| and |n_max(h)|, 9114 // adding $\Delta m$ to |m_min(h)| and |m_max(h)|, and subtracting 9115 // $\Delta m$ from |m_offset(h)|; 9116 // none of the other edge data needs to be modified. Initially the |m_offset| 9117 // field is~4096, but it will change if the user requests such a shift. 9118 // The contents of these five fields should always be positive and less than 9119 // 8192; |n_max| should, in fact, be less than 8191. Furthermore 9120 // |m_min+m_offset-4096| and |m_max+m_offset-4096| must also lie strictly 9121 // between 0 and 8192, so that the |info| fields of edge-weight nodes will 9122 // fit in a halfword. 9123 // 9124 // The header node of an edge structure also contains two somewhat unusual 9125 // fields that are called |last_window(h)| and |last_window_time(h)|. When this 9126 // structure is displayed in window~|k| of the user's screen, after that 9127 // window has been updated |t| times, \MF\ sets |last_window(h):=k| and 9128 // |last_window_time(h):=t|; it also sets |unsorted(p):=void| for all row 9129 // headers~|p|, after merging any existing unsorted weights with the sorted 9130 // ones. A subsequent display in the same window will be able to avoid 9131 // redisplaying rows whose |unsorted| list is still |void|, if the window 9132 // hasn't been used for something else in the meantime. 9133 // 9134 // A pointer to the row header of row |n_pos(h)-4096| is provided in 9135 // |n_rover(h)|. Most of the algorithms that update an edge structure 9136 // are able to get by without random row references; they usually 9137 // access rows that are neighbors of each other or of the current |n_pos| row. 9138 // Exception: If |link(h)=h| (so that the edge structure contains 9139 // no rows), we have |n_rover(h)=h|, and |n_pos(h)| is irrelevant. 9140 func (prg *prg) initEdges(h halfword) { 9141 *(*prg.mem[h].hh()).lh() = h 9142 *(*prg.mem[h].hh()).rh() = h 9143 9144 *(*prg.mem[int32(h)+1].hh()).lh() = uint16(zeroField + 4095) 9145 *(*prg.mem[int32(h)+1].hh()).rh() = uint16(zeroField - 4095) 9146 *(*prg.mem[int32(h)+2].hh()).lh() = uint16(zeroField + 4095) 9147 *(*prg.mem[int32(h)+2].hh()).rh() = uint16(zeroField - 4095) 9148 *(*prg.mem[int32(h)+3].hh()).lh() = uint16(zeroField) 9149 9150 *(*prg.mem[int32(h)+3].hh()).rh() = 0 9151 *prg.mem[int32(h)+4].int() = 0 9152 9153 *(*prg.mem[int32(h)+5].hh()).rh() = h 9154 *(*prg.mem[int32(h)+5].hh()).lh() = 0 9155 9156 } 9157 9158 // 328. 9159 9160 // tangle:pos ../../mf.web:7239:3: 9161 9162 // The |fix_offset| routine goes through all the edge-weight nodes of 9163 // |cur_edges| and adds a constant to their |info| fields, so that 9164 // |m_offset(cur_edges)| can be brought back to |zero_field|. (This 9165 // is necessary only in unusual cases when the offset has gotten too 9166 // large or too small.) 9167 func (prg *prg) fixOffset() { 9168 var ( 9169 p, q halfword // list traversers 9170 delta int32 // the amount of change 9171 ) 9172 delta = 8 * (int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) - zeroField) 9173 *(*prg.mem[int32(prg.curEdges)+3].hh()).lh() = uint16(zeroField) 9174 q = *(*prg.mem[prg.curEdges].hh()).rh() 9175 for int32(q) != int32(prg.curEdges) { 9176 p = *(*prg.mem[int32(q)+1].hh()).rh() 9177 for int32(p) != 3000 { 9178 *(*prg.mem[p].hh()).lh() = uint16(int32(*(*prg.mem[p].hh()).lh()) - delta) 9179 p = *(*prg.mem[p].hh()).rh() 9180 } 9181 p = *(*prg.mem[int32(q)+1].hh()).lh() 9182 for int32(p) > memMin+1 { 9183 *(*prg.mem[p].hh()).lh() = uint16(int32(*(*prg.mem[p].hh()).lh()) - delta) 9184 p = *(*prg.mem[p].hh()).rh() 9185 } 9186 q = *(*prg.mem[q].hh()).rh() 9187 } 9188 } 9189 9190 // 329. 9191 9192 // tangle:pos ../../mf.web:7264:3: 9193 9194 // The |edge_prep| routine makes the |cur_edges| structure ready to 9195 // accept new data whose coordinates satisfy |ml<=m<=mr| and |nl<=n<=nr-1|, 9196 // assuming that |-4096<ml<=mr<4096| and |-4096<nl<=nr<4096|. It makes 9197 // appropriate adjustments to |m_min|, |m_max|, |n_min|, and |n_max|, 9198 // adding new empty rows if necessary. 9199 func (prg *prg) edgePrep(ml, mr, nl, nr int32) { 9200 var ( 9201 delta halfword // amount of change 9202 p, q halfword // for list manipulation 9203 ) 9204 ml = ml + zeroField 9205 mr = mr + zeroField 9206 nl = nl + zeroField 9207 nr = nr - 1 + zeroField 9208 9209 if ml < int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh()) { 9210 *(*prg.mem[int32(prg.curEdges)+2].hh()).lh() = uint16(ml) 9211 } 9212 if mr > int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh()) { 9213 *(*prg.mem[int32(prg.curEdges)+2].hh()).rh() = uint16(mr) 9214 } 9215 if !(abs(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh())+int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())-zeroField-4096) < 4096) || !(abs(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh())+int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())-zeroField-4096) < 4096) { 9216 prg.fixOffset() 9217 } 9218 if int32(*(*prg.mem[prg.curEdges].hh()).rh()) == int32(prg.curEdges) { 9219 *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() = uint16(nr + 1) 9220 *(*prg.mem[int32(prg.curEdges)+1].hh()).rh() = uint16(nr) 9221 } 9222 if nl < int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh()) { 9223 delta = uint16(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh()) - nl) 9224 *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() = uint16(nl) 9225 p = *(*prg.mem[prg.curEdges].hh()).rh() 9226 for { 9227 q = prg.getNode(rowNodeSize) 9228 *(*prg.mem[int32(q)+1].hh()).rh() = 3000 9229 *(*prg.mem[int32(q)+1].hh()).lh() = uint16(memMin + 1) 9230 *(*prg.mem[p].hh()).lh() = q 9231 *(*prg.mem[q].hh()).rh() = p 9232 p = q 9233 delta = uint16(int32(delta) - 1) 9234 if int32(delta) == 0 { 9235 break 9236 } 9237 } 9238 *(*prg.mem[p].hh()).lh() = prg.curEdges 9239 *(*prg.mem[prg.curEdges].hh()).rh() = p 9240 if int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).rh()) == int32(prg.curEdges) { 9241 *(*prg.mem[int32(prg.curEdges)+5].hh()).lh() = uint16(nl - 1) 9242 } 9243 } 9244 if nr > int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh()) { 9245 delta = uint16(nr - int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh())) 9246 *(*prg.mem[int32(prg.curEdges)+1].hh()).rh() = uint16(nr) 9247 p = *(*prg.mem[prg.curEdges].hh()).lh() 9248 for { 9249 q = prg.getNode(rowNodeSize) 9250 *(*prg.mem[int32(q)+1].hh()).rh() = 3000 9251 *(*prg.mem[int32(q)+1].hh()).lh() = uint16(memMin + 1) 9252 *(*prg.mem[p].hh()).rh() = q 9253 *(*prg.mem[q].hh()).lh() = p 9254 p = q 9255 delta = uint16(int32(delta) - 1) 9256 if int32(delta) == 0 { 9257 break 9258 } 9259 } 9260 *(*prg.mem[p].hh()).rh() = prg.curEdges 9261 *(*prg.mem[prg.curEdges].hh()).lh() = p 9262 if int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).rh()) == int32(prg.curEdges) { 9263 *(*prg.mem[int32(prg.curEdges)+5].hh()).lh() = uint16(nr + 1) 9264 } 9265 } 9266 } 9267 9268 // 334. 9269 9270 // tangle:pos ../../mf.web:7353:3: 9271 9272 // Here's a trivial subroutine that copies an edge structure. (Let's hope 9273 // that the given structure isn't too gigantic.) 9274 func (prg *prg) copyEdges(h halfword) (r halfword) { 9275 var ( 9276 p, r1 halfword // variables that traverse the given structure 9277 hh, pp, qq, rr, ss halfword // variables that traverse the new structure 9278 ) 9279 hh = prg.getNode(edgeHeaderSize) 9280 prg.mem[int32(hh)+1] = prg.mem[int32(h)+1] 9281 prg.mem[int32(hh)+2] = prg.mem[int32(h)+2] 9282 prg.mem[int32(hh)+3] = prg.mem[int32(h)+3] 9283 prg.mem[int32(hh)+4] = prg.mem[int32(h)+4] // we've now copied |n_min|, |n_max|, 9284 // |m_min|, |m_max|, |m_offset|, |last_window|, and |last_window_time| 9285 9286 *(*prg.mem[int32(hh)+5].hh()).lh() = uint16(int32(*(*prg.mem[int32(hh)+1].hh()).rh()) + 1) 9287 *(*prg.mem[int32(hh)+5].hh()).rh() = hh 9288 9289 p = *(*prg.mem[h].hh()).rh() 9290 qq = hh 9291 for int32(p) != int32(h) { 9292 pp = prg.getNode(rowNodeSize) 9293 *(*prg.mem[qq].hh()).rh() = pp 9294 *(*prg.mem[pp].hh()).lh() = qq 9295 9296 // Copy both |sorted| and |unsorted| lists of |p| to |pp| 9297 r1 = *(*prg.mem[int32(p)+1].hh()).rh() 9298 rr = uint16(int32(pp) + 1) // |link(rr)=sorted(pp)| 9299 for int32(r1) != 3000 { 9300 ss = prg.getAvail() 9301 *(*prg.mem[rr].hh()).rh() = ss 9302 rr = ss 9303 *(*prg.mem[rr].hh()).lh() = *(*prg.mem[r1].hh()).lh() 9304 9305 r1 = *(*prg.mem[r1].hh()).rh() 9306 } 9307 *(*prg.mem[rr].hh()).rh() = 3000 9308 9309 r1 = *(*prg.mem[int32(p)+1].hh()).lh() 9310 rr = uint16(3000 - 1) 9311 for int32(r1) > memMin+1 { 9312 ss = prg.getAvail() 9313 *(*prg.mem[rr].hh()).rh() = ss 9314 rr = ss 9315 *(*prg.mem[rr].hh()).lh() = *(*prg.mem[r1].hh()).lh() 9316 9317 r1 = *(*prg.mem[r1].hh()).rh() 9318 } 9319 *(*prg.mem[rr].hh()).rh() = r1 9320 *(*prg.mem[int32(pp)+1].hh()).lh() = *(*prg.mem[3000-1].hh()).rh() 9321 p = *(*prg.mem[p].hh()).rh() 9322 qq = pp 9323 } 9324 *(*prg.mem[qq].hh()).rh() = hh 9325 *(*prg.mem[hh].hh()).lh() = qq 9326 r = hh 9327 return r 9328 } 9329 9330 // 336. 9331 9332 // tangle:pos ../../mf.web:7388:3: 9333 9334 // Another trivial routine flips |cur_edges| about the |x|-axis 9335 // (i.e., negates all the |y| coordinates), assuming that at least 9336 // one row is present. 9337 func (prg *prg) yReflectEdges() { 9338 var ( 9339 p, q, r1 halfword // list manipulation registers 9340 ) 9341 p = *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() 9342 *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() = uint16(zeroField + zeroField - 1 - int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh())) 9343 *(*prg.mem[int32(prg.curEdges)+1].hh()).rh() = uint16(zeroField + zeroField - 1 - int32(p)) 9344 *(*prg.mem[int32(prg.curEdges)+5].hh()).lh() = uint16(zeroField + zeroField - 1 - int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).lh())) 9345 9346 p = *(*prg.mem[prg.curEdges].hh()).rh() 9347 q = prg.curEdges // we assume that |p<>q| 9348 for { 9349 r1 = *(*prg.mem[p].hh()).rh() 9350 *(*prg.mem[p].hh()).rh() = q 9351 *(*prg.mem[q].hh()).lh() = p 9352 q = p 9353 p = r1 9354 if int32(q) == int32(prg.curEdges) { 9355 break 9356 } 9357 } 9358 *prg.mem[int32(prg.curEdges)+4].int() = 0 9359 } 9360 9361 // 337. 9362 9363 // tangle:pos ../../mf.web:7404:3: 9364 9365 // It's somewhat more difficult, yet not too hard, to reflect about the |y|-axis. 9366 func (prg *prg) xReflectEdges() { 9367 var ( 9368 p, q, r1, s halfword // list manipulation registers 9369 m int32 // |info| fields will be reflected with respect to this number 9370 ) 9371 p = *(*prg.mem[int32(prg.curEdges)+2].hh()).lh() 9372 *(*prg.mem[int32(prg.curEdges)+2].hh()).lh() = uint16(zeroField + zeroField - int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh())) 9373 *(*prg.mem[int32(prg.curEdges)+2].hh()).rh() = uint16(zeroField + zeroField - int32(p)) 9374 m = (zeroField+int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()))*8 + zeroW + 0 + zeroW + 0 9375 *(*prg.mem[int32(prg.curEdges)+3].hh()).lh() = uint16(zeroField) 9376 p = *(*prg.mem[prg.curEdges].hh()).rh() 9377 for { 9378 // Reflect the edge-and-weight data in |sorted(p)| 9379 q = *(*prg.mem[int32(p)+1].hh()).rh() 9380 r1 = 3000 9381 for int32(q) != 3000 { 9382 s = *(*prg.mem[q].hh()).rh() 9383 *(*prg.mem[q].hh()).rh() = r1 9384 r1 = q 9385 *(*prg.mem[r1].hh()).lh() = uint16(m - int32(*(*prg.mem[q].hh()).lh())) 9386 q = s 9387 } 9388 *(*prg.mem[int32(p)+1].hh()).rh() = r1 9389 9390 // Reflect the edge-and-weight data in |unsorted(p)| 9391 q = *(*prg.mem[int32(p)+1].hh()).lh() 9392 for int32(q) > memMin+1 { 9393 *(*prg.mem[q].hh()).lh() = uint16(m - int32(*(*prg.mem[q].hh()).lh())) 9394 q = *(*prg.mem[q].hh()).rh() 9395 } 9396 p = *(*prg.mem[p].hh()).rh() 9397 if int32(p) == int32(prg.curEdges) { 9398 break 9399 } 9400 } 9401 *prg.mem[int32(prg.curEdges)+4].int() = 0 9402 } 9403 9404 // 340. 9405 9406 // tangle:pos ../../mf.web:7443:3: 9407 9408 // Now let's multiply all the $y$~coordinates of a nonempty edge structure 9409 // by a small integer $s>1$: 9410 func (prg *prg) yScaleEdges(s int32) { 9411 var ( 9412 p, q, pp, r1, rr, ss halfword // list manipulation registers 9413 t int32 // replication counter 9414 ) 9415 if s*(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh())+1-zeroField) >= 4096 || s*(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh())-zeroField) <= -4096 { 9416 { 9417 if int32(prg.interaction) == errorStopMode { 9418 } 9419 prg.printNl(strNumber( /* "! " */ 261)) 9420 prg.print( /* "Scaled picture would be too big" */ 535) /* \xref[!\relax] */ 9421 } 9422 // \xref[Scaled picture...big] 9423 { 9424 prg.helpPtr = 3 9425 prg.helpLine[2] = /* "I can't yscale the picture as requested---it would" */ 536 9426 prg.helpLine[1] = /* "make some coordinates too large or too small." */ 537 9427 prg.helpLine[0] = /* "Proceed, and I'll omit the transformation." */ 538 9428 } 9429 prg.putGetError() 9430 } else { 9431 *(*prg.mem[int32(prg.curEdges)+1].hh()).rh() = uint16(s*(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh())+1-zeroField) - 1 + zeroField) 9432 *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() = uint16(s*(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh())-zeroField) + zeroField) 9433 9434 // Replicate every row exactly $s$ times 9435 p = prg.curEdges 9436 for { 9437 q = p 9438 p = *(*prg.mem[p].hh()).rh() 9439 for ii := int32(2); ii <= s; ii++ { 9440 t = ii 9441 _ = t 9442 pp = prg.getNode(rowNodeSize) 9443 *(*prg.mem[q].hh()).rh() = pp 9444 *(*prg.mem[p].hh()).lh() = pp 9445 *(*prg.mem[pp].hh()).rh() = p 9446 *(*prg.mem[pp].hh()).lh() = q 9447 q = pp 9448 9449 // Copy both |sorted| and |unsorted|... 9450 r1 = *(*prg.mem[int32(p)+1].hh()).rh() 9451 rr = uint16(int32(pp) + 1) // |link(rr)=sorted(pp)| 9452 for int32(r1) != 3000 { 9453 ss = prg.getAvail() 9454 *(*prg.mem[rr].hh()).rh() = ss 9455 rr = ss 9456 *(*prg.mem[rr].hh()).lh() = *(*prg.mem[r1].hh()).lh() 9457 9458 r1 = *(*prg.mem[r1].hh()).rh() 9459 } 9460 *(*prg.mem[rr].hh()).rh() = 3000 9461 9462 r1 = *(*prg.mem[int32(p)+1].hh()).lh() 9463 rr = uint16(3000 - 1) 9464 for int32(r1) > memMin+1 { 9465 ss = prg.getAvail() 9466 *(*prg.mem[rr].hh()).rh() = ss 9467 rr = ss 9468 *(*prg.mem[rr].hh()).lh() = *(*prg.mem[r1].hh()).lh() 9469 9470 r1 = *(*prg.mem[r1].hh()).rh() 9471 } 9472 *(*prg.mem[rr].hh()).rh() = r1 9473 *(*prg.mem[int32(pp)+1].hh()).lh() = *(*prg.mem[3000-1].hh()).rh() 9474 } 9475 if int32(*(*prg.mem[p].hh()).rh()) == int32(prg.curEdges) { 9476 break 9477 } 9478 } 9479 *prg.mem[int32(prg.curEdges)+4].int() = 0 9480 } 9481 } 9482 9483 // 342. 9484 9485 // tangle:pos ../../mf.web:7475:3: 9486 9487 // Scaling the $x$~coordinates is, of course, our next task. 9488 func (prg *prg) xScaleEdges(s int32) { 9489 var ( 9490 p, q halfword // list manipulation registers 9491 t/* 0..65535 */ uint16 // unpacked |info| field 9492 w/* 0..7 */ byte // unpacked weight 9493 delta int32 // amount added to scaled |info| 9494 ) 9495 if s*(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh())-zeroField) >= 4096 || s*(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh())-zeroField) <= -4096 { 9496 { 9497 if int32(prg.interaction) == errorStopMode { 9498 } 9499 prg.printNl(strNumber( /* "! " */ 261)) 9500 prg.print( /* "Scaled picture would be too big" */ 535) /* \xref[!\relax] */ 9501 } 9502 // \xref[Scaled picture...big] 9503 { 9504 prg.helpPtr = 3 9505 prg.helpLine[2] = /* "I can't xscale the picture as requested---it would" */ 539 9506 prg.helpLine[1] = /* "make some coordinates too large or too small." */ 537 9507 prg.helpLine[0] = /* "Proceed, and I'll omit the transformation." */ 538 9508 } 9509 prg.putGetError() 9510 } else if int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh()) != zeroField || int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh()) != zeroField { 9511 *(*prg.mem[int32(prg.curEdges)+2].hh()).rh() = uint16(s*(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh())-zeroField) + zeroField) 9512 *(*prg.mem[int32(prg.curEdges)+2].hh()).lh() = uint16(s*(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh())-zeroField) + zeroField) 9513 delta = 8*(zeroField-s*int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())) + 0 9514 *(*prg.mem[int32(prg.curEdges)+3].hh()).lh() = uint16(zeroField) 9515 9516 // Scale the $x$~coordinates of each row by $s$ 9517 q = *(*prg.mem[prg.curEdges].hh()).rh() 9518 for { 9519 p = *(*prg.mem[int32(q)+1].hh()).rh() 9520 for int32(p) != 3000 { 9521 t = uint16(int32(*(*prg.mem[p].hh()).lh()) - 0) 9522 w = byte(int32(t) % 8) 9523 *(*prg.mem[p].hh()).lh() = uint16((int32(t)-int32(w))*s + int32(w) + delta) 9524 p = *(*prg.mem[p].hh()).rh() 9525 } 9526 p = *(*prg.mem[int32(q)+1].hh()).lh() 9527 for int32(p) > memMin+1 { 9528 t = uint16(int32(*(*prg.mem[p].hh()).lh()) - 0) 9529 w = byte(int32(t) % 8) 9530 *(*prg.mem[p].hh()).lh() = uint16((int32(t)-int32(w))*s + int32(w) + delta) 9531 p = *(*prg.mem[p].hh()).rh() 9532 } 9533 q = *(*prg.mem[q].hh()).rh() 9534 if int32(q) == int32(prg.curEdges) { 9535 break 9536 } 9537 } 9538 *prg.mem[int32(prg.curEdges)+4].int() = 0 9539 } 9540 } 9541 9542 // 344. 9543 9544 // tangle:pos ../../mf.web:7516:3: 9545 9546 // Here is a routine that changes the signs of all the weights, without 9547 // changing anything else. 9548 func (prg *prg) negateEdges(h halfword) { 9549 var ( 9550 p, q, r1, s, t, u halfword // structure traversers 9551 ) 9552 p = *(*prg.mem[h].hh()).rh() 9553 for int32(p) != int32(h) { 9554 q = *(*prg.mem[int32(p)+1].hh()).lh() 9555 for int32(q) > memMin+1 { 9556 *(*prg.mem[q].hh()).lh() = uint16(8 - 2*((int32(*(*prg.mem[q].hh()).lh())-0)%8) + int32(*(*prg.mem[q].hh()).lh())) 9557 q = *(*prg.mem[q].hh()).rh() 9558 } 9559 q = *(*prg.mem[int32(p)+1].hh()).rh() 9560 if int32(q) != 3000 { 9561 for { 9562 *(*prg.mem[q].hh()).lh() = uint16(8 - 2*((int32(*(*prg.mem[q].hh()).lh())-0)%8) + int32(*(*prg.mem[q].hh()).lh())) 9563 q = *(*prg.mem[q].hh()).rh() 9564 if int32(q) == 3000 { 9565 break 9566 } 9567 } 9568 9569 // Put the list |sorted(p)| back into sort 9570 u = uint16(int32(p) + 1) 9571 q = *(*prg.mem[u].hh()).rh() 9572 r1 = q 9573 s = *(*prg.mem[r1].hh()).rh() // |q=sorted(p)| 9574 for true { 9575 if int32(*(*prg.mem[s].hh()).lh()) > int32(*(*prg.mem[r1].hh()).lh()) { 9576 *(*prg.mem[u].hh()).rh() = q 9577 if int32(s) == 3000 { 9578 goto done 9579 } 9580 u = r1 9581 q = s 9582 r1 = q 9583 s = *(*prg.mem[r1].hh()).rh() 9584 } else { 9585 t = s 9586 s = *(*prg.mem[t].hh()).rh() 9587 *(*prg.mem[t].hh()).rh() = q 9588 q = t 9589 } 9590 } 9591 9592 done: 9593 *(*prg.mem[r1].hh()).rh() = 3000 9594 } 9595 p = *(*prg.mem[p].hh()).rh() 9596 } 9597 *prg.mem[int32(h)+4].int() = 0 9598 } 9599 9600 // 346. 9601 9602 // tangle:pos ../../mf.web:7558:3: 9603 9604 // The |unsorted| edges of a row are merged into the |sorted| ones by 9605 // a subroutine called |sort_edges|. It uses simple insertion sort, 9606 // followed by a merge, because the unsorted list is supposedly quite short. 9607 // However, the unsorted list is assumed to be nonempty. 9608 func (prg *prg) sortEdges(h halfword) { 9609 var ( 9610 k halfword // key register that we compare to |info(q)| 9611 p, q, r1, s halfword 9612 ) 9613 r1 = *(*prg.mem[int32(h)+1].hh()).lh() 9614 *(*prg.mem[int32(h)+1].hh()).lh() = uint16(memMin) 9615 p = *(*prg.mem[r1].hh()).rh() 9616 *(*prg.mem[r1].hh()).rh() = 3000 9617 *(*prg.mem[3000-1].hh()).rh() = r1 9618 for int32(p) > memMin+1 { // sort node |p| into the list that starts at |temp_head| 9619 k = *(*prg.mem[p].hh()).lh() 9620 q = uint16(3000 - 1) 9621 for { 9622 r1 = q 9623 q = *(*prg.mem[r1].hh()).rh() 9624 if int32(k) <= int32(*(*prg.mem[q].hh()).lh()) { 9625 break 9626 } 9627 } 9628 *(*prg.mem[r1].hh()).rh() = p 9629 r1 = *(*prg.mem[p].hh()).rh() 9630 *(*prg.mem[p].hh()).rh() = q 9631 p = r1 9632 } 9633 9634 // Merge the |temp_head| list into |sorted(h)| 9635 { 9636 r1 = uint16(int32(h) + 1) 9637 q = *(*prg.mem[r1].hh()).rh() 9638 p = *(*prg.mem[3000-1].hh()).rh() 9639 for true { 9640 k = *(*prg.mem[p].hh()).lh() 9641 for int32(k) > int32(*(*prg.mem[q].hh()).lh()) { 9642 r1 = q 9643 q = *(*prg.mem[r1].hh()).rh() 9644 } 9645 *(*prg.mem[r1].hh()).rh() = p 9646 s = *(*prg.mem[p].hh()).rh() 9647 *(*prg.mem[p].hh()).rh() = q 9648 if int32(s) == 3000 { 9649 goto done 9650 } 9651 r1 = p 9652 p = s 9653 } 9654 9655 done: 9656 } 9657 } 9658 9659 // 348. 9660 9661 // tangle:pos ../../mf.web:7592:3: 9662 9663 // The |cull_edges| procedure ``optimizes'' an edge structure by making all 9664 // the pixel weights either |w_out| or~|w_in|. The weight will be~|w_in| after the 9665 // operation if and only if it was in the closed interval |[w_lo,w_hi]| 9666 // before, where |w_lo<=w_hi|. Either |w_out| or |w_in| is zero, while the other is 9667 // $\pm1$, $\pm2$, or $\pm3$. The parameters will be such that zero-weight 9668 // pixels will remain of weight zero. (This is fortunate, 9669 // because there are infinitely many of them.) 9670 // 9671 // The procedure also computes the tightest possible bounds on the resulting 9672 // data, by updating |m_min|, |m_max|, |n_min|, and~|n_max|. 9673 func (prg *prg) cullEdges(wLo, wHi, wOut, wIn int32) { 9674 var ( 9675 p, q, r1, s halfword // for list manipulation 9676 w int32 // new weight after culling 9677 d int32 // data register for unpacking 9678 m int32 // the previous column number, including |m_offset| 9679 mm int32 // the next column number, including |m_offset| 9680 ww int32 // accumulated weight before culling 9681 prevW int32 // value of |w| before column |m| 9682 n, minN, maxN halfword // current and extreme row numbers 9683 minD, maxD halfword // extremes of the new edge-and-weight data 9684 ) 9685 minD = 65535 9686 maxD = 0 9687 minN = 65535 9688 maxN = 0 9689 9690 p = *(*prg.mem[prg.curEdges].hh()).rh() 9691 n = *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() 9692 for int32(p) != int32(prg.curEdges) { 9693 if int32(*(*prg.mem[int32(p)+1].hh()).lh()) > memMin+1 { 9694 prg.sortEdges(p) 9695 } 9696 if int32(*(*prg.mem[int32(p)+1].hh()).rh()) != 3000 { 9697 r1 = uint16(3000 - 1) 9698 q = *(*prg.mem[int32(p)+1].hh()).rh() 9699 ww = 0 9700 m = 1000000 9701 prevW = 0 9702 for true { 9703 if int32(q) == 3000 { 9704 mm = 1000000 9705 } else { 9706 d = int32(*(*prg.mem[q].hh()).lh()) - 0 9707 mm = d / 8 9708 ww = ww + d%8 - zeroW 9709 } 9710 if mm > m { 9711 if w != prevW { 9712 s = prg.getAvail() 9713 *(*prg.mem[r1].hh()).rh() = s 9714 *(*prg.mem[s].hh()).lh() = uint16(8*m + 0 + zeroW + w - prevW) 9715 r1 = s 9716 prevW = w 9717 } 9718 if int32(q) == 3000 { 9719 goto done 9720 } 9721 } 9722 m = mm 9723 if ww >= wLo { 9724 if ww <= wHi { 9725 w = wIn 9726 } else { 9727 w = wOut 9728 } 9729 } else { 9730 w = wOut 9731 } 9732 s = *(*prg.mem[q].hh()).rh() 9733 { 9734 *(*prg.mem[q].hh()).rh() = prg.avail 9735 prg.avail = q 9736 prg.dynUsed = prg.dynUsed - 1 9737 } 9738 q = s 9739 } 9740 9741 done: 9742 *(*prg.mem[r1].hh()).rh() = 3000 9743 *(*prg.mem[int32(p)+1].hh()).rh() = *(*prg.mem[3000-1].hh()).rh() 9744 if int32(r1) != 3000-1 { 9745 if int32(minN) == 65535 { 9746 minN = n 9747 } 9748 maxN = n 9749 if int32(minD) > int32(*(*prg.mem[*(*prg.mem[3000-1].hh()).rh()].hh()).lh()) { 9750 minD = *(*prg.mem[*(*prg.mem[3000-1].hh()).rh()].hh()).lh() 9751 } 9752 if int32(maxD) < int32(*(*prg.mem[r1].hh()).lh()) { 9753 maxD = *(*prg.mem[r1].hh()).lh() 9754 } 9755 } 9756 } 9757 p = *(*prg.mem[p].hh()).rh() 9758 n = uint16(int32(n) + 1) 9759 } 9760 9761 // Delete empty rows at the top and/or bottom; update the boundary values in the header 9762 if int32(minN) > int32(maxN) { 9763 p = *(*prg.mem[prg.curEdges].hh()).rh() 9764 for int32(p) != int32(prg.curEdges) { 9765 q = *(*prg.mem[p].hh()).rh() 9766 prg.freeNode(p, halfword(rowNodeSize)) 9767 p = q 9768 } 9769 prg.initEdges(prg.curEdges) 9770 } else { 9771 n = *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() 9772 *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() = minN 9773 for int32(minN) > int32(n) { 9774 p = *(*prg.mem[prg.curEdges].hh()).rh() 9775 *(*prg.mem[prg.curEdges].hh()).rh() = *(*prg.mem[p].hh()).rh() 9776 *(*prg.mem[*(*prg.mem[p].hh()).rh()].hh()).lh() = prg.curEdges 9777 prg.freeNode(p, halfword(rowNodeSize)) 9778 n = uint16(int32(n) + 1) 9779 } 9780 n = *(*prg.mem[int32(prg.curEdges)+1].hh()).rh() 9781 *(*prg.mem[int32(prg.curEdges)+1].hh()).rh() = maxN 9782 *(*prg.mem[int32(prg.curEdges)+5].hh()).lh() = uint16(int32(maxN) + 1) 9783 *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() = prg.curEdges 9784 for int32(maxN) < int32(n) { 9785 p = *(*prg.mem[prg.curEdges].hh()).lh() 9786 *(*prg.mem[prg.curEdges].hh()).lh() = *(*prg.mem[p].hh()).lh() 9787 *(*prg.mem[*(*prg.mem[p].hh()).lh()].hh()).rh() = prg.curEdges 9788 prg.freeNode(p, halfword(rowNodeSize)) 9789 n = uint16(int32(n) - 1) 9790 } 9791 *(*prg.mem[int32(prg.curEdges)+2].hh()).lh() = uint16((int32(minD)-0)/8 - int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) + zeroField) 9792 *(*prg.mem[int32(prg.curEdges)+2].hh()).rh() = uint16((int32(maxD)-0)/8 - int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) + zeroField) 9793 } 9794 *prg.mem[int32(prg.curEdges)+4].int() = 0 9795 } 9796 9797 // 354. 9798 9799 // tangle:pos ../../mf.web:7698:3: 9800 9801 // The last and most difficult routine for transforming an edge structure---and 9802 // the most interesting one!---is |xy_swap_edges|, which interchanges the 9803 // r\^^Doles of rows and columns. Its task can be viewed as the job of 9804 // creating an edge structure that contains only horizontal edges, linked 9805 // together in columns, given an edge structure that contains only 9806 // vertical edges linked together in rows; we must do this without changing 9807 // the implied pixel weights. 9808 // 9809 // Given any two adjacent rows of an edge structure, it is not difficult to 9810 // determine the horizontal edges that lie ``between'' them: We simply look 9811 // for vertically adjacent pixels that have different weight, and insert 9812 // a horizontal edge containing the difference in weights. Every horizontal 9813 // edge determined in this way should be put into an appropriate linked 9814 // list. Since random access to these linked lists is desirable, we use 9815 // the |move| array to hold the list heads. If we work through the given 9816 // edge structure from top to bottom, the constructed lists will not need 9817 // to be sorted, since they will already be in order. 9818 // 9819 // The following algorithm makes use of some ideas suggested by John Hobby. 9820 // \xref[Hobby, John Douglas] 9821 // It assumes that the edge structure is non-null, i.e., that |link(cur_edges) 9822 // <>cur_edges|, hence |m_max(cur_edges)>=m_min(cur_edges)|. 9823 func (prg *prg) xySwapEdges() { 9824 var ( 9825 mMagic, nMagic int32 // special values that account for offsets 9826 p, q, r1, s halfword // pointers that traverse the given structure 9827 9828 // Other local variables for |xy_swap_edges| 9829 mSpread int32 // the difference between |m_max| and |m_min| 9830 j, jj/* 0..moveSize */ uint16 // indices into |move| 9831 m, mm int32 // |m| values at vertical edges 9832 pd, rd int32 // data fields from edge-and-weight nodes 9833 pm, rm int32 // |m| values from edge-and-weight nodes 9834 w int32 // the difference in accumulated weight 9835 ww int32 // as much of |w| that can be stored in a single node 9836 dw int32 // an increment to be added to |w| 9837 9838 extras int32 // the number of additional nodes to make weights |>3| 9839 xw/* -3..3 */ int8 // the additional weight in extra nodes 9840 k int32 // loop counter for inserting extra nodes 9841 ) 9842 mSpread = int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh()) - int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh()) // this is |>=0| by assumption 9843 if mSpread > moveSize { 9844 prg.overflow(strNumber( /* "move table size" */ 540), moveSize) 9845 } 9846 // \xref[METAFONT capacity exceeded move table size][\quad move table size] 9847 for ii := int32(0); ii <= mSpread; ii++ { 9848 j = uint16(ii) 9849 _ = j 9850 prg.move[j] = 3000 9851 } 9852 9853 // Insert blank rows at the top and bottom, and set |p| to the new top row 9854 p = prg.getNode(rowNodeSize) 9855 *(*prg.mem[int32(p)+1].hh()).rh() = 3000 9856 *(*prg.mem[int32(p)+1].hh()).lh() = uint16(memMin) 9857 9858 *(*prg.mem[p].hh()).lh() = prg.curEdges 9859 *(*prg.mem[*(*prg.mem[prg.curEdges].hh()).rh()].hh()).lh() = p // the new bottom row 9860 p = prg.getNode(rowNodeSize) 9861 *(*prg.mem[int32(p)+1].hh()).rh() = 3000 9862 *(*prg.mem[p].hh()).lh() = *(*prg.mem[prg.curEdges].hh()).lh() // the new top row 9863 9864 // Compute the magic offset values 9865 mMagic = int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh()) + int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) - zeroField 9866 nMagic = 8*int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh()) + 8 + zeroW + 0 9867 for { 9868 q = *(*prg.mem[p].hh()).lh() 9869 if int32(*(*prg.mem[int32(q)+1].hh()).lh()) > memMin+1 { 9870 prg.sortEdges(q) 9871 } 9872 9873 // Insert the horizontal edges defined by adjacent rows |p,q|, and destroy row~|p| 9874 r1 = *(*prg.mem[int32(p)+1].hh()).rh() 9875 prg.freeNode(p, halfword(rowNodeSize)) 9876 p = r1 9877 9878 pd = int32(*(*prg.mem[p].hh()).lh()) - 0 9879 pm = pd / 8 9880 9881 r1 = *(*prg.mem[int32(q)+1].hh()).rh() 9882 rd = int32(*(*prg.mem[r1].hh()).lh()) - 0 9883 rm = rd / 8 9884 w = 0 9885 for true { 9886 if pm < rm { 9887 mm = pm 9888 } else { 9889 mm = rm 9890 } 9891 if w != 0 { 9892 if m != mm { 9893 if mm-mMagic >= moveSize { 9894 prg.confusion(strNumber( /* "xy" */ 510)) 9895 } 9896 // \xref[this can't happen xy][\quad xy] 9897 extras = (abs(w) - 1) / 3 9898 if extras > 0 { 9899 if w > 0 { 9900 xw = int8(+3) 9901 } else { 9902 xw = int8(-3) 9903 } 9904 ww = w - extras*int32(xw) 9905 } else { 9906 ww = w 9907 } 9908 for { 9909 j = uint16(m - mMagic) 9910 for ii := int32(1); ii <= extras; ii++ { 9911 k = ii 9912 _ = k 9913 s = prg.getAvail() 9914 *(*prg.mem[s].hh()).lh() = uint16(nMagic + int32(xw)) 9915 *(*prg.mem[s].hh()).rh() = uint16(prg.move[j]) 9916 prg.move[j] = int32(s) 9917 } 9918 s = prg.getAvail() 9919 *(*prg.mem[s].hh()).lh() = uint16(nMagic + ww) 9920 *(*prg.mem[s].hh()).rh() = uint16(prg.move[j]) 9921 prg.move[j] = int32(s) 9922 9923 m = m + 1 9924 if m == mm { 9925 break 9926 } 9927 } 9928 } 9929 } 9930 if pd < rd { 9931 dw = pd%8 - zeroW 9932 9933 // Advance pointer |p| to the next vertical edge, after destroying the previous one 9934 s = *(*prg.mem[p].hh()).rh() 9935 { 9936 *(*prg.mem[p].hh()).rh() = prg.avail 9937 prg.avail = p 9938 prg.dynUsed = prg.dynUsed - 1 9939 } 9940 p = s 9941 pd = int32(*(*prg.mem[p].hh()).lh()) - 0 9942 pm = pd / 8 9943 } else { 9944 if int32(r1) == 3000 { 9945 goto done 9946 } // |rd=pd=ho(max_halfword)| 9947 dw = -(rd%8 - zeroW) 9948 9949 // Advance pointer |r| to the next vertical edge 9950 r1 = *(*prg.mem[r1].hh()).rh() 9951 rd = int32(*(*prg.mem[r1].hh()).lh()) - 0 9952 rm = rd / 8 9953 } 9954 m = mm 9955 w = w + dw 9956 } 9957 9958 done: 9959 ; 9960 p = q 9961 nMagic = nMagic - 8 9962 if int32(*(*prg.mem[p].hh()).lh()) == int32(prg.curEdges) { 9963 break 9964 } 9965 } 9966 prg.freeNode(p, halfword(rowNodeSize)) // now all original rows have been recycled 9967 9968 // Adjust the header to reflect the new edges 9969 prg.move[mSpread] = 0 9970 j = 0 9971 for prg.move[j] == 3000 { 9972 j = uint16(int32(j) + 1) 9973 } 9974 if int32(j) == mSpread { 9975 prg.initEdges(prg.curEdges) 9976 } else { 9977 mm = int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh()) 9978 *(*prg.mem[int32(prg.curEdges)+2].hh()).lh() = *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() 9979 *(*prg.mem[int32(prg.curEdges)+2].hh()).rh() = uint16(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh()) + 1) 9980 *(*prg.mem[int32(prg.curEdges)+3].hh()).lh() = uint16(zeroField) 9981 jj = uint16(mSpread - 1) 9982 for prg.move[jj] == 3000 { 9983 jj = uint16(int32(jj) - 1) 9984 } 9985 *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() = uint16(int32(j) + mm) 9986 *(*prg.mem[int32(prg.curEdges)+1].hh()).rh() = uint16(int32(jj) + mm) 9987 q = prg.curEdges 9988 for { 9989 p = prg.getNode(rowNodeSize) 9990 *(*prg.mem[q].hh()).rh() = p 9991 *(*prg.mem[p].hh()).lh() = q 9992 *(*prg.mem[int32(p)+1].hh()).rh() = uint16(prg.move[j]) 9993 *(*prg.mem[int32(p)+1].hh()).lh() = uint16(memMin) 9994 j = uint16(int32(j) + 1) 9995 q = p 9996 if int32(j) > int32(jj) { 9997 break 9998 } 9999 } 10000 *(*prg.mem[q].hh()).rh() = prg.curEdges 10001 *(*prg.mem[prg.curEdges].hh()).lh() = q 10002 *(*prg.mem[int32(prg.curEdges)+5].hh()).lh() = uint16(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh()) + 1) 10003 *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() = prg.curEdges 10004 *prg.mem[int32(prg.curEdges)+4].int() = 0 10005 } 10006 10007 } 10008 10009 // 361. 10010 10011 // tangle:pos ../../mf.web:7797:3: 10012 10013 // Certain ``magic'' values are needed to make the following code work, 10014 // because of the various offsets in our data structure. For now, let's not 10015 // worry about their precise values; we shall compute |m_magic| and |n_magic| 10016 // later, after we see what the code looks like. 10017 10018 // 366. 10019 10020 // tangle:pos ../../mf.web:7858:3: 10021 10022 // Now let's look at the subroutine that merges the edges from a given 10023 // edge structure into |cur_edges|. The given edge structure loses all its 10024 // edges. 10025 func (prg *prg) mergeEdges(h halfword) { 10026 var ( 10027 p, q, r1, pp, qq, rr halfword // list manipulation registers 10028 n int32 // row number 10029 k halfword // key register that we compare to |info(q)| 10030 delta int32 // change to the edge/weight data 10031 ) 10032 if int32(*(*prg.mem[h].hh()).rh()) != int32(h) { 10033 if int32(*(*prg.mem[int32(h)+2].hh()).lh()) < int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh()) || int32(*(*prg.mem[int32(h)+2].hh()).rh()) > int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh()) || int32(*(*prg.mem[int32(h)+1].hh()).lh()) < int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh()) || int32(*(*prg.mem[int32(h)+1].hh()).rh()) > int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh()) { 10034 prg.edgePrep(int32(*(*prg.mem[int32(h)+2].hh()).lh())-zeroField, int32(*(*prg.mem[int32(h)+2].hh()).rh())-zeroField, int32(*(*prg.mem[int32(h)+1].hh()).lh())-zeroField, int32(*(*prg.mem[int32(h)+1].hh()).rh())-zeroField+1) 10035 } 10036 if int32(*(*prg.mem[int32(h)+3].hh()).lh()) != int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) { 10037 pp = *(*prg.mem[h].hh()).rh() 10038 delta = 8 * (int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) - int32(*(*prg.mem[int32(h)+3].hh()).lh())) 10039 for { 10040 qq = *(*prg.mem[int32(pp)+1].hh()).rh() 10041 for int32(qq) != 3000 { 10042 *(*prg.mem[qq].hh()).lh() = uint16(int32(*(*prg.mem[qq].hh()).lh()) + delta) 10043 qq = *(*prg.mem[qq].hh()).rh() 10044 } 10045 qq = *(*prg.mem[int32(pp)+1].hh()).lh() 10046 for int32(qq) > memMin+1 { 10047 *(*prg.mem[qq].hh()).lh() = uint16(int32(*(*prg.mem[qq].hh()).lh()) + delta) 10048 qq = *(*prg.mem[qq].hh()).rh() 10049 } 10050 pp = *(*prg.mem[pp].hh()).rh() 10051 if int32(pp) == int32(h) { 10052 break 10053 } 10054 } 10055 } 10056 n = int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh()) 10057 p = *(*prg.mem[prg.curEdges].hh()).rh() 10058 pp = *(*prg.mem[h].hh()).rh() 10059 for n < int32(*(*prg.mem[int32(h)+1].hh()).lh()) { 10060 n = n + 1 10061 p = *(*prg.mem[p].hh()).rh() 10062 } 10063 for { 10064 // Merge row |pp| into row |p| 10065 qq = *(*prg.mem[int32(pp)+1].hh()).lh() 10066 if int32(qq) > memMin+1 { 10067 if int32(*(*prg.mem[int32(p)+1].hh()).lh()) <= memMin+1 { 10068 *(*prg.mem[int32(p)+1].hh()).lh() = qq 10069 } else { 10070 for int32(*(*prg.mem[qq].hh()).rh()) > memMin+1 { 10071 qq = *(*prg.mem[qq].hh()).rh() 10072 } 10073 *(*prg.mem[qq].hh()).rh() = *(*prg.mem[int32(p)+1].hh()).lh() 10074 *(*prg.mem[int32(p)+1].hh()).lh() = *(*prg.mem[int32(pp)+1].hh()).lh() 10075 } 10076 } 10077 *(*prg.mem[int32(pp)+1].hh()).lh() = uint16(memMin) 10078 qq = *(*prg.mem[int32(pp)+1].hh()).rh() 10079 if int32(qq) != 3000 { 10080 if int32(*(*prg.mem[int32(p)+1].hh()).lh()) == memMin+1 { 10081 *(*prg.mem[int32(p)+1].hh()).lh() = uint16(memMin) 10082 } 10083 *(*prg.mem[int32(pp)+1].hh()).rh() = 3000 10084 r1 = uint16(int32(p) + 1) 10085 q = *(*prg.mem[r1].hh()).rh() // |q=sorted(p)| 10086 if int32(q) == 3000 { 10087 *(*prg.mem[int32(p)+1].hh()).rh() = qq 10088 } else { 10089 for true { 10090 k = *(*prg.mem[qq].hh()).lh() 10091 for int32(k) > int32(*(*prg.mem[q].hh()).lh()) { 10092 r1 = q 10093 q = *(*prg.mem[r1].hh()).rh() 10094 } 10095 *(*prg.mem[r1].hh()).rh() = qq 10096 rr = *(*prg.mem[qq].hh()).rh() 10097 *(*prg.mem[qq].hh()).rh() = q 10098 if int32(rr) == 3000 { 10099 goto done 10100 } 10101 r1 = qq 10102 qq = rr 10103 } 10104 } 10105 } 10106 10107 done: 10108 ; 10109 pp = *(*prg.mem[pp].hh()).rh() 10110 p = *(*prg.mem[p].hh()).rh() 10111 if int32(pp) == int32(h) { 10112 break 10113 } 10114 } 10115 } 10116 } 10117 10118 // 369. 10119 10120 // tangle:pos ../../mf.web:7926:3: 10121 10122 // The |total_weight| routine computes the total of all pixel weights 10123 // in a given edge structure. It's not difficult to prove that this is 10124 // the sum of $(-w)$ times $x$ taken over all edges, 10125 // where $w$ and~$x$ are the weight and $x$~coordinates stored in an edge. 10126 // It's not necessary to worry that this quantity will overflow the 10127 // size of an |integer| register, because it will be less than~$2^[31]$ 10128 // unless the edge structure has more than 174,762 edges. However, we had 10129 // better not try to compute it as a |scaled| integer, because a total 10130 // weight of almost $12\times 2^[12]$ can be produced by only four edges. 10131 func (prg *prg) totalWeight(h halfword) (r int32) { // |h| is an edge header 10132 var ( 10133 p, q halfword // variables that traverse the given structure 10134 n int32 // accumulated total so far 10135 m/* 0..65535 */ uint16 // packed $x$ and $w$ values, including offsets 10136 ) 10137 n = 0 10138 p = *(*prg.mem[h].hh()).rh() 10139 for int32(p) != int32(h) { 10140 q = *(*prg.mem[int32(p)+1].hh()).rh() 10141 for int32(q) != 3000 { 10142 10143 // Add the contribution of node |q| to the total weight, and set |q:=link(q)| 10144 m = uint16(int32(*(*prg.mem[q].hh()).lh()) - 0) 10145 n = n - (int32(m)%8-zeroW)*(int32(m)/8) 10146 q = *(*prg.mem[q].hh()).rh() 10147 } 10148 q = *(*prg.mem[int32(p)+1].hh()).lh() 10149 for int32(q) > memMin+1 { 10150 10151 // Add the contribution of node |q| to the total weight, and set |q:=link(q)| 10152 m = uint16(int32(*(*prg.mem[q].hh()).lh()) - 0) 10153 n = n - (int32(m)%8-zeroW)*(int32(m)/8) 10154 q = *(*prg.mem[q].hh()).rh() 10155 } 10156 p = *(*prg.mem[p].hh()).rh() 10157 } 10158 r = n 10159 return r 10160 } 10161 10162 // 372. 10163 10164 // tangle:pos ../../mf.web:7983:3: 10165 10166 // Edge tracing is initiated by the |begin_edge_tracing| routine, 10167 // continued by the |trace_a_corner| routine, and terminated by the 10168 // |end_edge_tracing| routine. 10169 func (prg *prg) beginEdgeTracing() { 10170 prg.printDiagnostic(strNumber( /* "Tracing edges" */ 541), strNumber( /* "" */ 285), true) 10171 prg.print( /* " (weight " */ 542) 10172 prg.printInt(prg.curWt) 10173 prg.printChar(asciiCode(')')) 10174 prg.traceX = -4096 10175 } 10176 10177 func (prg *prg) traceACorner() { 10178 if int32(prg.fileOffset) > maxPrintLine-13 { 10179 prg.printNl(strNumber( /* "" */ 285)) 10180 } 10181 prg.printChar(asciiCode('(')) 10182 prg.printInt(prg.traceX) 10183 prg.printChar(asciiCode(',')) 10184 prg.printInt(prg.traceYy) 10185 prg.printChar(asciiCode(')')) 10186 prg.traceY = prg.traceYy 10187 } 10188 10189 func (prg *prg) endEdgeTracing() { 10190 if prg.traceX == -4096 { 10191 prg.printNl(strNumber( /* "(No new edges added.)" */ 543)) 10192 } else { 10193 prg.traceACorner() 10194 prg.printChar(asciiCode('.')) 10195 } 10196 prg.endDiagnostic(true) 10197 } 10198 10199 // 373. 10200 10201 // tangle:pos ../../mf.web:8006:3: 10202 10203 // Just after a new edge weight has been put into the |info| field of 10204 // node~|r|, in row~|n|, the following routine continues an ongoing trace. 10205 func (prg *prg) traceNewEdge(r1 halfword, n int32) { 10206 var ( 10207 d int32 // temporary data register 10208 w/* -3..3 */ int8 // weight associated with an edge transition 10209 m, n0, n1 int32 // column and row numbers 10210 ) 10211 d = int32(*(*prg.mem[r1].hh()).lh()) - 0 10212 w = int8(d%8 - zeroW) 10213 m = d/8 - int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) 10214 if int32(w) == prg.curWt { 10215 n0 = n + 1 10216 n1 = n 10217 } else { 10218 n0 = n 10219 n1 = n + 1 10220 } // the edges run from |(m,n0)| to |(m,n1)| 10221 if m != prg.traceX { 10222 if prg.traceX == -4096 { 10223 prg.printNl(strNumber( /* "" */ 285)) 10224 prg.traceYy = n0 10225 } else if prg.traceYy != n0 { 10226 prg.printChar(asciiCode('?')) 10227 } else { 10228 prg.traceACorner() 10229 } 10230 prg.traceX = m 10231 prg.traceACorner() 10232 } else { 10233 if n0 != prg.traceYy { 10234 prg.printChar(asciiCode('!')) 10235 } // shouldn't happen 10236 if n0 < n1 && prg.traceY > prg.traceYy || n0 > n1 && prg.traceY < prg.traceYy { 10237 prg.traceACorner() 10238 } 10239 } 10240 prg.traceYy = n1 10241 } 10242 10243 // 374. 10244 10245 // tangle:pos ../../mf.web:8034:3: 10246 10247 // One way to put new edge weights into an edge structure is to use the 10248 // following routine, which simply draws a straight line from |(x0,y0)| to 10249 // |(x1,y1)|. More precisely, it introduces weights for the edges of the 10250 // discrete path $\bigl(\lfloor t[x_0,x_1]+[1\over2]+\epsilon\rfloor, 10251 // \lfloor t[y_0,y_1]+[1\over2]+\epsilon\delta\rfloor\bigr)$, 10252 // as $t$ varies from 0 to~1, where $\epsilon$ and $\delta$ are extremely small 10253 // positive numbers. 10254 // 10255 // The structure header is assumed to be |cur_edges|; downward edge weights 10256 // will be |cur_wt|, while upward ones will be |-cur_wt|. 10257 // 10258 // Of course, this subroutine will be called only in connection with others 10259 // that eventually draw a complete cycle, so that the sum of the edge weights 10260 // in each row will be zero whenever the row is displayed. 10261 func (prg *prg) lineEdges(x0, y0, x1, y1 scaled) { 10262 var ( 10263 m0, n0, m1, n1 int32 // rounded and unscaled coordinates 10264 delx, dely scaled // the coordinate differences of the line 10265 yt scaled // smallest |y| coordinate that rounds the same as |y0| 10266 tx scaled // tentative change in |x| 10267 p, r1 halfword // list manipulation registers 10268 base int32 // amount added to edge-and-weight data 10269 n int32 // current row number 10270 ) 10271 n0 = prg.roundUnscaled(y0) 10272 n1 = prg.roundUnscaled(y1) 10273 if n0 != n1 { 10274 m0 = prg.roundUnscaled(x0) 10275 m1 = prg.roundUnscaled(x1) 10276 delx = x1 - x0 10277 dely = y1 - y0 10278 yt = n0*0200000 - 0100000 10279 y0 = y0 - yt 10280 y1 = y1 - yt 10281 if n0 < n1 { 10282 base = 8*int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) + 0 + zeroW - prg.curWt 10283 if m0 <= m1 { 10284 prg.edgePrep(m0, m1, n0, n1) 10285 } else { 10286 prg.edgePrep(m1, m0, n0, n1) 10287 } 10288 10289 // Move to row |n0|, pointed to by |p| 10290 n = int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).lh()) - zeroField 10291 p = *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() 10292 if n != n0 { 10293 if n < n0 { 10294 for { 10295 n = n + 1 10296 p = *(*prg.mem[p].hh()).rh() 10297 if n == n0 { 10298 break 10299 } 10300 } 10301 } else { 10302 for { 10303 n = n - 1 10304 p = *(*prg.mem[p].hh()).lh() 10305 if n == n0 { 10306 break 10307 } 10308 } 10309 } 10310 } 10311 y0 = 0200000 - y0 10312 for true { 10313 r1 = prg.getAvail() 10314 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[int32(p)+1].hh()).lh() 10315 *(*prg.mem[int32(p)+1].hh()).lh() = r1 10316 10317 tx = prg.takeFraction(delx, prg.makeFraction(y0, dely)) 10318 if prg.abVsCd(delx, y0, dely, tx) < 0 { 10319 tx = tx - 1 10320 } 10321 // now $|tx|=\lfloor|y0|\cdot|delx|/|dely|\rfloor$ 10322 *(*prg.mem[r1].hh()).lh() = uint16(8*prg.roundUnscaled(x0+tx) + base) 10323 10324 y1 = y1 - 0200000 10325 if prg.internal[tracingEdges-1] > 0 { 10326 prg.traceNewEdge(r1, n) 10327 } 10328 if y1 < 0200000 { 10329 goto done 10330 } 10331 p = *(*prg.mem[p].hh()).rh() 10332 y0 = y0 + 0200000 10333 n = n + 1 10334 } 10335 10336 done: 10337 } else { 10338 // Insert downward edges for a line 10339 base = 8*int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) + 0 + zeroW + prg.curWt 10340 if m0 <= m1 { 10341 prg.edgePrep(m0, m1, n1, n0) 10342 } else { 10343 prg.edgePrep(m1, m0, n1, n0) 10344 } 10345 n0 = n0 - 1 10346 // Move to row |n0|, pointed to by |p| 10347 n = int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).lh()) - zeroField 10348 p = *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() 10349 if n != n0 { 10350 if n < n0 { 10351 for { 10352 n = n + 1 10353 p = *(*prg.mem[p].hh()).rh() 10354 if n == n0 { 10355 break 10356 } 10357 } 10358 } else { 10359 for { 10360 n = n - 1 10361 p = *(*prg.mem[p].hh()).lh() 10362 if n == n0 { 10363 break 10364 } 10365 } 10366 } 10367 } 10368 for true { 10369 r1 = prg.getAvail() 10370 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[int32(p)+1].hh()).lh() 10371 *(*prg.mem[int32(p)+1].hh()).lh() = r1 10372 10373 tx = prg.takeFraction(delx, prg.makeFraction(y0, dely)) 10374 if prg.abVsCd(delx, y0, dely, tx) < 0 { 10375 tx = tx + 1 10376 } 10377 // now $|tx|=\lceil|y0|\cdot|delx|/|dely|\rceil$, since |dely<0| 10378 *(*prg.mem[r1].hh()).lh() = uint16(8*prg.roundUnscaled(x0-tx) + base) 10379 10380 y1 = y1 + 0200000 10381 if prg.internal[tracingEdges-1] > 0 { 10382 prg.traceNewEdge(r1, n) 10383 } 10384 if y1 >= 0 { 10385 goto done1 10386 } 10387 p = *(*prg.mem[p].hh()).lh() 10388 y0 = y0 + 0200000 10389 n = n - 1 10390 } 10391 10392 done1: 10393 } 10394 *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() = p 10395 *(*prg.mem[int32(prg.curEdges)+5].hh()).lh() = uint16(n + zeroField) 10396 } 10397 } 10398 10399 // 378. 10400 10401 // tangle:pos ../../mf.web:8114:3: 10402 10403 // \MF\ inserts most of its edges into edge structures via the 10404 // |move_to_edges| subroutine, which uses the data stored in the |move| array 10405 // to specify a sequence of ``rook moves.'' The starting point |(m0,n0)| 10406 // and finishing point |(m1,n1)| of these moves, as seen from the standpoint 10407 // of the first octant, are supplied as parameters; the moves should, however, 10408 // be rotated into a given octant. (We're going to study octant 10409 // transformations in great detail later; the reader may wish to come back to 10410 // this part of the program after mastering the mysteries of octants.) 10411 // 10412 // The rook moves themselves are defined as follows, from a |first_octant| 10413 // point of view: ``Go right |move[k]| steps, then go up one, for |0<=k<n1-n0|; 10414 // then go right |move[n1-n0]| steps and stop.'' The sum of |move[k]| 10415 // for |0<=k<=n1-n0| will be equal to |m1-m0|. 10416 // 10417 // As in the |line_edges| routine, we use |+cur_wt| as the weight of 10418 // all downward edges and |-cur_wt| as the weight of all upward edges, 10419 // after the moves have been rotated to the proper octant direction. 10420 // 10421 // There are two main cases to consider: \\[fast\_case] is for moves that 10422 // travel in the direction of octants 1, 4, 5, and~8, while \\[slow\_case] 10423 // is for moves that travel toward octants 2, 3, 6, and~7. The latter directions 10424 // are comparatively cumbersome because they generate more upward or downward 10425 // edges; a curve that travels horizontally doesn't produce any edges at all, 10426 // but a curve that travels vertically touches lots of rows. 10427 func (prg *prg) moveToEdges(m0, n0, m1, n1 int32) { 10428 var ( 10429 delta/* 0..moveSize */ uint16 // extent of |move| data 10430 k/* 0..moveSize */ uint16 // index into |move| 10431 p, r1 halfword // list manipulation registers 10432 dx int32 // change in edge-weight |info| when |x| changes by 1 10433 edgeAndWeight int32 // |info| to insert 10434 j int32 // number of consecutive vertical moves 10435 n int32 // the current row pointed to by |p| 10436 // sum:integer; [ ] 10437 ) 10438 delta = uint16(n1 - n0) 10439 // sum:=move[0]; for k:=1 to delta do sum:=sum+abs(move[k]); 10440 // if sum<>m1-m0 then confusion(["0"=]48); [ ] 10441 10442 // \xref[this can't happen 0][\quad 0] 10443 10444 // Prepare for and switch to the appropriate case, based on |octant| 10445 switch prg.octant { 10446 case firstOctant: 10447 dx = 8 10448 prg.edgePrep(m0, m1, n0, n1) 10449 goto fastCaseUp 10450 10451 case secondOctant: 10452 dx = 8 10453 prg.edgePrep(n0, n1, m0, m1) 10454 goto slowCaseUp 10455 10456 case thirdOctant: 10457 dx = -8 10458 prg.edgePrep(-n1, -n0, m0, m1) 10459 n0 = -n0 10460 10461 goto slowCaseUp 10462 10463 case fourthOctant: 10464 dx = -8 10465 prg.edgePrep(-m1, -m0, n0, n1) 10466 m0 = -m0 10467 10468 goto fastCaseUp 10469 10470 case fifthOctant: 10471 dx = -8 10472 prg.edgePrep(-m1, -m0, -n1, -n0) 10473 m0 = -m0 10474 10475 goto fastCaseDown 10476 10477 case sixthOctant: 10478 dx = -8 10479 prg.edgePrep(-n1, -n0, -m1, -m0) 10480 n0 = -n0 10481 10482 goto slowCaseDown 10483 10484 case seventhOctant: 10485 dx = 8 10486 prg.edgePrep(n0, n1, -m1, -m0) 10487 goto slowCaseDown 10488 10489 case eighthOctant: 10490 dx = 8 10491 prg.edgePrep(m0, m1, -n1, -n0) 10492 goto fastCaseDown 10493 10494 } // there are only eight octants 10495 10496 fastCaseUp: 10497 n = int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).lh()) - zeroField 10498 p = *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() 10499 if n != n0 { 10500 if n < n0 { 10501 for { 10502 n = n + 1 10503 p = *(*prg.mem[p].hh()).rh() 10504 if n == n0 { 10505 break 10506 } 10507 } 10508 } else { 10509 for { 10510 n = n - 1 10511 p = *(*prg.mem[p].hh()).lh() 10512 if n == n0 { 10513 break 10514 } 10515 } 10516 } 10517 } 10518 if int32(delta) > 0 { 10519 k = 0 10520 edgeAndWeight = 8*(m0+int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())) + 0 + zeroW - prg.curWt 10521 for { 10522 edgeAndWeight = edgeAndWeight + dx*prg.move[k] 10523 /* */ { 10524 r1 = prg.avail 10525 if int32(r1) == memMin { 10526 r1 = prg.getAvail() 10527 } else { 10528 prg.avail = *(*prg.mem[r1].hh()).rh() 10529 *(*prg.mem[r1].hh()).rh() = uint16(memMin) 10530 prg.dynUsed = prg.dynUsed + 1 10531 } 10532 } 10533 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[int32(p)+1].hh()).lh() 10534 *(*prg.mem[r1].hh()).lh() = uint16(edgeAndWeight) 10535 if prg.internal[tracingEdges-1] > 0 { 10536 prg.traceNewEdge(r1, n) 10537 } 10538 *(*prg.mem[int32(p)+1].hh()).lh() = r1 10539 p = *(*prg.mem[p].hh()).rh() 10540 k = uint16(int32(k) + 1) 10541 n = n + 1 10542 if int32(k) == int32(delta) { 10543 break 10544 } 10545 } 10546 } 10547 10548 goto done 10549 10550 fastCaseDown: 10551 n0 = -n0 - 1 10552 // Move to row |n0|, pointed to by |p| 10553 n = int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).lh()) - zeroField 10554 p = *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() 10555 if n != n0 { 10556 if n < n0 { 10557 for { 10558 n = n + 1 10559 p = *(*prg.mem[p].hh()).rh() 10560 if n == n0 { 10561 break 10562 } 10563 } 10564 } else { 10565 for { 10566 n = n - 1 10567 p = *(*prg.mem[p].hh()).lh() 10568 if n == n0 { 10569 break 10570 } 10571 } 10572 } 10573 } 10574 if int32(delta) > 0 { 10575 k = 0 10576 edgeAndWeight = 8*(m0+int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())) + 0 + zeroW + prg.curWt 10577 for { 10578 edgeAndWeight = edgeAndWeight + dx*prg.move[k] 10579 /* */ { 10580 r1 = prg.avail 10581 if int32(r1) == memMin { 10582 r1 = prg.getAvail() 10583 } else { 10584 prg.avail = *(*prg.mem[r1].hh()).rh() 10585 *(*prg.mem[r1].hh()).rh() = uint16(memMin) 10586 prg.dynUsed = prg.dynUsed + 1 10587 } 10588 } 10589 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[int32(p)+1].hh()).lh() 10590 *(*prg.mem[r1].hh()).lh() = uint16(edgeAndWeight) 10591 if prg.internal[tracingEdges-1] > 0 { 10592 prg.traceNewEdge(r1, n) 10593 } 10594 *(*prg.mem[int32(p)+1].hh()).lh() = r1 10595 p = *(*prg.mem[p].hh()).lh() 10596 k = uint16(int32(k) + 1) 10597 n = n - 1 10598 if int32(k) == int32(delta) { 10599 break 10600 } 10601 } 10602 } 10603 10604 goto done 10605 10606 slowCaseUp: 10607 edgeAndWeight = 8*(n0+int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())) + 0 + zeroW - prg.curWt 10608 n0 = m0 10609 k = 0 10610 // Move to row |n0|, pointed to by |p| 10611 n = int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).lh()) - zeroField 10612 p = *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() 10613 if n != n0 { 10614 if n < n0 { 10615 for { 10616 n = n + 1 10617 p = *(*prg.mem[p].hh()).rh() 10618 if n == n0 { 10619 break 10620 } 10621 } 10622 } else { 10623 for { 10624 n = n - 1 10625 p = *(*prg.mem[p].hh()).lh() 10626 if n == n0 { 10627 break 10628 } 10629 } 10630 } 10631 } 10632 for { 10633 j = prg.move[k] 10634 for j > 0 { 10635 { 10636 r1 = prg.avail 10637 if int32(r1) == memMin { 10638 r1 = prg.getAvail() 10639 } else { 10640 prg.avail = *(*prg.mem[r1].hh()).rh() 10641 *(*prg.mem[r1].hh()).rh() = uint16(memMin) 10642 prg.dynUsed = prg.dynUsed + 1 10643 } 10644 } 10645 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[int32(p)+1].hh()).lh() 10646 *(*prg.mem[r1].hh()).lh() = uint16(edgeAndWeight) 10647 if prg.internal[tracingEdges-1] > 0 { 10648 prg.traceNewEdge(r1, n) 10649 } 10650 *(*prg.mem[int32(p)+1].hh()).lh() = r1 10651 p = *(*prg.mem[p].hh()).rh() 10652 j = j - 1 10653 n = n + 1 10654 } 10655 edgeAndWeight = edgeAndWeight + dx 10656 k = uint16(int32(k) + 1) 10657 if int32(k) > int32(delta) { 10658 break 10659 } 10660 } 10661 10662 goto done 10663 10664 slowCaseDown: 10665 edgeAndWeight = 8*(n0+int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())) + 0 + zeroW + prg.curWt 10666 n0 = -m0 - 1 10667 k = 0 10668 // Move to row |n0|, pointed to by |p| 10669 n = int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).lh()) - zeroField 10670 p = *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() 10671 if n != n0 { 10672 if n < n0 { 10673 for { 10674 n = n + 1 10675 p = *(*prg.mem[p].hh()).rh() 10676 if n == n0 { 10677 break 10678 } 10679 } 10680 } else { 10681 for { 10682 n = n - 1 10683 p = *(*prg.mem[p].hh()).lh() 10684 if n == n0 { 10685 break 10686 } 10687 } 10688 } 10689 } 10690 for { 10691 j = prg.move[k] 10692 for j > 0 { 10693 { 10694 r1 = prg.avail 10695 if int32(r1) == memMin { 10696 r1 = prg.getAvail() 10697 } else { 10698 prg.avail = *(*prg.mem[r1].hh()).rh() 10699 *(*prg.mem[r1].hh()).rh() = uint16(memMin) 10700 prg.dynUsed = prg.dynUsed + 1 10701 } 10702 } 10703 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[int32(p)+1].hh()).lh() 10704 *(*prg.mem[r1].hh()).lh() = uint16(edgeAndWeight) 10705 if prg.internal[tracingEdges-1] > 0 { 10706 prg.traceNewEdge(r1, n) 10707 } 10708 *(*prg.mem[int32(p)+1].hh()).lh() = r1 10709 p = *(*prg.mem[p].hh()).lh() 10710 j = j - 1 10711 n = n - 1 10712 } 10713 edgeAndWeight = edgeAndWeight + dx 10714 k = uint16(int32(k) + 1) 10715 if int32(k) > int32(delta) { 10716 break 10717 } 10718 } 10719 10720 goto done 10721 10722 done: 10723 *(*prg.mem[int32(prg.curEdges)+5].hh()).lh() = uint16(n + zeroField) 10724 *(*prg.mem[int32(prg.curEdges)+5].hh()).rh() = p 10725 } 10726 10727 // 386. \[21] Subdivision into octants 10728 10729 // tangle:pos ../../mf.web:8266:35: 10730 10731 // When \MF\ digitizes a path, it reduces the problem to the special 10732 // case of paths that travel in ``first octant'' directions; i.e., 10733 // each cubic $z(t)=\bigl(x(t),y(t)\bigr)$ being digitized will have the property 10734 // that $0\L y'(t)\L x'(t)$. This assumption makes digitizing simpler 10735 // and faster than if the direction of motion has to be tested repeatedly. 10736 // 10737 // When $z(t)$ is cubic, $x'(t)$ and $y'(t)$ are quadratic, hence the four 10738 // polynomials $x'(t)$, $y'(t)$, $x'(t)-y'(t)$, and $x'(t)+y'(t)$ cross 10739 // through~0 at most twice each. If we subdivide the given cubic at these 10740 // places, we get at most nine subintervals in each of which 10741 // $x'(t)$, $y'(t)$, $x'(t)-y'(t)$, and $x'(t)+y'(t)$ all have a constant 10742 // sign. The curve can be transformed in each of these subintervals so that 10743 // it travels entirely in first octant directions, if we reflect $x\swap-x$, 10744 // $y\swap-y$, and/or $x\swap y$ as necessary. (Incidentally, it can be 10745 // shown that a cubic such that $x'(t)=16(2t-1)^2+2(2t-1)-1$ and 10746 // $y'(t)=8(2t-1)^2+4(2t-1)$ does indeed split into nine subintervals.) 10747 10748 // 387. 10749 10750 // tangle:pos ../../mf.web:8284:3: 10751 10752 // The transformation that rotates coordinates, so that first octant motion 10753 // can be assumed, is defined by the |skew| subroutine, which sets global 10754 // variables |cur_x| and |cur_y| to the values that are appropriate in a 10755 // given octant. (Octants are encoded as they were in the |n_arg| subroutine.) 10756 // 10757 // This transformation is ``skewed'' by replacing |(x,y)| by |(x-y,y)|, 10758 // once first octant motion has been established. It turns out that 10759 // skewed coordinates are somewhat better to work with when curves are 10760 // actually digitized. 10761 func (prg *prg) skew(x, y scaled, octant smallNumber) { 10762 switch octant { 10763 case firstOctant: 10764 prg.curX = x - y 10765 prg.curY = y 10766 case secondOctant: 10767 prg.curX = y - x 10768 prg.curY = x 10769 case thirdOctant: 10770 prg.curX = y + x 10771 prg.curY = -x 10772 case fourthOctant: 10773 prg.curX = -x - y 10774 prg.curY = y 10775 case fifthOctant: 10776 prg.curX = -x + y 10777 prg.curY = -y 10778 case sixthOctant: 10779 prg.curX = -y + x 10780 prg.curY = -x 10781 case seventhOctant: 10782 prg.curX = -y - x 10783 prg.curY = x 10784 case eighthOctant: 10785 prg.curX = x + y 10786 prg.curY = -y 10787 } // there are no other cases 10788 } 10789 10790 // 390. 10791 10792 // tangle:pos ../../mf.web:8333:3: 10793 10794 // The conversion to skewed and rotated coordinates takes place in 10795 // stages, and at one point in the transformation we will have negated the 10796 // $x$ and/or $y$ coordinates so as to make curves travel in the first 10797 // [\sl quadrant]. At this point the relevant ``octant'' code will be 10798 // either |first_octant| (when no transformation has been done), 10799 // or |fourth_octant=first_octant+negate_x| (when $x$ has been negated), 10800 // or |fifth_octant=first_octant+negate_x+negate_y| (when both have been 10801 // negated), or |eighth_octant=first_octant+negate_y| (when $y$ has been 10802 // negated). The |abnegate| routine is sometimes needed to convert 10803 // from one of these transformations to another. 10804 func (prg *prg) abnegate(x, y scaled, 10805 octantBefore, octantAfter smallNumber) { 10806 if octantBefore&1 != 0 == (octantAfter&1 != 0) { 10807 prg.curX = x 10808 } else { 10809 prg.curX = -x 10810 } 10811 if int32(octantBefore) > negateY == (int32(octantAfter) > negateY) { 10812 prg.curY = y 10813 } else { 10814 prg.curY = -y 10815 } 10816 } 10817 10818 // 391. 10819 10820 // tangle:pos ../../mf.web:8352:3: 10821 10822 // Now here's a subroutine that's handy for subdivision: Given a 10823 // quadratic polynomial $B(a,b,c;t)$, the |crossing_point| function 10824 // returns the unique |fraction| value |t| between 0 and~1 at which 10825 // $B(a,b,c;t)$ changes from positive to negative, or returns 10826 // |t=fraction_one+1| if no such value exists. If |a<0| (so that $B(a,b,c;t)$ 10827 // is already negative at |t=0|), |crossing_point| returns the value zero. 10828 func (prg *prg) crossingPoint(a, b, c int32) (r fraction) { 10829 var ( 10830 d int32 // recursive counter 10831 x, xx, x0, x1, x2 int32 // temporary registers for bisection 10832 ) 10833 if a < 0 { 10834 r = 0 10835 goto exit 10836 } 10837 if c >= 0 { 10838 if b >= 0 { 10839 if c > 0 { 10840 r = 02000000000 + 1 10841 goto exit 10842 } else if a == 0 && b == 0 { 10843 r = 02000000000 + 1 10844 goto exit 10845 } else { 10846 r = 02000000000 10847 goto exit 10848 } 10849 } 10850 if a == 0 { 10851 r = 0 10852 goto exit 10853 } 10854 } else if a == 0 { 10855 if b <= 0 { 10856 r = 0 10857 goto exit 10858 } 10859 } 10860 10861 // Use bisection to find the crossing point, if one exists 10862 d = 1 10863 x0 = a 10864 x1 = a - b 10865 x2 = b - c 10866 for { 10867 x = (x1 + x2) / 2 10868 if x1-x0 > x0 { 10869 x2 = x 10870 x0 = x0 + x0 10871 d = d + d 10872 } else { 10873 xx = x1 + x - x0 10874 if xx > x0 { 10875 x2 = x 10876 x0 = x0 + x0 10877 d = d + d 10878 } else { 10879 x0 = x0 - xx 10880 if x <= x0 { 10881 if x+x2 <= x0 { 10882 r = 02000000000 + 1 10883 goto exit 10884 } 10885 } 10886 x1 = x 10887 d = d + d + 1 10888 } 10889 } 10890 if d >= 02000000000 { 10891 break 10892 } 10893 } 10894 r = d - 02000000000 10895 10896 exit: 10897 ; 10898 return r 10899 } 10900 10901 // 393. 10902 10903 // tangle:pos ../../mf.web:8422:3: 10904 10905 // Octant subdivision is applied only to cycles, i.e., to closed paths. 10906 // A ``cycle spec'' is a data structure that contains specifications of 10907 // \xref[cycle spec] 10908 // cubic curves and octant mappings for the cycle that has been subdivided 10909 // into segments belonging to single octants. It is composed entirely of 10910 // knot nodes, similar to those in the representation of paths; but the 10911 // |explicit| type indications have been replaced by positive numbers 10912 // that give further information. Additional |endpoint| data is also 10913 // inserted at the octant boundaries. 10914 // 10915 // Recall that a cubic polynomial is represented by four control points 10916 // that appear in adjacent nodes |p| and~|q| of a knot list. The |x|~coordinates 10917 // are |x_coord(p)|, |right_x(p)|, |left_x(q)|, and |x_coord(q)|; the 10918 // |y|~coordinates are similar. We shall call this ``the cubic following~|p|'' 10919 // or ``the cubic between |p| and~|q|'' or ``the cubic preceding~|q|.'' 10920 // 10921 // Cycle specs are circular lists of cubic curves mixed with octant 10922 // boundaries. Like cubics, the octant boundaries are represented in 10923 // consecutive knot nodes |p| and~|q|. In such cases |right_type(p)= 10924 // left_type(q)=endpoint|, and the fields |right_x(p)|, |right_y(p)|, 10925 // |left_x(q)|, and |left_y(q)| are replaced by other fields called 10926 // |right_octant(p)|, |right_transition(p)|, |left_octant(q)|, and 10927 // |left_transition(q)|, respectively. For example, when the curve direction 10928 // moves from the third octant to the fourth octant, the boundary nodes say 10929 // |right_octant(p)=third_octant|, |left_octant(q)=fourth_octant|, 10930 // and |right_transition(p)=left_transition(q)=diagonal|. A |diagonal| 10931 // transition occurs when moving between octants 1~\AM~2, 3~\AM~4, 5~\AM~6, or 10932 // 7~\AM~8; an |axis| transition occurs when moving between octants 8~\AM~1, 10933 // 2~\AM~3, 4~\AM~5, 6~\AM~7. (Such transition information is redundant 10934 // but convenient.) Fields |x_coord(p)| and |y_coord(p)| will contain 10935 // coordinates of the transition point after rotation from third octant 10936 // to first octant; i.e., if the true coordinates are $(x,y)$, the 10937 // coordinates $(y,-x)$ will appear in node~|p|. Similarly, a fourth-octant 10938 // transformation will have been applied after the transition, so 10939 // we will have |x_coord(q)=$-x$| and |y_coord(q)=y|. 10940 // 10941 // The cubic between |p| and |q| will contain positive numbers in the 10942 // fields |right_type(p)| and |left_type(q)|; this makes cubics 10943 // distinguishable from octant boundaries, because |endpoint=0|. 10944 // The value of |right_type(p)| will be the current octant code, 10945 // during the time that cycle specs are being constructed; it will 10946 // refer later to a pen offset position, if the envelope of a cycle is 10947 // being computed. A cubic that comes from some subinterval of the $k$th 10948 // step in the original cyclic path will have |left_type(q)=k|. 10949 10950 // 394. 10951 10952 // tangle:pos ../../mf.web:8474:3: 10953 10954 // Here's a routine that prints a cycle spec in symbolic form, so that it 10955 // is possible to see what subdivision has been made. The point coordinates 10956 // are converted back from \MF's internal ``rotated'' form to the external 10957 // ``true'' form. The global variable~|cur_spec| should point to a knot just 10958 // after the beginning of an octant boundary, i.e., such that 10959 // |left_type(cur_spec)=endpoint|. 10960 func (prg *prg) printSpec(s strNumber) { 10961 var ( 10962 p, q halfword // for list traversal 10963 octant smallNumber // the current octant code 10964 ) 10965 prg.printDiagnostic(strNumber( /* "Cycle spec" */ 544), s, true) 10966 // \xref[Cycle spec at line...] 10967 p = prg.curSpec 10968 octant = byte(*prg.mem[int32(p)+3].int()) 10969 prg.printLn() 10970 prg.unskew(*prg.mem[int32(prg.curSpec)+1].int(), *prg.mem[int32(prg.curSpec)+2].int(), octant) 10971 prg.printTwo(prg.curX, prg.curY) 10972 prg.print( /* " % beginning in octant `" */ 545) 10973 for true { 10974 prg.print(int32(prg.octantDir[octant-1])) 10975 prg.printChar(asciiCode('\'')) 10976 for true { 10977 q = *(*prg.mem[p].hh()).rh() 10978 if int32(*(*prg.mem[p].hh()).b1()) == endpoint { 10979 goto notFound 10980 } 10981 10982 // Print the cubic between |p| and |q| 10983 { 10984 prg.printNl(strNumber( /* " ..controls " */ 556)) 10985 prg.unskew(*prg.mem[int32(p)+5].int(), *prg.mem[int32(p)+6].int(), octant) 10986 prg.printTwo(prg.curX, prg.curY) 10987 prg.print( /* " and " */ 523) 10988 prg.unskew(*prg.mem[int32(q)+3].int(), *prg.mem[int32(q)+4].int(), octant) 10989 prg.printTwo(prg.curX, prg.curY) 10990 prg.printNl(strNumber( /* " .." */ 520)) 10991 prg.unskew(*prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int(), octant) 10992 prg.printTwo(prg.curX, prg.curY) 10993 prg.print( /* " % segment " */ 557) 10994 prg.printInt(int32(*(*prg.mem[q].hh()).b0()) - 1) 10995 } 10996 p = q 10997 } 10998 10999 notFound: 11000 if int32(q) == int32(prg.curSpec) { 11001 goto done 11002 } 11003 p = q 11004 octant = byte(*prg.mem[int32(p)+3].int()) 11005 prg.printNl(strNumber( /* "% entering octant `" */ 546)) 11006 } 11007 // \xref[entering the nth octant] 11008 11009 // \xref[entering the nth octant] 11010 done: 11011 prg.printNl(strNumber( /* " & cycle" */ 547)) 11012 prg.endDiagnostic(true) 11013 } 11014 11015 // 398. 11016 11017 // tangle:pos ../../mf.web:8530:3: 11018 11019 // A much more compact version of a spec is printed to help users identify 11020 // ``strange paths.'' 11021 func (prg *prg) printStrange(s strNumber) { 11022 var ( 11023 p halfword // for list traversal 11024 f halfword // starting point in the cycle 11025 q halfword // octant boundary to be printed 11026 t int32 // segment number, plus 1 11027 ) 11028 if int32(prg.interaction) == errorStopMode { 11029 } 11030 prg.printNl(strNumber('>')) 11031 // \xref[>\relax] 11032 11033 // Find the starting point, |f| 11034 p = prg.curSpec 11035 t = maxQuarterword + 1 11036 for { 11037 p = *(*prg.mem[p].hh()).rh() 11038 if int32(*(*prg.mem[p].hh()).b0()) != endpoint { 11039 if int32(*(*prg.mem[p].hh()).b0()) < t { 11040 f = p 11041 } 11042 t = int32(*(*prg.mem[p].hh()).b0()) 11043 } 11044 if int32(p) == int32(prg.curSpec) { 11045 break 11046 } 11047 } 11048 11049 // Determine the octant boundary |q| that precedes |f| 11050 p = prg.curSpec 11051 q = p 11052 for { 11053 p = *(*prg.mem[p].hh()).rh() 11054 if int32(*(*prg.mem[p].hh()).b0()) == endpoint { 11055 q = p 11056 } 11057 if int32(p) == int32(f) { 11058 break 11059 } 11060 } 11061 t = 0 11062 for { 11063 if int32(*(*prg.mem[p].hh()).b0()) != endpoint { 11064 if int32(*(*prg.mem[p].hh()).b0()) != t { 11065 t = int32(*(*prg.mem[p].hh()).b0()) 11066 prg.printChar(asciiCode(' ')) 11067 prg.printInt(t - 1) 11068 } 11069 if int32(q) != memMin { 11070 if int32(*(*prg.mem[*(*prg.mem[q].hh()).rh()].hh()).b0()) == endpoint { 11071 prg.print( /* " (" */ 558) 11072 prg.print(int32(prg.octantDir[*prg.mem[int32(q)+3].int()-1])) 11073 q = *(*prg.mem[q].hh()).rh() 11074 for int32(*(*prg.mem[*(*prg.mem[q].hh()).rh()].hh()).b0()) == endpoint { 11075 prg.printChar(asciiCode(' ')) 11076 prg.print(int32(prg.octantDir[*prg.mem[int32(q)+3].int()-1])) 11077 q = *(*prg.mem[q].hh()).rh() 11078 } 11079 prg.printChar(asciiCode(')')) 11080 } 11081 prg.printChar(asciiCode(' ')) 11082 prg.print(int32(prg.octantDir[*prg.mem[int32(q)+3].int()-1])) 11083 q = uint16(memMin) 11084 } 11085 } else if int32(q) == memMin { 11086 q = p 11087 } 11088 p = *(*prg.mem[p].hh()).rh() 11089 if int32(p) == int32(f) { 11090 break 11091 } 11092 } 11093 prg.printChar(asciiCode(' ')) 11094 prg.printInt(int32(*(*prg.mem[p].hh()).b0()) - 1) 11095 if int32(q) != memMin { 11096 if int32(*(*prg.mem[*(*prg.mem[q].hh()).rh()].hh()).b0()) == endpoint { 11097 prg.print( /* " (" */ 558) 11098 prg.print(int32(prg.octantDir[*prg.mem[int32(q)+3].int()-1])) 11099 q = *(*prg.mem[q].hh()).rh() 11100 for int32(*(*prg.mem[*(*prg.mem[q].hh()).rh()].hh()).b0()) == endpoint { 11101 prg.printChar(asciiCode(' ')) 11102 prg.print(int32(prg.octantDir[*prg.mem[int32(q)+3].int()-1])) 11103 q = *(*prg.mem[q].hh()).rh() 11104 } 11105 prg.printChar(asciiCode(')')) 11106 } 11107 } 11108 { 11109 if int32(prg.interaction) == errorStopMode { 11110 } 11111 prg.printNl(strNumber( /* "! " */ 261)) 11112 prg.print(int32(s)) /* \xref[!\relax] */ 11113 } 11114 } 11115 11116 // 402. 11117 11118 // tangle:pos ../../mf.web:8597:3: 11119 11120 // The |make_spec| routine is what subdivides paths into octants: 11121 // Given a pointer |cur_spec| to a cyclic path, |make_spec| mungs the path data 11122 // and returns a pointer to the corresponding cyclic spec. 11123 // All “dead” cubics (i.e., cubics that don't move at all from 11124 // their starting points) will have been removed from the result. 11125 // 11126 // \xref[dead cubics] 11127 // 11128 // The idea of |make_spec| is fairly simple: Each cubic is first 11129 // subdivided, if necessary, into pieces belonging to single octants; 11130 // then the octant boundaries are inserted. But some of the details of 11131 // this transformation are not quite obvious. 11132 // 11133 // If |autorounding>0|, the path will be adjusted so that critical tangent 11134 // directions occur at “good” points with respect to the pen called |cur_pen|. 11135 // 11136 // The resulting spec will have all |x| and |y| coordinates at most 11137 // $2^[28]-|half_unit|-1-|safety_margin|$ in absolute value. The pointer 11138 // that is returned will start some octant, as required by |print_spec|. 11139 // \4 11140 // Declare subroutines needed by |make_spec| 11141 func (prg *prg) removeCubic(p halfword) { // removes the cubic following~|p| 11142 var ( 11143 q halfword // the node that disappears 11144 ) 11145 q = *(*prg.mem[p].hh()).rh() 11146 *(*prg.mem[p].hh()).b1() = *(*prg.mem[q].hh()).b1() 11147 *(*prg.mem[p].hh()).rh() = *(*prg.mem[q].hh()).rh() 11148 11149 *prg.mem[int32(p)+1].int() = *prg.mem[int32(q)+1].int() 11150 *prg.mem[int32(p)+2].int() = *prg.mem[int32(q)+2].int() 11151 11152 *prg.mem[int32(p)+5].int() = *prg.mem[int32(q)+5].int() 11153 *prg.mem[int32(p)+6].int() = *prg.mem[int32(q)+6].int() 11154 11155 prg.freeNode(q, halfword(knotNodeSize)) 11156 } 11157 11158 // \4 11159 // Declare the procedure called |split_cubic| 11160 func (prg *prg) splitCubic(p halfword, t fraction, 11161 xq, yq scaled) { // splits the cubic after |p| 11162 var ( 11163 v scaled // an intermediate value 11164 q, r1 halfword // for list manipulation 11165 ) 11166 q = *(*prg.mem[p].hh()).rh() 11167 r1 = prg.getNode(knotNodeSize) 11168 *(*prg.mem[p].hh()).rh() = r1 11169 *(*prg.mem[r1].hh()).rh() = q 11170 11171 *(*prg.mem[r1].hh()).b0() = *(*prg.mem[q].hh()).b0() 11172 *(*prg.mem[r1].hh()).b1() = *(*prg.mem[p].hh()).b1() 11173 11174 v = *prg.mem[int32(p)+5].int() - prg.takeFraction(*prg.mem[int32(p)+5].int()-*prg.mem[int32(q)+3].int(), t) 11175 *prg.mem[int32(p)+5].int() = *prg.mem[int32(p)+1].int() - prg.takeFraction(*prg.mem[int32(p)+1].int()-*prg.mem[int32(p)+5].int(), t) 11176 *prg.mem[int32(q)+3].int() = *prg.mem[int32(q)+3].int() - prg.takeFraction(*prg.mem[int32(q)+3].int()-xq, t) 11177 *prg.mem[int32(r1)+3].int() = *prg.mem[int32(p)+5].int() - prg.takeFraction(*prg.mem[int32(p)+5].int()-v, t) 11178 *prg.mem[int32(r1)+5].int() = v - prg.takeFraction(v-*prg.mem[int32(q)+3].int(), t) 11179 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(r1)+3].int() - prg.takeFraction(*prg.mem[int32(r1)+3].int()-*prg.mem[int32(r1)+5].int(), t) 11180 11181 v = *prg.mem[int32(p)+6].int() - prg.takeFraction(*prg.mem[int32(p)+6].int()-*prg.mem[int32(q)+4].int(), t) 11182 *prg.mem[int32(p)+6].int() = *prg.mem[int32(p)+2].int() - prg.takeFraction(*prg.mem[int32(p)+2].int()-*prg.mem[int32(p)+6].int(), t) 11183 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+4].int() - prg.takeFraction(*prg.mem[int32(q)+4].int()-yq, t) 11184 *prg.mem[int32(r1)+4].int() = *prg.mem[int32(p)+6].int() - prg.takeFraction(*prg.mem[int32(p)+6].int()-v, t) 11185 *prg.mem[int32(r1)+6].int() = v - prg.takeFraction(v-*prg.mem[int32(q)+4].int(), t) 11186 *prg.mem[int32(r1)+2].int() = *prg.mem[int32(r1)+4].int() - prg.takeFraction(*prg.mem[int32(r1)+4].int()-*prg.mem[int32(r1)+6].int(), t) 11187 } 11188 11189 func (prg *prg) quadrantSubdivide() { 11190 var ( 11191 p, q, r1, s, pp, qq halfword // for traversing the lists 11192 firstX, firstY scaled // unnegated coordinates of node |cur_spec| 11193 del1, del2, del3, del, dmax scaled // proportional to the control 11194 // points of a quadratic derived from a cubic 11195 11196 t fraction // where a quadratic crosses zero 11197 destX, destY scaled // final values of |x| and |y| in the current cubic 11198 constantX bool // is |x| constant between |p| and |q|? 11199 ) 11200 p = prg.curSpec 11201 firstX = *prg.mem[int32(prg.curSpec)+1].int() 11202 firstY = *prg.mem[int32(prg.curSpec)+2].int() 11203 for { 11204 continue1: 11205 q = *(*prg.mem[p].hh()).rh() 11206 11207 // Subdivide the cubic between |p| and |q| so that the results travel toward the right halfplane 11208 if int32(q) == int32(prg.curSpec) { 11209 destX = firstX 11210 destY = firstY 11211 } else { 11212 destX = *prg.mem[int32(q)+1].int() 11213 destY = *prg.mem[int32(q)+2].int() 11214 } 11215 del1 = *prg.mem[int32(p)+5].int() - *prg.mem[int32(p)+1].int() 11216 del2 = *prg.mem[int32(q)+3].int() - *prg.mem[int32(p)+5].int() 11217 del3 = destX - *prg.mem[int32(q)+3].int() 11218 11219 // Scale up |del1|, |del2|, and |del3| for greater accuracy; also set |del| to the first nonzero element of |(del1,del2,del3)| 11220 if del1 != 0 { 11221 del = del1 11222 } else if del2 != 0 { 11223 del = del2 11224 } else { 11225 del = del3 11226 } 11227 if del != 0 { 11228 dmax = abs(del1) 11229 if abs(del2) > dmax { 11230 dmax = abs(del2) 11231 } 11232 if abs(del3) > dmax { 11233 dmax = abs(del3) 11234 } 11235 for dmax < 01000000000 { 11236 dmax = dmax + dmax 11237 del1 = del1 + del1 11238 del2 = del2 + del2 11239 del3 = del3 + del3 11240 } 11241 } 11242 if del == 0 { 11243 constantX = true 11244 } else { 11245 constantX = false 11246 if del < 0 { 11247 *prg.mem[int32(p)+1].int() = -*prg.mem[int32(p)+1].int() 11248 *prg.mem[int32(p)+5].int() = -*prg.mem[int32(p)+5].int() 11249 *prg.mem[int32(q)+3].int() = -*prg.mem[int32(q)+3].int() 11250 11251 del1 = -del1 11252 del2 = -del2 11253 del3 = -del3 11254 11255 destX = -destX 11256 *(*prg.mem[p].hh()).b1() = byte(firstOctant + negateX) 11257 } 11258 t = prg.crossingPoint(del1, del2, del3) 11259 if t < 02000000000 { 11260 prg.splitCubic(p, t, destX, destY) 11261 r1 = *(*prg.mem[p].hh()).rh() 11262 if int32(*(*prg.mem[r1].hh()).b1()) > negateX { 11263 *(*prg.mem[r1].hh()).b1() = byte(firstOctant) 11264 } else { 11265 *(*prg.mem[r1].hh()).b1() = byte(firstOctant + negateX) 11266 } 11267 if *prg.mem[int32(r1)+1].int() < *prg.mem[int32(p)+1].int() { 11268 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(p)+1].int() 11269 } 11270 *prg.mem[int32(r1)+3].int() = *prg.mem[int32(r1)+1].int() 11271 if *prg.mem[int32(p)+5].int() > *prg.mem[int32(r1)+1].int() { 11272 *prg.mem[int32(p)+5].int() = *prg.mem[int32(r1)+1].int() 11273 } 11274 // we always have |x_coord(p)<=right_x(p)| 11275 *prg.mem[int32(r1)+1].int() = -*prg.mem[int32(r1)+1].int() 11276 *prg.mem[int32(r1)+5].int() = *prg.mem[int32(r1)+1].int() 11277 *prg.mem[int32(q)+3].int() = -*prg.mem[int32(q)+3].int() 11278 destX = -destX 11279 11280 del2 = del2 - prg.takeFraction(del2-del3, t) 11281 // now |0,del2,del3| represent $x'$ on the remaining interval 11282 if del2 > 0 { 11283 del2 = 0 11284 } 11285 t = prg.crossingPoint(0, -del2, -del3) 11286 if t < 02000000000 { 11287 prg.splitCubic(r1, t, destX, destY) 11288 s = *(*prg.mem[r1].hh()).rh() 11289 if *prg.mem[int32(s)+1].int() < destX { 11290 *prg.mem[int32(s)+1].int() = destX 11291 } 11292 if *prg.mem[int32(s)+1].int() < *prg.mem[int32(r1)+1].int() { 11293 *prg.mem[int32(s)+1].int() = *prg.mem[int32(r1)+1].int() 11294 } 11295 *(*prg.mem[s].hh()).b1() = *(*prg.mem[p].hh()).b1() 11296 *prg.mem[int32(s)+3].int() = *prg.mem[int32(s)+1].int() // now |x_coord(r)=right_x(r)<=left_x(s)| 11297 if *prg.mem[int32(q)+3].int() < destX { 11298 *prg.mem[int32(q)+3].int() = -destX 11299 } else if *prg.mem[int32(q)+3].int() > *prg.mem[int32(s)+1].int() { 11300 *prg.mem[int32(q)+3].int() = -*prg.mem[int32(s)+1].int() 11301 } else { 11302 *prg.mem[int32(q)+3].int() = -*prg.mem[int32(q)+3].int() 11303 } 11304 *prg.mem[int32(s)+1].int() = -*prg.mem[int32(s)+1].int() 11305 *prg.mem[int32(s)+5].int() = *prg.mem[int32(s)+1].int() 11306 } else { 11307 if *prg.mem[int32(r1)+1].int() > destX { 11308 *prg.mem[int32(r1)+1].int() = destX 11309 *prg.mem[int32(r1)+3].int() = -*prg.mem[int32(r1)+1].int() 11310 *prg.mem[int32(r1)+5].int() = *prg.mem[int32(r1)+1].int() 11311 } 11312 if *prg.mem[int32(q)+3].int() > destX { 11313 *prg.mem[int32(q)+3].int() = destX 11314 } else if *prg.mem[int32(q)+3].int() < *prg.mem[int32(r1)+1].int() { 11315 *prg.mem[int32(q)+3].int() = *prg.mem[int32(r1)+1].int() 11316 } 11317 } 11318 } 11319 } 11320 11321 // Subdivide all cubics between |p| and |q| so that the results travel toward the first quadrant; but |return| or |goto continue| if the cubic from |p| to |q| was dead 11322 pp = p 11323 for { 11324 qq = *(*prg.mem[pp].hh()).rh() 11325 prg.abnegate(*prg.mem[int32(qq)+1].int(), *prg.mem[int32(qq)+2].int(), *(*prg.mem[qq].hh()).b1(), *(*prg.mem[pp].hh()).b1()) 11326 destX = prg.curX 11327 destY = prg.curY 11328 11329 del1 = *prg.mem[int32(pp)+6].int() - *prg.mem[int32(pp)+2].int() 11330 del2 = *prg.mem[int32(qq)+4].int() - *prg.mem[int32(pp)+6].int() 11331 del3 = destY - *prg.mem[int32(qq)+4].int() 11332 11333 // Scale up |del1|, |del2|, and |del3| for greater accuracy; also set |del| to the first nonzero element of |(del1,del2,del3)| 11334 if del1 != 0 { 11335 del = del1 11336 } else if del2 != 0 { 11337 del = del2 11338 } else { 11339 del = del3 11340 } 11341 if del != 0 { 11342 dmax = abs(del1) 11343 if abs(del2) > dmax { 11344 dmax = abs(del2) 11345 } 11346 if abs(del3) > dmax { 11347 dmax = abs(del3) 11348 } 11349 for dmax < 01000000000 { 11350 dmax = dmax + dmax 11351 del1 = del1 + del1 11352 del2 = del2 + del2 11353 del3 = del3 + del3 11354 } 11355 } 11356 if del != 0 { 11357 if del < 0 { 11358 *prg.mem[int32(pp)+2].int() = -*prg.mem[int32(pp)+2].int() 11359 *prg.mem[int32(pp)+6].int() = -*prg.mem[int32(pp)+6].int() 11360 *prg.mem[int32(qq)+4].int() = -*prg.mem[int32(qq)+4].int() 11361 11362 del1 = -del1 11363 del2 = -del2 11364 del3 = -del3 11365 11366 destY = -destY 11367 *(*prg.mem[pp].hh()).b1() = byte(int32(*(*prg.mem[pp].hh()).b1()) + negateY) 11368 } 11369 t = prg.crossingPoint(del1, del2, del3) 11370 if t < 02000000000 { 11371 prg.splitCubic(pp, t, destX, destY) 11372 r1 = *(*prg.mem[pp].hh()).rh() 11373 if int32(*(*prg.mem[r1].hh()).b1()) > negateY { 11374 *(*prg.mem[r1].hh()).b1() = byte(int32(*(*prg.mem[r1].hh()).b1()) - negateY) 11375 } else { 11376 *(*prg.mem[r1].hh()).b1() = byte(int32(*(*prg.mem[r1].hh()).b1()) + negateY) 11377 } 11378 if *prg.mem[int32(r1)+2].int() < *prg.mem[int32(pp)+2].int() { 11379 *prg.mem[int32(r1)+2].int() = *prg.mem[int32(pp)+2].int() 11380 } 11381 *prg.mem[int32(r1)+4].int() = *prg.mem[int32(r1)+2].int() 11382 if *prg.mem[int32(pp)+6].int() > *prg.mem[int32(r1)+2].int() { 11383 *prg.mem[int32(pp)+6].int() = *prg.mem[int32(r1)+2].int() 11384 } 11385 // we always have |y_coord(pp)<=right_y(pp)| 11386 *prg.mem[int32(r1)+2].int() = -*prg.mem[int32(r1)+2].int() 11387 *prg.mem[int32(r1)+6].int() = *prg.mem[int32(r1)+2].int() 11388 *prg.mem[int32(qq)+4].int() = -*prg.mem[int32(qq)+4].int() 11389 destY = -destY 11390 11391 if *prg.mem[int32(r1)+1].int() < *prg.mem[int32(pp)+1].int() { 11392 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(pp)+1].int() 11393 } else if *prg.mem[int32(r1)+1].int() > destX { 11394 *prg.mem[int32(r1)+1].int() = destX 11395 } 11396 if *prg.mem[int32(r1)+3].int() > *prg.mem[int32(r1)+1].int() { 11397 *prg.mem[int32(r1)+3].int() = *prg.mem[int32(r1)+1].int() 11398 if *prg.mem[int32(pp)+5].int() > *prg.mem[int32(r1)+1].int() { 11399 *prg.mem[int32(pp)+5].int() = *prg.mem[int32(r1)+1].int() 11400 } 11401 } 11402 if *prg.mem[int32(r1)+5].int() < *prg.mem[int32(r1)+1].int() { 11403 *prg.mem[int32(r1)+5].int() = *prg.mem[int32(r1)+1].int() 11404 if *prg.mem[int32(qq)+3].int() < *prg.mem[int32(r1)+1].int() { 11405 *prg.mem[int32(qq)+3].int() = *prg.mem[int32(r1)+1].int() 11406 } 11407 } 11408 del2 = del2 - prg.takeFraction(del2-del3, t) 11409 // now |0,del2,del3| represent $y'$ on the remaining interval 11410 if del2 > 0 { 11411 del2 = 0 11412 } 11413 t = prg.crossingPoint(0, -del2, -del3) 11414 if t < 02000000000 { 11415 prg.splitCubic(r1, t, destX, destY) 11416 s = *(*prg.mem[r1].hh()).rh() 11417 11418 if *prg.mem[int32(s)+2].int() < destY { 11419 *prg.mem[int32(s)+2].int() = destY 11420 } 11421 if *prg.mem[int32(s)+2].int() < *prg.mem[int32(r1)+2].int() { 11422 *prg.mem[int32(s)+2].int() = *prg.mem[int32(r1)+2].int() 11423 } 11424 *(*prg.mem[s].hh()).b1() = *(*prg.mem[pp].hh()).b1() 11425 *prg.mem[int32(s)+4].int() = *prg.mem[int32(s)+2].int() // now |y_coord(r)=right_y(r)<=left_y(s)| 11426 if *prg.mem[int32(qq)+4].int() < destY { 11427 *prg.mem[int32(qq)+4].int() = -destY 11428 } else if *prg.mem[int32(qq)+4].int() > *prg.mem[int32(s)+2].int() { 11429 *prg.mem[int32(qq)+4].int() = -*prg.mem[int32(s)+2].int() 11430 } else { 11431 *prg.mem[int32(qq)+4].int() = -*prg.mem[int32(qq)+4].int() 11432 } 11433 *prg.mem[int32(s)+2].int() = -*prg.mem[int32(s)+2].int() 11434 *prg.mem[int32(s)+6].int() = *prg.mem[int32(s)+2].int() 11435 if *prg.mem[int32(s)+1].int() < *prg.mem[int32(r1)+1].int() { 11436 *prg.mem[int32(s)+1].int() = *prg.mem[int32(r1)+1].int() 11437 } else if *prg.mem[int32(s)+1].int() > destX { 11438 *prg.mem[int32(s)+1].int() = destX 11439 } 11440 if *prg.mem[int32(s)+3].int() > *prg.mem[int32(s)+1].int() { 11441 *prg.mem[int32(s)+3].int() = *prg.mem[int32(s)+1].int() 11442 if *prg.mem[int32(r1)+5].int() > *prg.mem[int32(s)+1].int() { 11443 *prg.mem[int32(r1)+5].int() = *prg.mem[int32(s)+1].int() 11444 } 11445 } 11446 if *prg.mem[int32(s)+5].int() < *prg.mem[int32(s)+1].int() { 11447 *prg.mem[int32(s)+5].int() = *prg.mem[int32(s)+1].int() 11448 if *prg.mem[int32(qq)+3].int() < *prg.mem[int32(s)+1].int() { 11449 *prg.mem[int32(qq)+3].int() = *prg.mem[int32(s)+1].int() 11450 } 11451 } 11452 } else { 11453 if *prg.mem[int32(r1)+2].int() > destY { 11454 *prg.mem[int32(r1)+2].int() = destY 11455 *prg.mem[int32(r1)+4].int() = -*prg.mem[int32(r1)+2].int() 11456 *prg.mem[int32(r1)+6].int() = *prg.mem[int32(r1)+2].int() 11457 } 11458 if *prg.mem[int32(qq)+4].int() > destY { 11459 *prg.mem[int32(qq)+4].int() = destY 11460 } else if *prg.mem[int32(qq)+4].int() < *prg.mem[int32(r1)+2].int() { 11461 *prg.mem[int32(qq)+4].int() = *prg.mem[int32(r1)+2].int() 11462 } 11463 } 11464 } 11465 } else if constantX { 11466 if int32(q) != int32(p) { 11467 prg.removeCubic(p) // remove the dead cycle and recycle node |q| 11468 if int32(prg.curSpec) != int32(q) { 11469 goto continue1 11470 } else { 11471 prg.curSpec = p 11472 goto exit 11473 } // the final cubic was dead and is gone 11474 } 11475 } else if !(*(*prg.mem[pp].hh()).b1()&1 != 0) { 11476 *prg.mem[int32(pp)+2].int() = -*prg.mem[int32(pp)+2].int() 11477 *prg.mem[int32(pp)+6].int() = -*prg.mem[int32(pp)+6].int() 11478 *prg.mem[int32(qq)+4].int() = -*prg.mem[int32(qq)+4].int() 11479 11480 del1 = -del1 11481 del2 = -del2 11482 del3 = -del3 11483 11484 destY = -destY 11485 *(*prg.mem[pp].hh()).b1() = byte(int32(*(*prg.mem[pp].hh()).b1()) + negateY) 11486 } 11487 pp = qq 11488 if int32(pp) == int32(q) { 11489 break 11490 } 11491 } 11492 if constantX { 11493 pp = p 11494 for { 11495 qq = *(*prg.mem[pp].hh()).rh() 11496 if int32(*(*prg.mem[pp].hh()).b1()) > negateY { 11497 *(*prg.mem[pp].hh()).b1() = byte(int32(*(*prg.mem[pp].hh()).b1()) + negateX) 11498 *prg.mem[int32(pp)+1].int() = -*prg.mem[int32(pp)+1].int() 11499 *prg.mem[int32(pp)+5].int() = -*prg.mem[int32(pp)+5].int() 11500 *prg.mem[int32(qq)+3].int() = -*prg.mem[int32(qq)+3].int() 11501 } 11502 pp = qq 11503 if int32(pp) == int32(q) { 11504 break 11505 } 11506 } 11507 } 11508 p = q 11509 if int32(p) == int32(prg.curSpec) { 11510 break 11511 } 11512 } 11513 11514 exit: 11515 } 11516 11517 func (prg *prg) octantSubdivide() { 11518 var ( 11519 p, q, r1, s halfword // for traversing the lists 11520 del1, del2, del3, del, dmax scaled // proportional to the control 11521 // points of a quadratic derived from a cubic 11522 11523 t fraction // where a quadratic crosses zero 11524 destX, destY scaled // final values of |x| and |y| in the current cubic 11525 ) 11526 p = prg.curSpec 11527 for { 11528 q = *(*prg.mem[p].hh()).rh() 11529 11530 *prg.mem[int32(p)+1].int() = *prg.mem[int32(p)+1].int() - *prg.mem[int32(p)+2].int() 11531 *prg.mem[int32(p)+5].int() = *prg.mem[int32(p)+5].int() - *prg.mem[int32(p)+6].int() 11532 *prg.mem[int32(q)+3].int() = *prg.mem[int32(q)+3].int() - *prg.mem[int32(q)+4].int() 11533 11534 // Subdivide the cubic between |p| and |q| so that the results travel toward the first octant 11535 11536 // Set up the variables |(del1,del2,del3)| to represent $x'-y'$ 11537 if int32(q) == int32(prg.curSpec) { 11538 prg.unskew(*prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int(), *(*prg.mem[q].hh()).b1()) 11539 prg.skew(prg.curX, prg.curY, *(*prg.mem[p].hh()).b1()) 11540 destX = prg.curX 11541 destY = prg.curY 11542 } else { 11543 prg.abnegate(*prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int(), *(*prg.mem[q].hh()).b1(), *(*prg.mem[p].hh()).b1()) 11544 destX = prg.curX - prg.curY 11545 destY = prg.curY 11546 } 11547 del1 = *prg.mem[int32(p)+5].int() - *prg.mem[int32(p)+1].int() 11548 del2 = *prg.mem[int32(q)+3].int() - *prg.mem[int32(p)+5].int() 11549 del3 = destX - *prg.mem[int32(q)+3].int() 11550 11551 // Scale up |del1|, |del2|, and |del3| for greater accuracy; also set |del| to the first nonzero element of |(del1,del2,del3)| 11552 if del1 != 0 { 11553 del = del1 11554 } else if del2 != 0 { 11555 del = del2 11556 } else { 11557 del = del3 11558 } 11559 if del != 0 { 11560 dmax = abs(del1) 11561 if abs(del2) > dmax { 11562 dmax = abs(del2) 11563 } 11564 if abs(del3) > dmax { 11565 dmax = abs(del3) 11566 } 11567 for dmax < 01000000000 { 11568 dmax = dmax + dmax 11569 del1 = del1 + del1 11570 del2 = del2 + del2 11571 del3 = del3 + del3 11572 } 11573 } 11574 if del != 0 { 11575 if del < 0 { 11576 *prg.mem[int32(p)+2].int() = *prg.mem[int32(p)+1].int() + *prg.mem[int32(p)+2].int() 11577 *prg.mem[int32(p)+1].int() = -*prg.mem[int32(p)+1].int() 11578 11579 *prg.mem[int32(p)+6].int() = *prg.mem[int32(p)+5].int() + *prg.mem[int32(p)+6].int() 11580 *prg.mem[int32(p)+5].int() = -*prg.mem[int32(p)+5].int() 11581 11582 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+3].int() + *prg.mem[int32(q)+4].int() 11583 *prg.mem[int32(q)+3].int() = -*prg.mem[int32(q)+3].int() 11584 11585 del1 = -del1 11586 del2 = -del2 11587 del3 = -del3 11588 11589 destY = destX + destY 11590 destX = -destX 11591 11592 *(*prg.mem[p].hh()).b1() = byte(int32(*(*prg.mem[p].hh()).b1()) + switchXAndY) 11593 } 11594 t = prg.crossingPoint(del1, del2, del3) 11595 if t < 02000000000 { 11596 prg.splitCubic(p, t, destX, destY) 11597 r1 = *(*prg.mem[p].hh()).rh() 11598 if int32(*(*prg.mem[r1].hh()).b1()) > switchXAndY { 11599 *(*prg.mem[r1].hh()).b1() = byte(int32(*(*prg.mem[r1].hh()).b1()) - switchXAndY) 11600 } else { 11601 *(*prg.mem[r1].hh()).b1() = byte(int32(*(*prg.mem[r1].hh()).b1()) + switchXAndY) 11602 } 11603 if *prg.mem[int32(r1)+2].int() < *prg.mem[int32(p)+2].int() { 11604 *prg.mem[int32(r1)+2].int() = *prg.mem[int32(p)+2].int() 11605 } else if *prg.mem[int32(r1)+2].int() > destY { 11606 *prg.mem[int32(r1)+2].int() = destY 11607 } 11608 if *prg.mem[int32(p)+1].int()+*prg.mem[int32(r1)+2].int() > destX+destY { 11609 *prg.mem[int32(r1)+2].int() = destX + destY - *prg.mem[int32(p)+1].int() 11610 } 11611 if *prg.mem[int32(r1)+4].int() > *prg.mem[int32(r1)+2].int() { 11612 *prg.mem[int32(r1)+4].int() = *prg.mem[int32(r1)+2].int() 11613 if *prg.mem[int32(p)+6].int() > *prg.mem[int32(r1)+2].int() { 11614 *prg.mem[int32(p)+6].int() = *prg.mem[int32(r1)+2].int() 11615 } 11616 } 11617 if *prg.mem[int32(r1)+6].int() < *prg.mem[int32(r1)+2].int() { 11618 *prg.mem[int32(r1)+6].int() = *prg.mem[int32(r1)+2].int() 11619 if *prg.mem[int32(q)+4].int() < *prg.mem[int32(r1)+2].int() { 11620 *prg.mem[int32(q)+4].int() = *prg.mem[int32(r1)+2].int() 11621 } 11622 } 11623 if *prg.mem[int32(r1)+1].int() < *prg.mem[int32(p)+1].int() { 11624 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(p)+1].int() 11625 } else if *prg.mem[int32(r1)+1].int()+*prg.mem[int32(r1)+2].int() > destX+destY { 11626 *prg.mem[int32(r1)+1].int() = destX + destY - *prg.mem[int32(r1)+2].int() 11627 } 11628 *prg.mem[int32(r1)+3].int() = *prg.mem[int32(r1)+1].int() 11629 if *prg.mem[int32(p)+5].int() > *prg.mem[int32(r1)+1].int() { 11630 *prg.mem[int32(p)+5].int() = *prg.mem[int32(r1)+1].int() 11631 } 11632 // we always have |x_coord(p)<=right_x(p)| 11633 *prg.mem[int32(r1)+2].int() = *prg.mem[int32(r1)+2].int() + *prg.mem[int32(r1)+1].int() 11634 *prg.mem[int32(r1)+6].int() = *prg.mem[int32(r1)+6].int() + *prg.mem[int32(r1)+1].int() 11635 11636 *prg.mem[int32(r1)+1].int() = -*prg.mem[int32(r1)+1].int() 11637 *prg.mem[int32(r1)+5].int() = *prg.mem[int32(r1)+1].int() 11638 11639 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+4].int() + *prg.mem[int32(q)+3].int() 11640 *prg.mem[int32(q)+3].int() = -*prg.mem[int32(q)+3].int() 11641 11642 destY = destY + destX 11643 destX = -destX 11644 if *prg.mem[int32(r1)+6].int() < *prg.mem[int32(r1)+2].int() { 11645 *prg.mem[int32(r1)+6].int() = *prg.mem[int32(r1)+2].int() 11646 if *prg.mem[int32(q)+4].int() < *prg.mem[int32(r1)+2].int() { 11647 *prg.mem[int32(q)+4].int() = *prg.mem[int32(r1)+2].int() 11648 } 11649 } 11650 del2 = del2 - prg.takeFraction(del2-del3, t) 11651 // now |0,del2,del3| represent $x'-y'$ on the remaining interval 11652 if del2 > 0 { 11653 del2 = 0 11654 } 11655 t = prg.crossingPoint(0, -del2, -del3) 11656 if t < 02000000000 { 11657 prg.splitCubic(r1, t, destX, destY) 11658 s = *(*prg.mem[r1].hh()).rh() 11659 11660 if *prg.mem[int32(s)+2].int() < *prg.mem[int32(r1)+2].int() { 11661 *prg.mem[int32(s)+2].int() = *prg.mem[int32(r1)+2].int() 11662 } else if *prg.mem[int32(s)+2].int() > destY { 11663 *prg.mem[int32(s)+2].int() = destY 11664 } 11665 if *prg.mem[int32(r1)+1].int()+*prg.mem[int32(s)+2].int() > destX+destY { 11666 *prg.mem[int32(s)+2].int() = destX + destY - *prg.mem[int32(r1)+1].int() 11667 } 11668 if *prg.mem[int32(s)+4].int() > *prg.mem[int32(s)+2].int() { 11669 *prg.mem[int32(s)+4].int() = *prg.mem[int32(s)+2].int() 11670 if *prg.mem[int32(r1)+6].int() > *prg.mem[int32(s)+2].int() { 11671 *prg.mem[int32(r1)+6].int() = *prg.mem[int32(s)+2].int() 11672 } 11673 } 11674 if *prg.mem[int32(s)+6].int() < *prg.mem[int32(s)+2].int() { 11675 *prg.mem[int32(s)+6].int() = *prg.mem[int32(s)+2].int() 11676 if *prg.mem[int32(q)+4].int() < *prg.mem[int32(s)+2].int() { 11677 *prg.mem[int32(q)+4].int() = *prg.mem[int32(s)+2].int() 11678 } 11679 } 11680 if *prg.mem[int32(s)+1].int()+*prg.mem[int32(s)+2].int() > destX+destY { 11681 *prg.mem[int32(s)+1].int() = destX + destY - *prg.mem[int32(s)+2].int() 11682 } else { 11683 if *prg.mem[int32(s)+1].int() < destX { 11684 *prg.mem[int32(s)+1].int() = destX 11685 } 11686 if *prg.mem[int32(s)+1].int() < *prg.mem[int32(r1)+1].int() { 11687 *prg.mem[int32(s)+1].int() = *prg.mem[int32(r1)+1].int() 11688 } 11689 } 11690 *(*prg.mem[s].hh()).b1() = *(*prg.mem[p].hh()).b1() 11691 *prg.mem[int32(s)+3].int() = *prg.mem[int32(s)+1].int() // now |x_coord(r)=right_x(r)<=left_x(s)| 11692 if *prg.mem[int32(q)+3].int() < destX { 11693 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+4].int() + destX 11694 *prg.mem[int32(q)+3].int() = -destX 11695 } else if *prg.mem[int32(q)+3].int() > *prg.mem[int32(s)+1].int() { 11696 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+4].int() + *prg.mem[int32(s)+1].int() 11697 *prg.mem[int32(q)+3].int() = -*prg.mem[int32(s)+1].int() 11698 } else { 11699 *prg.mem[int32(q)+4].int() = *prg.mem[int32(q)+4].int() + *prg.mem[int32(q)+3].int() 11700 *prg.mem[int32(q)+3].int() = -*prg.mem[int32(q)+3].int() 11701 } 11702 *prg.mem[int32(s)+2].int() = *prg.mem[int32(s)+2].int() + *prg.mem[int32(s)+1].int() 11703 *prg.mem[int32(s)+6].int() = *prg.mem[int32(s)+6].int() + *prg.mem[int32(s)+1].int() 11704 11705 *prg.mem[int32(s)+1].int() = -*prg.mem[int32(s)+1].int() 11706 *prg.mem[int32(s)+5].int() = *prg.mem[int32(s)+1].int() 11707 11708 if *prg.mem[int32(s)+6].int() < *prg.mem[int32(s)+2].int() { 11709 *prg.mem[int32(s)+6].int() = *prg.mem[int32(s)+2].int() 11710 if *prg.mem[int32(q)+4].int() < *prg.mem[int32(s)+2].int() { 11711 *prg.mem[int32(q)+4].int() = *prg.mem[int32(s)+2].int() 11712 } 11713 } 11714 } else { 11715 if *prg.mem[int32(r1)+1].int() > destX { 11716 *prg.mem[int32(r1)+1].int() = destX 11717 *prg.mem[int32(r1)+3].int() = -*prg.mem[int32(r1)+1].int() 11718 *prg.mem[int32(r1)+5].int() = *prg.mem[int32(r1)+1].int() 11719 } 11720 if *prg.mem[int32(q)+3].int() > destX { 11721 *prg.mem[int32(q)+3].int() = destX 11722 } else if *prg.mem[int32(q)+3].int() < *prg.mem[int32(r1)+1].int() { 11723 *prg.mem[int32(q)+3].int() = *prg.mem[int32(r1)+1].int() 11724 } 11725 } 11726 } 11727 } 11728 p = q 11729 if int32(p) == int32(prg.curSpec) { 11730 break 11731 } 11732 } 11733 } 11734 11735 func (prg *prg) makeSafe() { 11736 var ( 11737 k/* 0..maxWiggle */ uint16 // runs through the list of inputs 11738 allSafe bool // does everything look OK so far? 11739 nextA scaled // |after[k]| before it might have changed 11740 deltaA, deltaB scaled // |after[k+1]-after[k]| and |before[k+1]-before[k]| 11741 ) 11742 prg.before[prg.curRoundingPtr] = prg.before[0] // wrap around 11743 prg.nodeToRound[prg.curRoundingPtr] = prg.nodeToRound[0] 11744 for { 11745 prg.after[prg.curRoundingPtr] = prg.after[0] 11746 allSafe = true 11747 nextA = prg.after[0] 11748 for ii := int32(0); ii <= int32(prg.curRoundingPtr)-1; ii++ { 11749 k = uint16(ii) 11750 _ = k 11751 deltaB = prg.before[int32(k)+1] - prg.before[k] 11752 if deltaB >= 0 { 11753 deltaA = prg.after[int32(k)+1] - nextA 11754 } else { 11755 deltaA = nextA - prg.after[int32(k)+1] 11756 } 11757 nextA = prg.after[int32(k)+1] 11758 if deltaA < 0 || deltaA > abs(deltaB+deltaB) { 11759 allSafe = false 11760 prg.after[k] = prg.before[k] 11761 if int32(k) == int32(prg.curRoundingPtr)-1 { 11762 prg.after[0] = prg.before[0] 11763 } else { 11764 prg.after[int32(k)+1] = prg.before[int32(k)+1] 11765 } 11766 } 11767 } 11768 if allSafe { 11769 break 11770 } 11771 } 11772 } 11773 11774 func (prg *prg) beforeAndAfter(b, a scaled, p halfword) { 11775 if int32(prg.curRoundingPtr) == int32(prg.maxRoundingPtr) { 11776 if int32(prg.maxRoundingPtr) < maxWiggle { 11777 prg.maxRoundingPtr = uint16(int32(prg.maxRoundingPtr) + 1) 11778 } else { 11779 prg.overflow(strNumber( /* "rounding table size" */ 568), maxWiggle) 11780 } 11781 } 11782 // \xref[METAFONT capacity exceeded rounding table size][\quad rounding table size] 11783 prg.after[prg.curRoundingPtr] = a 11784 prg.before[prg.curRoundingPtr] = b 11785 prg.nodeToRound[prg.curRoundingPtr] = p 11786 prg.curRoundingPtr = uint16(int32(prg.curRoundingPtr) + 1) 11787 } 11788 11789 func (prg *prg) goodVal(b, o scaled) (r scaled) { 11790 var ( 11791 a scaled // accumulator 11792 ) 11793 a = b + o 11794 if a >= 0 { 11795 a = a - a%prg.curGran - o 11796 } else { 11797 a = a + -(a+1)%prg.curGran - prg.curGran + 1 - o 11798 } 11799 if b-a < a+prg.curGran-b { 11800 r = a 11801 } else { 11802 r = a + prg.curGran 11803 } 11804 return r 11805 } 11806 11807 func (prg *prg) compromise(u, v scaled) (r scaled) { 11808 r = prg.goodVal(u+u, -u-v) / 2 11809 return r 11810 } 11811 11812 func (prg *prg) xyRound() { 11813 var ( 11814 p, q halfword // list manipulation registers 11815 b, a scaled // before and after values 11816 penEdge scaled // offset that governs rounding 11817 alpha fraction // coefficient of linear transformation 11818 ) 11819 prg.curGran = abs(prg.internal[granularity-1]) 11820 if prg.curGran == 0 { 11821 prg.curGran = 0200000 11822 } 11823 p = prg.curSpec 11824 prg.curRoundingPtr = 0 11825 for { 11826 q = *(*prg.mem[p].hh()).rh() 11827 11828 // If node |q| is a transition point for |x| coordinates, compute and save its before-and-after coordinates 11829 if *(*prg.mem[p].hh()).b1()&1 != 0 != (*(*prg.mem[q].hh()).b1()&1 != 0) { 11830 if *(*prg.mem[q].hh()).b1()&1 != 0 { 11831 b = *prg.mem[int32(q)+1].int() 11832 } else { 11833 b = -*prg.mem[int32(q)+1].int() 11834 } 11835 if abs(*prg.mem[int32(q)+1].int()-*prg.mem[int32(q)+5].int()) < 655 || abs(*prg.mem[int32(q)+1].int()+*prg.mem[int32(q)+3].int()) < 655 { 11836 if int32(prg.curPen) == memMin+3 { 11837 penEdge = 0 11838 } else if int32(prg.curPathType) == doublePathCode { 11839 penEdge = prg.compromise(*prg.mem[int32(*(*prg.mem[int32(prg.curPen)+secondOctant].hh()).rh())+2].int(), *prg.mem[int32(*(*prg.mem[int32(prg.curPen)+seventhOctant].hh()).rh())+2].int()) 11840 } else if *(*prg.mem[q].hh()).b1()&1 != 0 { 11841 penEdge = *prg.mem[int32(*(*prg.mem[int32(prg.curPen)+seventhOctant].hh()).rh())+2].int() 11842 } else { 11843 penEdge = *prg.mem[int32(*(*prg.mem[int32(prg.curPen)+secondOctant].hh()).rh())+2].int() 11844 } 11845 a = prg.goodVal(b, penEdge) 11846 } else { 11847 a = b 11848 } 11849 if abs(a) > prg.maxAllowed { 11850 if a > 0 { 11851 a = prg.maxAllowed 11852 } else { 11853 a = -prg.maxAllowed 11854 } 11855 } 11856 prg.beforeAndAfter(b, a, q) 11857 } 11858 p = q 11859 if int32(p) == int32(prg.curSpec) { 11860 break 11861 } 11862 } 11863 if int32(prg.curRoundingPtr) > 0 { 11864 prg.makeSafe() 11865 for { 11866 prg.curRoundingPtr = uint16(int32(prg.curRoundingPtr) - 1) 11867 if prg.after[prg.curRoundingPtr] != prg.before[prg.curRoundingPtr] || prg.after[int32(prg.curRoundingPtr)+1] != prg.before[int32(prg.curRoundingPtr)+1] { 11868 p = prg.nodeToRound[prg.curRoundingPtr] 11869 if *(*prg.mem[p].hh()).b1()&1 != 0 { 11870 b = prg.before[prg.curRoundingPtr] 11871 a = prg.after[prg.curRoundingPtr] 11872 } else { 11873 b = -prg.before[prg.curRoundingPtr] 11874 a = -prg.after[prg.curRoundingPtr] 11875 } 11876 if prg.before[prg.curRoundingPtr] == prg.before[int32(prg.curRoundingPtr)+1] { 11877 alpha = 02000000000 11878 } else { 11879 alpha = prg.makeFraction(prg.after[int32(prg.curRoundingPtr)+1]-prg.after[prg.curRoundingPtr], prg.before[int32(prg.curRoundingPtr)+1]-prg.before[prg.curRoundingPtr]) 11880 } 11881 for { 11882 *prg.mem[int32(p)+1].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+1].int()-b) + a 11883 *prg.mem[int32(p)+5].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+5].int()-b) + a 11884 p = *(*prg.mem[p].hh()).rh() 11885 *prg.mem[int32(p)+3].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+3].int()-b) + a 11886 if int32(p) == int32(prg.nodeToRound[int32(prg.curRoundingPtr)+1]) { 11887 break 11888 } 11889 } 11890 } 11891 if int32(prg.curRoundingPtr) == 0 { 11892 break 11893 } 11894 } 11895 } 11896 p = prg.curSpec 11897 prg.curRoundingPtr = 0 11898 for { 11899 q = *(*prg.mem[p].hh()).rh() 11900 11901 // If node |q| is a transition point for |y| coordinates, compute and save its before-and-after coordinates 11902 if int32(*(*prg.mem[p].hh()).b1()) > negateY != (int32(*(*prg.mem[q].hh()).b1()) > negateY) { 11903 if int32(*(*prg.mem[q].hh()).b1()) <= negateY { 11904 b = *prg.mem[int32(q)+2].int() 11905 } else { 11906 b = -*prg.mem[int32(q)+2].int() 11907 } 11908 if abs(*prg.mem[int32(q)+2].int()-*prg.mem[int32(q)+6].int()) < 655 || abs(*prg.mem[int32(q)+2].int()+*prg.mem[int32(q)+4].int()) < 655 { 11909 if int32(prg.curPen) == memMin+3 { 11910 penEdge = 0 11911 } else if int32(prg.curPathType) == doublePathCode { 11912 penEdge = prg.compromise(*prg.mem[int32(*(*prg.mem[int32(prg.curPen)+fourthOctant].hh()).rh())+2].int(), *prg.mem[int32(*(*prg.mem[int32(prg.curPen)+firstOctant].hh()).rh())+2].int()) 11913 } else if int32(*(*prg.mem[q].hh()).b1()) <= negateY { 11914 penEdge = *prg.mem[int32(*(*prg.mem[int32(prg.curPen)+firstOctant].hh()).rh())+2].int() 11915 } else { 11916 penEdge = *prg.mem[int32(*(*prg.mem[int32(prg.curPen)+fourthOctant].hh()).rh())+2].int() 11917 } 11918 a = prg.goodVal(b, penEdge) 11919 } else { 11920 a = b 11921 } 11922 if abs(a) > prg.maxAllowed { 11923 if a > 0 { 11924 a = prg.maxAllowed 11925 } else { 11926 a = -prg.maxAllowed 11927 } 11928 } 11929 prg.beforeAndAfter(b, a, q) 11930 } 11931 p = q 11932 if int32(p) == int32(prg.curSpec) { 11933 break 11934 } 11935 } 11936 if int32(prg.curRoundingPtr) > 0 { 11937 prg.makeSafe() 11938 for { 11939 prg.curRoundingPtr = uint16(int32(prg.curRoundingPtr) - 1) 11940 if prg.after[prg.curRoundingPtr] != prg.before[prg.curRoundingPtr] || prg.after[int32(prg.curRoundingPtr)+1] != prg.before[int32(prg.curRoundingPtr)+1] { 11941 p = prg.nodeToRound[prg.curRoundingPtr] 11942 if int32(*(*prg.mem[p].hh()).b1()) <= negateY { 11943 b = prg.before[prg.curRoundingPtr] 11944 a = prg.after[prg.curRoundingPtr] 11945 } else { 11946 b = -prg.before[prg.curRoundingPtr] 11947 a = -prg.after[prg.curRoundingPtr] 11948 } 11949 if prg.before[prg.curRoundingPtr] == prg.before[int32(prg.curRoundingPtr)+1] { 11950 alpha = 02000000000 11951 } else { 11952 alpha = prg.makeFraction(prg.after[int32(prg.curRoundingPtr)+1]-prg.after[prg.curRoundingPtr], prg.before[int32(prg.curRoundingPtr)+1]-prg.before[prg.curRoundingPtr]) 11953 } 11954 for { 11955 *prg.mem[int32(p)+2].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+2].int()-b) + a 11956 *prg.mem[int32(p)+6].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+6].int()-b) + a 11957 p = *(*prg.mem[p].hh()).rh() 11958 *prg.mem[int32(p)+4].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+4].int()-b) + a 11959 if int32(p) == int32(prg.nodeToRound[int32(prg.curRoundingPtr)+1]) { 11960 break 11961 } 11962 } 11963 } 11964 if int32(prg.curRoundingPtr) == 0 { 11965 break 11966 } 11967 } 11968 } 11969 } 11970 11971 func (prg *prg) diagRound() { 11972 var ( 11973 p, q, pp halfword // list manipulation registers 11974 b, a, bb, aa, d, c, dd, cc scaled // before and after values 11975 penEdge scaled // offset that governs rounding 11976 alpha, beta fraction // coefficients of linear transformation 11977 nextA scaled // |after[k]| before it might have changed 11978 allSafe bool // does everything look OK so far? 11979 k/* 0..maxWiggle */ uint16 // runs through before-and-after values 11980 firstX, firstY scaled // coordinates before rounding 11981 ) 11982 p = prg.curSpec 11983 prg.curRoundingPtr = 0 11984 for { 11985 q = *(*prg.mem[p].hh()).rh() 11986 11987 // If node |q| is a transition point between octants, compute and save its before-and-after coordinates 11988 if int32(*(*prg.mem[p].hh()).b1()) != int32(*(*prg.mem[q].hh()).b1()) { 11989 if int32(*(*prg.mem[q].hh()).b1()) > switchXAndY { 11990 b = -*prg.mem[int32(q)+1].int() 11991 } else { 11992 b = *prg.mem[int32(q)+1].int() 11993 } 11994 if abs(int32(*(*prg.mem[q].hh()).b1())-int32(*(*prg.mem[p].hh()).b1())) == switchXAndY { 11995 if abs(*prg.mem[int32(q)+1].int()-*prg.mem[int32(q)+5].int()) < 655 || abs(*prg.mem[int32(q)+1].int()+*prg.mem[int32(q)+3].int()) < 655 { 11996 if int32(prg.curPen) == memMin+3 { 11997 penEdge = 0 11998 } else if int32(prg.curPathType) == doublePathCode { 11999 switch *(*prg.mem[q].hh()).b1() { 12000 case firstOctant, secondOctant: 12001 penEdge = prg.compromise(*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+firstOctant].hh()).rh()].hh()).lh())+1].int(), -*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+fifthOctant].hh()).rh()].hh()).lh())+1].int()) 12002 case fifthOctant, sixthOctant: 12003 penEdge = -prg.compromise(*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+firstOctant].hh()).rh()].hh()).lh())+1].int(), -*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+fifthOctant].hh()).rh()].hh()).lh())+1].int()) 12004 case thirdOctant, fourthOctant: 12005 penEdge = prg.compromise(*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+fourthOctant].hh()).rh()].hh()).lh())+1].int(), -*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+eighthOctant].hh()).rh()].hh()).lh())+1].int()) 12006 case seventhOctant, eighthOctant: 12007 penEdge = -prg.compromise(*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+fourthOctant].hh()).rh()].hh()).lh())+1].int(), -*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+eighthOctant].hh()).rh()].hh()).lh())+1].int()) 12008 } 12009 } else if int32(*(*prg.mem[q].hh()).b1()) <= switchXAndY { 12010 penEdge = *prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+int32(*(*prg.mem[q].hh()).b1())].hh()).rh()].hh()).lh())+1].int() 12011 } else { 12012 penEdge = -*prg.mem[int32(*(*prg.mem[*(*prg.mem[int32(prg.curPen)+int32(*(*prg.mem[q].hh()).b1())].hh()).rh()].hh()).lh())+1].int() 12013 } 12014 if *(*prg.mem[q].hh()).b1()&1 != 0 { 12015 a = prg.goodVal(b, penEdge+prg.curGran/2) 12016 } else { 12017 a = prg.goodVal(b-1, penEdge+prg.curGran/2) 12018 } 12019 } else { 12020 a = b 12021 } 12022 } else { 12023 a = b 12024 } 12025 prg.beforeAndAfter(b, a, q) 12026 } 12027 p = q 12028 if int32(p) == int32(prg.curSpec) { 12029 break 12030 } 12031 } 12032 if int32(prg.curRoundingPtr) > 0 { 12033 p = prg.nodeToRound[0] 12034 firstX = *prg.mem[int32(p)+1].int() 12035 firstY = *prg.mem[int32(p)+2].int() 12036 12037 // Make sure that all the diagonal roundings are safe 12038 prg.before[prg.curRoundingPtr] = prg.before[0] // cf.~|make_safe| 12039 prg.nodeToRound[prg.curRoundingPtr] = prg.nodeToRound[0] 12040 for { 12041 prg.after[prg.curRoundingPtr] = prg.after[0] 12042 allSafe = true 12043 nextA = prg.after[0] 12044 for ii := int32(0); ii <= int32(prg.curRoundingPtr)-1; ii++ { 12045 k = uint16(ii) 12046 _ = k 12047 a = nextA 12048 b = prg.before[k] 12049 nextA = prg.after[int32(k)+1] 12050 aa = nextA 12051 bb = prg.before[int32(k)+1] 12052 if a != b || aa != bb { 12053 p = prg.nodeToRound[k] 12054 pp = prg.nodeToRound[int32(k)+1] 12055 12056 // Determine the before-and-after values of both coordinates 12057 if aa == bb { 12058 if int32(pp) == int32(prg.nodeToRound[0]) { 12059 prg.unskew(firstX, firstY, *(*prg.mem[pp].hh()).b1()) 12060 } else { 12061 prg.unskew(*prg.mem[int32(pp)+1].int(), *prg.mem[int32(pp)+2].int(), *(*prg.mem[pp].hh()).b1()) 12062 } 12063 prg.skew(prg.curX, prg.curY, *(*prg.mem[p].hh()).b1()) 12064 bb = prg.curX 12065 aa = bb 12066 dd = prg.curY 12067 cc = dd 12068 if int32(*(*prg.mem[p].hh()).b1()) > switchXAndY { 12069 b = -b 12070 a = -a 12071 } 12072 } else { 12073 if int32(*(*prg.mem[p].hh()).b1()) > switchXAndY { 12074 bb = -bb 12075 aa = -aa 12076 b = -b 12077 a = -a 12078 } 12079 if int32(pp) == int32(prg.nodeToRound[0]) { 12080 dd = firstY - bb 12081 } else { 12082 dd = *prg.mem[int32(pp)+2].int() - bb 12083 } 12084 if (aa-bb)&1 != 0 { 12085 if int32(*(*prg.mem[p].hh()).b1()) > switchXAndY { 12086 cc = dd - (aa-bb+1)/2 12087 } else { 12088 cc = dd - (aa-bb-1)/2 12089 } 12090 } else { 12091 cc = dd - (aa-bb)/2 12092 } 12093 } 12094 d = *prg.mem[int32(p)+2].int() 12095 if (a-b)&1 != 0 { 12096 if int32(*(*prg.mem[p].hh()).b1()) > switchXAndY { 12097 c = d - (a-b-1)/2 12098 } else { 12099 c = d - (a-b+1)/2 12100 } 12101 } else { 12102 c = d - (a-b)/2 12103 } 12104 if aa < a || cc < c || aa-a > 2*(bb-b) || cc-c > 2*(dd-d) { 12105 allSafe = false 12106 prg.after[k] = prg.before[k] 12107 if int32(k) == int32(prg.curRoundingPtr)-1 { 12108 prg.after[0] = prg.before[0] 12109 } else { 12110 prg.after[int32(k)+1] = prg.before[int32(k)+1] 12111 } 12112 } 12113 } 12114 } 12115 if allSafe { 12116 break 12117 } 12118 } 12119 for ii := int32(0); ii <= int32(prg.curRoundingPtr)-1; ii++ { 12120 k = uint16(ii) 12121 _ = k 12122 a = prg.after[k] 12123 b = prg.before[k] 12124 aa = prg.after[int32(k)+1] 12125 bb = prg.before[int32(k)+1] 12126 if a != b || aa != bb { 12127 p = prg.nodeToRound[k] 12128 pp = prg.nodeToRound[int32(k)+1] 12129 12130 // Determine the before-and-after values of both coordinates 12131 if aa == bb { 12132 if int32(pp) == int32(prg.nodeToRound[0]) { 12133 prg.unskew(firstX, firstY, *(*prg.mem[pp].hh()).b1()) 12134 } else { 12135 prg.unskew(*prg.mem[int32(pp)+1].int(), *prg.mem[int32(pp)+2].int(), *(*prg.mem[pp].hh()).b1()) 12136 } 12137 prg.skew(prg.curX, prg.curY, *(*prg.mem[p].hh()).b1()) 12138 bb = prg.curX 12139 aa = bb 12140 dd = prg.curY 12141 cc = dd 12142 if int32(*(*prg.mem[p].hh()).b1()) > switchXAndY { 12143 b = -b 12144 a = -a 12145 } 12146 } else { 12147 if int32(*(*prg.mem[p].hh()).b1()) > switchXAndY { 12148 bb = -bb 12149 aa = -aa 12150 b = -b 12151 a = -a 12152 } 12153 if int32(pp) == int32(prg.nodeToRound[0]) { 12154 dd = firstY - bb 12155 } else { 12156 dd = *prg.mem[int32(pp)+2].int() - bb 12157 } 12158 if (aa-bb)&1 != 0 { 12159 if int32(*(*prg.mem[p].hh()).b1()) > switchXAndY { 12160 cc = dd - (aa-bb+1)/2 12161 } else { 12162 cc = dd - (aa-bb-1)/2 12163 } 12164 } else { 12165 cc = dd - (aa-bb)/2 12166 } 12167 } 12168 d = *prg.mem[int32(p)+2].int() 12169 if (a-b)&1 != 0 { 12170 if int32(*(*prg.mem[p].hh()).b1()) > switchXAndY { 12171 c = d - (a-b-1)/2 12172 } else { 12173 c = d - (a-b+1)/2 12174 } 12175 } else { 12176 c = d - (a-b)/2 12177 } 12178 if b == bb { 12179 alpha = 02000000000 12180 } else { 12181 alpha = prg.makeFraction(aa-a, bb-b) 12182 } 12183 if d == dd { 12184 beta = 02000000000 12185 } else { 12186 beta = prg.makeFraction(cc-c, dd-d) 12187 } 12188 for { 12189 *prg.mem[int32(p)+1].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+1].int()-b) + a 12190 *prg.mem[int32(p)+2].int() = prg.takeFraction(beta, *prg.mem[int32(p)+2].int()-d) + c 12191 *prg.mem[int32(p)+5].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+5].int()-b) + a 12192 *prg.mem[int32(p)+6].int() = prg.takeFraction(beta, *prg.mem[int32(p)+6].int()-d) + c 12193 p = *(*prg.mem[p].hh()).rh() 12194 *prg.mem[int32(p)+3].int() = prg.takeFraction(alpha, *prg.mem[int32(p)+3].int()-b) + a 12195 *prg.mem[int32(p)+4].int() = prg.takeFraction(beta, *prg.mem[int32(p)+4].int()-d) + c 12196 if int32(p) == int32(pp) { 12197 break 12198 } 12199 } 12200 } 12201 } 12202 } 12203 } 12204 12205 func (prg *prg) newBoundary(p halfword, octant smallNumber) { 12206 var ( 12207 q, r1 halfword // for list manipulation 12208 ) 12209 q = *(*prg.mem[p].hh()).rh() // we assume that |right_type(q)<>endpoint| 12210 r1 = prg.getNode(knotNodeSize) 12211 *(*prg.mem[r1].hh()).rh() = q 12212 *(*prg.mem[p].hh()).rh() = r1 12213 *(*prg.mem[r1].hh()).b0() = *(*prg.mem[q].hh()).b0() // but possibly |left_type(q)=endpoint| 12214 *prg.mem[int32(r1)+3].int() = *prg.mem[int32(q)+3].int() 12215 *prg.mem[int32(r1)+4].int() = *prg.mem[int32(q)+4].int() 12216 *(*prg.mem[r1].hh()).b1() = byte(endpoint) 12217 *(*prg.mem[q].hh()).b0() = byte(endpoint) 12218 *prg.mem[int32(r1)+5].int() = int32(octant) 12219 *prg.mem[int32(q)+3].int() = int32(*(*prg.mem[q].hh()).b1()) 12220 prg.unskew(*prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int(), *(*prg.mem[q].hh()).b1()) 12221 prg.skew(prg.curX, prg.curY, octant) 12222 *prg.mem[int32(r1)+1].int() = prg.curX 12223 *prg.mem[int32(r1)+2].int() = prg.curY 12224 } 12225 12226 func (prg *prg) makeSpec(h halfword, 12227 safetyMargin scaled, tracing int32) (r halfword) { 12228 var ( 12229 p, q, r1, s halfword // for traversing the lists 12230 k int32 // serial number of path segment, or octant code 12231 chopped int32 // positive if data truncated, 12232 // negative if data dangerously large 12233 12234 // Other local variables for |make_spec| 12235 o1, o2 smallNumber // octant numbers 12236 clockwise bool // should we turn clockwise? 12237 dx1, dy1, dx2, dy2 int32 // directions of travel at a cusp 12238 dmax, del int32 // temporary registers 12239 ) 12240 prg.curSpec = h 12241 if tracing > 0 { 12242 prg.printPath(prg.curSpec, strNumber( /* ", before subdivision into octants" */ 559), true) 12243 } 12244 prg.maxAllowed = 02000000000 - 0100000 - 1 - safetyMargin 12245 12246 // Truncate the values of all coordinates that exceed |max_allowed|, and stamp segment numbers in each |left_type| field 12247 p = prg.curSpec 12248 k = 1 12249 chopped = 0 12250 dmax = prg.maxAllowed / 2 12251 for { 12252 if abs(*prg.mem[int32(p)+3].int()) >= dmax { 12253 if abs(*prg.mem[int32(p)+3].int()) > prg.maxAllowed { 12254 chopped = 1 12255 if *prg.mem[int32(p)+3].int() > 0 { 12256 *prg.mem[int32(p)+3].int() = prg.maxAllowed 12257 } else { 12258 *prg.mem[int32(p)+3].int() = -prg.maxAllowed 12259 } 12260 } else if chopped == 0 { 12261 chopped = -1 12262 } 12263 } 12264 if abs(*prg.mem[int32(p)+4].int()) >= dmax { 12265 if abs(*prg.mem[int32(p)+4].int()) > prg.maxAllowed { 12266 chopped = 1 12267 if *prg.mem[int32(p)+4].int() > 0 { 12268 *prg.mem[int32(p)+4].int() = prg.maxAllowed 12269 } else { 12270 *prg.mem[int32(p)+4].int() = -prg.maxAllowed 12271 } 12272 } else if chopped == 0 { 12273 chopped = -1 12274 } 12275 } 12276 if abs(*prg.mem[int32(p)+1].int()) >= dmax { 12277 if abs(*prg.mem[int32(p)+1].int()) > prg.maxAllowed { 12278 chopped = 1 12279 if *prg.mem[int32(p)+1].int() > 0 { 12280 *prg.mem[int32(p)+1].int() = prg.maxAllowed 12281 } else { 12282 *prg.mem[int32(p)+1].int() = -prg.maxAllowed 12283 } 12284 } else if chopped == 0 { 12285 chopped = -1 12286 } 12287 } 12288 if abs(*prg.mem[int32(p)+2].int()) >= dmax { 12289 if abs(*prg.mem[int32(p)+2].int()) > prg.maxAllowed { 12290 chopped = 1 12291 if *prg.mem[int32(p)+2].int() > 0 { 12292 *prg.mem[int32(p)+2].int() = prg.maxAllowed 12293 } else { 12294 *prg.mem[int32(p)+2].int() = -prg.maxAllowed 12295 } 12296 } else if chopped == 0 { 12297 chopped = -1 12298 } 12299 } 12300 if abs(*prg.mem[int32(p)+5].int()) >= dmax { 12301 if abs(*prg.mem[int32(p)+5].int()) > prg.maxAllowed { 12302 chopped = 1 12303 if *prg.mem[int32(p)+5].int() > 0 { 12304 *prg.mem[int32(p)+5].int() = prg.maxAllowed 12305 } else { 12306 *prg.mem[int32(p)+5].int() = -prg.maxAllowed 12307 } 12308 } else if chopped == 0 { 12309 chopped = -1 12310 } 12311 } 12312 if abs(*prg.mem[int32(p)+6].int()) >= dmax { 12313 if abs(*prg.mem[int32(p)+6].int()) > prg.maxAllowed { 12314 chopped = 1 12315 if *prg.mem[int32(p)+6].int() > 0 { 12316 *prg.mem[int32(p)+6].int() = prg.maxAllowed 12317 } else { 12318 *prg.mem[int32(p)+6].int() = -prg.maxAllowed 12319 } 12320 } else if chopped == 0 { 12321 chopped = -1 12322 } 12323 } 12324 12325 p = *(*prg.mem[p].hh()).rh() 12326 *(*prg.mem[p].hh()).b0() = byte(k) 12327 if k < maxQuarterword { 12328 k = k + 1 12329 } else { 12330 k = 1 12331 } 12332 if int32(p) == int32(prg.curSpec) { 12333 break 12334 } 12335 } 12336 if chopped > 0 { 12337 { 12338 if int32(prg.interaction) == errorStopMode { 12339 } 12340 prg.printNl(strNumber( /* "! " */ 261)) 12341 prg.print( /* "Curve out of range" */ 563) /* \xref[!\relax] */ 12342 } 12343 // \xref[Curve out of range] 12344 { 12345 prg.helpPtr = 4 12346 prg.helpLine[3] = /* "At least one of the coordinates in the path I'm about to" */ 564 12347 prg.helpLine[2] = /* "digitize was really huge (potentially bigger than 4095)." */ 565 12348 prg.helpLine[1] = /* "So I've cut it back to the maximum size." */ 566 12349 prg.helpLine[0] = /* "The results will probably be pretty wild." */ 567 12350 } 12351 prg.putGetError() 12352 } 12353 prg.quadrantSubdivide() // subdivide each cubic into pieces belonging to quadrants 12354 if prg.internal[autorounding-1] > 0 && chopped == 0 { 12355 prg.xyRound() 12356 } 12357 prg.octantSubdivide() // complete the subdivision 12358 if prg.internal[autorounding-1] > 0200000 && chopped == 0 { 12359 prg.diagRound() 12360 } 12361 12362 // Remove dead cubics 12363 p = prg.curSpec 12364 for { 12365 continue1: 12366 q = *(*prg.mem[p].hh()).rh() 12367 if int32(p) != int32(q) { 12368 if *prg.mem[int32(p)+1].int() == *prg.mem[int32(p)+5].int() { 12369 if *prg.mem[int32(p)+2].int() == *prg.mem[int32(p)+6].int() { 12370 if *prg.mem[int32(p)+1].int() == *prg.mem[int32(q)+3].int() { 12371 if *prg.mem[int32(p)+2].int() == *prg.mem[int32(q)+4].int() { 12372 prg.unskew(*prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int(), *(*prg.mem[q].hh()).b1()) 12373 prg.skew(prg.curX, prg.curY, *(*prg.mem[p].hh()).b1()) 12374 if *prg.mem[int32(p)+1].int() == prg.curX { 12375 if *prg.mem[int32(p)+2].int() == prg.curY { 12376 prg.removeCubic(p) // remove the cubic following |p| 12377 if int32(q) != int32(prg.curSpec) { 12378 goto continue1 12379 } 12380 prg.curSpec = p 12381 q = p 12382 } 12383 } 12384 } 12385 } 12386 } 12387 } 12388 } 12389 p = q 12390 if int32(p) == int32(prg.curSpec) { 12391 break 12392 } 12393 } 12394 12395 // Insert octant boundaries and compute the turning number 12396 prg.turningNumber = 0 12397 p = prg.curSpec 12398 q = *(*prg.mem[p].hh()).rh() 12399 for { 12400 r1 = *(*prg.mem[q].hh()).rh() 12401 if int32(*(*prg.mem[p].hh()).b1()) != int32(*(*prg.mem[q].hh()).b1()) || int32(q) == int32(r1) { 12402 prg.newBoundary(p, *(*prg.mem[p].hh()).b1()) 12403 s = *(*prg.mem[p].hh()).rh() 12404 o1 = prg.octantNumber[*(*prg.mem[p].hh()).b1()-1] 12405 o2 = prg.octantNumber[*(*prg.mem[q].hh()).b1()-1] 12406 switch int32(o2) - int32(o1) { 12407 case 1, -7, 7, -1: 12408 goto done 12409 case 2, -6: 12410 clockwise = false 12411 case 3, -5, 4, -4, 12412 5, -3: 12413 // Decide whether or not to go clockwise 12414 dx1 = *prg.mem[int32(s)+1].int() - *prg.mem[int32(s)+3].int() 12415 dy1 = *prg.mem[int32(s)+2].int() - *prg.mem[int32(s)+4].int() 12416 if dx1 == 0 { 12417 if dy1 == 0 { 12418 dx1 = *prg.mem[int32(s)+1].int() - *prg.mem[int32(p)+5].int() 12419 dy1 = *prg.mem[int32(s)+2].int() - *prg.mem[int32(p)+6].int() 12420 if dx1 == 0 { 12421 if dy1 == 0 { 12422 dx1 = *prg.mem[int32(s)+1].int() - *prg.mem[int32(p)+1].int() 12423 dy1 = *prg.mem[int32(s)+2].int() - *prg.mem[int32(p)+2].int() 12424 } 12425 } // and they [\sl can't] both be zero 12426 } 12427 } 12428 dmax = abs(dx1) 12429 if abs(dy1) > dmax { 12430 dmax = abs(dy1) 12431 } 12432 for dmax < 02000000000 { 12433 dmax = dmax + dmax 12434 dx1 = dx1 + dx1 12435 dy1 = dy1 + dy1 12436 } 12437 dx2 = *prg.mem[int32(q)+5].int() - *prg.mem[int32(q)+1].int() 12438 dy2 = *prg.mem[int32(q)+6].int() - *prg.mem[int32(q)+2].int() 12439 if dx2 == 0 { 12440 if dy2 == 0 { 12441 dx2 = *prg.mem[int32(r1)+3].int() - *prg.mem[int32(q)+1].int() 12442 dy2 = *prg.mem[int32(r1)+4].int() - *prg.mem[int32(q)+2].int() 12443 if dx2 == 0 { 12444 if dy2 == 0 { 12445 if int32(*(*prg.mem[r1].hh()).b1()) == endpoint { 12446 prg.curX = *prg.mem[int32(r1)+1].int() 12447 prg.curY = *prg.mem[int32(r1)+2].int() 12448 } else { 12449 prg.unskew(*prg.mem[int32(r1)+1].int(), *prg.mem[int32(r1)+2].int(), *(*prg.mem[r1].hh()).b1()) 12450 prg.skew(prg.curX, prg.curY, *(*prg.mem[q].hh()).b1()) 12451 } 12452 dx2 = prg.curX - *prg.mem[int32(q)+1].int() 12453 dy2 = prg.curY - *prg.mem[int32(q)+2].int() 12454 } 12455 } // and they [\sl can't] both be zero 12456 } 12457 } 12458 dmax = abs(dx2) 12459 if abs(dy2) > dmax { 12460 dmax = abs(dy2) 12461 } 12462 for dmax < 02000000000 { 12463 dmax = dmax + dmax 12464 dx2 = dx2 + dx2 12465 dy2 = dy2 + dy2 12466 } 12467 prg.unskew(dx1, dy1, *(*prg.mem[p].hh()).b1()) 12468 del = prg.pythAdd(prg.curX, prg.curY) 12469 12470 dx1 = prg.makeFraction(prg.curX, del) 12471 dy1 = prg.makeFraction(prg.curY, del) 12472 // $\cos\theta_1$ and $\sin\theta_1$ 12473 prg.unskew(dx2, dy2, *(*prg.mem[q].hh()).b1()) 12474 del = prg.pythAdd(prg.curX, prg.curY) 12475 12476 dx2 = prg.makeFraction(prg.curX, del) 12477 dy2 = prg.makeFraction(prg.curY, del) 12478 // $\cos\theta_2$ and $\sin\theta_2$ 12479 del = prg.takeFraction(dx1, dy2) - prg.takeFraction(dx2, dy1) // $\sin(\theta_2-\theta_1)$ 12480 if del > 4684844 { 12481 clockwise = false 12482 } else if del < -4684844 { 12483 clockwise = true 12484 } else { 12485 clockwise = prg.revTurns 12486 } 12487 12488 case 6, -2: 12489 clockwise = true 12490 case 0: 12491 clockwise = prg.revTurns 12492 } // there are no other cases 12493 12494 // Insert additional boundary nodes, then |goto done| 12495 for true { 12496 if clockwise { 12497 if int32(o1) == 1 { 12498 o1 = 8 12499 } else { 12500 o1 = byte(int32(o1) - 1) 12501 } 12502 } else if int32(o1) == 8 { 12503 o1 = 1 12504 } else { 12505 o1 = byte(int32(o1) + 1) 12506 } 12507 if int32(o1) == int32(o2) { 12508 goto done 12509 } 12510 prg.newBoundary(s, prg.octantCode[o1-1]) 12511 s = *(*prg.mem[s].hh()).rh() 12512 *prg.mem[int32(s)+3].int() = *prg.mem[int32(s)+5].int() 12513 } 12514 12515 done: 12516 if int32(q) == int32(r1) { 12517 q = *(*prg.mem[q].hh()).rh() 12518 r1 = q 12519 p = s 12520 *(*prg.mem[s].hh()).rh() = q 12521 *prg.mem[int32(q)+3].int() = *prg.mem[int32(q)+5].int() 12522 *(*prg.mem[q].hh()).b0() = byte(endpoint) 12523 prg.freeNode(prg.curSpec, halfword(knotNodeSize)) 12524 prg.curSpec = q 12525 } 12526 12527 // Fix up the transition fields and adjust the turning number 12528 p = *(*prg.mem[p].hh()).rh() 12529 for { 12530 s = *(*prg.mem[p].hh()).rh() 12531 o1 = prg.octantNumber[*prg.mem[int32(p)+5].int()-1] 12532 o2 = prg.octantNumber[*prg.mem[int32(s)+3].int()-1] 12533 if abs(int32(o1)-int32(o2)) == 1 { 12534 if int32(o2) < int32(o1) { 12535 o2 = o1 12536 } 12537 if o2&1 != 0 { 12538 *prg.mem[int32(p)+6].int() = axis 12539 } else { 12540 *prg.mem[int32(p)+6].int() = diagonal 12541 } 12542 } else { 12543 if int32(o1) == 8 { 12544 prg.turningNumber = prg.turningNumber + 1 12545 } else { 12546 prg.turningNumber = prg.turningNumber - 1 12547 } 12548 *prg.mem[int32(p)+6].int() = axis 12549 } 12550 *prg.mem[int32(s)+4].int() = *prg.mem[int32(p)+6].int() 12551 p = s 12552 if int32(p) == int32(q) { 12553 break 12554 } 12555 } 12556 } 12557 p = q 12558 q = r1 12559 if int32(p) == int32(prg.curSpec) { 12560 break 12561 } 12562 } 12563 12564 for int32(*(*prg.mem[prg.curSpec].hh()).b0()) != endpoint { 12565 prg.curSpec = *(*prg.mem[prg.curSpec].hh()).rh() 12566 } 12567 if tracing > 0 { 12568 if prg.internal[autorounding-1] <= 0 || chopped != 0 { 12569 prg.printSpec(strNumber( /* ", after subdivision" */ 560)) 12570 } else if prg.internal[autorounding-1] > 0200000 { 12571 prg.printSpec(strNumber( /* ", after subdivision and double autorounding" */ 561)) 12572 } else { 12573 prg.printSpec(strNumber( /* ", after subdivision and autorounding" */ 562)) 12574 } 12575 } 12576 r = prg.curSpec 12577 return r 12578 } 12579 12580 // 422. 12581 12582 // tangle:pos ../../mf.web:9070:3: 12583 12584 // The swapping here doesn't simply interchange |x| and |y| values, 12585 // because the coordinates are skewed. It turns out that this is easier 12586 // than ordinary swapping, because it can be done in two assignment statements 12587 // rather than three. 12588 12589 // 460. \[22] Filling a contour 12590 12591 // tangle:pos ../../mf.web:9791:28: 12592 12593 // Given the low-level machinery for making moves and for transforming a 12594 // cyclic path into a cycle spec, we're almost able to fill a digitized path. 12595 // All we need is a high-level routine that walks through the cycle spec and 12596 // controls the overall process. 12597 // 12598 // Our overall goal is to plot the integer points $\bigl(\round(x(t)), 12599 // \round(y(t))\bigr)$ and to connect them by rook moves, assuming that 12600 // $\round(x(t))$ and $\round(y(t))$ don't both jump simultaneously from 12601 // one integer to another as $t$~varies; these rook moves will be the edge 12602 // of the contour that will be filled. We have reduced this problem to the 12603 // case of curves that travel in first octant directions, i.e., curves 12604 // such that $0\L y'(t)\L x'(t)$, by transforming the original coordinates. 12605 // 12606 // \def\xtilde[[\tilde x]] \def\ytilde[[\tilde y]] 12607 // Another transformation makes the problem still simpler. We shall say that 12608 // we are working with [\sl biased coordinates\/] when $(x,y)$ has been 12609 // replaced by $(\xtilde,\ytilde)=(x-y,y+[1\over2])$. When a curve travels 12610 // in first octant directions, the corresponding curve with biased 12611 // coordinates travels in first [\sl quadrant\/] directions; the latter 12612 // condition is symmetric in $x$ and~$y$, so it has advantages for the 12613 // design of algorithms. The |make_spec| routine gives us skewed coordinates 12614 // $(x-y,y)$, hence we obtain biased coordinates by simply adding $1\over2$ 12615 // to the second component. 12616 // 12617 // The most important fact about biased coordinates is that we can determine the 12618 // rounded unbiased path $\bigl(\round(x(t)),\round(y(t))\bigr)$ from the 12619 // truncated biased path $\bigl(\lfloor\xtilde(t)\rfloor,\lfloor\ytilde(t)\rfloor 12620 // \bigr)$ and information about the initial and final endpoints. If the 12621 // unrounded and unbiased 12622 // path begins at $(x_0,y_0)$ and ends at $(x_1,y_1)$, it's possible to 12623 // prove (by induction on the length of the truncated biased path) that the 12624 // rounded unbiased path is obtained by the following construction: 12625 // 12626 // \yskip\textindent[1)] Start at $\bigl(\round(x_0),\round(y_0)\bigr)$. 12627 // 12628 // \yskip\textindent[2)] If $(x_0+[1\over2])\bmod1\G(y_0+[1\over2])\bmod1$, 12629 // move one step right. 12630 // 12631 // \yskip\textindent[3)] Whenever the path 12632 // $\bigl(\lfloor\xtilde(t)\rfloor,\lfloor\ytilde(t)\rfloor\bigr)$ 12633 // takes an upward step (i.e., when 12634 // $\lfloor\xtilde(t+\epsilon)\rfloor=\lfloor\xtilde(t)\rfloor$ and 12635 // $\lfloor\ytilde(t+\epsilon)\rfloor=\lfloor\ytilde(t)\rfloor+1$), 12636 // move one step up and then one step right. 12637 // 12638 // \yskip\textindent[4)] Whenever the path 12639 // $\bigl(\lfloor\xtilde(t)\rfloor,\lfloor\ytilde(t)\rfloor\bigr)$ 12640 // takes a rightward step (i.e., when 12641 // $\lfloor\xtilde(t+\epsilon)\rfloor=\lfloor\xtilde(t)\rfloor+1$ and 12642 // $\lfloor\ytilde(t+\epsilon)\rfloor=\lfloor\ytilde(t)\rfloor$), 12643 // move one step right. 12644 // 12645 // \yskip\textindent[5)] Finally, if 12646 // $(x_1+[1\over2])\bmod1\G(y_1+[1\over2])\bmod1$, move one step left (thereby 12647 // cancelling the previous move, which was one step right). You will now be 12648 // at the point $\bigl(\round(x_1),\round(y_1)\bigr)$. 12649 12650 // 463. 12651 12652 // tangle:pos ../../mf.web:9913:3: 12653 12654 // Here's a procedure that handles the details of rounding at the 12655 // endpoints: Given skewed coordinates |(x,y)|, it sets |(m1,n1)| 12656 // to the corresponding rounded lattice points, taking the current 12657 // |octant| into account. Global variable |d1| is also set to 1 if 12658 // $(x+y+[1\over2])\bmod1\G(y+[1\over2])\bmod1$. 12659 func (prg *prg) endRound(x, y scaled) { 12660 y = y + 0100000 - int32(prg.yCorr[prg.octant-1]) 12661 x = x + y - int32(prg.xCorr[prg.octant-1]) 12662 prg.m1 = prg.floorUnscaled(x) 12663 prg.n1 = prg.floorUnscaled(y) 12664 if x-0200000*prg.m1 >= y-0200000*prg.n1+int32(prg.zCorr[prg.octant-1]) { 12665 prg.d1 = 1 12666 } else { 12667 prg.d1 = 0 12668 } 12669 } 12670 12671 // 465. 12672 12673 // tangle:pos ../../mf.web:9933:3: 12674 12675 // We're ready now to fill the pixels enclosed by a given cycle spec~|h|; 12676 // the knot list that represents the cycle is destroyed in the process. 12677 // The edge structure that gets all the resulting data is |cur_edges|, 12678 // and the edges are weighted by |cur_wt|. 12679 func (prg *prg) fillSpec(h halfword) { 12680 var ( 12681 p, q, r1, s halfword // for list traversal 12682 ) 12683 if prg.internal[tracingEdges-1] > 0 { 12684 prg.beginEdgeTracing() 12685 } 12686 p = h // we assume that |left_type(h)=endpoint| 12687 for { 12688 prg.octant = byte(*prg.mem[int32(p)+3].int()) 12689 12690 // Set variable |q| to the node at the end of the current octant 12691 q = p 12692 for int32(*(*prg.mem[q].hh()).b1()) != endpoint { 12693 q = *(*prg.mem[q].hh()).rh() 12694 } 12695 if int32(q) != int32(p) { 12696 prg.endRound(*prg.mem[int32(p)+1].int(), *prg.mem[int32(p)+2].int()) 12697 prg.m0 = prg.m1 12698 prg.n0 = prg.n1 12699 prg.d0 = prg.d1 12700 12701 prg.endRound(*prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int()) 12702 12703 // Make the moves for the current octant 12704 if prg.n1-prg.n0 >= moveSize { 12705 prg.overflow(strNumber( /* "move table size" */ 540), moveSize) 12706 } 12707 // \xref[METAFONT capacity exceeded move table size][\quad move table size] 12708 prg.move[0] = int32(prg.d0) 12709 prg.movePtr = 0 12710 r1 = p 12711 for { 12712 s = *(*prg.mem[r1].hh()).rh() 12713 12714 prg.makeMoves(*prg.mem[int32(r1)+1].int(), *prg.mem[int32(r1)+5].int(), *prg.mem[int32(s)+3].int(), *prg.mem[int32(s)+1].int(), *prg.mem[int32(r1)+2].int()+0100000, *prg.mem[int32(r1)+6].int()+0100000, *prg.mem[int32(s)+4].int()+0100000, *prg.mem[int32(s)+2].int()+0100000, prg.xyCorr[prg.octant-1], prg.yCorr[prg.octant-1]) 12715 r1 = s 12716 if int32(r1) == int32(q) { 12717 break 12718 } 12719 } 12720 prg.move[prg.movePtr] = prg.move[prg.movePtr] - int32(prg.d1) 12721 if prg.internal[smoothing-1] > 0 { 12722 prg.smoothMoves(0, int32(prg.movePtr)) 12723 } 12724 prg.moveToEdges(prg.m0, prg.n0, prg.m1, prg.n1) 12725 } 12726 p = *(*prg.mem[q].hh()).rh() 12727 if int32(p) == int32(h) { 12728 break 12729 } 12730 } 12731 prg.tossKnotList(h) 12732 if prg.internal[tracingEdges-1] > 0 { 12733 prg.endEdgeTracing() 12734 } 12735 } 12736 12737 // 469. \[23] Polygonal pens 12738 12739 // tangle:pos ../../mf.web:9980:25: 12740 12741 // The next few parts of the program deal with the additional complications 12742 // associated with ``envelopes,'' leading up to an algorithm that fills a 12743 // contour with respect to a pen whose boundary is a convex polygon. The 12744 // mathematics underlying this algorithm is based on simple aspects of the 12745 // theory of tracings developed by Leo Guibas, Lyle Ramshaw, and Jorge 12746 // Stolfi [``A kinetic framework for computational geometry,'' 12747 // [\sl Proc.\ IEEE Symp.\ Foundations of Computer Science\/ \bf24] (1983), 12748 // 100--111]. 12749 // \xref[Guibas, Leonidas Ioannis] 12750 // \xref[Ramshaw, Lyle Harold] 12751 // \xref[Stolfi, Jorge] 12752 // 12753 // If the vertices of the polygon are $w_0$, $w_1$, \dots, $w_[n-1]$, $w_n=w_0$, 12754 // in counterclockwise order, the convexity condition requires that ``left 12755 // turns'' are made at each vertex when a person proceeds from $w_0$ to 12756 // $w_1$ to $\cdots$ to~$w_n$. The envelope is obtained if we offset a given 12757 // curve $z(t)$ by $w_k$ when that curve is traveling in a direction 12758 // $z'(t)$ lying between the directions $w_k-w_[k-1]$ and $w\k-w_k$. 12759 // At times~$t$ when the curve direction $z'(t)$ increases past 12760 // $w\k-w_k$, we temporarily stop plotting the offset curve and we insert 12761 // a straight line from $z(t)+w_k$ to $z(t)+w\k$; notice that this straight 12762 // line is tangent to the offset curve. Similarly, when the curve direction 12763 // decreases past $w_k-w_[k-1]$, we stop plotting and insert a straight 12764 // line from $z(t)+w_k$ to $z(t)+w_[k-1]$; the latter line is actually a 12765 // ``retrograde'' step, which won't be part of the final envelope under 12766 // \MF's assumptions. The result of this construction is a continuous path 12767 // that consists of alternating curves and straight line segments. The 12768 // segments are usually so short, in practice, that they blend with the 12769 // curves; after all, it's possible to represent any digitized path as 12770 // a sequence of digitized straight lines. 12771 // 12772 // The nicest feature of this approach to envelopes is that it blends 12773 // perfectly with the octant subdivision process we have already developed. 12774 // The envelope travels in the same direction as the curve itself, as we 12775 // plot it, and we need merely be careful what offset is being added. 12776 // Retrograde motion presents a problem, but we will see that there is 12777 // a decent way to handle it. 12778 12779 // 470. 12780 12781 // tangle:pos ../../mf.web:10019:3: 12782 12783 // We shall represent pens by maintaining eight lists of offsets, 12784 // one for each octant direction. The offsets at the boundary points 12785 // where a curve turns into a new octant will appear in the lists for 12786 // both octants. This means that we can restrict consideration to 12787 // segments of the original polygon whose directions aim in the first 12788 // octant, as we have done in the simpler case when envelopes were not 12789 // required. 12790 // 12791 // An example should help to clarify this situation: Consider the 12792 // quadrilateral whose vertices are $w_0=(0,-1)$, $w_1=(3,-1)$, 12793 // $w_2=(6,1)$, and $w_3=(1,2)$. A curve that travels in the first octant 12794 // will be offset by $w_1$ or $w_2$, unless its slope drops to zero 12795 // en route to the eighth octant; in the latter case we should switch to $w_0$ as 12796 // we cross the octant boundary. Our list for the first octant will 12797 // contain the three offsets $w_0$, $w_1$,~$w_2$. By convention we will 12798 // duplicate a boundary offset if the angle between octants doesn't 12799 // explicitly appear; in this case there is no explicit line of slope~1 12800 // at the end of the list, so the full list is 12801 // $$w_0\;w_1\;w_2\;w_2\;=\;(0,-1)\;(3,-1)\;(6,1)\;(6,1).$$ 12802 // With skewed coordinates $(u-v,v)$ instead of $(u,v)$ we obtain the list 12803 // $$w_0\;w_1\;w_2\;w_2\;\mapsto\;(1,-1)\;(4,-1)\;(5,1)\;(5,1),$$ 12804 // which is what actually appears in the data structure. In the second 12805 // octant there's only one offset; we list it twice (with coordinates 12806 // interchanged, so as to make the second octant look like the first), 12807 // and skew those coordinates, obtaining 12808 // $$\tabskip\centering 12809 // \halign to\hsize[$\hfil#\;\mapsto\;[]$\tabskip=0pt& 12810 // $#\hfil$&\quad in the #\hfil\tabskip\centering\cr 12811 // w_2\;w_2&(-5,6)\;(-5,6)\cr 12812 // \noalign[\vskip\belowdisplayskip 12813 // \vbox[\noindent\strut as the list of transformed and skewed offsets to use 12814 // when curves travel in the second octant. Similarly, we will have\strut] 12815 // \vskip\abovedisplayskip] 12816 // w_2\;w_2&(7,-6)\;(7,-6)&third;\cr 12817 // w_2\;w_2\;w_3\;w_3&(-7,1)\;(-7,1)\;(-3,2)\;(-3,2)&fourth;\cr 12818 // w_3\;w_3&(1,-2)\;(1,-2)&fifth;\cr 12819 // w_3\;w_3\;w_0\;w_0&(-1,1)\;(-1,1)\;(1,0)\;(1,0)&sixth;\cr 12820 // w_0\;w_0&(1,0)\;(1,0)&seventh;\cr 12821 // w_0\;w_0&(-1,1)\;(-1,1)&eighth.\cr]$$ 12822 // Notice that $w_1$ is considered here to be internal to the first octant; 12823 // it's not part of the eighth. We could equally well have taken $w_0$ out 12824 // of the first octant list and put it into the eighth; then the first octant 12825 // list would have been 12826 // $$w_1\;w_1\;w_2\;w_2\;\mapsto\;(4,-1)\;(4,-1)\;(5,1)\;(5,1)$$ 12827 // and the eighth octant list would have been 12828 // $$w_0\;w_0\;w_1\;\mapsto\;(-1,1)\;(-1,1)\;(2,1).$$ 12829 // 12830 // Actually, there's one more complication: The order of offsets is reversed 12831 // in even-numbered octants, because the transformation of coordinates has 12832 // reversed counterclockwise and clockwise orientations in those octants. 12833 // The offsets in the fourth octant, for example, are really $w_3$, $w_3$, 12834 // $w_2$,~$w_2$, not $w_2$, $w_2$, $w_3$,~$w_3$. 12835 12836 // 471. 12837 12838 // tangle:pos ../../mf.web:10072:3: 12839 12840 // In general, the list of offsets for an octant will have the form 12841 // $$w_0\;\;w_1\;\;\ldots\;\;w_n\;\;w_[n+1]$$ 12842 // (if we renumber the subscripts in each list), where $w_0$ and $w_[n+1]$ 12843 // are offsets common to the neighboring lists. We'll often have $w_0=w_1$ 12844 // and/or $w_n=w_[n+1]$, but the other $w$'s will be distinct. Curves 12845 // that travel between slope~0 and direction $w_2-w_1$ will use offset~$w_1$; 12846 // curves that travel between directions $w_k-w_[k-1]$ and $w\k-w_k$ will 12847 // use offset~$w_k$, for $1<k<n$; curves between direction $w_n-w_[n-1]$ 12848 // and slope~1 (actually slope~$\infty$ after skewing) will use offset~$w_n$. 12849 // In even-numbered octants, the directions are actually $w_k-w\k$ instead 12850 // of $w\k-w_k$, because the offsets have been listed in reverse order. 12851 // 12852 // Each offset $w_k$ is represented by skewed coordinates $(u_k-v_k,v_k)$, 12853 // where $(u_k,v_k)$ is the representation of $w_k$ after it has been rotated 12854 // into a first-octant disguise. 12855 12856 // 472. 12857 12858 // tangle:pos ../../mf.web:10088:3: 12859 12860 // The top-level data structure of a pen polygon is a 10-word node containing 12861 // a reference count followed by pointers to the eight offset lists, followed 12862 // by an indication of the pen's range of values. 12863 // \xref[reference counts] 12864 // 12865 // If |p|~points to such a node, and if the 12866 // offset list for, say, the fourth octant has entries $w_0$, $w_1$, \dots, 12867 // $w_n$,~$w_[n+1]$, then |info(p+fourth_octant)| will equal~$n$, and 12868 // |link(p+fourth_octant)| will point to the offset node containing~$w_0$. 12869 // Memory location |p+fourth_octant| is said to be the [\sl header\/] of 12870 // the pen-offset list for the fourth octant. Since this is an even-numbered 12871 // octant, $w_0$ is the offset that goes with the fifth octant, and 12872 // $w_[n+1]$ goes with the third. 12873 // 12874 // The elements of the offset list themselves are doubly linked 3-word nodes, 12875 // containing coordinates in their |x_coord| and |y_coord| fields. 12876 // The two link fields are called |link| and |knil|; if |w|~points to 12877 // the node for~$w_k$, then |link(w)| and |knil(w)| point respectively 12878 // to the nodes for $w\k$ and~$w_[k-1]$. If |h| is the list header, 12879 // |link(h)| points to the node for~$w_0$ and |knil(link(h))| to the 12880 // node for~$w_[n+1]$. 12881 // 12882 // The tenth word of a pen header node contains the maximum absolute value of 12883 // an $x$ or $y$ coordinate among all of the unskewed pen offsets. 12884 // 12885 // The |link| field of a pen header node should be |null| if and only if 12886 // the pen is a single point. 12887 12888 // 476. 12889 12890 // tangle:pos ../../mf.web:10171:3: 12891 12892 // Here's a trivial subroutine that inserts a copy of an offset 12893 // on the |link| side of its clone in the doubly linked list. 12894 func (prg *prg) dupOffset(w halfword) { 12895 var ( 12896 r1 halfword // the new node 12897 ) 12898 r1 = prg.getNode(coordNodeSize) 12899 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(w)+1].int() 12900 *prg.mem[int32(r1)+2].int() = *prg.mem[int32(w)+2].int() 12901 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[w].hh()).rh() 12902 *(*prg.mem[*(*prg.mem[w].hh()).rh()].hh()).lh() = r1 12903 *(*prg.mem[r1].hh()).lh() = w 12904 *(*prg.mem[w].hh()).rh() = r1 12905 } 12906 12907 // 477. 12908 12909 // tangle:pos ../../mf.web:10183:3: 12910 12911 // The following algorithm is somewhat more interesting: It converts a 12912 // knot list for a cyclic path into a pen polygon, ignoring everything 12913 // but the |x_coord|, |y_coord|, and |link| fields. If the given path 12914 // vertices do not define a convex polygon, an error message is issued 12915 // and the null pen is returned. 12916 func (prg *prg) makePen(h halfword) (r halfword) { 12917 var ( 12918 o, oo, k smallNumber // octant numbers---old, new, and current 12919 p halfword // top-level node for the new pen 12920 q, r1, s, w, hh halfword // for list manipulation 12921 n int32 // offset counter 12922 dx, dy scaled // polygon direction 12923 mc scaled // the largest coordinate 12924 ) 12925 q = h 12926 r1 = *(*prg.mem[q].hh()).rh() 12927 mc = abs(*prg.mem[int32(h)+1].int()) 12928 if int32(q) == int32(r1) { 12929 hh = h 12930 *(*prg.mem[h].hh()).b1() = 0 // this trick is explained below 12931 if mc < abs(*prg.mem[int32(h)+2].int()) { 12932 mc = abs(*prg.mem[int32(h)+2].int()) 12933 } 12934 } else { 12935 o = 0 12936 hh = uint16(memMin) 12937 for true { 12938 s = *(*prg.mem[r1].hh()).rh() 12939 if mc < abs(*prg.mem[int32(r1)+1].int()) { 12940 mc = abs(*prg.mem[int32(r1)+1].int()) 12941 } 12942 if mc < abs(*prg.mem[int32(r1)+2].int()) { 12943 mc = abs(*prg.mem[int32(r1)+2].int()) 12944 } 12945 dx = *prg.mem[int32(r1)+1].int() - *prg.mem[int32(q)+1].int() 12946 dy = *prg.mem[int32(r1)+2].int() - *prg.mem[int32(q)+2].int() 12947 if dx == 0 { 12948 if dy == 0 { 12949 goto notFound 12950 } 12951 } // double point 12952 if prg.abVsCd(dx, *prg.mem[int32(s)+2].int()-*prg.mem[int32(r1)+2].int(), dy, *prg.mem[int32(s)+1].int()-*prg.mem[int32(r1)+1].int()) < 0 { 12953 goto notFound 12954 } // right turn 12955 12956 // Determine the octant code for direction |(dx,dy)| 12957 if dx > 0 { 12958 prg.octant = byte(firstOctant) 12959 } else if dx == 0 { 12960 if dy > 0 { 12961 prg.octant = byte(firstOctant) 12962 } else { 12963 prg.octant = byte(firstOctant + negateX) 12964 } 12965 } else { 12966 dx = -dx 12967 prg.octant = byte(firstOctant + negateX) 12968 } 12969 if dy < 0 { 12970 dy = -dy 12971 prg.octant = byte(int32(prg.octant) + negateY) 12972 } else if dy == 0 { 12973 if int32(prg.octant) > firstOctant { 12974 prg.octant = byte(firstOctant + negateX + negateY) 12975 } 12976 } 12977 if dx < dy { 12978 prg.octant = byte(int32(prg.octant) + switchXAndY) 12979 } 12980 *(*prg.mem[q].hh()).b1() = prg.octant 12981 oo = prg.octantNumber[prg.octant-1] 12982 if int32(o) > int32(oo) { 12983 if int32(hh) != memMin { 12984 goto notFound 12985 } // $>360^\circ$ 12986 hh = q 12987 } 12988 o = oo 12989 if int32(q) == int32(h) && int32(hh) != memMin { 12990 goto done 12991 } 12992 q = r1 12993 r1 = s 12994 } 12995 12996 done: 12997 } 12998 if mc >= 02000000000-0100000 { 12999 goto notFound 13000 } 13001 p = prg.getNode(penNodeSize) 13002 q = hh 13003 *prg.mem[int32(p)+9].int() = mc 13004 *(*prg.mem[p].hh()).lh() = uint16(memMin) 13005 if int32(*(*prg.mem[q].hh()).rh()) != int32(q) { 13006 *(*prg.mem[p].hh()).rh() = uint16(memMin + 1) 13007 } 13008 for ii := int32(1); ii <= 8; ii++ { 13009 k = smallNumber(ii) 13010 _ = k 13011 // Construct the offset list for the |k|th octant 13012 prg.octant = prg.octantCode[k-1] 13013 n = 0 13014 h = uint16(int32(p) + int32(prg.octant)) 13015 for true { 13016 r1 = prg.getNode(coordNodeSize) 13017 prg.skew(*prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int(), prg.octant) 13018 *prg.mem[int32(r1)+1].int() = prg.curX 13019 *prg.mem[int32(r1)+2].int() = prg.curY 13020 if n == 0 { 13021 *(*prg.mem[h].hh()).rh() = r1 13022 } else if k&1 != 0 { 13023 *(*prg.mem[w].hh()).rh() = r1 13024 *(*prg.mem[r1].hh()).lh() = w 13025 } else { 13026 *(*prg.mem[w].hh()).lh() = r1 13027 *(*prg.mem[r1].hh()).rh() = w 13028 } 13029 w = r1 13030 if int32(*(*prg.mem[q].hh()).b1()) != int32(prg.octant) { 13031 goto done1 13032 } 13033 q = *(*prg.mem[q].hh()).rh() 13034 n = n + 1 13035 } 13036 13037 done1: 13038 r1 = *(*prg.mem[h].hh()).rh() 13039 if k&1 != 0 { 13040 *(*prg.mem[w].hh()).rh() = r1 13041 *(*prg.mem[r1].hh()).lh() = w 13042 } else { 13043 *(*prg.mem[w].hh()).lh() = r1 13044 *(*prg.mem[r1].hh()).rh() = w 13045 *(*prg.mem[h].hh()).rh() = w 13046 r1 = w 13047 } 13048 if *prg.mem[int32(r1)+2].int() != *prg.mem[int32(*(*prg.mem[r1].hh()).rh())+2].int() || n == 0 { 13049 prg.dupOffset(r1) 13050 n = n + 1 13051 } 13052 r1 = *(*prg.mem[r1].hh()).lh() 13053 if *prg.mem[int32(r1)+1].int() != *prg.mem[int32(*(*prg.mem[r1].hh()).lh())+1].int() { 13054 prg.dupOffset(r1) 13055 } else { 13056 n = n - 1 13057 } 13058 if n >= maxQuarterword { 13059 prg.overflow(strNumber( /* "pen polygon size" */ 579), maxQuarterword) 13060 } 13061 // \xref[METAFONT capacity exceeded pen polygon size][\quad pen polygon size] 13062 *(*prg.mem[h].hh()).lh() = uint16(n) 13063 } 13064 13065 goto found 13066 13067 notFound: 13068 p = uint16(memMin + 3) 13069 // Complain about a bad pen path 13070 if mc >= 02000000000-0100000 { 13071 { 13072 if int32(prg.interaction) == errorStopMode { 13073 } 13074 prg.printNl(strNumber( /* "! " */ 261)) 13075 prg.print( /* "Pen too large" */ 573) /* \xref[!\relax] */ 13076 } 13077 // \xref[Pen too large] 13078 { 13079 prg.helpPtr = 2 13080 prg.helpLine[1] = /* "The cycle you specified has a coordinate of 4095.5 or more." */ 574 13081 prg.helpLine[0] = /* "So I've replaced it by the trivial path `(0,0)..cycle'." */ 575 13082 } 13083 13084 } else { 13085 { 13086 if int32(prg.interaction) == errorStopMode { 13087 } 13088 prg.printNl(strNumber( /* "! " */ 261)) 13089 prg.print( /* "Pen cycle must be convex" */ 576) /* \xref[!\relax] */ 13090 } 13091 // \xref[Pen cycle must be convex] 13092 { 13093 prg.helpPtr = 3 13094 prg.helpLine[2] = /* "The cycle you specified either has consecutive equal points" */ 577 13095 prg.helpLine[1] = /* "or turns right or turns through more than 360 degrees." */ 578 13096 prg.helpLine[0] = /* "So I've replaced it by the trivial path `(0,0)..cycle'." */ 575 13097 } 13098 13099 } 13100 prg.putGetError() 13101 13102 found: 13103 if prg.internal[tracingPens-1] > 0 { 13104 prg.printPen(p, strNumber( /* " (newly created)" */ 572), true) 13105 } 13106 r = p 13107 return r 13108 } 13109 13110 // 484. 13111 13112 // tangle:pos ../../mf.web:10332:3: 13113 13114 // Conversely, |make_path| goes back from a pen to a cyclic path that 13115 // might have generated it. The structure of this subroutine is essentially 13116 // the same as |print_pen|. 13117 // \4 13118 // Declare the function called |trivial_knot| 13119 func (prg *prg) trivialKnot(x, y scaled) (r halfword) { 13120 var ( 13121 p halfword // a new knot for explicit coordinates |x| and |y| 13122 ) 13123 p = prg.getNode(knotNodeSize) 13124 *(*prg.mem[p].hh()).b0() = byte(explicit) 13125 *(*prg.mem[p].hh()).b1() = byte(explicit) 13126 13127 *prg.mem[int32(p)+1].int() = x 13128 *prg.mem[int32(p)+3].int() = x 13129 *prg.mem[int32(p)+5].int() = x 13130 13131 *prg.mem[int32(p)+2].int() = y 13132 *prg.mem[int32(p)+4].int() = y 13133 *prg.mem[int32(p)+6].int() = y 13134 13135 r = p 13136 return r 13137 } 13138 13139 func (prg *prg) makePath(penHead halfword) (r halfword) { 13140 var ( 13141 p halfword // the most recently copied knot 13142 k/* 1..8 */ byte // octant number 13143 h halfword // offset list head 13144 m, n int32 // offset indices 13145 w, ww halfword // pointers that traverse the offset list 13146 ) 13147 p = uint16(3000 - 1) 13148 for ii := int32(1); ii <= 8; ii++ { 13149 k = byte(ii) 13150 _ = k 13151 prg.octant = prg.octantCode[k-1] 13152 h = uint16(int32(penHead) + int32(prg.octant)) 13153 n = int32(*(*prg.mem[h].hh()).lh()) 13154 w = *(*prg.mem[h].hh()).rh() 13155 if !(k&1 != 0) { 13156 w = *(*prg.mem[w].hh()).lh() 13157 } // in even octants, start at $w_[n+1]$ 13158 for ii := int32(1); ii <= n+1; ii++ { 13159 m = ii 13160 _ = m 13161 if k&1 != 0 { 13162 ww = *(*prg.mem[w].hh()).rh() 13163 } else { 13164 ww = *(*prg.mem[w].hh()).lh() 13165 } 13166 if *prg.mem[int32(ww)+1].int() != *prg.mem[int32(w)+1].int() || *prg.mem[int32(ww)+2].int() != *prg.mem[int32(w)+2].int() { 13167 prg.unskew(*prg.mem[int32(ww)+1].int(), *prg.mem[int32(ww)+2].int(), prg.octant) 13168 *(*prg.mem[p].hh()).rh() = prg.trivialKnot(prg.curX, prg.curY) 13169 p = *(*prg.mem[p].hh()).rh() 13170 } 13171 w = ww 13172 } 13173 } 13174 if int32(p) == 3000-1 { 13175 w = *(*prg.mem[int32(penHead)+firstOctant].hh()).rh() 13176 p = prg.trivialKnot(*prg.mem[int32(w)+1].int()+*prg.mem[int32(w)+2].int(), *prg.mem[int32(w)+2].int()) 13177 *(*prg.mem[3000-1].hh()).rh() = p 13178 } 13179 *(*prg.mem[p].hh()).rh() = *(*prg.mem[3000-1].hh()).rh() 13180 r = *(*prg.mem[3000-1].hh()).rh() 13181 return r 13182 } 13183 13184 // 488. 13185 13186 // tangle:pos ../../mf.web:10396:3: 13187 13188 // The |find_offset| procedure sets |(cur_x,cur_y)| to the offset associated 13189 // with a given direction~|(x,y)| and a given pen~|p|. If |x=y=0|, the 13190 // result is |(0,0)|. If two different offsets apply, one of them is 13191 // chosen arbitrarily. 13192 func (prg *prg) findOffset(x, y scaled, p halfword) { 13193 var ( 13194 octant/* firstOctant..sixthOctant */ byte // octant code for |(x,y)| 13195 s/* -1.. +1 */ int8 // sign of the octant 13196 n int32 // number of offsets remaining 13197 h, w, ww halfword // list traversal registers 13198 ) 13199 if x > 0 { 13200 octant = byte(firstOctant) 13201 } else if x == 0 { 13202 if y <= 0 { 13203 if y == 0 { 13204 prg.curX = 0 13205 prg.curY = 0 13206 goto exit 13207 } else { 13208 octant = byte(firstOctant + negateX) 13209 } 13210 } else { 13211 octant = byte(firstOctant) 13212 } 13213 } else { 13214 x = -x 13215 if y == 0 { 13216 octant = byte(firstOctant + negateX + negateY) 13217 } else { 13218 octant = byte(firstOctant + negateX) 13219 } 13220 } 13221 if y < 0 { 13222 octant = byte(int32(octant) + negateY) 13223 y = -y 13224 } 13225 if x >= y { 13226 x = x - y 13227 } else { 13228 octant = byte(int32(octant) + switchXAndY) 13229 x = y - x 13230 y = y - x 13231 } 13232 if prg.octantNumber[octant-1]&1 != 0 { 13233 s = int8(-1) 13234 } else { 13235 s = int8(+1) 13236 } 13237 h = uint16(int32(p) + int32(octant)) 13238 w = *(*prg.mem[*(*prg.mem[h].hh()).rh()].hh()).rh() 13239 ww = *(*prg.mem[w].hh()).rh() 13240 n = int32(*(*prg.mem[h].hh()).lh()) 13241 for n > 1 { 13242 if prg.abVsCd(x, *prg.mem[int32(ww)+2].int()-*prg.mem[int32(w)+2].int(), y, *prg.mem[int32(ww)+1].int()-*prg.mem[int32(w)+1].int()) != int32(s) { 13243 goto done 13244 } 13245 w = ww 13246 ww = *(*prg.mem[w].hh()).rh() 13247 n = n - 1 13248 } 13249 13250 done: 13251 prg.unskew(*prg.mem[int32(w)+1].int(), *prg.mem[int32(w)+2].int(), octant) 13252 13253 exit: 13254 } 13255 13256 // 490. \[24] Filling an envelope 13257 13258 // tangle:pos ../../mf.web:10438:30: 13259 13260 // We are about to reach the culmination of \MF's digital plotting routines: 13261 // Almost all of the previous algorithms will be brought to bear on \MF's 13262 // most difficult task, which is to fill the envelope of a given cyclic path 13263 // with respect to a given pen polygon. 13264 // 13265 // But we still must complete some of the preparatory work before taking such 13266 // a big plunge. 13267 13268 // 491. 13269 13270 // tangle:pos ../../mf.web:10447:3: 13271 13272 // Given a pointer |c| to a nonempty list of cubics, 13273 // and a pointer~|h| to the header information of a pen polygon segment, 13274 // the |offset_prep| routine changes the list into cubics that are 13275 // associated with particular pen offsets. Namely, the cubic between |p| 13276 // and~|q| should be associated with the |k|th offset when |right_type(p)=k|. 13277 // 13278 // List |c| is actually part of a cycle spec, so it terminates at the 13279 // first node whose |right_type| is |endpoint|. The cubics all have 13280 // monotone-nondecreasing $x(t)$ and $y(t)$. 13281 // \4 13282 // Declare subroutines needed by |offset_prep| 13283 func (prg *prg) splitForOffset(p halfword, t fraction) { 13284 var ( 13285 q halfword // the successor of |p| 13286 r1 halfword // the new node 13287 ) 13288 q = *(*prg.mem[p].hh()).rh() 13289 prg.splitCubic(p, t, *prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int()) 13290 r1 = *(*prg.mem[p].hh()).rh() 13291 if *prg.mem[int32(r1)+2].int() < *prg.mem[int32(p)+2].int() { 13292 *prg.mem[int32(r1)+2].int() = *prg.mem[int32(p)+2].int() 13293 } else if *prg.mem[int32(r1)+2].int() > *prg.mem[int32(q)+2].int() { 13294 *prg.mem[int32(r1)+2].int() = *prg.mem[int32(q)+2].int() 13295 } 13296 if *prg.mem[int32(r1)+1].int() < *prg.mem[int32(p)+1].int() { 13297 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(p)+1].int() 13298 } else if *prg.mem[int32(r1)+1].int() > *prg.mem[int32(q)+1].int() { 13299 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(q)+1].int() 13300 } 13301 } 13302 13303 func (prg *prg) finOffsetPrep(p halfword, k halfword, w halfword, 13304 x0, x1, x2, y0, y1, y2 int32, rising bool, n int32) { 13305 var ( 13306 ww halfword // for list manipulation 13307 du, dv scaled // for slope calculation 13308 t0, t1, t2 int32 // test coefficients 13309 t fraction // place where the derivative passes a critical slope 13310 s fraction // slope or reciprocal slope 13311 v int32 // intermediate value for updating |x0..y2| 13312 ) 13313 for true { 13314 *(*prg.mem[p].hh()).b1() = byte(k) 13315 if rising { 13316 if int32(k) == n { 13317 goto exit 13318 } else { 13319 ww = *(*prg.mem[w].hh()).rh() 13320 } 13321 } else if int32(k) == 1 { 13322 goto exit 13323 } else { 13324 ww = *(*prg.mem[w].hh()).lh() 13325 } // a pointer to $w_[k-1]$ 13326 13327 // Compute test coefficients |(t0,t1,t2)| for $s(t)$ versus $s_k$ or $s_[k-1]$ 13328 du = *prg.mem[int32(ww)+1].int() - *prg.mem[int32(w)+1].int() 13329 dv = *prg.mem[int32(ww)+2].int() - *prg.mem[int32(w)+2].int() 13330 if abs(du) >= abs(dv) { 13331 s = prg.makeFraction(dv, du) 13332 t0 = prg.takeFraction(x0, s) - y0 13333 t1 = prg.takeFraction(x1, s) - y1 13334 t2 = prg.takeFraction(x2, s) - y2 13335 } else { 13336 s = prg.makeFraction(du, dv) 13337 t0 = x0 - prg.takeFraction(y0, s) 13338 t1 = x1 - prg.takeFraction(y1, s) 13339 t2 = x2 - prg.takeFraction(y2, s) 13340 } 13341 t = prg.crossingPoint(t0, t1, t2) 13342 if t >= 02000000000 { 13343 goto exit 13344 } 13345 13346 // Split the cubic at $t$, and split off another cubic if the derivative crosses back 13347 { 13348 prg.splitForOffset(p, t) 13349 *(*prg.mem[p].hh()).b1() = byte(k) 13350 p = *(*prg.mem[p].hh()).rh() 13351 13352 v = x0 - prg.takeFraction(x0-x1, t) 13353 x1 = x1 - prg.takeFraction(x1-x2, t) 13354 x0 = v - prg.takeFraction(v-x1, t) 13355 13356 v = y0 - prg.takeFraction(y0-y1, t) 13357 y1 = y1 - prg.takeFraction(y1-y2, t) 13358 y0 = v - prg.takeFraction(v-y1, t) 13359 13360 t1 = t1 - prg.takeFraction(t1-t2, t) 13361 if t1 > 0 { 13362 t1 = 0 13363 } // without rounding error, |t1| would be |<=0| 13364 t = prg.crossingPoint(0, -t1, -t2) 13365 if t < 02000000000 { 13366 prg.splitForOffset(p, t) 13367 *(*prg.mem[*(*prg.mem[p].hh()).rh()].hh()).b1() = byte(k) 13368 13369 v = x1 - prg.takeFraction(x1-x2, t) 13370 x1 = x0 - prg.takeFraction(x0-x1, t) 13371 x2 = x1 - prg.takeFraction(x1-v, t) 13372 13373 v = y1 - prg.takeFraction(y1-y2, t) 13374 y1 = y0 - prg.takeFraction(y0-y1, t) 13375 y2 = y1 - prg.takeFraction(y1-v, t) 13376 } 13377 } 13378 if rising { 13379 k = uint16(int32(k) + 1) 13380 } else { 13381 k = uint16(int32(k) - 1) 13382 } 13383 w = ww 13384 } 13385 13386 exit: 13387 } 13388 13389 func (prg *prg) offsetPrep(c, h halfword) { 13390 var ( 13391 n halfword // the number of pen offsets 13392 p, q, r1, lh, ww halfword // for list manipulation 13393 k halfword // the current offset index 13394 w halfword // a pointer to offset $w_k$ 13395 13396 // Other local variables for |offset_prep| 13397 x0, x1, x2, y0, y1, y2 int32 // representatives of derivatives 13398 t0, t1, t2 int32 // coefficients of polynomial for slope testing 13399 du, dv, dx, dy int32 // for slopes of the pen and the curve 13400 maxCoef int32 // used while scaling 13401 x0a, x1a, x2a, y0a, y1a, y2a int32 // intermediate values 13402 t fraction // where the derivative passes through zero 13403 s fraction // slope or reciprocal slope 13404 ) 13405 p = c 13406 n = *(*prg.mem[h].hh()).lh() 13407 lh = *(*prg.mem[h].hh()).rh() // now |lh| points to $w_0$ 13408 for int32(*(*prg.mem[p].hh()).b1()) != endpoint { 13409 q = *(*prg.mem[p].hh()).rh() 13410 13411 // Split the cubic between |p| and |q|, if necessary, into cubics associated with single offsets, after which |q| should point to the end of the final such cubic 13412 if int32(n) <= 1 { 13413 *(*prg.mem[p].hh()).b1() = 1 13414 } else { 13415 x0 = *prg.mem[int32(p)+5].int() - *prg.mem[int32(p)+1].int() // should be |>=0| 13416 x2 = *prg.mem[int32(q)+1].int() - *prg.mem[int32(q)+3].int() // likewise 13417 x1 = *prg.mem[int32(q)+3].int() - *prg.mem[int32(p)+5].int() // but this might be negative 13418 y0 = *prg.mem[int32(p)+6].int() - *prg.mem[int32(p)+2].int() 13419 y2 = *prg.mem[int32(q)+2].int() - *prg.mem[int32(q)+4].int() 13420 y1 = *prg.mem[int32(q)+4].int() - *prg.mem[int32(p)+6].int() 13421 maxCoef = abs(x0) // we take |abs| just to make sure 13422 if abs(x1) > maxCoef { 13423 maxCoef = abs(x1) 13424 } 13425 if abs(x2) > maxCoef { 13426 maxCoef = abs(x2) 13427 } 13428 if abs(y0) > maxCoef { 13429 maxCoef = abs(y0) 13430 } 13431 if abs(y1) > maxCoef { 13432 maxCoef = abs(y1) 13433 } 13434 if abs(y2) > maxCoef { 13435 maxCoef = abs(y2) 13436 } 13437 if maxCoef == 0 { 13438 goto notFound 13439 } 13440 for maxCoef < 01000000000 { 13441 maxCoef = maxCoef + maxCoef 13442 x0 = x0 + x0 13443 x1 = x1 + x1 13444 x2 = x2 + x2 13445 y0 = y0 + y0 13446 y1 = y1 + y1 13447 y2 = y2 + y2 13448 } 13449 13450 // Find the initial slope, |dy/dx| 13451 dx = x0 13452 dy = y0 13453 if dx == 0 { 13454 if dy == 0 { 13455 dx = x1 13456 dy = y1 13457 if dx == 0 { 13458 if dy == 0 { 13459 dx = x2 13460 dy = y2 13461 } 13462 } 13463 } 13464 } 13465 if dx == 0 { 13466 prg.finOffsetPrep(p, n, *(*prg.mem[*(*prg.mem[lh].hh()).lh()].hh()).lh(), -x0, -x1, -x2, -y0, -y1, -y2, false, int32(n)) 13467 } else { 13468 k = 1 13469 w = *(*prg.mem[lh].hh()).rh() 13470 for true { 13471 if int32(k) == int32(n) { 13472 goto done 13473 } 13474 ww = *(*prg.mem[w].hh()).rh() 13475 if prg.abVsCd(dy, abs(*prg.mem[int32(ww)+1].int()-*prg.mem[int32(w)+1].int()), dx, abs(*prg.mem[int32(ww)+2].int()-*prg.mem[int32(w)+2].int())) >= 0 { 13476 k = uint16(int32(k) + 1) 13477 w = ww 13478 } else { 13479 goto done 13480 } 13481 } 13482 13483 done: 13484 ; 13485 13486 // Complete the offset splitting process 13487 if int32(k) == 1 { 13488 t = 02000000000 + 1 13489 } else { 13490 ww = *(*prg.mem[w].hh()).lh() 13491 // Compute test coeff... 13492 du = *prg.mem[int32(ww)+1].int() - *prg.mem[int32(w)+1].int() 13493 dv = *prg.mem[int32(ww)+2].int() - *prg.mem[int32(w)+2].int() 13494 if abs(du) >= abs(dv) { 13495 s = prg.makeFraction(dv, du) 13496 t0 = prg.takeFraction(x0, s) - y0 13497 t1 = prg.takeFraction(x1, s) - y1 13498 t2 = prg.takeFraction(x2, s) - y2 13499 } else { 13500 s = prg.makeFraction(du, dv) 13501 t0 = x0 - prg.takeFraction(y0, s) 13502 t1 = x1 - prg.takeFraction(y1, s) 13503 t2 = x2 - prg.takeFraction(y2, s) 13504 } 13505 t = prg.crossingPoint(-t0, -t1, -t2) 13506 } 13507 if t >= 02000000000 { 13508 prg.finOffsetPrep(p, k, w, x0, x1, x2, y0, y1, y2, true, int32(n)) 13509 } else { 13510 prg.splitForOffset(p, t) 13511 r1 = *(*prg.mem[p].hh()).rh() 13512 13513 x1a = x0 - prg.takeFraction(x0-x1, t) 13514 x1 = x1 - prg.takeFraction(x1-x2, t) 13515 x2a = x1a - prg.takeFraction(x1a-x1, t) 13516 13517 y1a = y0 - prg.takeFraction(y0-y1, t) 13518 y1 = y1 - prg.takeFraction(y1-y2, t) 13519 y2a = y1a - prg.takeFraction(y1a-y1, t) 13520 13521 prg.finOffsetPrep(p, k, w, x0, x1a, x2a, y0, y1a, y2a, true, int32(n)) 13522 x0 = x2a 13523 y0 = y2a 13524 t1 = t1 - prg.takeFraction(t1-t2, t) 13525 if t1 < 0 { 13526 t1 = 0 13527 } 13528 t = prg.crossingPoint(0, t1, t2) 13529 if t < 02000000000 { 13530 prg.splitForOffset(r1, t) 13531 13532 x1a = x1 - prg.takeFraction(x1-x2, t) 13533 x1 = x0 - prg.takeFraction(x0-x1, t) 13534 x0a = x1 - prg.takeFraction(x1-x1a, t) 13535 13536 y1a = y1 - prg.takeFraction(y1-y2, t) 13537 y1 = y0 - prg.takeFraction(y0-y1, t) 13538 y0a = y1 - prg.takeFraction(y1-y1a, t) 13539 13540 prg.finOffsetPrep(*(*prg.mem[r1].hh()).rh(), k, w, x0a, x1a, x2, y0a, y1a, y2, true, int32(n)) 13541 x2 = x0a 13542 y2 = y0a 13543 } 13544 prg.finOffsetPrep(r1, halfword(int32(k)-1), ww, -x0, -x1, -x2, -y0, -y1, -y2, false, int32(n)) 13545 } 13546 } 13547 13548 notFound: 13549 } 13550 13551 // Advance |p| to node |q|, removing any “dead” cubics that might have been introduced by the splitting process 13552 for { 13553 r1 = *(*prg.mem[p].hh()).rh() 13554 if *prg.mem[int32(p)+1].int() == *prg.mem[int32(p)+5].int() { 13555 if *prg.mem[int32(p)+2].int() == *prg.mem[int32(p)+6].int() { 13556 if *prg.mem[int32(p)+1].int() == *prg.mem[int32(r1)+3].int() { 13557 if *prg.mem[int32(p)+2].int() == *prg.mem[int32(r1)+4].int() { 13558 if *prg.mem[int32(p)+1].int() == *prg.mem[int32(r1)+1].int() { 13559 if *prg.mem[int32(p)+2].int() == *prg.mem[int32(r1)+2].int() { 13560 prg.removeCubic(p) 13561 if int32(r1) == int32(q) { 13562 q = p 13563 } 13564 r1 = p 13565 } 13566 } 13567 } 13568 } 13569 } 13570 } 13571 p = r1 13572 if int32(p) == int32(q) { 13573 break 13574 } 13575 } 13576 } 13577 } 13578 13579 // 500. 13580 13581 // tangle:pos ../../mf.web:10652:3: 13582 13583 // Now we must consider the general problem of |offset_prep|, when 13584 // nothing is known about a given cubic. We start by finding its 13585 // slope $s(0)$ in the vicinity of |t=0|. 13586 // 13587 // If $z'(t)=0$, the given cubic is numerically unstable, since the 13588 // slope direction is probably being influenced primarily by rounding 13589 // errors. A user who specifies such cuspy curves should expect to generate 13590 // rather wild results. The present code tries its best to believe the 13591 // existing data, as if no rounding errors were present. 13592 13593 // 506. 13594 13595 // tangle:pos ../../mf.web:10725:3: 13596 13597 // OK, it's time now for the biggie. The |fill_envelope| routine generalizes 13598 // |fill_spec| to polygonal envelopes. Its outer structure is essentially the 13599 // same as before, except that octants with no cubics do contribute to 13600 // the envelope. 13601 // \4 13602 // Declare the procedure called |skew_line_edges| 13603 func (prg *prg) skewLineEdges(p, w, ww halfword) { 13604 var ( 13605 x0, y0, x1, y1 scaled // from and to 13606 ) 13607 if *prg.mem[int32(w)+1].int() != *prg.mem[int32(ww)+1].int() || *prg.mem[int32(w)+2].int() != *prg.mem[int32(ww)+2].int() { 13608 x0 = *prg.mem[int32(p)+1].int() + *prg.mem[int32(w)+1].int() 13609 y0 = *prg.mem[int32(p)+2].int() + *prg.mem[int32(w)+2].int() 13610 13611 x1 = *prg.mem[int32(p)+1].int() + *prg.mem[int32(ww)+1].int() 13612 y1 = *prg.mem[int32(p)+2].int() + *prg.mem[int32(ww)+2].int() 13613 13614 prg.unskew(x0, y0, prg.octant) // unskew and unrotate the coordinates 13615 x0 = prg.curX 13616 y0 = prg.curY 13617 13618 prg.unskew(x1, y1, prg.octant) 13619 13620 if prg.internal[tracingEdges-1] > 0200000 { 13621 prg.printNl(strNumber( /* "@ retrograde line from " */ 584)) 13622 // \xref[]]]\AT!_retro_][\.[\AT! retrograde line...]] 13623 // \xref[retrograde line...] 13624 prg.printTwo(x0, y0) 13625 prg.print( /* " to " */ 583) 13626 prg.printTwo(prg.curX, prg.curY) 13627 prg.printNl(strNumber( /* "" */ 285)) 13628 } 13629 13630 prg.lineEdges(x0, y0, prg.curX, prg.curY) // then draw a straight line 13631 } 13632 } 13633 13634 // \4 13635 // Declare the procedure called |dual_moves| 13636 func (prg *prg) dualMoves(h, p, q halfword) { 13637 var ( 13638 r1, s halfword // for list traversal 13639 13640 // Other local variables for |fill_envelope| 13641 m, n int32 // current lattice position 13642 mm0, mm1 int32 // skewed equivalents of |m0| and |m1| 13643 k int32 // current offset number 13644 w, ww halfword // pointers to the current offset and its neighbor 13645 smoothBot, smoothTop/* 0..moveSize */ uint16 // boundaries of smoothing 13646 xx, yy, xp, yp, delx, dely, tx, ty scaled 13647 // registers for coordinate calculations 13648 ) 13649 k = int32(*(*prg.mem[h].hh()).lh()) + 1 13650 ww = *(*prg.mem[h].hh()).rh() 13651 w = *(*prg.mem[ww].hh()).lh() 13652 13653 mm0 = prg.floorUnscaled(*prg.mem[int32(p)+1].int() + *prg.mem[int32(w)+1].int() - int32(prg.xyCorr[prg.octant-1])) 13654 mm1 = prg.floorUnscaled(*prg.mem[int32(q)+1].int() + *prg.mem[int32(ww)+1].int() - int32(prg.xyCorr[prg.octant-1])) 13655 for ii := int32(1); ii <= prg.n1-prg.n0+1; ii++ { 13656 n = ii 13657 _ = n 13658 prg.envMove[n] = mm1 13659 } 13660 prg.envMove[0] = mm0 13661 prg.movePtr = 0 13662 m = mm0 13663 r1 = p // recall that |right_type(q)=endpoint=0| now 13664 for true { 13665 if int32(r1) == int32(q) { 13666 smoothTop = prg.movePtr 13667 } 13668 for int32(*(*prg.mem[r1].hh()).b1()) != k { 13669 13670 // Insert a line segment dually to approach the correct offset 13671 xx = *prg.mem[int32(r1)+1].int() + *prg.mem[int32(w)+1].int() 13672 yy = *prg.mem[int32(r1)+2].int() + *prg.mem[int32(w)+2].int() + 0100000 13673 if prg.internal[tracingEdges-1] > 0200000 { 13674 prg.printNl(strNumber( /* "@ transition line " */ 585)) 13675 prg.printInt(k) 13676 prg.print( /* ", from " */ 586) 13677 // \xref[]]]\AT!_trans_][\.[\AT! transition line...]] 13678 // \xref[transition line...] 13679 prg.unskew(xx, yy-0100000, prg.octant) 13680 prg.printTwo(prg.curX, prg.curY) 13681 } 13682 13683 if int32(*(*prg.mem[r1].hh()).b1()) < k { 13684 k = k - 1 13685 w = *(*prg.mem[w].hh()).lh() 13686 xp = *prg.mem[int32(r1)+1].int() + *prg.mem[int32(w)+1].int() 13687 yp = *prg.mem[int32(r1)+2].int() + *prg.mem[int32(w)+2].int() + 0100000 13688 if yp != yy { 13689 ty = prg.floorScaled(yy - int32(prg.yCorr[prg.octant-1])) 13690 dely = yp - yy 13691 yy = yy - ty 13692 ty = yp - int32(prg.yCorr[prg.octant-1]) - ty 13693 if ty >= 0200000 { 13694 delx = xp - xx 13695 yy = 0200000 - yy 13696 for true { 13697 if m < prg.envMove[prg.movePtr] { 13698 prg.envMove[prg.movePtr] = m 13699 } 13700 tx = prg.takeFraction(delx, prg.makeFraction(yy, dely)) 13701 if prg.abVsCd(tx, dely, delx, yy)+int32(prg.xyCorr[prg.octant-1]) > 0 { 13702 tx = tx - 1 13703 } 13704 m = prg.floorUnscaled(xx + tx) 13705 ty = ty - 0200000 13706 prg.movePtr = uint16(int32(prg.movePtr) + 1) 13707 if ty < 0200000 { 13708 goto done1 13709 } 13710 yy = yy + 0200000 13711 } 13712 13713 done1: 13714 if m < prg.envMove[prg.movePtr] { 13715 prg.envMove[prg.movePtr] = m 13716 } 13717 } 13718 } 13719 } else { 13720 k = k + 1 13721 w = *(*prg.mem[w].hh()).rh() 13722 xp = *prg.mem[int32(r1)+1].int() + *prg.mem[int32(w)+1].int() 13723 yp = *prg.mem[int32(r1)+2].int() + *prg.mem[int32(w)+2].int() + 0100000 13724 } 13725 if prg.internal[tracingEdges-1] > 0200000 { 13726 prg.print( /* " to " */ 583) 13727 prg.unskew(xp, yp-0100000, prg.octant) 13728 prg.printTwo(prg.curX, prg.curY) 13729 prg.printNl(strNumber( /* "" */ 285)) 13730 } 13731 13732 m = prg.floorUnscaled(xp - int32(prg.xyCorr[prg.octant-1])) 13733 prg.movePtr = uint16(prg.floorUnscaled(yp-int32(prg.yCorr[prg.octant-1])) - prg.n0) 13734 if m < prg.envMove[prg.movePtr] { 13735 prg.envMove[prg.movePtr] = m 13736 } 13737 } 13738 if int32(r1) == int32(p) { 13739 smoothBot = prg.movePtr 13740 } 13741 if int32(r1) == int32(q) { 13742 goto done 13743 } 13744 prg.move[prg.movePtr] = 1 13745 n = int32(prg.movePtr) 13746 s = *(*prg.mem[r1].hh()).rh() 13747 13748 prg.makeMoves(*prg.mem[int32(r1)+1].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(r1)+5].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(s)+3].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(s)+1].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(r1)+2].int()+*prg.mem[int32(w)+2].int()+0100000, *prg.mem[int32(r1)+6].int()+*prg.mem[int32(w)+2].int()+0100000, *prg.mem[int32(s)+4].int()+*prg.mem[int32(w)+2].int()+0100000, *prg.mem[int32(s)+2].int()+*prg.mem[int32(w)+2].int()+0100000, prg.xyCorr[prg.octant-1], prg.yCorr[prg.octant-1]) 13749 13750 // Transfer moves dually from the |move| array to |env_move| 13751 for { 13752 if m < prg.envMove[n] { 13753 prg.envMove[n] = m 13754 } 13755 m = m + prg.move[n] - 1 13756 n = n + 1 13757 if n > int32(prg.movePtr) { 13758 break 13759 } 13760 } 13761 r1 = s 13762 } 13763 13764 done: 13765 prg.move[0] = int32(prg.d0) + prg.envMove[1] - mm0 13766 for ii := int32(1); ii <= int32(prg.movePtr); ii++ { 13767 n = ii 13768 _ = n 13769 prg.move[n] = prg.envMove[n+1] - prg.envMove[n] + 1 13770 } 13771 prg.move[prg.movePtr] = prg.move[prg.movePtr] - int32(prg.d1) 13772 if prg.internal[smoothing-1] > 0 { 13773 prg.smoothMoves(int32(smoothBot), int32(smoothTop)) 13774 } 13775 prg.moveToEdges(prg.m0, prg.n0, prg.m1, prg.n1) 13776 if *prg.mem[int32(q)+6].int() == diagonal { 13777 w = *(*prg.mem[h].hh()).rh() 13778 prg.skewLineEdges(q, w, *(*prg.mem[w].hh()).lh()) 13779 } 13780 } 13781 13782 func (prg *prg) fillEnvelope(specHead halfword) { 13783 var ( 13784 p, q, r1, s halfword // for list traversal 13785 h halfword // head of pen offset list for current octant 13786 www halfword // a pen offset of temporary interest 13787 13788 // Other local variables for |fill_envelope| 13789 m, n int32 // current lattice position 13790 mm0, mm1 int32 // skewed equivalents of |m0| and |m1| 13791 k int32 // current offset number 13792 w, ww halfword // pointers to the current offset and its neighbor 13793 smoothBot, smoothTop/* 0..moveSize */ uint16 // boundaries of smoothing 13794 xx, yy, xp, yp, delx, dely, tx, ty scaled 13795 // registers for coordinate calculations 13796 ) 13797 if prg.internal[tracingEdges-1] > 0 { 13798 prg.beginEdgeTracing() 13799 } 13800 p = specHead // we assume that |left_type(spec_head)=endpoint| 13801 for { 13802 prg.octant = byte(*prg.mem[int32(p)+3].int()) 13803 h = uint16(int32(prg.curPen) + int32(prg.octant)) 13804 13805 // Set variable |q| to the node at the end of the current octant 13806 q = p 13807 for int32(*(*prg.mem[q].hh()).b1()) != endpoint { 13808 q = *(*prg.mem[q].hh()).rh() 13809 } 13810 13811 // Determine the envelope's starting and ending lattice points |(m0,n0)| and |(m1,n1)| 13812 w = *(*prg.mem[h].hh()).rh() 13813 if *prg.mem[int32(p)+4].int() == diagonal { 13814 w = *(*prg.mem[w].hh()).lh() 13815 } 13816 if prg.internal[tracingEdges-1] > 0200000 { 13817 prg.printNl(strNumber( /* "@ Octant " */ 580)) 13818 prg.print(int32(prg.octantDir[prg.octant-1])) 13819 // \xref[]]]\AT!_Octant][\.[\AT! Octant...]] 13820 prg.print( /* " (" */ 558) 13821 prg.printInt(int32(*(*prg.mem[h].hh()).lh())) 13822 prg.print( /* " offset" */ 581) 13823 if int32(*(*prg.mem[h].hh()).lh()) != 1 { 13824 prg.printChar(asciiCode('s')) 13825 } 13826 prg.print( /* "), from " */ 582) 13827 prg.unskew(*prg.mem[int32(p)+1].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(p)+2].int()+*prg.mem[int32(w)+2].int(), prg.octant) 13828 prg.printTwo(prg.curX, prg.curY) 13829 13830 ww = *(*prg.mem[h].hh()).rh() 13831 if *prg.mem[int32(q)+6].int() == diagonal { 13832 ww = *(*prg.mem[ww].hh()).lh() 13833 } 13834 prg.print( /* " to " */ 583) 13835 prg.unskew(*prg.mem[int32(q)+1].int()+*prg.mem[int32(ww)+1].int(), *prg.mem[int32(q)+2].int()+*prg.mem[int32(ww)+2].int(), prg.octant) 13836 prg.printTwo(prg.curX, prg.curY) 13837 } 13838 13839 ww = *(*prg.mem[h].hh()).rh() 13840 www = ww // starting and ending offsets 13841 if prg.octantNumber[prg.octant-1]&1 != 0 { 13842 www = *(*prg.mem[www].hh()).lh() 13843 } else { 13844 ww = *(*prg.mem[ww].hh()).lh() 13845 } 13846 if int32(w) != int32(ww) { 13847 prg.skewLineEdges(p, w, ww) 13848 } 13849 prg.endRound(*prg.mem[int32(p)+1].int()+*prg.mem[int32(ww)+1].int(), *prg.mem[int32(p)+2].int()+*prg.mem[int32(ww)+2].int()) 13850 prg.m0 = prg.m1 13851 prg.n0 = prg.n1 13852 prg.d0 = prg.d1 13853 13854 prg.endRound(*prg.mem[int32(q)+1].int()+*prg.mem[int32(www)+1].int(), *prg.mem[int32(q)+2].int()+*prg.mem[int32(www)+2].int()) 13855 if prg.n1-prg.n0 >= moveSize { 13856 prg.overflow(strNumber( /* "move table size" */ 540), moveSize) 13857 } 13858 prg.offsetPrep(p, h) // this may clobber node~|q|, if it becomes ``dead'' 13859 13860 // Set variable |q| to the node at the end of the current octant 13861 q = p 13862 for int32(*(*prg.mem[q].hh()).b1()) != endpoint { 13863 q = *(*prg.mem[q].hh()).rh() 13864 } 13865 13866 // Make the envelope moves for the current octant and insert them in the pixel data 13867 if prg.octantNumber[prg.octant-1]&1 != 0 { 13868 k = 0 13869 w = *(*prg.mem[h].hh()).rh() 13870 ww = *(*prg.mem[w].hh()).lh() 13871 mm0 = prg.floorUnscaled(*prg.mem[int32(p)+1].int() + *prg.mem[int32(w)+1].int() - int32(prg.xyCorr[prg.octant-1])) 13872 mm1 = prg.floorUnscaled(*prg.mem[int32(q)+1].int() + *prg.mem[int32(ww)+1].int() - int32(prg.xyCorr[prg.octant-1])) 13873 for ii := int32(0); ii <= prg.n1-prg.n0-1; ii++ { 13874 n = ii 13875 _ = n 13876 prg.envMove[n] = mm0 13877 } 13878 prg.envMove[prg.n1-prg.n0] = mm1 13879 prg.movePtr = 0 13880 m = mm0 13881 r1 = p 13882 *(*prg.mem[q].hh()).b1() = byte(int32(*(*prg.mem[h].hh()).lh()) + 1) 13883 for true { 13884 if int32(r1) == int32(q) { 13885 smoothTop = prg.movePtr 13886 } 13887 for int32(*(*prg.mem[r1].hh()).b1()) != k { 13888 13889 // Insert a line segment to approach the correct offset 13890 xx = *prg.mem[int32(r1)+1].int() + *prg.mem[int32(w)+1].int() 13891 yy = *prg.mem[int32(r1)+2].int() + *prg.mem[int32(w)+2].int() + 0100000 13892 if prg.internal[tracingEdges-1] > 0200000 { 13893 prg.printNl(strNumber( /* "@ transition line " */ 585)) 13894 prg.printInt(k) 13895 prg.print( /* ", from " */ 586) 13896 // \xref[]]]\AT!_trans_][\.[\AT! transition line...]] 13897 // \xref[transition line...] 13898 prg.unskew(xx, yy-0100000, prg.octant) 13899 prg.printTwo(prg.curX, prg.curY) 13900 } 13901 13902 if int32(*(*prg.mem[r1].hh()).b1()) > k { 13903 k = k + 1 13904 w = *(*prg.mem[w].hh()).rh() 13905 xp = *prg.mem[int32(r1)+1].int() + *prg.mem[int32(w)+1].int() 13906 yp = *prg.mem[int32(r1)+2].int() + *prg.mem[int32(w)+2].int() + 0100000 13907 if yp != yy { 13908 ty = prg.floorScaled(yy - int32(prg.yCorr[prg.octant-1])) 13909 dely = yp - yy 13910 yy = yy - ty 13911 ty = yp - int32(prg.yCorr[prg.octant-1]) - ty 13912 if ty >= 0200000 { 13913 delx = xp - xx 13914 yy = 0200000 - yy 13915 for true { 13916 tx = prg.takeFraction(delx, prg.makeFraction(yy, dely)) 13917 if prg.abVsCd(tx, dely, delx, yy)+int32(prg.xyCorr[prg.octant-1]) > 0 { 13918 tx = tx - 1 13919 } 13920 m = prg.floorUnscaled(xx + tx) 13921 if m > prg.envMove[prg.movePtr] { 13922 prg.envMove[prg.movePtr] = m 13923 } 13924 ty = ty - 0200000 13925 if ty < 0200000 { 13926 goto done1 13927 } 13928 yy = yy + 0200000 13929 prg.movePtr = uint16(int32(prg.movePtr) + 1) 13930 } 13931 13932 done1: 13933 } 13934 } 13935 } else { 13936 k = k - 1 13937 w = *(*prg.mem[w].hh()).lh() 13938 xp = *prg.mem[int32(r1)+1].int() + *prg.mem[int32(w)+1].int() 13939 yp = *prg.mem[int32(r1)+2].int() + *prg.mem[int32(w)+2].int() + 0100000 13940 } 13941 if prg.internal[tracingEdges-1] > 0200000 { 13942 prg.print( /* " to " */ 583) 13943 prg.unskew(xp, yp-0100000, prg.octant) 13944 prg.printTwo(prg.curX, prg.curY) 13945 prg.printNl(strNumber( /* "" */ 285)) 13946 } 13947 13948 m = prg.floorUnscaled(xp - int32(prg.xyCorr[prg.octant-1])) 13949 prg.movePtr = uint16(prg.floorUnscaled(yp-int32(prg.yCorr[prg.octant-1])) - prg.n0) 13950 if m > prg.envMove[prg.movePtr] { 13951 prg.envMove[prg.movePtr] = m 13952 } 13953 } 13954 if int32(r1) == int32(p) { 13955 smoothBot = prg.movePtr 13956 } 13957 if int32(r1) == int32(q) { 13958 goto done 13959 } 13960 prg.move[prg.movePtr] = 1 13961 n = int32(prg.movePtr) 13962 s = *(*prg.mem[r1].hh()).rh() 13963 13964 prg.makeMoves(*prg.mem[int32(r1)+1].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(r1)+5].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(s)+3].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(s)+1].int()+*prg.mem[int32(w)+1].int(), *prg.mem[int32(r1)+2].int()+*prg.mem[int32(w)+2].int()+0100000, *prg.mem[int32(r1)+6].int()+*prg.mem[int32(w)+2].int()+0100000, *prg.mem[int32(s)+4].int()+*prg.mem[int32(w)+2].int()+0100000, *prg.mem[int32(s)+2].int()+*prg.mem[int32(w)+2].int()+0100000, prg.xyCorr[prg.octant-1], prg.yCorr[prg.octant-1]) 13965 13966 // Transfer moves from the |move| array to |env_move| 13967 for { 13968 m = m + prg.move[n] - 1 13969 if m > prg.envMove[n] { 13970 prg.envMove[n] = m 13971 } 13972 n = n + 1 13973 if n > int32(prg.movePtr) { 13974 break 13975 } 13976 } 13977 r1 = s 13978 } 13979 13980 done: 13981 prg.move[0] = int32(prg.d0) + prg.envMove[0] - mm0 13982 for ii := int32(1); ii <= int32(prg.movePtr); ii++ { 13983 n = ii 13984 _ = n 13985 prg.move[n] = prg.envMove[n] - prg.envMove[n-1] + 1 13986 } 13987 prg.move[prg.movePtr] = prg.move[prg.movePtr] - int32(prg.d1) 13988 if prg.internal[smoothing-1] > 0 { 13989 prg.smoothMoves(int32(smoothBot), int32(smoothTop)) 13990 } 13991 prg.moveToEdges(prg.m0, prg.n0, prg.m1, prg.n1) 13992 if *prg.mem[int32(q)+6].int() == axis { 13993 w = *(*prg.mem[h].hh()).rh() 13994 prg.skewLineEdges(q, *(*prg.mem[w].hh()).lh(), w) 13995 } 13996 } else { 13997 prg.dualMoves(h, p, q) 13998 } 13999 *(*prg.mem[q].hh()).b1() = byte(endpoint) 14000 p = *(*prg.mem[q].hh()).rh() 14001 if int32(p) == int32(specHead) { 14002 break 14003 } 14004 } 14005 if prg.internal[tracingEdges-1] > 0 { 14006 prg.endEdgeTracing() 14007 } 14008 prg.tossKnotList(specHead) 14009 } 14010 14011 // 524. \[25] Elliptical pens 14012 14013 // tangle:pos ../../mf.web:11071:26: 14014 14015 // To get the envelope of a cyclic path with respect to an ellipse, \MF\ 14016 // calculates the envelope with respect to a polygonal approximation to 14017 // the ellipse, using an approach due to John Hobby (Ph.D. thesis, 14018 // Stanford University, 1985). 14019 // \xref[Hobby, John Douglas] 14020 // This has two important advantages over trying to obtain the ``exact'' 14021 // envelope: 14022 // 14023 // \yskip\textindent[1)]It gives better results, because the polygon has been 14024 // designed to counteract problems that arise from digitization; the 14025 // polygon includes sub-pixel corrections to an exact ellipse that make 14026 // the results essentially independent of where the path falls on the raster. 14027 // For example, the exact envelope with respect to a pen of diameter~1 14028 // blackens a pixel if and only if the path intersects a circle of diameter~1 14029 // inscribed in that pixel; the resulting pattern has ``blots'' when the path 14030 // is traveling diagonally in unfortunate raster positions. A much better 14031 // result is obtained when pixels are blackened only when the path intersects 14032 // an inscribed [\sl diamond\/] of diameter~1. Such a diamond is precisely 14033 // the polygon that \MF\ uses in the special case of a circle whose diameter is~1. 14034 // 14035 // \yskip\textindent[2)]Polygonal envelopes of cubic splines are cubic 14036 // splines, hence it isn't necessary to introduce completely different 14037 // routines. By contrast, exact envelopes of cubic splines with respect 14038 // to circles are complicated curves, more difficult to plot than cubics. 14039 14040 // 525. 14041 14042 // tangle:pos ../../mf.web:11097:3: 14043 14044 // Hobby's construction involves some interesting number theory. 14045 // If $u$ and~$v$ are relatively prime integers, we divide the 14046 // set of integer points $(m,n)$ into equivalence classes by saying 14047 // that $(m,n)$ belongs to class $um+vn$. Then any two integer points 14048 // that lie on a line of slope $-u/v$ belong to the same class, because 14049 // such points have the form $(m+tv,n-tu)$. Neighboring lines of slope $-u/v$ 14050 // that go through integer points are separated by distance $1/\psqrt[u^2+v^2]$ 14051 // from each other, and these lines are perpendicular to lines of slope~$v/u$. 14052 // If we start at the origin and travel a distance $k/\psqrt[u^2+v^2]$ in 14053 // direction $(u,v)$, we reach the line of slope~$-u/v$ whose points 14054 // belong to class~$k$. 14055 // 14056 // For example, let $u=2$ and $v=3$. Then the points $(0,0)$, $(3,-2)$, 14057 // $\ldots$ belong to class~0; the points $(-1,1)$, $(2,-1)$, $\ldots$ belong 14058 // to class~1; and the distance between these two lines is $1/\sqrt[13]$. 14059 // The point $(2,3)$ itself belongs to class~13, hence its distance from 14060 // the origin is $13/\sqrt[13]=\sqrt[13]$ (which we already knew). 14061 // 14062 // Suppose we wish to plot envelopes with respect to polygons with 14063 // integer vertices. Then the best polygon for curves that travel in 14064 // direction $(v,-u)$ will contain the points of class~$k$ such that 14065 // $k/\psqrt[u^2+v^2]$ is as close as possible to~$d$, where $d$ is the 14066 // maximum distance of the given ellipse from the line $ux+vy=0$. 14067 // 14068 // The |fillin| correction assumes that a diagonal line has an 14069 // apparent thickness $$2f\cdot\min(\vert u\vert,\vert v\vert)/\psqrt[u^2+v^2]$$ 14070 // greater than would be obtained with truly square pixels. (If a 14071 // white pixel at an exterior corner is assumed to have apparent 14072 // darkness $f_1$ and a black pixel at an interior corner is assumed 14073 // to have apparent darkness $1-f_2$, then $f=f_1-f_2$ is the |fillin| 14074 // parameter.) Under this assumption we want to choose $k$ so that 14075 // $\bigl(k+2f\cdot\min(\vert u\vert,\vert v\vert)\bigr)\big/\psqrt[u^2+v^2]$ 14076 // is as close as possible to $d$. 14077 // 14078 // Integer coordinates for the vertices work nicely because the thickness of 14079 // the envelope at any given slope is independent of the position of the 14080 // path with respect to the raster. It turns out, in fact, that the same 14081 // property holds for polygons whose vertices have coordinates that are 14082 // integer multiples of~$1\over2$, because ellipses are symmetric about 14083 // the origin. It's convenient to double all dimensions and require the 14084 // resulting polygon to have vertices with integer coordinates. For example, 14085 // to get a circle of [\sl diameter]~$r$, we shall compute integer 14086 // coordinates for a circle of [\sl radius]~$r$. The circle of radius~$r$ 14087 // will want to be represented by a polygon that contains the boundary 14088 // points $(0,\pm r)$ and~$(\pm r,0)$; later we will divide everything 14089 // by~2 and get a polygon with $(0,\pm[1\over2]r)$ and $(\pm[1\over2]r,0)$ 14090 // on its boundary. 14091 14092 // 526. 14093 14094 // tangle:pos ../../mf.web:11145:3: 14095 14096 // In practice the important slopes are those having small values of 14097 // $u$ and~$v$; these make regular patterns in which our eyes quickly 14098 // spot irregularities. For example, horizontal and vertical lines 14099 // (when $u=0$ and $\vert v\vert=1$, or $\vert u\vert=1$ and $v=0$) 14100 // are the most important; diagonal lines (when $\vert u\vert=\vert v\vert=1$) 14101 // are next; and then come lines with slope $\pm2$ or $\pm1/2$. 14102 // 14103 // The nicest way to generate all rational directions having small 14104 // numerators and denominators is to generalize the Stern--Brocot tree 14105 // [cf.~[\sl Concrete Mathematics], section 4.5] 14106 // \xref[Brocot, Achille] 14107 // \xref[Stern, Moritz Abraham] 14108 // to a ``Stern--Brocot wreath'' as follows: Begin with four nodes 14109 // arranged in a circle, containing the respective directions 14110 // $(u,v)=(1,0)$, $(0,1)$, $(-1,0)$, and~$(0,-1)$. Then between pairs of 14111 // consecutive terms $(u,v)$ and $(u',v')$ of the wreath, insert the 14112 // direction $(u+u',v+v')$; continue doing this until some stopping 14113 // criterion is fulfilled. 14114 // 14115 // It is not difficult to verify that, regardless of the stopping 14116 // criterion, consecutive directions $(u,v)$ and $(u',v')$ of this 14117 // wreath will always satisfy the relation $uv'-u'v=1$. Such pairs 14118 // of directions have a nice property with respect to the equivalence 14119 // classes described above. Let $l$ be a line of equivalent integer points 14120 // $(m+tv,n-tu)$ with respect to~$(u,v)$, and let $l'$ be a line of 14121 // equivalent integer points $(m'+tv',n'-tu')$ with respect to~$(u',v')$. 14122 // Then $l$ and~$l'$ intersect in an integer point $(m'',n'')$, because 14123 // the determinant of the linear equations for intersection is $uv'-u'v=1$. 14124 // Notice that the class number of $(m'',n'')$ with respect to $(u+u',v+v')$ 14125 // is the sum of its class numbers with respect to $(u,v)$ and~$(u',v')$. 14126 // Moreover, consecutive points on~$l$ and~$l'$ belong to classes that 14127 // differ by exactly~1 with respect to $(u+u',v+v')$. 14128 // 14129 // This leads to a nice algorithm in which we construct a polygon having 14130 // ``correct'' class numbers for as many small-integer directions $(u,v)$ 14131 // as possible: Assuming that lines $l$ and~$l'$ contain points of the 14132 // correct class for $(u,v)$ and~$(u',v')$, respectively, we determine 14133 // the intersection $(m'',n'')$ and compute its class with respect to 14134 // $(u+u',v+v')$. If the class is too large to be the best approximation, 14135 // we move back the proper number of steps from $(m'',n'')$ toward smaller 14136 // class numbers on both $l$ and~$l'$, unless this requires moving to points 14137 // that are no longer in the polygon; in this way we arrive at two points that 14138 // determine a line~$l''$ having the appropriate class. The process continues 14139 // recursively, until it cannot proceed without removing the last remaining 14140 // point from the class for $(u,v)$ or the class for $(u',v')$. 14141 14142 // 527. 14143 14144 // tangle:pos ../../mf.web:11191:3: 14145 14146 // The |make_ellipse| subroutine produces a pointer to a cyclic path 14147 // whose vertices define a polygon suitable for envelopes. The control 14148 // points on this path will be ignored; in fact, the fields in knot nodes 14149 // that are usually reserved for control points are occupied by other 14150 // data that helps |make_ellipse| compute the desired polygon. 14151 // 14152 // Parameters |major_axis| and |minor_axis| define the axes of the ellipse; 14153 // and parameter |theta| is an angle by which the ellipse is rotated 14154 // counterclockwise. If |theta=0|, the ellipse has the equation 14155 // $(x/a)^2+(y/b)^2=1$, where |a=major_axis/2| and |b=minor_axis/2|. 14156 // In general, the points of the ellipse are generated in the complex plane 14157 // by the formula $e^[i\theta](a\cos t+ib\sin t)$, as $t$~ranges over all 14158 // angles. Notice that if |major_axis=minor_axis=d|, we obtain a circle 14159 // of diameter~|d|, regardless of the value of |theta|. 14160 // 14161 // The method sketched above is used to produce the elliptical polygon, 14162 // except that the main work is done only in the halfplane obtained from 14163 // the three starting directions $(0,-1)$, $(1,0)$,~$(0,1)$. Since the ellipse 14164 // has circular symmetry, we use the fact that the last half of the polygon 14165 // is simply the negative of the first half. Furthermore, we need to compute only 14166 // one quarter of the polygon if the ellipse has axis symmetry. 14167 func (prg *prg) makeEllipse(majorAxis, minorAxis scaled, 14168 theta angle) (r halfword) { 14169 var ( 14170 p, q, r1, s halfword // for list manipulation 14171 h halfword // head of the constructed knot list 14172 alpha, beta, gamma, delta int32 // special points 14173 c, d int32 // class numbers 14174 u, v int32 // directions 14175 symmetric bool // should the result be symmetric about the axes? 14176 ) 14177 if majorAxis == minorAxis || theta%0550000000 == 0 { 14178 symmetric = true 14179 alpha = 0 14180 if theta/0550000000&1 != 0 { 14181 beta = majorAxis 14182 gamma = minorAxis 14183 prg.nSin = 02000000000 14184 prg.nCos = 0 // |n_sin| and |n_cos| are used later 14185 } else { 14186 beta = minorAxis 14187 gamma = majorAxis 14188 theta = 0 14189 } // |n_sin| and |n_cos| aren't needed in this case 14190 } else { 14191 symmetric = false 14192 prg.nSinCos(theta) // set up $|n_sin|=\sin\theta$ and $|n_cos|=\cos\theta$ 14193 gamma = prg.takeFraction(majorAxis, prg.nSin) 14194 delta = prg.takeFraction(minorAxis, prg.nCos) 14195 beta = prg.pythAdd(gamma, delta) 14196 alpha = prg.takeFraction(prg.takeFraction(majorAxis, prg.makeFraction(gamma, beta)), prg.nCos) - prg.takeFraction(prg.takeFraction(minorAxis, prg.makeFraction(delta, beta)), prg.nSin) 14197 alpha = (alpha + 0100000) / 0200000 14198 gamma = prg.pythAdd(prg.takeFraction(majorAxis, prg.nCos), prg.takeFraction(minorAxis, prg.nSin)) 14199 } 14200 beta = (beta + 0100000) / 0200000 14201 gamma = (gamma + 0100000) / 0200000 14202 p = prg.getNode(knotNodeSize) 14203 q = prg.getNode(knotNodeSize) 14204 r1 = prg.getNode(knotNodeSize) 14205 if symmetric { 14206 s = uint16(memMin) 14207 } else { 14208 s = prg.getNode(knotNodeSize) 14209 } 14210 h = p 14211 *(*prg.mem[p].hh()).rh() = q 14212 *(*prg.mem[q].hh()).rh() = r1 14213 *(*prg.mem[r1].hh()).rh() = s // |s=null| or |link(s)=null| 14214 14215 // Revise the values of $\alpha$, $\beta$, $\gamma$, if necessary, so that degenerate lines of length zero will not be obtained 14216 if beta == 0 { 14217 beta = 1 14218 } 14219 if gamma == 0 { 14220 gamma = 1 14221 } 14222 if gamma <= abs(alpha) { 14223 if alpha > 0 { 14224 alpha = gamma - 1 14225 } else { 14226 alpha = 1 - gamma 14227 } 14228 } 14229 *prg.mem[int32(p)+1].int() = -(alpha * 0100000) 14230 *prg.mem[int32(p)+2].int() = -(beta * 0100000) 14231 *prg.mem[int32(q)+1].int() = gamma * 0100000 14232 14233 *prg.mem[int32(q)+2].int() = *prg.mem[int32(p)+2].int() 14234 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(q)+1].int() 14235 14236 *prg.mem[int32(p)+5].int() = 0 14237 *prg.mem[int32(q)+3].int() = -0100000 14238 14239 *prg.mem[int32(q)+5].int() = 0100000 14240 *prg.mem[int32(r1)+3].int() = 0 14241 14242 *prg.mem[int32(r1)+5].int() = 0 14243 *prg.mem[int32(p)+6].int() = beta 14244 *prg.mem[int32(q)+6].int() = gamma 14245 *prg.mem[int32(r1)+6].int() = beta 14246 14247 *prg.mem[int32(q)+4].int() = gamma + alpha 14248 if symmetric { 14249 *prg.mem[int32(r1)+2].int() = 0 14250 *prg.mem[int32(r1)+4].int() = beta 14251 } else { 14252 *prg.mem[int32(r1)+2].int() = -*prg.mem[int32(p)+2].int() 14253 *prg.mem[int32(r1)+4].int() = beta + beta 14254 14255 *prg.mem[int32(s)+1].int() = -*prg.mem[int32(p)+1].int() 14256 *prg.mem[int32(s)+2].int() = *prg.mem[int32(r1)+2].int() 14257 14258 *prg.mem[int32(s)+3].int() = 0100000 14259 *prg.mem[int32(s)+4].int() = gamma - alpha 14260 } 14261 14262 // Interpolate new vertices in the ellipse data structure until improvement is impossible 14263 for true { 14264 u = *prg.mem[int32(p)+5].int() + *prg.mem[int32(q)+5].int() 14265 v = *prg.mem[int32(q)+3].int() + *prg.mem[int32(r1)+3].int() 14266 c = *prg.mem[int32(p)+6].int() + *prg.mem[int32(q)+6].int() 14267 14268 // Compute the distance |d| from class~0 to the edge of the ellipse in direction |(u,v)|, times $\psqrt[u^2+v^2]$, rounded to the nearest integer 14269 delta = prg.pythAdd(u, v) 14270 if majorAxis == minorAxis { 14271 d = majorAxis 14272 } else { 14273 if theta == 0 { 14274 alpha = u 14275 beta = v 14276 } else { 14277 alpha = prg.takeFraction(u, prg.nCos) + prg.takeFraction(v, prg.nSin) 14278 beta = prg.takeFraction(v, prg.nCos) - prg.takeFraction(u, prg.nSin) 14279 } 14280 alpha = prg.makeFraction(alpha, delta) 14281 beta = prg.makeFraction(beta, delta) 14282 d = prg.pythAdd(prg.takeFraction(majorAxis, alpha), prg.takeFraction(minorAxis, beta)) 14283 } 14284 alpha = abs(u) 14285 beta = abs(v) 14286 if alpha < beta { 14287 alpha = abs(v) 14288 beta = abs(u) 14289 } // now $\alpha=\max(\vert u\vert,\vert v\vert)$, 14290 // $\beta=\min(\vert u\vert,\vert v\vert)$ 14291 14292 if prg.internal[fillin-1] != 0 { 14293 d = d - prg.takeFraction(prg.internal[fillin-1], prg.makeFraction(beta+beta, delta)) 14294 } 14295 d = prg.takeFraction((d+4)/8, delta) 14296 alpha = alpha / 0100000 14297 if d < alpha { 14298 d = alpha 14299 } 14300 delta = c - d // we want to move |delta| steps back 14301 // from the intersection vertex~|q| 14302 14303 if delta > 0 { 14304 if delta > *prg.mem[int32(r1)+4].int() { 14305 delta = *prg.mem[int32(r1)+4].int() 14306 } 14307 if delta >= *prg.mem[int32(q)+4].int() { 14308 delta = *prg.mem[int32(q)+4].int() 14309 14310 *prg.mem[int32(p)+6].int() = c - delta 14311 *prg.mem[int32(p)+5].int() = u 14312 *prg.mem[int32(q)+3].int() = v 14313 14314 *prg.mem[int32(q)+1].int() = *prg.mem[int32(q)+1].int() - delta**prg.mem[int32(r1)+3].int() 14315 *prg.mem[int32(q)+2].int() = *prg.mem[int32(q)+2].int() + delta**prg.mem[int32(q)+5].int() 14316 14317 *prg.mem[int32(r1)+4].int() = *prg.mem[int32(r1)+4].int() - delta 14318 } else { 14319 // Insert a new line for direction |(u,v)| between |p| and~|q| 14320 s = prg.getNode(knotNodeSize) 14321 *(*prg.mem[p].hh()).rh() = s 14322 *(*prg.mem[s].hh()).rh() = q 14323 14324 *prg.mem[int32(s)+1].int() = *prg.mem[int32(q)+1].int() + delta**prg.mem[int32(q)+3].int() 14325 *prg.mem[int32(s)+2].int() = *prg.mem[int32(q)+2].int() - delta**prg.mem[int32(p)+5].int() 14326 14327 *prg.mem[int32(q)+1].int() = *prg.mem[int32(q)+1].int() - delta**prg.mem[int32(r1)+3].int() 14328 *prg.mem[int32(q)+2].int() = *prg.mem[int32(q)+2].int() + delta**prg.mem[int32(q)+5].int() 14329 14330 *prg.mem[int32(s)+3].int() = *prg.mem[int32(q)+3].int() 14331 *prg.mem[int32(s)+5].int() = u 14332 *prg.mem[int32(q)+3].int() = v 14333 14334 *prg.mem[int32(s)+6].int() = c - delta 14335 14336 *prg.mem[int32(s)+4].int() = *prg.mem[int32(q)+4].int() - delta 14337 *prg.mem[int32(q)+4].int() = delta 14338 *prg.mem[int32(r1)+4].int() = *prg.mem[int32(r1)+4].int() - delta 14339 } 14340 } else { 14341 p = q 14342 } 14343 14344 // Move to the next remaining triple |(p,q,r)|, removing and skipping past zero-length lines that might be present; |goto done| if all triples have been processed 14345 for true { 14346 q = *(*prg.mem[p].hh()).rh() 14347 if int32(q) == memMin { 14348 goto done 14349 } 14350 if *prg.mem[int32(q)+4].int() == 0 { 14351 *(*prg.mem[p].hh()).rh() = *(*prg.mem[q].hh()).rh() 14352 *prg.mem[int32(p)+6].int() = *prg.mem[int32(q)+6].int() 14353 *prg.mem[int32(p)+5].int() = *prg.mem[int32(q)+5].int() 14354 prg.freeNode(q, halfword(knotNodeSize)) 14355 } else { 14356 r1 = *(*prg.mem[q].hh()).rh() 14357 if int32(r1) == memMin { 14358 goto done 14359 } 14360 if *prg.mem[int32(r1)+4].int() == 0 { 14361 *(*prg.mem[p].hh()).rh() = r1 14362 prg.freeNode(q, halfword(knotNodeSize)) 14363 p = r1 14364 } else { 14365 goto found 14366 } 14367 } 14368 } 14369 14370 found: 14371 } 14372 14373 done: 14374 ; 14375 if symmetric { 14376 s = uint16(memMin) 14377 q = h 14378 for true { 14379 r1 = prg.getNode(knotNodeSize) 14380 *(*prg.mem[r1].hh()).rh() = s 14381 s = r1 14382 14383 *prg.mem[int32(s)+1].int() = *prg.mem[int32(q)+1].int() 14384 *prg.mem[int32(s)+2].int() = -*prg.mem[int32(q)+2].int() 14385 if int32(q) == int32(p) { 14386 goto done1 14387 } 14388 q = *(*prg.mem[q].hh()).rh() 14389 if *prg.mem[int32(q)+2].int() == 0 { 14390 goto done1 14391 } 14392 } 14393 14394 done1: 14395 if int32(*(*prg.mem[p].hh()).rh()) != memMin { 14396 prg.freeNode(*(*prg.mem[p].hh()).rh(), halfword(knotNodeSize)) 14397 } 14398 *(*prg.mem[p].hh()).rh() = s 14399 beta = -*prg.mem[int32(h)+2].int() 14400 for *prg.mem[int32(p)+2].int() != beta { 14401 p = *(*prg.mem[p].hh()).rh() 14402 } 14403 q = *(*prg.mem[p].hh()).rh() 14404 } 14405 14406 // Complete the ellipse by copying the negative of the half already computed 14407 if int32(q) != memMin { 14408 if *prg.mem[int32(h)+5].int() == 0 { 14409 p = h 14410 h = *(*prg.mem[h].hh()).rh() 14411 prg.freeNode(p, halfword(knotNodeSize)) 14412 14413 *prg.mem[int32(q)+1].int() = -*prg.mem[int32(h)+1].int() 14414 } 14415 p = q 14416 } else { 14417 q = p 14418 } 14419 r1 = *(*prg.mem[h].hh()).rh() // now |p=q|, |x_coord(p)=-x_coord(h)|, |y_coord(p)=-y_coord(h)| 14420 for { 14421 s = prg.getNode(knotNodeSize) 14422 *(*prg.mem[p].hh()).rh() = s 14423 p = s 14424 14425 *prg.mem[int32(p)+1].int() = -*prg.mem[int32(r1)+1].int() 14426 *prg.mem[int32(p)+2].int() = -*prg.mem[int32(r1)+2].int() 14427 r1 = *(*prg.mem[r1].hh()).rh() 14428 if int32(r1) == int32(q) { 14429 break 14430 } 14431 } 14432 *(*prg.mem[p].hh()).rh() = h 14433 r = h 14434 return r 14435 } 14436 14437 // 538. \[26] Direction and intersection times 14438 14439 // tangle:pos ../../mf.web:11496:43: 14440 14441 // A path of length $n$ is defined parametrically by functions $x(t)$ and 14442 // $y(t)$, for |0<=t<=n|; we can regard $t$ as the ``time'' at which the path 14443 // reaches the point $\bigl(x(t),y(t)\bigr)$. In this section of the program 14444 // we shall consider operations that determine special times associated with 14445 // given paths: the first time that a path travels in a given direction, and 14446 // a pair of times at which two paths cross each other. 14447 14448 // 539. 14449 14450 // tangle:pos ../../mf.web:11504:3: 14451 14452 // Let's start with the easier task. The function |find_direction_time| is 14453 // given a direction |(x,y)| and a path starting at~|h|. If the path never 14454 // travels in direction |(x,y)|, the direction time will be~|-1|; otherwise 14455 // it will be nonnegative. 14456 // 14457 // Certain anomalous cases can arise: If |(x,y)=(0,0)|, so that the given 14458 // direction is undefined, the direction time will be~0. If $\bigl(x'(t), 14459 // y'(t)\bigr)=(0,0)$, so that the path direction is undefined, it will be 14460 // assumed to match any given direction at time~|t|. 14461 // 14462 // The routine solves this problem in nondegenerate cases by rotating the path 14463 // and the given direction so that |(x,y)=(1,0)|; i.e., the main task will be 14464 // to find when a given path first travels ``due east.'' 14465 func (prg *prg) findDirectionTime(x, y scaled, h halfword) (r scaled) { 14466 var ( 14467 max scaled // $\max\bigl(\vert x\vert,\vert y\vert\bigr)$ 14468 p, q halfword // for list traversal 14469 n scaled // the direction time at knot |p| 14470 tt scaled // the direction time within a cubic 14471 14472 // Other local variables for |find_direction_time| 14473 x1, x2, x3, y1, y2, y3 scaled // multiples of rotated derivatives 14474 theta, phi angle // angles of exit and entry at a knot 14475 t fraction // temp storage 14476 ) 14477 if abs(x) < abs(y) { 14478 x = prg.makeFraction(x, abs(y)) 14479 if y > 0 { 14480 y = 02000000000 14481 } else { 14482 y = -02000000000 14483 } 14484 } else if x == 0 { 14485 r = 0 14486 goto exit 14487 } else { 14488 y = prg.makeFraction(y, abs(x)) 14489 if x > 0 { 14490 x = 02000000000 14491 } else { 14492 x = -02000000000 14493 } 14494 } 14495 n = 0 14496 p = h 14497 for true { 14498 if int32(*(*prg.mem[p].hh()).b1()) == endpoint { 14499 goto notFound 14500 } 14501 q = *(*prg.mem[p].hh()).rh() 14502 14503 // Rotate the cubic between |p| and |q|; then |goto found| if the rotated cubic travels due east at some time |tt|; but |goto not_found| if an entire cyclic path has been traversed 14504 tt = 0 14505 14506 // Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples of the control points of the rotated derivatives 14507 x1 = *prg.mem[int32(p)+5].int() - *prg.mem[int32(p)+1].int() 14508 x2 = *prg.mem[int32(q)+3].int() - *prg.mem[int32(p)+5].int() 14509 x3 = *prg.mem[int32(q)+1].int() - *prg.mem[int32(q)+3].int() 14510 14511 y1 = *prg.mem[int32(p)+6].int() - *prg.mem[int32(p)+2].int() 14512 y2 = *prg.mem[int32(q)+4].int() - *prg.mem[int32(p)+6].int() 14513 y3 = *prg.mem[int32(q)+2].int() - *prg.mem[int32(q)+4].int() 14514 14515 max = abs(x1) 14516 if abs(x2) > max { 14517 max = abs(x2) 14518 } 14519 if abs(x3) > max { 14520 max = abs(x3) 14521 } 14522 if abs(y1) > max { 14523 max = abs(y1) 14524 } 14525 if abs(y2) > max { 14526 max = abs(y2) 14527 } 14528 if abs(y3) > max { 14529 max = abs(y3) 14530 } 14531 if max == 0 { 14532 goto found 14533 } 14534 for max < 01000000000 { 14535 max = max + max 14536 x1 = x1 + x1 14537 x2 = x2 + x2 14538 x3 = x3 + x3 14539 y1 = y1 + y1 14540 y2 = y2 + y2 14541 y3 = y3 + y3 14542 } 14543 t = x1 14544 x1 = prg.takeFraction(x1, x) + prg.takeFraction(y1, y) 14545 y1 = prg.takeFraction(y1, x) - prg.takeFraction(t, y) 14546 14547 t = x2 14548 x2 = prg.takeFraction(x2, x) + prg.takeFraction(y2, y) 14549 y2 = prg.takeFraction(y2, x) - prg.takeFraction(t, y) 14550 14551 t = x3 14552 x3 = prg.takeFraction(x3, x) + prg.takeFraction(y3, y) 14553 y3 = prg.takeFraction(y3, x) - prg.takeFraction(t, y) 14554 if y1 == 0 { 14555 if x1 >= 0 { 14556 goto found 14557 } 14558 } 14559 if n > 0 { 14560 theta = prg.nArg(x1, y1) 14561 if theta >= 0 { 14562 if phi <= 0 { 14563 if phi >= theta-01320000000 { 14564 goto found 14565 } 14566 } 14567 } 14568 if theta <= 0 { 14569 if phi >= 0 { 14570 if phi <= theta+01320000000 { 14571 goto found 14572 } 14573 } 14574 } 14575 if int32(p) == int32(h) { 14576 goto notFound 14577 } 14578 } 14579 if x3 != 0 || y3 != 0 { 14580 phi = prg.nArg(x3, y3) 14581 } 14582 14583 // Exit to |found| if the curve whose derivatives are specified by |x1,x2,x3,y1,y2,y3| travels eastward at some time~|tt| 14584 if x1 < 0 { 14585 if x2 < 0 { 14586 if x3 < 0 { 14587 goto done 14588 } 14589 } 14590 } 14591 if prg.abVsCd(y1, y3, y2, y2) == 0 { 14592 if prg.abVsCd(y1, y2, 0, 0) < 0 { 14593 t = prg.makeFraction(y1, y1-y2) 14594 x1 = x1 - prg.takeFraction(x1-x2, t) 14595 x2 = x2 - prg.takeFraction(x2-x3, t) 14596 if x1-prg.takeFraction(x1-x2, t) >= 0 { 14597 tt = (t + 04000) / 010000 14598 goto found 14599 } 14600 } else if y3 == 0 { 14601 if y1 == 0 { 14602 t = prg.crossingPoint(-x1, -x2, -x3) 14603 if t <= 02000000000 { 14604 tt = (t + 04000) / 010000 14605 goto found 14606 } 14607 if prg.abVsCd(x1, x3, x2, x2) <= 0 { 14608 t = prg.makeFraction(x1, x1-x2) 14609 { 14610 tt = (t + 04000) / 010000 14611 goto found 14612 } 14613 } 14614 } else if x3 >= 0 { 14615 tt = 0200000 14616 goto found 14617 } 14618 } 14619 14620 goto done 14621 } 14622 if y1 <= 0 { 14623 if y1 < 0 { 14624 y1 = -y1 14625 y2 = -y2 14626 y3 = -y3 14627 } else if y2 > 0 { 14628 y2 = -y2 14629 y3 = -y3 14630 } 14631 } 14632 14633 // Check the places where $B(y_1,y_2,y_3;t)=0$ to see if $B(x_1,x_2,x_3;t)\ge0$ 14634 t = prg.crossingPoint(y1, y2, y3) 14635 if t > 02000000000 { 14636 goto done 14637 } 14638 y2 = y2 - prg.takeFraction(y2-y3, t) 14639 x1 = x1 - prg.takeFraction(x1-x2, t) 14640 x2 = x2 - prg.takeFraction(x2-x3, t) 14641 x1 = x1 - prg.takeFraction(x1-x2, t) 14642 if x1 >= 0 { 14643 tt = (t + 04000) / 010000 14644 goto found 14645 } 14646 if y2 > 0 { 14647 y2 = 0 14648 } 14649 tt = t 14650 t = prg.crossingPoint(0, -y2, -y3) 14651 if t > 02000000000 { 14652 goto done 14653 } 14654 x1 = x1 - prg.takeFraction(x1-x2, t) 14655 x2 = x2 - prg.takeFraction(x2-x3, t) 14656 if x1-prg.takeFraction(x1-x2, t) >= 0 { 14657 t = tt - prg.takeFraction(tt-02000000000, t) 14658 { 14659 tt = (t + 04000) / 010000 14660 goto found 14661 } 14662 } 14663 14664 done: 14665 ; 14666 p = q 14667 n = n + 0200000 14668 } 14669 14670 notFound: 14671 r = -0200000 14672 goto exit 14673 14674 found: 14675 r = n + tt 14676 14677 exit: 14678 ; 14679 return r 14680 } 14681 14682 // 545. 14683 14684 // tangle:pos ../../mf.web:11608:3: 14685 14686 // In this step we want to use the |crossing_point| routine to find the 14687 // roots of the quadratic equation $B(y_1,y_2,y_3;t)=0$. 14688 // Several complications arise: If the quadratic equation has a double root, 14689 // the curve never crosses zero, and |crossing_point| will find nothing; 14690 // this case occurs iff $y_1y_3=y_2^2$ and $y_1y_2<0$. If the quadratic 14691 // equation has simple roots, or only one root, we may have to negate it 14692 // so that $B(y_1,y_2,y_3;t)$ crosses from positive to negative at its first root. 14693 // And finally, we need to do special things if $B(y_1,y_2,y_3;t)$ is 14694 // identically zero. 14695 14696 // 550. 14697 14698 // tangle:pos ../../mf.web:11692:3: 14699 14700 // The intersection of two cubics can be found by an interesting variant 14701 // of the general bisection scheme described in the introduction to |make_moves|.\ 14702 // 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)$, 14703 // we wish to find a pair of times $(t_1,t_2)$ such that $w(t_1)=z(t_2)$, 14704 // if an intersection exists. First we find the smallest rectangle that 14705 // encloses the points $\[w_0,w_1,w_2,w_3\]$ and check that it overlaps 14706 // the smallest rectangle that encloses 14707 // $\[z_0,z_1,z_2,z_3\]$; if not, the cubics certainly don't intersect. 14708 // But if the rectangles do overlap, we bisect the intervals, getting 14709 // new cubics $w'$ and~$w''$, $z'$~and~$z''$; the intersection routine first 14710 // tries for an intersection between $w'$ and~$z'$, then (if unsuccessful) 14711 // between $w'$ and~$z''$, then (if still unsuccessful) between $w''$ and~$z'$, 14712 // finally (if thrice unsuccessful) between $w''$ and~$z''$. After $l$~successful 14713 // levels of bisection we will have determined the intersection times $t_1$ 14714 // and~$t_2$ to $l$~bits of accuracy. 14715 // 14716 // \def\submin[_[\rm min]] \def\submax[_[\rm max]] 14717 // As before, it is better to work with the numbers $W_k=2^l(w_k-w_[k-1])$ 14718 // and $Z_k=2^l(z_k-z_[k-1])$ rather than the coefficients $w_k$ and $z_k$ 14719 // themselves. We also need one other quantity, $\Delta=2^l(w_0-z_0)$, 14720 // to determine when the enclosing rectangles overlap. Here's why: 14721 // The $x$~coordinates of~$w(t)$ are between $u\submin$ and $u\submax$, 14722 // and the $x$~coordinates of~$z(t)$ are between $x\submin$ and $x\submax$, 14723 // if we write $w_k=(u_k,v_k)$ and $z_k=(x_k,y_k)$ and $u\submin= 14724 // \min(u_0,u_1,u_2,u_3)$, etc. These intervals of $x$~coordinates 14725 // overlap if and only if $u\submin\L x\submax$ and 14726 // $x\submin\L u\submax$. Letting 14727 // $$U\submin=\min(0,U_1,U_1+U_2,U_1+U_2+U_3),\; 14728 // U\submax=\max(0,U_1,U_1+U_2,U_1+U_2+U_3),$$ 14729 // we have $2^lu\submin=2^lu_0+U\submin$, etc.; the condition for overlap 14730 // reduces to 14731 // $$X\submin-U\submax\L 2^l(u_0-x_0)\L X\submax-U\submin.$$ 14732 // Thus we want to maintain the quantity $2^l(u_0-x_0)$; similarly, 14733 // the quantity $2^l(v_0-y_0)$ accounts for the $y$~coordinates. The 14734 // coordinates of $\Delta=2^l(w_0-z_0)$ must stay bounded as $l$ increases, 14735 // because of the overlap condition; i.e., we know that $X\submin$, 14736 // $X\submax$, and their relatives are bounded, hence $X\submax- 14737 // U\submin$ and $X\submin-U\submax$ are bounded. 14738 14739 // 551. 14740 14741 // tangle:pos ../../mf.web:11731:3: 14742 14743 // Incidentally, if the given cubics intersect more than once, the process 14744 // just sketched will not necessarily find the lexicographically smallest pair 14745 // $(t_1,t_2)$. The solution actually obtained will be smallest in ``shuffled 14746 // order''; i.e., if $t_1=(.a_1a_2\ldots a_[16])_2$ and 14747 // $t_2=(.b_1b_2\ldots b_[16])_2$, then we will minimize 14748 // $a_1b_1a_2b_2\ldots a_[16]b_[16]$, not 14749 // $a_1a_2\ldots a_[16]b_1b_2\ldots b_[16]$. 14750 // Shuffled order agrees with lexicographic order if all pairs of solutions 14751 // $(t_1,t_2)$ and $(t_1',t_2')$ have the property that $t_1<t_1'$ iff 14752 // $t_2<t_2'$; but in general, lexicographic order can be quite different, 14753 // and the bisection algorithm would be substantially less efficient if it were 14754 // constrained by lexicographic order. 14755 // 14756 // For example, suppose that an overlap has been found for $l=3$ and 14757 // $(t_1,t_2)= (.101,.011)$ in binary, but that no overlap is produced by 14758 // either of the alternatives $(.1010,.0110)$, $(.1010,.0111)$ at level~4. 14759 // Then there is probably an intersection in one of the subintervals 14760 // $(.1011,.011x)$; but lexicographic order would require us to explore 14761 // $(.1010,.1xxx)$ and $(.1011,.00xx)$ and $(.1011,.010x)$ first. We wouldn't 14762 // want to store all of the subdivision data for the second path, so the 14763 // subdivisions would have to be regenerated many times. Such inefficiencies 14764 // would be associated with every `1' in the binary representation of~$t_1$. 14765 14766 // 554. 14767 14768 // tangle:pos ../../mf.web:11839:3: 14769 14770 // Computation of the min and max is a tedious but fairly fast sequence of 14771 // instructions; exactly four comparisons are made in each branch. 14772 14773 // 556. 14774 14775 // tangle:pos ../../mf.web:11886:3: 14776 14777 // The given cubics $B(w_0,w_1,w_2,w_3;t)$ and 14778 // $B(z_0,z_1,z_2,z_3;t)$ are specified in adjacent knot nodes |(p,link(p))| 14779 // and |(pp,link(pp))|, respectively. 14780 func (prg *prg) cubicIntersection(p, pp halfword) { 14781 var ( 14782 q, qq halfword // |link(p)|, |link(pp)| 14783 ) 14784 prg.timeToGo = maxPatience 14785 prg.maxT = 2 14786 14787 // Initialize for intersections at level zero 14788 q = *(*prg.mem[p].hh()).rh() 14789 qq = *(*prg.mem[pp].hh()).rh() 14790 prg.bisectPtr = uint16(intPackets) 14791 14792 prg.bisectStack[int32(prg.bisectPtr)-5] = *prg.mem[int32(p)+5].int() - *prg.mem[int32(p)+1].int() 14793 prg.bisectStack[int32(prg.bisectPtr)-5+1] = *prg.mem[int32(q)+3].int() - *prg.mem[int32(p)+5].int() 14794 prg.bisectStack[int32(prg.bisectPtr)-5+2] = *prg.mem[int32(q)+1].int() - *prg.mem[int32(q)+3].int() 14795 if prg.bisectStack[int32(prg.bisectPtr)-5] < 0 { 14796 if prg.bisectStack[int32(prg.bisectPtr)-5+2] >= 0 { 14797 if prg.bisectStack[int32(prg.bisectPtr)-5+1] < 0 { 14798 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] 14799 } else { 14800 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] 14801 } 14802 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+2] 14803 if prg.bisectStack[int32(prg.bisectPtr)-5+4] < 0 { 14804 prg.bisectStack[int32(prg.bisectPtr)-5+4] = 0 14805 } 14806 } else { 14807 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+2] 14808 if prg.bisectStack[int32(prg.bisectPtr)-5+3] > prg.bisectStack[int32(prg.bisectPtr)-5] { 14809 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] 14810 } 14811 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] 14812 if prg.bisectStack[int32(prg.bisectPtr)-5+4] < 0 { 14813 prg.bisectStack[int32(prg.bisectPtr)-5+4] = 0 14814 } 14815 } 14816 } else if prg.bisectStack[int32(prg.bisectPtr)-5+2] <= 0 { 14817 if prg.bisectStack[int32(prg.bisectPtr)-5+1] > 0 { 14818 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] 14819 } else { 14820 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] 14821 } 14822 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+2] 14823 if prg.bisectStack[int32(prg.bisectPtr)-5+3] > 0 { 14824 prg.bisectStack[int32(prg.bisectPtr)-5+3] = 0 14825 } 14826 } else { 14827 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+2] 14828 if prg.bisectStack[int32(prg.bisectPtr)-5+4] < prg.bisectStack[int32(prg.bisectPtr)-5] { 14829 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] 14830 } 14831 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] 14832 if prg.bisectStack[int32(prg.bisectPtr)-5+3] > 0 { 14833 prg.bisectStack[int32(prg.bisectPtr)-5+3] = 0 14834 } 14835 } 14836 14837 prg.bisectStack[int32(prg.bisectPtr)-10] = *prg.mem[int32(p)+6].int() - *prg.mem[int32(p)+2].int() 14838 prg.bisectStack[int32(prg.bisectPtr)-10+1] = *prg.mem[int32(q)+4].int() - *prg.mem[int32(p)+6].int() 14839 prg.bisectStack[int32(prg.bisectPtr)-10+2] = *prg.mem[int32(q)+2].int() - *prg.mem[int32(q)+4].int() 14840 if prg.bisectStack[int32(prg.bisectPtr)-10] < 0 { 14841 if prg.bisectStack[int32(prg.bisectPtr)-10+2] >= 0 { 14842 if prg.bisectStack[int32(prg.bisectPtr)-10+1] < 0 { 14843 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] 14844 } else { 14845 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] 14846 } 14847 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+2] 14848 if prg.bisectStack[int32(prg.bisectPtr)-10+4] < 0 { 14849 prg.bisectStack[int32(prg.bisectPtr)-10+4] = 0 14850 } 14851 } else { 14852 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+2] 14853 if prg.bisectStack[int32(prg.bisectPtr)-10+3] > prg.bisectStack[int32(prg.bisectPtr)-10] { 14854 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] 14855 } 14856 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] 14857 if prg.bisectStack[int32(prg.bisectPtr)-10+4] < 0 { 14858 prg.bisectStack[int32(prg.bisectPtr)-10+4] = 0 14859 } 14860 } 14861 } else if prg.bisectStack[int32(prg.bisectPtr)-10+2] <= 0 { 14862 if prg.bisectStack[int32(prg.bisectPtr)-10+1] > 0 { 14863 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] 14864 } else { 14865 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] 14866 } 14867 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+2] 14868 if prg.bisectStack[int32(prg.bisectPtr)-10+3] > 0 { 14869 prg.bisectStack[int32(prg.bisectPtr)-10+3] = 0 14870 } 14871 } else { 14872 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+2] 14873 if prg.bisectStack[int32(prg.bisectPtr)-10+4] < prg.bisectStack[int32(prg.bisectPtr)-10] { 14874 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] 14875 } 14876 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] 14877 if prg.bisectStack[int32(prg.bisectPtr)-10+3] > 0 { 14878 prg.bisectStack[int32(prg.bisectPtr)-10+3] = 0 14879 } 14880 } 14881 14882 prg.bisectStack[int32(prg.bisectPtr)-15] = *prg.mem[int32(pp)+5].int() - *prg.mem[int32(pp)+1].int() 14883 prg.bisectStack[int32(prg.bisectPtr)-15+1] = *prg.mem[int32(qq)+3].int() - *prg.mem[int32(pp)+5].int() 14884 prg.bisectStack[int32(prg.bisectPtr)-15+2] = *prg.mem[int32(qq)+1].int() - *prg.mem[int32(qq)+3].int() 14885 if prg.bisectStack[int32(prg.bisectPtr)-15] < 0 { 14886 if prg.bisectStack[int32(prg.bisectPtr)-15+2] >= 0 { 14887 if prg.bisectStack[int32(prg.bisectPtr)-15+1] < 0 { 14888 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] 14889 } else { 14890 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] 14891 } 14892 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+2] 14893 if prg.bisectStack[int32(prg.bisectPtr)-15+4] < 0 { 14894 prg.bisectStack[int32(prg.bisectPtr)-15+4] = 0 14895 } 14896 } else { 14897 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+2] 14898 if prg.bisectStack[int32(prg.bisectPtr)-15+3] > prg.bisectStack[int32(prg.bisectPtr)-15] { 14899 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] 14900 } 14901 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] 14902 if prg.bisectStack[int32(prg.bisectPtr)-15+4] < 0 { 14903 prg.bisectStack[int32(prg.bisectPtr)-15+4] = 0 14904 } 14905 } 14906 } else if prg.bisectStack[int32(prg.bisectPtr)-15+2] <= 0 { 14907 if prg.bisectStack[int32(prg.bisectPtr)-15+1] > 0 { 14908 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] 14909 } else { 14910 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] 14911 } 14912 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+2] 14913 if prg.bisectStack[int32(prg.bisectPtr)-15+3] > 0 { 14914 prg.bisectStack[int32(prg.bisectPtr)-15+3] = 0 14915 } 14916 } else { 14917 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+2] 14918 if prg.bisectStack[int32(prg.bisectPtr)-15+4] < prg.bisectStack[int32(prg.bisectPtr)-15] { 14919 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] 14920 } 14921 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] 14922 if prg.bisectStack[int32(prg.bisectPtr)-15+3] > 0 { 14923 prg.bisectStack[int32(prg.bisectPtr)-15+3] = 0 14924 } 14925 } 14926 14927 prg.bisectStack[int32(prg.bisectPtr)-20] = *prg.mem[int32(pp)+6].int() - *prg.mem[int32(pp)+2].int() 14928 prg.bisectStack[int32(prg.bisectPtr)-20+1] = *prg.mem[int32(qq)+4].int() - *prg.mem[int32(pp)+6].int() 14929 prg.bisectStack[int32(prg.bisectPtr)-20+2] = *prg.mem[int32(qq)+2].int() - *prg.mem[int32(qq)+4].int() 14930 if prg.bisectStack[int32(prg.bisectPtr)-20] < 0 { 14931 if prg.bisectStack[int32(prg.bisectPtr)-20+2] >= 0 { 14932 if prg.bisectStack[int32(prg.bisectPtr)-20+1] < 0 { 14933 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] 14934 } else { 14935 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] 14936 } 14937 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+2] 14938 if prg.bisectStack[int32(prg.bisectPtr)-20+4] < 0 { 14939 prg.bisectStack[int32(prg.bisectPtr)-20+4] = 0 14940 } 14941 } else { 14942 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+2] 14943 if prg.bisectStack[int32(prg.bisectPtr)-20+3] > prg.bisectStack[int32(prg.bisectPtr)-20] { 14944 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] 14945 } 14946 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] 14947 if prg.bisectStack[int32(prg.bisectPtr)-20+4] < 0 { 14948 prg.bisectStack[int32(prg.bisectPtr)-20+4] = 0 14949 } 14950 } 14951 } else if prg.bisectStack[int32(prg.bisectPtr)-20+2] <= 0 { 14952 if prg.bisectStack[int32(prg.bisectPtr)-20+1] > 0 { 14953 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] 14954 } else { 14955 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] 14956 } 14957 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+2] 14958 if prg.bisectStack[int32(prg.bisectPtr)-20+3] > 0 { 14959 prg.bisectStack[int32(prg.bisectPtr)-20+3] = 0 14960 } 14961 } else { 14962 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+2] 14963 if prg.bisectStack[int32(prg.bisectPtr)-20+4] < prg.bisectStack[int32(prg.bisectPtr)-20] { 14964 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] 14965 } 14966 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] 14967 if prg.bisectStack[int32(prg.bisectPtr)-20+3] > 0 { 14968 prg.bisectStack[int32(prg.bisectPtr)-20+3] = 0 14969 } 14970 } 14971 14972 prg.delx = *prg.mem[int32(p)+1].int() - *prg.mem[int32(pp)+1].int() 14973 prg.dely = *prg.mem[int32(p)+2].int() - *prg.mem[int32(pp)+2].int() 14974 14975 prg.tol = 0 14976 prg.uv = prg.bisectPtr 14977 prg.xy = prg.bisectPtr 14978 prg.threeL = 0 14979 prg.curT = 1 14980 prg.curTt = 1 14981 for true { 14982 continue1: 14983 if prg.delx-prg.tol <= prg.bisectStack[int32(prg.xy)-15+4]-prg.bisectStack[int32(prg.uv)-5+3] { 14984 if prg.delx+prg.tol >= prg.bisectStack[int32(prg.xy)-15+3]-prg.bisectStack[int32(prg.uv)-5+4] { 14985 if prg.dely-prg.tol <= prg.bisectStack[int32(prg.xy)-20+4]-prg.bisectStack[int32(prg.uv)-10+3] { 14986 if prg.dely+prg.tol >= prg.bisectStack[int32(prg.xy)-20+3]-prg.bisectStack[int32(prg.uv)-10+4] { 14987 if prg.curT >= prg.maxT { 14988 if prg.maxT == 0400000 { 14989 prg.curT = (prg.curT + 1) / 2 14990 prg.curTt = (prg.curTt + 1) / 2 14991 goto exit 14992 } 14993 prg.maxT = prg.maxT + prg.maxT 14994 prg.apprT = prg.curT 14995 prg.apprTt = prg.curTt 14996 } 14997 14998 // Subdivide for a new level of intersection 14999 prg.bisectStack[prg.bisectPtr] = prg.delx 15000 prg.bisectStack[int32(prg.bisectPtr)+1] = prg.dely 15001 prg.bisectStack[int32(prg.bisectPtr)+2] = prg.tol 15002 prg.bisectStack[int32(prg.bisectPtr)+3] = int32(prg.uv) 15003 prg.bisectStack[int32(prg.bisectPtr)+4] = int32(prg.xy) 15004 prg.bisectPtr = uint16(int32(prg.bisectPtr) + intIncrement) 15005 15006 prg.curT = prg.curT + prg.curT 15007 prg.curTt = prg.curTt + prg.curTt 15008 15009 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] = prg.bisectStack[int32(prg.uv)-5] 15010 prg.bisectStack[int32(prg.bisectPtr)-5+2] = prg.bisectStack[int32(prg.uv)-5+2] 15011 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] = (prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.uv)-5+1]) / 2 15012 prg.bisectStack[int32(prg.bisectPtr)-5+1] = (prg.bisectStack[int32(prg.bisectPtr)-5+2] + prg.bisectStack[int32(prg.uv)-5+1]) / 2 15013 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+2] = (prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+1]) / 2 15014 prg.bisectStack[int32(prg.bisectPtr)-5] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+2] 15015 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] < 0 { 15016 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+2] >= 0 { 15017 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] < 0 { 15018 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] 15019 } else { 15020 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] 15021 } 15022 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+2] 15023 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] < 0 { 15024 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] = 0 15025 } 15026 } else { 15027 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+2] 15028 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] > prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] { 15029 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] 15030 } 15031 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] 15032 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] < 0 { 15033 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] = 0 15034 } 15035 } 15036 } else if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+2] <= 0 { 15037 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] > 0 { 15038 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] 15039 } else { 15040 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] 15041 } 15042 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+2] 15043 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] > 0 { 15044 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] = 0 15045 } 15046 } else { 15047 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+2] 15048 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] < prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] { 15049 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] 15050 } 15051 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-5] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+1] 15052 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] > 0 { 15053 prg.bisectStack[int32(prg.bisectPtr)-intPackets-5+3] = 0 15054 } 15055 } 15056 if prg.bisectStack[int32(prg.bisectPtr)-5] < 0 { 15057 if prg.bisectStack[int32(prg.bisectPtr)-5+2] >= 0 { 15058 if prg.bisectStack[int32(prg.bisectPtr)-5+1] < 0 { 15059 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] 15060 } else { 15061 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] 15062 } 15063 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+2] 15064 if prg.bisectStack[int32(prg.bisectPtr)-5+4] < 0 { 15065 prg.bisectStack[int32(prg.bisectPtr)-5+4] = 0 15066 } 15067 } else { 15068 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+2] 15069 if prg.bisectStack[int32(prg.bisectPtr)-5+3] > prg.bisectStack[int32(prg.bisectPtr)-5] { 15070 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] 15071 } 15072 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] 15073 if prg.bisectStack[int32(prg.bisectPtr)-5+4] < 0 { 15074 prg.bisectStack[int32(prg.bisectPtr)-5+4] = 0 15075 } 15076 } 15077 } else if prg.bisectStack[int32(prg.bisectPtr)-5+2] <= 0 { 15078 if prg.bisectStack[int32(prg.bisectPtr)-5+1] > 0 { 15079 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] 15080 } else { 15081 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] 15082 } 15083 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+2] 15084 if prg.bisectStack[int32(prg.bisectPtr)-5+3] > 0 { 15085 prg.bisectStack[int32(prg.bisectPtr)-5+3] = 0 15086 } 15087 } else { 15088 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] + prg.bisectStack[int32(prg.bisectPtr)-5+2] 15089 if prg.bisectStack[int32(prg.bisectPtr)-5+4] < prg.bisectStack[int32(prg.bisectPtr)-5] { 15090 prg.bisectStack[int32(prg.bisectPtr)-5+4] = prg.bisectStack[int32(prg.bisectPtr)-5] 15091 } 15092 prg.bisectStack[int32(prg.bisectPtr)-5+3] = prg.bisectStack[int32(prg.bisectPtr)-5] + prg.bisectStack[int32(prg.bisectPtr)-5+1] 15093 if prg.bisectStack[int32(prg.bisectPtr)-5+3] > 0 { 15094 prg.bisectStack[int32(prg.bisectPtr)-5+3] = 0 15095 } 15096 } 15097 15098 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] = prg.bisectStack[int32(prg.uv)-10] 15099 prg.bisectStack[int32(prg.bisectPtr)-10+2] = prg.bisectStack[int32(prg.uv)-10+2] 15100 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] = (prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.uv)-10+1]) / 2 15101 prg.bisectStack[int32(prg.bisectPtr)-10+1] = (prg.bisectStack[int32(prg.bisectPtr)-10+2] + prg.bisectStack[int32(prg.uv)-10+1]) / 2 15102 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+2] = (prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+1]) / 2 15103 prg.bisectStack[int32(prg.bisectPtr)-10] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+2] 15104 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] < 0 { 15105 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+2] >= 0 { 15106 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] < 0 { 15107 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] 15108 } else { 15109 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] 15110 } 15111 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+2] 15112 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] < 0 { 15113 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] = 0 15114 } 15115 } else { 15116 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+2] 15117 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] > prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] { 15118 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] 15119 } 15120 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] 15121 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] < 0 { 15122 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] = 0 15123 } 15124 } 15125 } else if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+2] <= 0 { 15126 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] > 0 { 15127 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] 15128 } else { 15129 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] 15130 } 15131 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+2] 15132 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] > 0 { 15133 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] = 0 15134 } 15135 } else { 15136 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+2] 15137 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] < prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] { 15138 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] 15139 } 15140 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-10] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+1] 15141 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] > 0 { 15142 prg.bisectStack[int32(prg.bisectPtr)-intPackets-10+3] = 0 15143 } 15144 } 15145 if prg.bisectStack[int32(prg.bisectPtr)-10] < 0 { 15146 if prg.bisectStack[int32(prg.bisectPtr)-10+2] >= 0 { 15147 if prg.bisectStack[int32(prg.bisectPtr)-10+1] < 0 { 15148 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] 15149 } else { 15150 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] 15151 } 15152 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+2] 15153 if prg.bisectStack[int32(prg.bisectPtr)-10+4] < 0 { 15154 prg.bisectStack[int32(prg.bisectPtr)-10+4] = 0 15155 } 15156 } else { 15157 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+2] 15158 if prg.bisectStack[int32(prg.bisectPtr)-10+3] > prg.bisectStack[int32(prg.bisectPtr)-10] { 15159 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] 15160 } 15161 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] 15162 if prg.bisectStack[int32(prg.bisectPtr)-10+4] < 0 { 15163 prg.bisectStack[int32(prg.bisectPtr)-10+4] = 0 15164 } 15165 } 15166 } else if prg.bisectStack[int32(prg.bisectPtr)-10+2] <= 0 { 15167 if prg.bisectStack[int32(prg.bisectPtr)-10+1] > 0 { 15168 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] 15169 } else { 15170 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] 15171 } 15172 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+2] 15173 if prg.bisectStack[int32(prg.bisectPtr)-10+3] > 0 { 15174 prg.bisectStack[int32(prg.bisectPtr)-10+3] = 0 15175 } 15176 } else { 15177 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] + prg.bisectStack[int32(prg.bisectPtr)-10+2] 15178 if prg.bisectStack[int32(prg.bisectPtr)-10+4] < prg.bisectStack[int32(prg.bisectPtr)-10] { 15179 prg.bisectStack[int32(prg.bisectPtr)-10+4] = prg.bisectStack[int32(prg.bisectPtr)-10] 15180 } 15181 prg.bisectStack[int32(prg.bisectPtr)-10+3] = prg.bisectStack[int32(prg.bisectPtr)-10] + prg.bisectStack[int32(prg.bisectPtr)-10+1] 15182 if prg.bisectStack[int32(prg.bisectPtr)-10+3] > 0 { 15183 prg.bisectStack[int32(prg.bisectPtr)-10+3] = 0 15184 } 15185 } 15186 15187 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] = prg.bisectStack[int32(prg.xy)-15] 15188 prg.bisectStack[int32(prg.bisectPtr)-15+2] = prg.bisectStack[int32(prg.xy)-15+2] 15189 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] = (prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.xy)-15+1]) / 2 15190 prg.bisectStack[int32(prg.bisectPtr)-15+1] = (prg.bisectStack[int32(prg.bisectPtr)-15+2] + prg.bisectStack[int32(prg.xy)-15+1]) / 2 15191 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+2] = (prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+1]) / 2 15192 prg.bisectStack[int32(prg.bisectPtr)-15] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+2] 15193 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] < 0 { 15194 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+2] >= 0 { 15195 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] < 0 { 15196 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] 15197 } else { 15198 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] 15199 } 15200 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+2] 15201 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] < 0 { 15202 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] = 0 15203 } 15204 } else { 15205 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+2] 15206 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] > prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] { 15207 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] 15208 } 15209 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] 15210 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] < 0 { 15211 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] = 0 15212 } 15213 } 15214 } else if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+2] <= 0 { 15215 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] > 0 { 15216 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] 15217 } else { 15218 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] 15219 } 15220 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+2] 15221 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] > 0 { 15222 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] = 0 15223 } 15224 } else { 15225 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+2] 15226 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] < prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] { 15227 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] 15228 } 15229 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-15] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+1] 15230 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] > 0 { 15231 prg.bisectStack[int32(prg.bisectPtr)-intPackets-15+3] = 0 15232 } 15233 } 15234 if prg.bisectStack[int32(prg.bisectPtr)-15] < 0 { 15235 if prg.bisectStack[int32(prg.bisectPtr)-15+2] >= 0 { 15236 if prg.bisectStack[int32(prg.bisectPtr)-15+1] < 0 { 15237 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] 15238 } else { 15239 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] 15240 } 15241 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+2] 15242 if prg.bisectStack[int32(prg.bisectPtr)-15+4] < 0 { 15243 prg.bisectStack[int32(prg.bisectPtr)-15+4] = 0 15244 } 15245 } else { 15246 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+2] 15247 if prg.bisectStack[int32(prg.bisectPtr)-15+3] > prg.bisectStack[int32(prg.bisectPtr)-15] { 15248 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] 15249 } 15250 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] 15251 if prg.bisectStack[int32(prg.bisectPtr)-15+4] < 0 { 15252 prg.bisectStack[int32(prg.bisectPtr)-15+4] = 0 15253 } 15254 } 15255 } else if prg.bisectStack[int32(prg.bisectPtr)-15+2] <= 0 { 15256 if prg.bisectStack[int32(prg.bisectPtr)-15+1] > 0 { 15257 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] 15258 } else { 15259 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] 15260 } 15261 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+2] 15262 if prg.bisectStack[int32(prg.bisectPtr)-15+3] > 0 { 15263 prg.bisectStack[int32(prg.bisectPtr)-15+3] = 0 15264 } 15265 } else { 15266 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] + prg.bisectStack[int32(prg.bisectPtr)-15+2] 15267 if prg.bisectStack[int32(prg.bisectPtr)-15+4] < prg.bisectStack[int32(prg.bisectPtr)-15] { 15268 prg.bisectStack[int32(prg.bisectPtr)-15+4] = prg.bisectStack[int32(prg.bisectPtr)-15] 15269 } 15270 prg.bisectStack[int32(prg.bisectPtr)-15+3] = prg.bisectStack[int32(prg.bisectPtr)-15] + prg.bisectStack[int32(prg.bisectPtr)-15+1] 15271 if prg.bisectStack[int32(prg.bisectPtr)-15+3] > 0 { 15272 prg.bisectStack[int32(prg.bisectPtr)-15+3] = 0 15273 } 15274 } 15275 15276 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] = prg.bisectStack[int32(prg.xy)-20] 15277 prg.bisectStack[int32(prg.bisectPtr)-20+2] = prg.bisectStack[int32(prg.xy)-20+2] 15278 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] = (prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.xy)-20+1]) / 2 15279 prg.bisectStack[int32(prg.bisectPtr)-20+1] = (prg.bisectStack[int32(prg.bisectPtr)-20+2] + prg.bisectStack[int32(prg.xy)-20+1]) / 2 15280 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+2] = (prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+1]) / 2 15281 prg.bisectStack[int32(prg.bisectPtr)-20] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+2] 15282 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] < 0 { 15283 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+2] >= 0 { 15284 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] < 0 { 15285 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] 15286 } else { 15287 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] 15288 } 15289 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+2] 15290 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] < 0 { 15291 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] = 0 15292 } 15293 } else { 15294 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+2] 15295 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] > prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] { 15296 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] 15297 } 15298 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] 15299 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] < 0 { 15300 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] = 0 15301 } 15302 } 15303 } else if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+2] <= 0 { 15304 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] > 0 { 15305 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] 15306 } else { 15307 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] 15308 } 15309 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+2] 15310 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] > 0 { 15311 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] = 0 15312 } 15313 } else { 15314 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+2] 15315 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] < prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] { 15316 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+4] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] 15317 } 15318 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] = prg.bisectStack[int32(prg.bisectPtr)-intPackets-20] + prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+1] 15319 if prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] > 0 { 15320 prg.bisectStack[int32(prg.bisectPtr)-intPackets-20+3] = 0 15321 } 15322 } 15323 if prg.bisectStack[int32(prg.bisectPtr)-20] < 0 { 15324 if prg.bisectStack[int32(prg.bisectPtr)-20+2] >= 0 { 15325 if prg.bisectStack[int32(prg.bisectPtr)-20+1] < 0 { 15326 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] 15327 } else { 15328 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] 15329 } 15330 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+2] 15331 if prg.bisectStack[int32(prg.bisectPtr)-20+4] < 0 { 15332 prg.bisectStack[int32(prg.bisectPtr)-20+4] = 0 15333 } 15334 } else { 15335 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+2] 15336 if prg.bisectStack[int32(prg.bisectPtr)-20+3] > prg.bisectStack[int32(prg.bisectPtr)-20] { 15337 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] 15338 } 15339 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] 15340 if prg.bisectStack[int32(prg.bisectPtr)-20+4] < 0 { 15341 prg.bisectStack[int32(prg.bisectPtr)-20+4] = 0 15342 } 15343 } 15344 } else if prg.bisectStack[int32(prg.bisectPtr)-20+2] <= 0 { 15345 if prg.bisectStack[int32(prg.bisectPtr)-20+1] > 0 { 15346 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] 15347 } else { 15348 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] 15349 } 15350 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+2] 15351 if prg.bisectStack[int32(prg.bisectPtr)-20+3] > 0 { 15352 prg.bisectStack[int32(prg.bisectPtr)-20+3] = 0 15353 } 15354 } else { 15355 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] + prg.bisectStack[int32(prg.bisectPtr)-20+2] 15356 if prg.bisectStack[int32(prg.bisectPtr)-20+4] < prg.bisectStack[int32(prg.bisectPtr)-20] { 15357 prg.bisectStack[int32(prg.bisectPtr)-20+4] = prg.bisectStack[int32(prg.bisectPtr)-20] 15358 } 15359 prg.bisectStack[int32(prg.bisectPtr)-20+3] = prg.bisectStack[int32(prg.bisectPtr)-20] + prg.bisectStack[int32(prg.bisectPtr)-20+1] 15360 if prg.bisectStack[int32(prg.bisectPtr)-20+3] > 0 { 15361 prg.bisectStack[int32(prg.bisectPtr)-20+3] = 0 15362 } 15363 } 15364 15365 prg.uv = uint16(int32(prg.bisectPtr) - intPackets) 15366 prg.xy = uint16(int32(prg.bisectPtr) - intPackets) 15367 prg.delx = prg.delx + prg.delx 15368 prg.dely = prg.dely + prg.dely 15369 15370 prg.tol = prg.tol - prg.threeL + int32(prg.tolStep) 15371 prg.tol = prg.tol + prg.tol 15372 prg.threeL = prg.threeL + int32(prg.tolStep) 15373 15374 goto continue1 15375 } 15376 } 15377 } 15378 } 15379 if prg.timeToGo > 0 { 15380 prg.timeToGo = prg.timeToGo - 1 15381 } else { 15382 for prg.apprT < 0200000 { 15383 prg.apprT = prg.apprT + prg.apprT 15384 prg.apprTt = prg.apprTt + prg.apprTt 15385 } 15386 prg.curT = prg.apprT 15387 prg.curTt = prg.apprTt 15388 goto exit 15389 } 15390 15391 // Advance to the next pair |(cur_t,cur_tt)| 15392 15393 // Advance to the next pair |(cur_t,cur_tt)| 15394 notFound: 15395 if prg.curTt&1 != 0 { 15396 if prg.curT&1 != 0 { 15397 prg.curT = prg.curT / 2 15398 prg.curTt = prg.curTt / 2 15399 if prg.curT == 0 { 15400 goto exit 15401 } 15402 prg.bisectPtr = uint16(int32(prg.bisectPtr) - intIncrement) 15403 prg.threeL = prg.threeL - int32(prg.tolStep) 15404 prg.delx = prg.bisectStack[prg.bisectPtr] 15405 prg.dely = prg.bisectStack[int32(prg.bisectPtr)+1] 15406 prg.tol = prg.bisectStack[int32(prg.bisectPtr)+2] 15407 prg.uv = uint16(prg.bisectStack[int32(prg.bisectPtr)+3]) 15408 prg.xy = uint16(prg.bisectStack[int32(prg.bisectPtr)+4]) 15409 15410 goto notFound 15411 } else { 15412 prg.curT = prg.curT + 1 15413 prg.delx = prg.delx + prg.bisectStack[int32(prg.uv)-5] + prg.bisectStack[int32(prg.uv)-5+1] + prg.bisectStack[int32(prg.uv)-5+2] 15414 prg.dely = prg.dely + prg.bisectStack[int32(prg.uv)-10] + prg.bisectStack[int32(prg.uv)-10+1] + prg.bisectStack[int32(prg.uv)-10+2] 15415 prg.uv = uint16(int32(prg.uv) + intPackets) // switch from |l_packets| to |r_packets| 15416 prg.curTt = prg.curTt - 1 15417 prg.xy = uint16(int32(prg.xy) - intPackets) // switch from |r_packets| to |l_packets| 15418 prg.delx = prg.delx + prg.bisectStack[int32(prg.xy)-15] + prg.bisectStack[int32(prg.xy)-15+1] + prg.bisectStack[int32(prg.xy)-15+2] 15419 prg.dely = prg.dely + prg.bisectStack[int32(prg.xy)-20] + prg.bisectStack[int32(prg.xy)-20+1] + prg.bisectStack[int32(prg.xy)-20+2] 15420 } 15421 } else { 15422 prg.curTt = prg.curTt + 1 15423 prg.tol = prg.tol + prg.threeL 15424 prg.delx = prg.delx - prg.bisectStack[int32(prg.xy)-15] - prg.bisectStack[int32(prg.xy)-15+1] - prg.bisectStack[int32(prg.xy)-15+2] 15425 prg.dely = prg.dely - prg.bisectStack[int32(prg.xy)-20] - prg.bisectStack[int32(prg.xy)-20+1] - prg.bisectStack[int32(prg.xy)-20+2] 15426 prg.xy = uint16(int32(prg.xy) + intPackets) // switch from |l_packets| to |r_packets| 15427 } 15428 } 15429 15430 exit: 15431 } 15432 15433 // 562. 15434 15435 // tangle:pos ../../mf.web:12006:3: 15436 15437 // The |path_intersection| procedure is much simpler. 15438 // It invokes |cubic_intersection| in lexicographic order until finding a 15439 // pair of cubics that intersect. The final intersection times are placed in 15440 // |cur_t| and~|cur_tt|. 15441 func (prg *prg) pathIntersection(h, hh halfword) { 15442 var ( 15443 p, pp halfword // link registers that traverse the given paths 15444 n, nn int32 // integer parts of intersection times, minus |unity| 15445 ) 15446 if int32(*(*prg.mem[h].hh()).b1()) == endpoint { 15447 *prg.mem[int32(h)+5].int() = *prg.mem[int32(h)+1].int() 15448 *prg.mem[int32(h)+3].int() = *prg.mem[int32(h)+1].int() 15449 *prg.mem[int32(h)+6].int() = *prg.mem[int32(h)+2].int() 15450 *prg.mem[int32(h)+4].int() = *prg.mem[int32(h)+2].int() 15451 *(*prg.mem[h].hh()).b1() = byte(explicit) 15452 } 15453 if int32(*(*prg.mem[hh].hh()).b1()) == endpoint { 15454 *prg.mem[int32(hh)+5].int() = *prg.mem[int32(hh)+1].int() 15455 *prg.mem[int32(hh)+3].int() = *prg.mem[int32(hh)+1].int() 15456 *prg.mem[int32(hh)+6].int() = *prg.mem[int32(hh)+2].int() 15457 *prg.mem[int32(hh)+4].int() = *prg.mem[int32(hh)+2].int() 15458 *(*prg.mem[hh].hh()).b1() = byte(explicit) 15459 } 15460 15461 prg.tolStep = 0 15462 for { 15463 n = -0200000 15464 p = h 15465 for { 15466 if int32(*(*prg.mem[p].hh()).b1()) != endpoint { 15467 nn = -0200000 15468 pp = hh 15469 for { 15470 if int32(*(*prg.mem[pp].hh()).b1()) != endpoint { 15471 prg.cubicIntersection(p, pp) 15472 if prg.curT > 0 { 15473 prg.curT = prg.curT + n 15474 prg.curTt = prg.curTt + nn 15475 goto exit 15476 } 15477 } 15478 nn = nn + 0200000 15479 pp = *(*prg.mem[pp].hh()).rh() 15480 if int32(pp) == int32(hh) { 15481 break 15482 } 15483 } 15484 } 15485 n = n + 0200000 15486 p = *(*prg.mem[p].hh()).rh() 15487 if int32(p) == int32(h) { 15488 break 15489 } 15490 } 15491 prg.tolStep = byte(int32(prg.tolStep) + 3) 15492 if int32(prg.tolStep) > 3 { 15493 break 15494 } 15495 } 15496 prg.curT = -0200000 15497 prg.curTt = -0200000 15498 15499 exit: 15500 } 15501 15502 // 564. \[27] Online graphic output 15503 15504 // tangle:pos ../../mf.web:12046:32: 15505 15506 // \MF\ displays images on the user's screen by means of a few primitive 15507 // operations that are defined below. These operations have deliberately been 15508 // kept simple so that they can be implemented without great difficulty on a 15509 // wide variety of machines. Since \PASCAL\ has no traditional standards for 15510 // graphic output, some system-dependent code needs to be written in order to 15511 // support this aspect of \MF; but the necessary routines are usually quite 15512 // easy to write. 15513 // \xref[system dependencies] 15514 // 15515 // In fact, there are exactly four such routines: 15516 // 15517 // \yskip\hang 15518 // |init_screen| does whatever initialization is necessary to 15519 // support the other operations; it is a boolean function that returns 15520 // |false| if graphic output cannot be supported (e.g., if the other three 15521 // routines have not been written, or if the user doesn't have the 15522 // right kind of terminal). 15523 // 15524 // \yskip\hang 15525 // |blank_rectangle| updates a buffer area in memory so that 15526 // all pixels in a specified rectangle will be set to the background color. 15527 // 15528 // \yskip\hang 15529 // |paint_row| assigns values to specified pixels in a row of 15530 // the buffer just mentioned, based on ``transition'' indices explained below. 15531 // 15532 // \yskip\hang 15533 // |update_screen| displays the current screen buffer; the 15534 // effects of |blank_rectangle| and |paint_row| commands may or may not 15535 // become visible until the next |update_screen| operation is performed. 15536 // (Thus, |update_screen| is analogous to |update_terminal|.) 15537 // 15538 // \yskip\noindent 15539 // The \PASCAL\ code here is a minimum version of |init_screen| and 15540 // |update_screen|, usable on \MF\ installations that don't 15541 // support screen output. If |init_screen| is changed to return |true| 15542 // instead of |false|, the other routines will simply log the fact 15543 // that they have been called; they won't really display anything. 15544 // The standard test routines for \MF\ use this log information to check 15545 // that \MF\ is working properly, but the |wlog| instructions should be 15546 // removed from production versions of \MF. 15547 func (prg *prg) initScreen() (r bool) { 15548 r = true // screen instructions will be logged 15549 return r 15550 } 15551 15552 func (prg *prg) updateScreen() { 15553 prg.logFile.Writeln("Calling UPDATESCREEN") // for testing only 15554 } 15555 15556 // 567. 15557 15558 // tangle:pos ../../mf.web:12126:3: 15559 15560 // The |blank_rectangle| routine simply whitens all pixels that lie in 15561 // columns |left_col| through |right_col-1|, inclusive, of rows 15562 // |top_row| through |bot_row-1|, inclusive, given four parameters that satisfy 15563 // the relations 15564 // $$\hbox[|0<=left_col<=right_col<=screen_width|,\quad 15565 // |0<=top_row<=bot_row<=screen_depth|.]$$ 15566 // If |left_col=right_col| or |top_row=bot_row|, nothing happens. 15567 // 15568 // The commented-out code in the following procedure is for illustrative 15569 // purposes only. 15570 // \xref[system dependencies] 15571 func (prg *prg) blankRectangle(leftCol, rightCol screenCol, 15572 topRow, botRow screenRow) { 15573 prg.logFile.Writeln() // this will be done only after |init_screen=true| 15574 prg.logFile.Writeln("Calling BLANKRECTANGLE(", leftCol, knuth.WriteWidth(1), ",", rightCol, knuth.WriteWidth(1), ",", topRow, knuth.WriteWidth(1), ",", botRow, knuth.WriteWidth(1), ")") 15575 } 15576 15577 // 568. 15578 15579 // tangle:pos ../../mf.web:12150:3: 15580 15581 // The real work of screen display is done by |paint_row|. But it's not 15582 // hard work, because the operation affects only 15583 // one of the screen rows, and it affects only a contiguous set of columns 15584 // in that row. There are four parameters: |r|~(the row), 15585 // |b|~(the initial color), 15586 // |a|~(the array of transition specifications), 15587 // and |n|~(the number of transitions). The elements of~|a| will satisfy 15588 // $$0\L a[0]<a[1]<\cdots<a[n]\L |screen_width|;$$ 15589 // the value of |r| will satisfy |0<=r<screen_depth|; and |n| will be positive. 15590 // 15591 // The general idea is to paint blocks of pixels in alternate colors; 15592 // the precise details are best conveyed by means of a \PASCAL\ 15593 // program (see the commented-out code below). 15594 // \xref[system dependencies] 15595 func (prg *prg) paintRow(r1 screenRow, b pixelColor, a transSpec, 15596 n screenCol) { 15597 var ( 15598 k screenCol // an index into |a| 15599 ) 15600 prg.logFile.Write("Calling PAINTROW(", r1, knuth.WriteWidth(1), ",", b, knuth.WriteWidth(1), ";") 15601 // this is done only after |init_screen=true| 15602 for ii := int32(0); ii <= int32(n); ii++ { 15603 k = screenCol(ii) 15604 _ = k 15605 prg.logFile.Write(a[k], knuth.WriteWidth(1)) 15606 if int32(k) != int32(n) { 15607 prg.logFile.Write(",") 15608 } 15609 } 15610 prg.logFile.Writeln(")") 15611 } 15612 15613 // 574. 15614 15615 // tangle:pos ../../mf.web:12259:3: 15616 15617 // Opening a window isn't like opening a file, because you can open it 15618 // as often as you like, and you never have to close it again. The idea is 15619 // simply to define special points on the current screen display. 15620 // 15621 // Overlapping window specifications may cause complex effects that can 15622 // be understood only by scrutinizing \MF's display algorithms; thus it 15623 // has been left undefined in the \MF\ user manual, although the behavior 15624 // \xref[METAFONTbook][\sl The [\logos METAFONT\/]book] 15625 // is in fact predictable. 15626 // 15627 // Here is a subroutine that implements the command `\&[openwindow]~|k| 15628 // \&[from]~$(\\[r0],\\[c0])$ \&[to]~$(\\[r1],\\[c1])$ \&[at]~$(x,y)$'. 15629 func (prg *prg) openAWindow(k windowNumber, r0, c0, r11, c1 scaled, 15630 x, y scaled) { 15631 var ( 15632 m, n int32 // pixel coordinates 15633 ) 15634 if r0 < 0 { 15635 r0 = 0 15636 } else { 15637 r0 = prg.roundUnscaled(r0) 15638 } 15639 r11 = prg.roundUnscaled(r11) 15640 if r11 > screenDepth { 15641 r11 = screenDepth 15642 } 15643 if r11 < r0 { 15644 if r0 > screenDepth { 15645 r0 = r11 15646 } else { 15647 r11 = r0 15648 } 15649 } 15650 if c0 < 0 { 15651 c0 = 0 15652 } else { 15653 c0 = prg.roundUnscaled(c0) 15654 } 15655 c1 = prg.roundUnscaled(c1) 15656 if c1 > screenWidth { 15657 c1 = screenWidth 15658 } 15659 if c1 < c0 { 15660 if c0 > screenWidth { 15661 c0 = c1 15662 } else { 15663 c1 = c0 15664 } 15665 } 15666 prg.windowOpen[k] = true 15667 prg.windowTime[k] = prg.windowTime[k] + 1 15668 15669 prg.leftCol[k] = byte(c0) 15670 prg.rightCol[k] = byte(c1) 15671 prg.topRow[k] = byte(r0) 15672 prg.botRow[k] = byte(r11) 15673 15674 // Compute the offsets between screen coordinates and actual coordinates 15675 m = prg.roundUnscaled(x) 15676 n = prg.roundUnscaled(y) - 1 15677 15678 prg.mWindow[k] = c0 - m 15679 prg.nWindow[k] = r0 + n 15680 { 15681 if !prg.screenStarted { 15682 prg.screenOk = prg.initScreen() 15683 prg.screenStarted = true 15684 } 15685 } 15686 if prg.screenOk { 15687 prg.blankRectangle(screenCol(c0), screenCol(c1), screenRow(r0), screenRow(r11)) 15688 prg.updateScreen() 15689 } 15690 } 15691 15692 // 577. 15693 15694 // tangle:pos ../../mf.web:12319:3: 15695 15696 // Now here comes \MF's most complicated operation related to window 15697 // display: Given the number~|k| of an open window, the pixels of positive 15698 // weight in |cur_edges| will be shown as |black| in the window; all other 15699 // pixels will be shown as |white|. 15700 func (prg *prg) dispEdges(k windowNumber) { 15701 var ( 15702 p, q halfword // for list manipulation 15703 alreadyThere bool // is a previous incarnation in the window? 15704 r1 int32 // row number 15705 15706 // Other local variables for |disp_edges| 15707 n screenCol // the highest active index in |row_transition| 15708 w, ww int32 // old and new accumulated weights 15709 b pixelColor // status of first pixel in the row transitions 15710 m, mm int32 // old and new screen column positions 15711 d int32 // edge-and-weight without |min_halfword| compensation 15712 mAdjustment int32 // conversion between edge and screen coordinates 15713 rightEdge int32 // largest edge-and-weight that could affect the window 15714 minCol screenCol // the smallest screen column number in the window 15715 ) 15716 if prg.screenOk { 15717 if int32(prg.leftCol[k]) < int32(prg.rightCol[k]) { 15718 if int32(prg.topRow[k]) < int32(prg.botRow[k]) { 15719 alreadyThere = false 15720 if int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).rh()) == int32(k) { 15721 if *prg.mem[int32(prg.curEdges)+4].int() == prg.windowTime[k] { 15722 alreadyThere = true 15723 } 15724 } 15725 if !alreadyThere { 15726 prg.blankRectangle(prg.leftCol[k], prg.rightCol[k], prg.topRow[k], prg.botRow[k]) 15727 } 15728 15729 // Initialize for the display computations 15730 mAdjustment = prg.mWindow[k] - int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) 15731 15732 rightEdge = 8 * (int32(prg.rightCol[k]) - mAdjustment) 15733 15734 minCol = prg.leftCol[k] 15735 p = *(*prg.mem[prg.curEdges].hh()).rh() 15736 r1 = prg.nWindow[k] - (int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh()) - zeroField) 15737 for int32(p) != int32(prg.curEdges) && r1 >= int32(prg.topRow[k]) { 15738 if r1 < int32(prg.botRow[k]) { 15739 if int32(*(*prg.mem[int32(p)+1].hh()).lh()) > memMin+1 { 15740 prg.sortEdges(p) 15741 } else if int32(*(*prg.mem[int32(p)+1].hh()).lh()) == memMin+1 { 15742 if alreadyThere { 15743 goto done 15744 } 15745 } 15746 *(*prg.mem[int32(p)+1].hh()).lh() = uint16(memMin + 1) // this time we'll paint, but maybe not next time 15747 15748 // Set up the parameters needed for |paint_row|; but |goto done| if no painting is needed after all 15749 n = 0 15750 ww = 0 15751 m = -1 15752 w = 0 15753 q = *(*prg.mem[int32(p)+1].hh()).rh() 15754 prg.rowTransition[0] = minCol 15755 for true { 15756 if int32(q) == 3000 { 15757 d = rightEdge 15758 } else { 15759 d = int32(*(*prg.mem[q].hh()).lh()) - 0 15760 } 15761 mm = d/8 + mAdjustment 15762 if mm != m { 15763 if w <= 0 { 15764 if ww > 0 { 15765 if m > int32(minCol) { 15766 if int32(n) == 0 { 15767 if alreadyThere { 15768 b = byte(white) 15769 n = byte(int32(n) + 1) 15770 } else { 15771 b = byte(black) 15772 } 15773 } else { 15774 n = byte(int32(n) + 1) 15775 } 15776 prg.rowTransition[n] = byte(m) 15777 } 15778 } 15779 } else if ww <= 0 { 15780 if m > int32(minCol) { 15781 if int32(n) == 0 { 15782 b = byte(black) 15783 } 15784 n = byte(int32(n) + 1) 15785 prg.rowTransition[n] = byte(m) 15786 } 15787 } 15788 m = mm 15789 w = ww 15790 } 15791 if d >= rightEdge { 15792 goto found 15793 } 15794 ww = ww + d%8 - zeroW 15795 q = *(*prg.mem[q].hh()).rh() 15796 } 15797 15798 found: 15799 if alreadyThere || ww > 0 { 15800 if int32(n) == 0 { 15801 if ww > 0 { 15802 b = byte(black) 15803 } else { 15804 b = byte(white) 15805 } 15806 } 15807 n = byte(int32(n) + 1) 15808 prg.rowTransition[n] = prg.rightCol[k] 15809 } else if int32(n) == 0 { 15810 goto done 15811 } 15812 15813 prg.paintRow(screenRow(r1), b, prg.rowTransition, n) 15814 15815 done: 15816 } 15817 p = *(*prg.mem[p].hh()).rh() 15818 r1 = r1 - 1 15819 } 15820 prg.updateScreen() 15821 prg.windowTime[k] = prg.windowTime[k] + 1 15822 *(*prg.mem[int32(prg.curEdges)+3].hh()).rh() = uint16(k) 15823 *prg.mem[int32(prg.curEdges)+4].int() = prg.windowTime[k] 15824 } 15825 } 15826 } 15827 } 15828 15829 // 588. 15830 15831 // tangle:pos ../../mf.web:12536:3: 15832 15833 // Actually the description above contains a little white lie. There's 15834 // another kind of variable called |proto_dependent|, which is 15835 // just like a |dependent| one except that the $\alpha$ coefficients 15836 // in its dependency list are |scaled| instead of being fractions. 15837 // Proto-dependency lists are mixed with dependency lists in the 15838 // nodes reachable from |dep_head|. 15839 15840 // 591. 15841 15842 // tangle:pos ../../mf.web:12578:3: 15843 15844 // The maximum absolute value of a coefficient in a given dependency list 15845 // is returned by the following simple function. 15846 func (prg *prg) maxCoef(p halfword) (r fraction) { 15847 var ( 15848 x fraction // the maximum so far 15849 ) 15850 x = 0 15851 for int32(*(*prg.mem[p].hh()).lh()) != memMin { 15852 if abs(*prg.mem[int32(p)+1].int()) > x { 15853 x = abs(*prg.mem[int32(p)+1].int()) 15854 } 15855 p = *(*prg.mem[p].hh()).rh() 15856 } 15857 r = x 15858 return r 15859 } 15860 15861 // 597. 15862 15863 // tangle:pos ../../mf.web:12697:3: 15864 15865 // It is convenient to have another subroutine for the special case 15866 // of |p_plus_fq| when |f=1.0|. In this routine lists |p| and |q| are 15867 // both of the same type~|t| (either |dependent| or |proto_dependent|). 15868 func (prg *prg) pPlusQ(p halfword, q halfword, t smallNumber) (r halfword) { 15869 var ( 15870 pp, qq halfword // |info(p)| and |info(q)|, respectively 15871 r1, s halfword // for list manipulation 15872 threshold int32 // defines a neighborhood of zero 15873 v int32 // temporary register 15874 ) 15875 if int32(t) == dependent { 15876 threshold = fractionThreshold 15877 } else { 15878 threshold = scaledThreshold 15879 } 15880 r1 = uint16(3000 - 1) 15881 pp = *(*prg.mem[p].hh()).lh() 15882 qq = *(*prg.mem[q].hh()).lh() 15883 for true { 15884 if int32(pp) == int32(qq) { 15885 if int32(pp) == memMin { 15886 goto done 15887 } else { 15888 // Contribute a term from |p|, plus the corresponding term from |q| 15889 v = *prg.mem[int32(p)+1].int() + *prg.mem[int32(q)+1].int() 15890 *prg.mem[int32(p)+1].int() = v 15891 s = p 15892 p = *(*prg.mem[p].hh()).rh() 15893 pp = *(*prg.mem[p].hh()).lh() 15894 if abs(v) < threshold { 15895 prg.freeNode(s, halfword(depNodeSize)) 15896 } else { 15897 if abs(v) >= 04525252525 { 15898 if prg.watchCoefs { 15899 *(*prg.mem[qq].hh()).b0() = byte(independentNeedingFix) 15900 prg.fixNeeded = true 15901 } 15902 } 15903 *(*prg.mem[r1].hh()).rh() = s 15904 r1 = s 15905 } 15906 q = *(*prg.mem[q].hh()).rh() 15907 qq = *(*prg.mem[q].hh()).lh() 15908 } 15909 } else if *prg.mem[int32(pp)+1].int() < *prg.mem[int32(qq)+1].int() { 15910 s = prg.getNode(depNodeSize) 15911 *(*prg.mem[s].hh()).lh() = qq 15912 *prg.mem[int32(s)+1].int() = *prg.mem[int32(q)+1].int() 15913 q = *(*prg.mem[q].hh()).rh() 15914 qq = *(*prg.mem[q].hh()).lh() 15915 *(*prg.mem[r1].hh()).rh() = s 15916 r1 = s 15917 } else { 15918 *(*prg.mem[r1].hh()).rh() = p 15919 r1 = p 15920 p = *(*prg.mem[p].hh()).rh() 15921 pp = *(*prg.mem[p].hh()).lh() 15922 } 15923 } 15924 15925 done: 15926 *prg.mem[int32(p)+1].int() = prg.slowAdd(*prg.mem[int32(p)+1].int(), *prg.mem[int32(q)+1].int()) 15927 *(*prg.mem[r1].hh()).rh() = p 15928 prg.depFinal = p 15929 r = *(*prg.mem[3000-1].hh()).rh() 15930 return r 15931 } 15932 15933 // 599. 15934 15935 // tangle:pos ../../mf.web:12736:3: 15936 15937 // A somewhat simpler routine will multiply a dependency list 15938 // by a given constant~|v|. The constant is either a |fraction| less than 15939 // |fraction_one|, or it is |scaled|. In the latter case we might be forced to 15940 // convert a dependency list to a proto-dependency list. 15941 // Parameters |t0| and |t1| are the list types before and after; 15942 // they should agree unless |t0=dependent| and |t1=proto_dependent| 15943 // and |v_is_scaled=true|. 15944 func (prg *prg) pTimesV(p halfword, v int32, 15945 t0, t1 smallNumber, vIsScaled bool) (r halfword) { 15946 var ( 15947 r1, s halfword // for list manipulation 15948 w int32 // tentative coefficient 15949 threshold int32 15950 scalingDown bool 15951 ) 15952 if int32(t0) != int32(t1) { 15953 scalingDown = true 15954 } else { 15955 scalingDown = !vIsScaled 15956 } 15957 if int32(t1) == dependent { 15958 threshold = halfFractionThreshold 15959 } else { 15960 threshold = halfScaledThreshold 15961 } 15962 r1 = uint16(3000 - 1) 15963 for int32(*(*prg.mem[p].hh()).lh()) != memMin { 15964 if scalingDown { 15965 w = prg.takeFraction(v, *prg.mem[int32(p)+1].int()) 15966 } else { 15967 w = prg.takeScaled(v, *prg.mem[int32(p)+1].int()) 15968 } 15969 if abs(w) <= threshold { 15970 s = *(*prg.mem[p].hh()).rh() 15971 prg.freeNode(p, halfword(depNodeSize)) 15972 p = s 15973 } else { 15974 if abs(w) >= 04525252525 { 15975 prg.fixNeeded = true 15976 *(*prg.mem[*(*prg.mem[p].hh()).lh()].hh()).b0() = byte(independentNeedingFix) 15977 } 15978 *(*prg.mem[r1].hh()).rh() = p 15979 r1 = p 15980 *prg.mem[int32(p)+1].int() = w 15981 p = *(*prg.mem[p].hh()).rh() 15982 } 15983 } 15984 *(*prg.mem[r1].hh()).rh() = p 15985 if vIsScaled { 15986 *prg.mem[int32(p)+1].int() = prg.takeScaled(*prg.mem[int32(p)+1].int(), v) 15987 } else { 15988 *prg.mem[int32(p)+1].int() = prg.takeFraction(*prg.mem[int32(p)+1].int(), v) 15989 } 15990 r = *(*prg.mem[3000-1].hh()).rh() 15991 return r 15992 } 15993 15994 // 601. 15995 15996 // tangle:pos ../../mf.web:12804:3: 15997 15998 // Here's another utility routine for dependency lists. When an independent 15999 // variable becomes dependent, we want to remove it from all existing 16000 // dependencies. The |p_with_x_becoming_q| function computes the 16001 // dependency list of~|p| after variable~|x| has been replaced by~|q|. 16002 // 16003 // This procedure has basically the same calling conventions as |p_plus_fq|: 16004 // List~|q| is unchanged; list~|p| is destroyed; the constant node and the 16005 // final link are inherited from~|p|; and the fourth parameter tells whether 16006 // or not |p| is |proto_dependent|. However, the global variable |dep_final| 16007 // is not altered if |x| does not occur in list~|p|. 16008 func (prg *prg) pWithXBecomingQ(p, x, q halfword, t smallNumber) (r halfword) { 16009 var ( 16010 r1, s halfword // for list manipulation 16011 v int32 // coefficient of |x| 16012 sx int32 // serial number of |x| 16013 ) 16014 s = p 16015 r1 = uint16(3000 - 1) 16016 sx = *prg.mem[int32(x)+1].int() 16017 for *prg.mem[int32(*(*prg.mem[s].hh()).lh())+1].int() > sx { 16018 r1 = s 16019 s = *(*prg.mem[s].hh()).rh() 16020 } 16021 if int32(*(*prg.mem[s].hh()).lh()) != int32(x) { 16022 r = p 16023 } else { 16024 *(*prg.mem[3000-1].hh()).rh() = p 16025 *(*prg.mem[r1].hh()).rh() = *(*prg.mem[s].hh()).rh() 16026 v = *prg.mem[int32(s)+1].int() 16027 prg.freeNode(s, halfword(depNodeSize)) 16028 r = prg.pPlusFq(*(*prg.mem[3000-1].hh()).rh(), v, q, t, smallNumber(dependent)) 16029 } 16030 return r 16031 } 16032 16033 // 606. 16034 16035 // tangle:pos ../../mf.web:12916:3: 16036 16037 // The |new_dep| routine installs a dependency list~|p| into the value node~|q|, 16038 // linking it into the list of all known dependencies. We assume that 16039 // |dep_final| points to the final node of list~|p|. 16040 func (prg *prg) newDep(q, p halfword) { 16041 var ( 16042 r1 halfword // what used to be the first dependency 16043 ) 16044 *(*prg.mem[int32(q)+1].hh()).rh() = p 16045 *(*prg.mem[int32(q)+1].hh()).lh() = uint16(memMin + 3 + 10) 16046 r1 = *(*prg.mem[memMin+3+10].hh()).rh() 16047 *(*prg.mem[prg.depFinal].hh()).rh() = r1 16048 *(*prg.mem[int32(r1)+1].hh()).lh() = prg.depFinal 16049 *(*prg.mem[memMin+3+10].hh()).rh() = q 16050 } 16051 16052 // 607. 16053 16054 // tangle:pos ../../mf.web:12927:3: 16055 16056 // Here is one of the ways a dependency list gets started. 16057 // The |const_dependency| routine produces a list that has nothing but 16058 // a constant term. 16059 func (prg *prg) constDependency(v scaled) (r halfword) { 16060 prg.depFinal = prg.getNode(depNodeSize) 16061 *prg.mem[int32(prg.depFinal)+1].int() = v 16062 *(*prg.mem[prg.depFinal].hh()).lh() = uint16(memMin) 16063 r = prg.depFinal 16064 return r 16065 } 16066 16067 // 608. 16068 16069 // tangle:pos ../../mf.web:12937:3: 16070 16071 // And here's a more interesting way to start a dependency list from scratch: 16072 // The parameter to |single_dependency| is the location of an 16073 // independent variable~|x|, and the result is the simple dependency list 16074 // `|x+0|'. 16075 // 16076 // In the unlikely event that the given independent variable has been doubled so 16077 // often that we can't refer to it with a nonzero coefficient, 16078 // |single_dependency| returns the simple list `0'. This case can be 16079 // recognized by testing that the returned list pointer is equal to 16080 // |dep_final|. 16081 func (prg *prg) singleDependency(p halfword) (r halfword) { 16082 var ( 16083 q halfword // the new dependency list 16084 m int32 // the number of doublings 16085 ) 16086 m = *prg.mem[int32(p)+1].int() % sScale 16087 if m > 28 { 16088 r = prg.constDependency(scaled(0)) 16089 } else { 16090 q = prg.getNode(depNodeSize) 16091 *prg.mem[int32(q)+1].int() = prg.twoToThe[28-m] 16092 *(*prg.mem[q].hh()).lh() = p 16093 16094 *(*prg.mem[q].hh()).rh() = prg.constDependency(scaled(0)) 16095 r = q 16096 } 16097 return r 16098 } 16099 16100 // 609. 16101 16102 // tangle:pos ../../mf.web:12959:3: 16103 16104 // We sometimes need to make an exact copy of a dependency list. 16105 func (prg *prg) copyDepList(p halfword) (r halfword) { 16106 var ( 16107 q halfword // the new dependency list 16108 ) 16109 q = prg.getNode(depNodeSize) 16110 prg.depFinal = q 16111 for true { 16112 *(*prg.mem[prg.depFinal].hh()).lh() = *(*prg.mem[p].hh()).lh() 16113 *prg.mem[int32(prg.depFinal)+1].int() = *prg.mem[int32(p)+1].int() 16114 if int32(*(*prg.mem[prg.depFinal].hh()).lh()) == memMin { 16115 goto done 16116 } 16117 *(*prg.mem[prg.depFinal].hh()).rh() = prg.getNode(depNodeSize) 16118 prg.depFinal = *(*prg.mem[prg.depFinal].hh()).rh() 16119 p = *(*prg.mem[p].hh()).rh() 16120 } 16121 16122 done: 16123 r = q 16124 return r 16125 } 16126 16127 // 610. 16128 16129 // tangle:pos ../../mf.web:12973:3: 16130 16131 // But how do variables normally become known? Ah, now we get to the heart of the 16132 // equation-solving mechanism. The |linear_eq| procedure is given a |dependent| 16133 // or |proto_dependent| list,~|p|, in which at least one independent variable 16134 // appears. It equates this list to zero, by choosing an independent variable 16135 // with the largest coefficient and making it dependent on the others. The 16136 // newly dependent variable is eliminated from all current dependencies, 16137 // thereby possibly making other dependent variables known. 16138 // 16139 // The given list |p| is, of course, totally destroyed by all this processing. 16140 func (prg *prg) linearEq(p halfword, t smallNumber) { 16141 var ( 16142 q, r1, s halfword // for link manipulation 16143 x halfword // the variable that loses its independence 16144 n int32 // the number of times |x| had been halved 16145 v int32 // the coefficient of |x| in list |p| 16146 prevR halfword // lags one step behind |r| 16147 finalNode halfword // the constant term of the new dependency list 16148 w int32 // a tentative coefficient 16149 ) 16150 q = p 16151 r1 = *(*prg.mem[p].hh()).rh() 16152 v = *prg.mem[int32(q)+1].int() 16153 for int32(*(*prg.mem[r1].hh()).lh()) != memMin { 16154 if abs(*prg.mem[int32(r1)+1].int()) > abs(v) { 16155 q = r1 16156 v = *prg.mem[int32(r1)+1].int() 16157 } 16158 r1 = *(*prg.mem[r1].hh()).rh() 16159 } 16160 x = *(*prg.mem[q].hh()).lh() 16161 n = *prg.mem[int32(x)+1].int() % sScale 16162 16163 // Divide list |p| by |-v|, removing node |q| 16164 s = uint16(3000 - 1) 16165 *(*prg.mem[s].hh()).rh() = p 16166 r1 = p 16167 for { 16168 if int32(r1) == int32(q) { 16169 *(*prg.mem[s].hh()).rh() = *(*prg.mem[r1].hh()).rh() 16170 prg.freeNode(r1, halfword(depNodeSize)) 16171 } else { 16172 w = prg.makeFraction(*prg.mem[int32(r1)+1].int(), v) 16173 if abs(w) <= halfFractionThreshold { 16174 *(*prg.mem[s].hh()).rh() = *(*prg.mem[r1].hh()).rh() 16175 prg.freeNode(r1, halfword(depNodeSize)) 16176 } else { 16177 *prg.mem[int32(r1)+1].int() = -w 16178 s = r1 16179 } 16180 } 16181 r1 = *(*prg.mem[s].hh()).rh() 16182 if int32(*(*prg.mem[r1].hh()).lh()) == memMin { 16183 break 16184 } 16185 } 16186 if int32(t) == protoDependent { 16187 *prg.mem[int32(r1)+1].int() = -prg.makeScaled(*prg.mem[int32(r1)+1].int(), v) 16188 } else if v != -02000000000 { 16189 *prg.mem[int32(r1)+1].int() = -prg.makeFraction(*prg.mem[int32(r1)+1].int(), v) 16190 } 16191 finalNode = r1 16192 p = *(*prg.mem[3000-1].hh()).rh() 16193 if prg.internal[tracingEquations-1] > 0 { 16194 if prg.interesting(x) { 16195 prg.beginDiagnostic() 16196 prg.printNl(strNumber( /* "## " */ 596)) 16197 prg.printVariableName(x) 16198 // \xref[]]]\#\#_][\.[\#\#]] 16199 w = n 16200 for w > 0 { 16201 prg.print( /* "*4" */ 589) 16202 w = w - 2 16203 } 16204 prg.printChar(asciiCode('=')) 16205 prg.printDependency(p, smallNumber(dependent)) 16206 prg.endDiagnostic(false) 16207 } 16208 } 16209 16210 // Simplify all existing dependencies by substituting for |x| 16211 prevR = uint16(memMin + 3 + 10) 16212 r1 = *(*prg.mem[memMin+3+10].hh()).rh() 16213 for int32(r1) != memMin+3+10 { 16214 s = *(*prg.mem[int32(r1)+1].hh()).rh() 16215 q = prg.pWithXBecomingQ(s, x, p, *(*prg.mem[r1].hh()).b0()) 16216 if int32(*(*prg.mem[q].hh()).lh()) == memMin { 16217 prg.makeKnown(r1, q) 16218 } else { 16219 *(*prg.mem[int32(r1)+1].hh()).rh() = q 16220 for { 16221 q = *(*prg.mem[q].hh()).rh() 16222 if int32(*(*prg.mem[q].hh()).lh()) == memMin { 16223 break 16224 } 16225 } 16226 prevR = q 16227 } 16228 r1 = *(*prg.mem[prevR].hh()).rh() 16229 } 16230 16231 // Change variable |x| from |independent| to |dependent| or |known| 16232 if n > 0 { 16233 s = uint16(3000 - 1) 16234 *(*prg.mem[3000-1].hh()).rh() = p 16235 r1 = p 16236 for { 16237 if n > 30 { 16238 w = 0 16239 } else { 16240 w = *prg.mem[int32(r1)+1].int() / prg.twoToThe[n] 16241 } 16242 if abs(w) <= halfFractionThreshold && int32(*(*prg.mem[r1].hh()).lh()) != memMin { 16243 *(*prg.mem[s].hh()).rh() = *(*prg.mem[r1].hh()).rh() 16244 prg.freeNode(r1, halfword(depNodeSize)) 16245 } else { 16246 *prg.mem[int32(r1)+1].int() = w 16247 s = r1 16248 } 16249 r1 = *(*prg.mem[s].hh()).rh() 16250 if int32(*(*prg.mem[s].hh()).lh()) == memMin { 16251 break 16252 } 16253 } 16254 p = *(*prg.mem[3000-1].hh()).rh() 16255 } 16256 if int32(*(*prg.mem[p].hh()).lh()) == memMin { 16257 *(*prg.mem[x].hh()).b0() = byte(known) 16258 *prg.mem[int32(x)+1].int() = *prg.mem[int32(p)+1].int() 16259 if abs(*prg.mem[int32(x)+1].int()) >= 02000000000 { 16260 prg.valTooBig(*prg.mem[int32(x)+1].int()) 16261 } 16262 prg.freeNode(p, halfword(depNodeSize)) 16263 if prg.curExp == int32(x) { 16264 if int32(prg.curType) == independent { 16265 prg.curExp = *prg.mem[int32(x)+1].int() 16266 prg.curType = byte(known) 16267 prg.freeNode(x, halfword(valueNodeSize)) 16268 } 16269 } 16270 } else { 16271 *(*prg.mem[x].hh()).b0() = byte(dependent) 16272 prg.depFinal = finalNode 16273 prg.newDep(x, p) 16274 if prg.curExp == int32(x) { 16275 if int32(prg.curType) == independent { 16276 prg.curType = byte(dependent) 16277 } 16278 } 16279 } 16280 if prg.fixNeeded { 16281 prg.fixDependencies() 16282 } 16283 } 16284 16285 // 618. \[29] Dynamic nonlinear equations 16286 16287 // tangle:pos ../../mf.web:13105:38: 16288 16289 // Variables of numeric type are maintained by the general scheme of 16290 // independent, dependent, and known values that we have just studied; 16291 // and the components of pair and transform variables are handled in the 16292 // same way. But \MF\ also has five other types of values: \&[boolean], 16293 // \&[string], \&[pen], \&[path], and \&[picture]; what about them? 16294 // 16295 // Equations are allowed between nonlinear quantities, but only in a 16296 // simple form. Two variables that haven't yet been assigned values are 16297 // either equal to each other, or they're not. 16298 // 16299 // Before a boolean variable has received a value, its type is |unknown_boolean|; 16300 // similarly, there are variables whose type is |unknown_string|, |unknown_pen|, 16301 // |unknown_path|, and |unknown_picture|. In such cases the value is either 16302 // |null| (which means that no other variables are equivalent to this one), or 16303 // it points to another variable of the same undefined type. The pointers in the 16304 // latter case form a cycle of nodes, which we shall call a ``ring.'' 16305 // Rings of undefined variables may include capsules, which arise as 16306 // intermediate results within expressions or as \&[expr] parameters to macros. 16307 // 16308 // When one member of a ring receives a value, the same value is given to 16309 // all the other members. In the case of paths and pictures, this implies 16310 // making separate copies of a potentially large data structure; users should 16311 // restrain their enthusiasm for such generality, unless they have lots and 16312 // lots of memory space. 16313 16314 // 619. 16315 16316 // tangle:pos ../../mf.web:13131:3: 16317 16318 // The following procedure is called when a capsule node is being 16319 // added to a ring (e.g., when an unknown variable is mentioned in an expression). 16320 func (prg *prg) newRingEntry(p halfword) (r halfword) { 16321 var ( 16322 q halfword // the new capsule node 16323 ) 16324 q = prg.getNode(valueNodeSize) 16325 *(*prg.mem[q].hh()).b1() = byte(capsule) 16326 *(*prg.mem[q].hh()).b0() = *(*prg.mem[p].hh()).b0() 16327 if *prg.mem[int32(p)+1].int() == memMin { 16328 *prg.mem[int32(q)+1].int() = int32(p) 16329 } else { 16330 *prg.mem[int32(q)+1].int() = *prg.mem[int32(p)+1].int() 16331 } 16332 *prg.mem[int32(p)+1].int() = int32(q) 16333 r = q 16334 return r 16335 } 16336 16337 // 621. 16338 16339 // tangle:pos ../../mf.web:13157:3: 16340 16341 // Eventually there might be an equation that assigns values to all of the 16342 // variables in a ring. The |nonlinear_eq| subroutine does the necessary 16343 // propagation of values. 16344 // 16345 // If the parameter |flush_p| is |true|, node |p| itself needn't receive a 16346 // value; it will soon be recycled. 16347 func (prg *prg) nonlinearEq(v int32, p halfword, flushP bool) { 16348 var ( 16349 t smallNumber // the type of ring |p| 16350 q, r1 halfword // link manipulation registers 16351 ) 16352 t = byte(int32(*(*prg.mem[p].hh()).b0()) - unknownTag) 16353 q = uint16(*prg.mem[int32(p)+1].int()) 16354 if flushP { 16355 *(*prg.mem[p].hh()).b0() = byte(vacuous) 16356 } else { 16357 p = q 16358 } 16359 for { 16360 r1 = uint16(*prg.mem[int32(q)+1].int()) 16361 *(*prg.mem[q].hh()).b0() = t 16362 switch t { 16363 case booleanType: 16364 *prg.mem[int32(q)+1].int() = v 16365 case stringType: 16366 *prg.mem[int32(q)+1].int() = v 16367 { 16368 if int32(prg.strRef[v]) < maxStrRef { 16369 prg.strRef[v] = byte(int32(prg.strRef[v]) + 1) 16370 } 16371 } 16372 16373 case penType: 16374 *prg.mem[int32(q)+1].int() = v 16375 *(*prg.mem[v].hh()).lh() = uint16(int32(*(*prg.mem[v].hh()).lh()) + 1) 16376 16377 case pathType: 16378 *prg.mem[int32(q)+1].int() = int32(prg.copyPath(halfword(v))) 16379 case pictureType: 16380 *prg.mem[int32(q)+1].int() = int32(prg.copyEdges(halfword(v))) 16381 } // there ain't no more cases 16382 q = r1 16383 if int32(q) == int32(p) { 16384 break 16385 } 16386 } 16387 } 16388 16389 // 622. 16390 16391 // tangle:pos ../../mf.web:13183:3: 16392 16393 // If two members of rings are equated, and if they have the same type, 16394 // the |ring_merge| procedure is called on to make them equivalent. 16395 func (prg *prg) ringMerge(p, q halfword) { 16396 var ( 16397 r1 halfword // traverses one list 16398 ) 16399 r1 = uint16(*prg.mem[int32(p)+1].int()) 16400 for int32(r1) != int32(p) { 16401 if int32(r1) == int32(q) { 16402 { 16403 { 16404 if int32(prg.interaction) == errorStopMode { 16405 } 16406 prg.printNl(strNumber( /* "! " */ 261)) 16407 prg.print( /* "Redundant equation" */ 599) /* \xref[!\relax] */ 16408 } 16409 16410 // \xref[Redundant equation] 16411 { 16412 prg.helpPtr = 2 16413 prg.helpLine[1] = /* "I already knew that this equation was true." */ 600 16414 prg.helpLine[0] = /* "But perhaps no harm has been done; let's continue." */ 601 16415 } 16416 16417 prg.putGetError() 16418 } 16419 16420 goto exit 16421 } 16422 r1 = uint16(*prg.mem[int32(r1)+1].int()) 16423 } 16424 r1 = uint16(*prg.mem[int32(p)+1].int()) 16425 *prg.mem[int32(p)+1].int() = *prg.mem[int32(q)+1].int() 16426 *prg.mem[int32(q)+1].int() = int32(r1) 16427 16428 exit: 16429 } 16430 16431 // 626. 16432 16433 // tangle:pos ../../mf.web:13271:3: 16434 16435 // Here is a procedure that displays a given command in braces, in the 16436 // user's transcript file. 16437 func (prg *prg) showCmdMod(c, m int32) { 16438 prg.beginDiagnostic() 16439 prg.printNl(strNumber('{')) 16440 prg.printCmdMod(c, m) 16441 prg.printChar(asciiCode('}')) 16442 prg.endDiagnostic(false) 16443 } // \2 16444 16445 func (prg *prg) showContext() { 16446 var ( 16447 oldSetting/* 0..maxSelector */ byte // saved |selector| setting 16448 16449 // Local variables for formatting calculations 16450 i/* 0..bufSize */ uint16 // index into |buffer| 16451 l int32 // length of descriptive information on line 1 16452 m int32 // context information gathered for line 2 16453 n/* 0..errorLine */ byte // length of line 1 16454 p int32 // starting or ending place in |trick_buf| 16455 q int32 // temporary index 16456 ) 16457 prg.filePtr = prg.inputPtr 16458 prg.inputStack[prg.filePtr] = prg.curInput 16459 // store current state 16460 for true { 16461 prg.curInput = prg.inputStack[prg.filePtr] // enter into the context 16462 16463 // Display the current context 16464 if int32(prg.filePtr) == int32(prg.inputPtr) || int32(prg.curInput.indexField) <= maxInOpen || int32(prg.curInput.indexField) != backedUp || int32(prg.curInput.locField) != memMin { 16465 prg.tally = 0 // get ready to count characters 16466 oldSetting = prg.selector 16467 if int32(prg.curInput.indexField) <= maxInOpen { 16468 if int32(prg.curInput.nameField) <= 1 { 16469 if int32(prg.curInput.nameField) == 0 && int32(prg.filePtr) == 0 { 16470 prg.printNl(strNumber( /* "<*>" */ 603)) 16471 } else { 16472 prg.printNl(strNumber( /* "<insert>" */ 604)) 16473 } 16474 } else if int32(prg.curInput.nameField) == 2 { 16475 prg.printNl(strNumber( /* "<scantokens>" */ 605)) 16476 } else { 16477 prg.printNl(strNumber( /* "l." */ 606)) 16478 prg.printInt(prg.line) 16479 } 16480 prg.printChar(asciiCode(' ')) 16481 16482 // Pseudoprint the line 16483 { 16484 l = prg.tally 16485 prg.tally = 0 16486 prg.selector = byte(pseudo) 16487 prg.trickCount = 1000000 16488 } 16489 if int32(prg.curInput.limitField) > 0 { 16490 for ii := int32(prg.curInput.startField); ii <= int32(prg.curInput.limitField)-1; ii++ { 16491 i = uint16(ii) 16492 _ = i 16493 if int32(i) == int32(prg.curInput.locField) { 16494 prg.firstCount = prg.tally 16495 prg.trickCount = prg.tally + 1 + errorLine - halfErrorLine 16496 if prg.trickCount < errorLine { 16497 prg.trickCount = errorLine 16498 } 16499 } 16500 prg.print(int32(prg.buffer[i])) 16501 } 16502 } 16503 } else { 16504 switch prg.curInput.indexField { 16505 case foreverText: 16506 prg.printNl(strNumber( /* "<forever> " */ 607)) 16507 case loopText: 16508 // Print the current loop value 16509 prg.printNl(strNumber( /* "<for(" */ 612)) 16510 p = int32(prg.paramStack[prg.curInput.limitField]) 16511 if p != memMin { 16512 if int32(*(*prg.mem[p].hh()).rh()) == memMin+1 { 16513 prg.printExp(halfword(p), smallNumber(0)) 16514 } else { 16515 prg.showTokenList(p, memMin, 20, prg.tally) 16516 } 16517 } 16518 prg.print( /* ")> " */ 613) 16519 16520 case parameter: 16521 prg.printNl(strNumber( /* "<argument> " */ 608)) 16522 case backedUp: 16523 if int32(prg.curInput.locField) == memMin { 16524 prg.printNl(strNumber( /* "<recently read> " */ 609)) 16525 } else { 16526 prg.printNl(strNumber( /* "<to be read again> " */ 610)) 16527 } 16528 case inserted: 16529 prg.printNl(strNumber( /* "<inserted text> " */ 611)) 16530 case macro: 16531 prg.printLn() 16532 if int32(prg.curInput.nameField) != memMin { 16533 prg.slowPrint(int32(*prg.hash[prg.curInput.nameField-1].rh())) 16534 } else { 16535 // Print the name of a \&[vardef]'d macro 16536 p = int32(prg.paramStack[prg.curInput.limitField]) 16537 if p == memMin { 16538 prg.showTokenList(int32(prg.paramStack[int32(prg.curInput.limitField)+1]), memMin, 20, prg.tally) 16539 } else { 16540 q = p 16541 for int32(*(*prg.mem[q].hh()).rh()) != memMin { 16542 q = int32(*(*prg.mem[q].hh()).rh()) 16543 } 16544 *(*prg.mem[q].hh()).rh() = prg.paramStack[int32(prg.curInput.limitField)+1] 16545 prg.showTokenList(p, memMin, 20, prg.tally) 16546 *(*prg.mem[q].hh()).rh() = uint16(memMin) 16547 } 16548 } 16549 prg.print( /* "->" */ 501) 16550 16551 default: 16552 prg.printNl(strNumber('?')) // this should never happen 16553 // \xref[?\relax] 16554 } 16555 16556 // Pseudoprint the token list 16557 { 16558 l = prg.tally 16559 prg.tally = 0 16560 prg.selector = byte(pseudo) 16561 prg.trickCount = 1000000 16562 } 16563 if int32(prg.curInput.indexField) != macro { 16564 prg.showTokenList(int32(prg.curInput.startField), int32(prg.curInput.locField), 100000, 0) 16565 } else { 16566 prg.showMacro(prg.curInput.startField, int32(prg.curInput.locField), 100000) 16567 } 16568 } 16569 prg.selector = oldSetting // stop pseudoprinting 16570 16571 // Print two lines using the tricky pseudoprinted information 16572 if prg.trickCount == 1000000 { 16573 prg.firstCount = prg.tally 16574 prg.trickCount = prg.tally + 1 + errorLine - halfErrorLine 16575 if prg.trickCount < errorLine { 16576 prg.trickCount = errorLine 16577 } 16578 } 16579 // |set_trick_count| must be performed 16580 if prg.tally < prg.trickCount { 16581 m = prg.tally - prg.firstCount 16582 } else { 16583 m = prg.trickCount - prg.firstCount 16584 } // context on line 2 16585 if l+prg.firstCount <= halfErrorLine { 16586 p = 0 16587 n = byte(l + prg.firstCount) 16588 } else { 16589 prg.print( /* "..." */ 276) 16590 p = l + prg.firstCount - halfErrorLine + 3 16591 n = byte(halfErrorLine) 16592 } 16593 for ii := p; ii <= prg.firstCount-1; ii++ { 16594 q = ii 16595 _ = q 16596 prg.printChar(prg.trickBuf[q%errorLine]) 16597 } 16598 prg.printLn() 16599 for ii := int32(1); ii <= int32(n); ii++ { 16600 q = ii 16601 _ = q 16602 prg.printChar(asciiCode(' ')) 16603 } // print |n| spaces to begin line~2 16604 if m+int32(n) <= errorLine { 16605 p = prg.firstCount + m 16606 } else { 16607 p = prg.firstCount + (errorLine - int32(n) - 3) 16608 } 16609 for ii := prg.firstCount; ii <= p-1; ii++ { 16610 q = ii 16611 _ = q 16612 prg.printChar(prg.trickBuf[q%errorLine]) 16613 } 16614 if m+int32(n) > errorLine { 16615 prg.print( /* "..." */ 276) 16616 } 16617 } 16618 if int32(prg.curInput.indexField) <= maxInOpen { 16619 if int32(prg.curInput.nameField) > 2 || int32(prg.filePtr) == 0 { 16620 goto done 16621 } 16622 } 16623 prg.filePtr = byte(int32(prg.filePtr) - 1) 16624 } 16625 16626 done: 16627 prg.curInput = prg.inputStack[prg.inputPtr] // restore original state 16628 } 16629 16630 // 642. 16631 16632 // tangle:pos ../../mf.web:13601:3: 16633 16634 // The following code tells the print routines to gather 16635 // the desired information. 16636 16637 // 647. \[32] Maintaining the input stacks 16638 16639 // tangle:pos ../../mf.web:13655:39: 16640 16641 // The following subroutines change the input status in commonly needed ways. 16642 // 16643 // First comes |push_input|, which stores the current state and creates a 16644 // new level (having, initially, the same properties as the old). 16645 16646 // 648. 16647 16648 // tangle:pos ../../mf.web:13671:3: 16649 16650 // And of course what goes up must come down. 16651 16652 // 649. 16653 16654 // tangle:pos ../../mf.web:13677:3: 16655 16656 // Here is a procedure that starts a new level of token-list input, given 16657 // a token list |p| and its type |t|. If |t=macro|, the calling routine should 16658 // set |name|, reset~|loc|, and increase the macro's reference count. 16659 func (prg *prg) beginTokenList(p halfword, t quarterword) { 16660 { 16661 if int32(prg.inputPtr) > int32(prg.maxInStack) { 16662 prg.maxInStack = prg.inputPtr 16663 if int32(prg.inputPtr) == stackSize { 16664 prg.overflow(strNumber( /* "input stack size" */ 614), stackSize) 16665 } /* \xref[METAFONT capacity exceeded input stack size][\quad input stack size] */ 16666 } 16667 prg.inputStack[prg.inputPtr] = prg.curInput 16668 prg.inputPtr = byte(int32(prg.inputPtr) + 1) 16669 } 16670 prg.curInput.startField = p 16671 prg.curInput.indexField = t 16672 prg.curInput.limitField = uint16(prg.paramPtr) 16673 prg.curInput.locField = p 16674 } 16675 16676 // 650. 16677 16678 // tangle:pos ../../mf.web:13688:3: 16679 16680 // When a token list has been fully scanned, the following computations 16681 // should be done as we leave that level of input. 16682 // \xref[inner loop] 16683 func (prg *prg) endTokenList() { 16684 var ( 16685 p halfword // temporary register 16686 ) 16687 if int32(prg.curInput.indexField) >= backedUp { 16688 if int32(prg.curInput.indexField) <= inserted { 16689 prg.flushTokenList(prg.curInput.startField) 16690 goto done 16691 } else { 16692 prg.deleteMacRef(prg.curInput.startField) 16693 } 16694 } // update reference count 16695 for int32(prg.paramPtr) > int32(prg.curInput.limitField) { // parameters must be flushed 16696 prg.paramPtr = byte(int32(prg.paramPtr) - 1) 16697 p = prg.paramStack[prg.paramPtr] 16698 if int32(p) != memMin { 16699 if int32(*(*prg.mem[p].hh()).rh()) == memMin+1 { 16700 prg.recycleValue(p) 16701 prg.freeNode(p, halfword(valueNodeSize)) 16702 } else { 16703 prg.flushTokenList(p) 16704 } 16705 } // it's a \&[suffix] or \&[text] parameter 16706 } 16707 16708 done: 16709 { 16710 prg.inputPtr = byte(int32(prg.inputPtr) - 1) 16711 prg.curInput = prg.inputStack[prg.inputPtr] 16712 } 16713 { 16714 if prg.interrupt != 0 { 16715 prg.pauseForInstructions() 16716 } 16717 } 16718 } 16719 16720 // 651. 16721 16722 // tangle:pos ../../mf.web:13712:3: 16723 16724 // The contents of |cur_cmd,cur_mod,cur_sym| are placed into an equivalent 16725 // token by the |cur_tok| routine. 16726 // \xref[inner loop] 16727 // \4 16728 // Declare the procedure called |make_exp_copy| 16729 // \4 16730 // Declare subroutines needed by |make_exp_copy| 16731 func (prg *prg) encapsulate(p halfword) { 16732 prg.curExp = int32(prg.getNode(valueNodeSize)) 16733 *(*prg.mem[prg.curExp].hh()).b0() = prg.curType 16734 *(*prg.mem[prg.curExp].hh()).b1() = byte(capsule) 16735 prg.newDep(halfword(prg.curExp), p) 16736 } 16737 16738 func (prg *prg) install(r1, q halfword) { 16739 var ( 16740 p halfword // temporary register 16741 ) 16742 if int32(*(*prg.mem[q].hh()).b0()) == known { 16743 *prg.mem[int32(r1)+1].int() = *prg.mem[int32(q)+1].int() 16744 *(*prg.mem[r1].hh()).b0() = byte(known) 16745 } else if int32(*(*prg.mem[q].hh()).b0()) == independent { 16746 p = prg.singleDependency(q) 16747 if int32(p) == int32(prg.depFinal) { 16748 *(*prg.mem[r1].hh()).b0() = byte(known) 16749 *prg.mem[int32(r1)+1].int() = 0 16750 prg.freeNode(p, halfword(depNodeSize)) 16751 } else { 16752 *(*prg.mem[r1].hh()).b0() = byte(dependent) 16753 prg.newDep(r1, p) 16754 } 16755 } else { 16756 *(*prg.mem[r1].hh()).b0() = *(*prg.mem[q].hh()).b0() 16757 prg.newDep(r1, prg.copyDepList(*(*prg.mem[int32(q)+1].hh()).rh())) 16758 } 16759 } 16760 16761 func (prg *prg) makeExpCopy(p halfword) { 16762 var ( 16763 q, r1, t halfword // registers for list manipulation 16764 ) 16765 restart: 16766 prg.curType = *(*prg.mem[p].hh()).b0() 16767 switch prg.curType { 16768 case vacuous, booleanType, known: 16769 prg.curExp = *prg.mem[int32(p)+1].int() 16770 case unknownBoolean, unknownString, unknownPen, unknownPicture, 16771 unknownPath: 16772 prg.curExp = int32(prg.newRingEntry(p)) 16773 case stringType: 16774 prg.curExp = *prg.mem[int32(p)+1].int() 16775 { 16776 if int32(prg.strRef[prg.curExp]) < maxStrRef { 16777 prg.strRef[prg.curExp] = byte(int32(prg.strRef[prg.curExp]) + 1) 16778 } 16779 } 16780 16781 case penType: 16782 prg.curExp = *prg.mem[int32(p)+1].int() 16783 *(*prg.mem[prg.curExp].hh()).lh() = uint16(int32(*(*prg.mem[prg.curExp].hh()).lh()) + 1) 16784 16785 case pictureType: 16786 prg.curExp = int32(prg.copyEdges(halfword(*prg.mem[int32(p)+1].int()))) 16787 case pathType, futurePen: 16788 prg.curExp = int32(prg.copyPath(halfword(*prg.mem[int32(p)+1].int()))) 16789 case transformType, pairType: 16790 // Copy the big node |p| 16791 if *prg.mem[int32(p)+1].int() == memMin { 16792 prg.initBigNode(p) 16793 } 16794 t = prg.getNode(valueNodeSize) 16795 *(*prg.mem[t].hh()).b1() = byte(capsule) 16796 *(*prg.mem[t].hh()).b0() = prg.curType 16797 prg.initBigNode(t) 16798 16799 q = uint16(*prg.mem[int32(p)+1].int() + int32(prg.bigNodeSize[prg.curType-13])) 16800 r1 = uint16(*prg.mem[int32(t)+1].int() + int32(prg.bigNodeSize[prg.curType-13])) 16801 for { 16802 q = uint16(int32(q) - 2) 16803 r1 = uint16(int32(r1) - 2) 16804 prg.install(r1, q) 16805 if int32(q) == *prg.mem[int32(p)+1].int() { 16806 break 16807 } 16808 } 16809 prg.curExp = int32(t) 16810 16811 case dependent, protoDependent: 16812 prg.encapsulate(prg.copyDepList(*(*prg.mem[int32(p)+1].hh()).rh())) 16813 case numericType: 16814 { 16815 if prg.serialNo > 017777777777-sScale { 16816 prg.overflow(strNumber( /* "independent variables" */ 587), prg.serialNo/sScale) 16817 } /* \xref[METAFONT capacity exceeded independent variables][\quad independent variables] */ 16818 *(*prg.mem[p].hh()).b0() = byte(independent) 16819 prg.serialNo = prg.serialNo + sScale 16820 *prg.mem[int32(p)+1].int() = prg.serialNo 16821 } 16822 goto restart 16823 16824 case independent: 16825 q = prg.singleDependency(p) 16826 if int32(q) == int32(prg.depFinal) { 16827 prg.curType = byte(known) 16828 prg.curExp = 0 16829 prg.freeNode(q, halfword(depNodeSize)) 16830 } else { 16831 prg.curType = byte(dependent) 16832 prg.encapsulate(q) 16833 } 16834 16835 default: 16836 prg.confusion(strNumber( /* "copy" */ 800)) 16837 // \xref[this can't happen copy][\quad copy] 16838 } 16839 } 16840 16841 func (prg *prg) curTok() (r halfword) { 16842 var ( 16843 p halfword // a new token node 16844 saveType smallNumber // |cur_type| to be restored 16845 saveExp int32 // |cur_exp| to be restored 16846 ) 16847 if int32(prg.curSym) == 0 { 16848 if int32(prg.curCmd) == capsuleToken { 16849 saveType = prg.curType 16850 saveExp = prg.curExp 16851 prg.makeExpCopy(halfword(prg.curMod)) 16852 p = prg.stashCurExp() 16853 *(*prg.mem[p].hh()).rh() = uint16(memMin) 16854 prg.curType = saveType 16855 prg.curExp = saveExp 16856 } else { 16857 p = prg.getNode(tokenNodeSize) 16858 *prg.mem[int32(p)+1].int() = prg.curMod 16859 *(*prg.mem[p].hh()).b1() = byte(token) 16860 if int32(prg.curCmd) == numericToken { 16861 *(*prg.mem[p].hh()).b0() = byte(known) 16862 } else { 16863 *(*prg.mem[p].hh()).b0() = byte(stringType) 16864 } 16865 } 16866 } else { 16867 { 16868 p = prg.avail 16869 if int32(p) == memMin { 16870 p = prg.getAvail() 16871 } else { 16872 prg.avail = *(*prg.mem[p].hh()).rh() 16873 *(*prg.mem[p].hh()).rh() = uint16(memMin) 16874 prg.dynUsed = prg.dynUsed + 1 16875 } 16876 } 16877 *(*prg.mem[p].hh()).lh() = prg.curSym 16878 } 16879 r = p 16880 return r 16881 } 16882 16883 // 652. 16884 16885 // tangle:pos ../../mf.web:13737:3: 16886 16887 // Sometimes \MF\ has read too far and wants to ``unscan'' what it has 16888 // seen. The |back_input| procedure takes care of this by putting the token 16889 // just scanned back into the input stream, ready to be read again. 16890 // If |cur_sym<>0|, the values of |cur_cmd| and |cur_mod| are irrelevant. 16891 func (prg *prg) backInput() { // undoes one token of input 16892 var ( 16893 p halfword // a token list of length one 16894 ) 16895 p = prg.curTok() 16896 for int32(prg.curInput.indexField) > maxInOpen && int32(prg.curInput.locField) == memMin { 16897 prg.endTokenList() 16898 } // conserve stack space 16899 prg.beginTokenList(p, quarterword(backedUp)) 16900 } 16901 16902 func (prg *prg) backError() { 16903 prg.okToInterrupt = false 16904 prg.backInput() 16905 prg.okToInterrupt = true 16906 prg.error1() 16907 } 16908 16909 func (prg *prg) insError() { 16910 prg.okToInterrupt = false 16911 prg.backInput() 16912 prg.curInput.indexField = byte(inserted) 16913 prg.okToInterrupt = true 16914 prg.error1() 16915 } // \2 16916 16917 func (prg *prg) beginFileReading() { 16918 if int32(prg.inOpen) == maxInOpen { 16919 prg.overflow(strNumber( /* "text input levels" */ 615), maxInOpen) 16920 } 16921 // \xref[METAFONT capacity exceeded text input levels][\quad text input levels] 16922 if int32(prg.first) == bufSize { 16923 prg.overflow(strNumber( /* "buffer size" */ 256), bufSize) 16924 } 16925 // \xref[METAFONT capacity exceeded buffer size][\quad buffer size] 16926 prg.inOpen = byte(int32(prg.inOpen) + 1) /* */ 16927 { 16928 if int32(prg.inputPtr) > int32(prg.maxInStack) { 16929 prg.maxInStack = prg.inputPtr 16930 if int32(prg.inputPtr) == stackSize { 16931 prg.overflow(strNumber( /* "input stack size" */ 614), stackSize) 16932 } /* \xref[METAFONT capacity exceeded input stack size][\quad input stack size] */ 16933 } 16934 prg.inputStack[prg.inputPtr] = prg.curInput 16935 prg.inputPtr = byte(int32(prg.inputPtr) + 1) 16936 } 16937 prg.curInput.indexField = prg.inOpen 16938 prg.lineStack[prg.curInput.indexField-1] = prg.line 16939 prg.curInput.startField = prg.first 16940 prg.curInput.nameField = 0 // |terminal_input| is now |true| 16941 } 16942 16943 // 655. 16944 16945 // tangle:pos ../../mf.web:13778:3: 16946 16947 // Conversely, the variables must be downdated when such a level of input 16948 // is finished: 16949 func (prg *prg) endFileReading() { 16950 prg.first = prg.curInput.startField 16951 prg.line = prg.lineStack[prg.curInput.indexField-1] 16952 if int32(prg.curInput.indexField) != int32(prg.inOpen) { 16953 prg.confusion(strNumber( /* "endinput" */ 616)) 16954 } 16955 // \xref[this can't happen endinput][\quad endinput] 16956 if int32(prg.curInput.nameField) > 2 { 16957 prg.aClose(prg.inputFile[prg.curInput.indexField-1]) 16958 } // forget it 16959 // 16960 { 16961 prg.inputPtr = byte(int32(prg.inputPtr) - 1) 16962 prg.curInput = prg.inputStack[prg.inputPtr] 16963 } 16964 prg.inOpen = byte(int32(prg.inOpen) - 1) 16965 } // \2 16966 16967 func (prg *prg) clearForErrorPrompt() { 16968 for int32(prg.curInput.indexField) <= maxInOpen && int32(prg.curInput.nameField) == 0 && int32(prg.inputPtr) > 0 && int32(prg.curInput.locField) == int32(prg.curInput.limitField) { 16969 prg.endFileReading() 16970 } 16971 prg.printLn() 16972 } 16973 16974 // 658. \[33] Getting the next token 16975 16976 // tangle:pos ../../mf.web:13813:33: 16977 16978 // The heart of \MF's input mechanism is the |get_next| procedure, which 16979 // we shall develop in the next few sections of the program. Perhaps we 16980 // shouldn't actually call it the ``heart,'' however; it really acts as \MF's 16981 // eyes and mouth, reading the source files and gobbling them up. And it also 16982 // helps \MF\ to regurgitate stored token lists that are to be processed again. 16983 // 16984 // The main duty of |get_next| is to input one token and to set |cur_cmd| 16985 // and |cur_mod| to that token's command code and modifier. Furthermore, if 16986 // the input token is a symbolic token, that token's |hash| address 16987 // is stored in |cur_sym|; otherwise |cur_sym| is set to zero. 16988 // 16989 // Underlying this simple description is a certain amount of complexity 16990 // because of all the cases that need to be handled. 16991 // However, the inner loop of |get_next| is reasonably short and fast. 16992 16993 // 661. 16994 16995 // tangle:pos ../../mf.web:13856:3: 16996 16997 // The following subroutine 16998 // is called when an `\&[outer]' symbolic token has been scanned or 16999 // when the end of a file has been reached. These two cases are distinguished 17000 // by |cur_sym|, which is zero at the end of a file. 17001 func (prg *prg) checkOuterValidity() (r bool) { 17002 var ( 17003 p halfword // points to inserted token list 17004 ) 17005 if int32(prg.scannerStatus) == normal { 17006 r = true 17007 } else { 17008 prg.deletionsAllowed = false 17009 17010 // Back up an outer symbolic token so that it can be reread 17011 if int32(prg.curSym) != 0 { 17012 p = prg.getAvail() 17013 *(*prg.mem[p].hh()).lh() = prg.curSym 17014 prg.beginTokenList(p, quarterword(backedUp)) // prepare to read the symbolic token again 17015 } 17016 if int32(prg.scannerStatus) > skipping { 17017 prg.runaway() // print the definition-so-far 17018 if int32(prg.curSym) == 0 { 17019 if int32(prg.interaction) == errorStopMode { 17020 } 17021 prg.printNl(strNumber( /* "! " */ 261)) 17022 prg.print( /* "File ended" */ 622) /* \xref[!\relax] */ 17023 } else { 17024 { 17025 if int32(prg.interaction) == errorStopMode { 17026 } 17027 prg.printNl(strNumber( /* "! " */ 261)) 17028 prg.print( /* "Forbidden token found" */ 623) /* \xref[!\relax] */ 17029 } 17030 // \xref[Forbidden token found...] 17031 } 17032 prg.print( /* " while scanning " */ 624) 17033 { 17034 prg.helpPtr = 4 17035 prg.helpLine[3] = /* "I suspect you have forgotten an `enddef'," */ 625 17036 prg.helpLine[2] = /* "causing me to read past where you wanted me to stop." */ 626 17037 prg.helpLine[1] = /* "I'll try to recover; but if the error is serious," */ 627 17038 prg.helpLine[0] = /* "you'd better type `E' or `X' now and fix your file." */ 628 17039 } 17040 17041 switch prg.scannerStatus { 17042 case flushing: 17043 prg.print( /* "to the end of the statement" */ 629) 17044 prg.helpLine[3] = /* "A previous error seems to have propagated," */ 630 17045 prg.curSym = uint16(hashBase + hashSize + 6) 17046 17047 case absorbing: 17048 prg.print( /* "a text argument" */ 631) 17049 prg.helpLine[3] = /* "It seems that a right delimiter was left out," */ 632 17050 if prg.warningInfo == 0 { 17051 prg.curSym = uint16(hashBase + hashSize + 10) 17052 } else { 17053 prg.curSym = uint16(hashBase + hashSize + 2) 17054 *prg.eqtb[hashBase+hashSize+2-1].rh() = uint16(prg.warningInfo) 17055 } 17056 17057 case varDefining, opDefining: 17058 prg.print( /* "the definition of " */ 633) 17059 if int32(prg.scannerStatus) == opDefining { 17060 prg.slowPrint(int32(*prg.hash[prg.warningInfo-1].rh())) 17061 } else { 17062 prg.printVariableName(halfword(prg.warningInfo)) 17063 } 17064 prg.curSym = uint16(hashBase + hashSize + 8) 17065 17066 case loopDefining: 17067 prg.print( /* "the text of a " */ 634) 17068 prg.slowPrint(int32(*prg.hash[prg.warningInfo-1].rh())) 17069 prg.print( /* " loop" */ 635) 17070 prg.helpLine[3] = /* "I suspect you have forgotten an `endfor'," */ 636 17071 prg.curSym = uint16(hashBase + hashSize + 7) 17072 17073 } // there are no other cases 17074 prg.insError() 17075 } else { 17076 { 17077 if int32(prg.interaction) == errorStopMode { 17078 } 17079 prg.printNl(strNumber( /* "! " */ 261)) 17080 prg.print( /* "Incomplete if; all text was ignored after line " */ 617) /* \xref[!\relax] */ 17081 } 17082 // \xref[Incomplete if...] 17083 prg.printInt(prg.warningInfo) 17084 17085 { 17086 prg.helpPtr = 3 17087 prg.helpLine[2] = /* "A forbidden `outer' token occurred in skipped text." */ 618 17088 prg.helpLine[1] = /* "This kind of error happens when you say `if...' and forget" */ 619 17089 prg.helpLine[0] = /* "the matching `fi'. I've inserted a `fi'; this might work." */ 620 17090 } 17091 if int32(prg.curSym) == 0 { 17092 prg.helpLine[2] = 17093 /* "The file ended while I was skipping conditional text." */ 621 17094 } 17095 prg.curSym = uint16(hashBase + hashSize + 9) 17096 prg.insError() 17097 } 17098 prg.deletionsAllowed = true 17099 r = false 17100 } 17101 return r 17102 } // \2 17103 17104 func (prg *prg) getNext() { 17105 // go here at crucial stages when scanning a number 17106 var ( 17107 k/* 0..bufSize */ uint16 // an index into |buffer| 17108 c asciiCode // the current character in the buffer 17109 class asciiCode // its class number 17110 n, f int32 // registers for decimal-to-binary conversion 17111 ) 17112 restart: 17113 prg.curSym = 0 17114 if int32(prg.curInput.indexField) <= maxInOpen { 17115 switch1: 17116 c = prg.buffer[prg.curInput.locField] 17117 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 17118 class = prg.charClass[c] 17119 switch class { 17120 case digitClass: 17121 goto startNumericToken 17122 case periodClass: 17123 class = prg.charClass[prg.buffer[prg.curInput.locField]] 17124 if int32(class) > periodClass { 17125 goto switch1 17126 } else if int32(class) < periodClass { 17127 n = 0 17128 goto startDecimalToken 17129 } 17130 // \xref[. ][\..\ token] 17131 17132 case spaceClass: 17133 goto switch1 17134 case percentClass: 17135 if int32(prg.curInput.nameField) > 2 { 17136 prg.line = prg.line + 1 17137 prg.first = prg.curInput.startField 17138 if !prg.forceEof { 17139 if prg.inputLn(prg.inputFile[prg.curInput.indexField-1], true) { 17140 prg.firmUpTheLine() 17141 } else { 17142 prg.forceEof = true 17143 } 17144 } 17145 if prg.forceEof { 17146 prg.printChar(asciiCode(')')) 17147 prg.openParens = byte(int32(prg.openParens) - 1) 17148 // show user that file has been read 17149 prg.forceEof = false 17150 prg.endFileReading() // resume previous level 17151 if prg.checkOuterValidity() { 17152 goto restart 17153 } else { 17154 goto restart 17155 } 17156 } 17157 prg.buffer[prg.curInput.limitField] = '%' 17158 prg.first = uint16(int32(prg.curInput.limitField) + 1) 17159 prg.curInput.locField = prg.curInput.startField // ready to read 17160 } else { 17161 if int32(prg.inputPtr) > 0 { 17162 prg.endFileReading() 17163 goto restart // resume previous level 17164 } 17165 if int32(prg.selector) < logOnly { 17166 prg.openLogFile() 17167 } 17168 if int32(prg.interaction) > nonstopMode { 17169 if int32(prg.curInput.limitField) == int32(prg.curInput.startField) { 17170 prg.printNl(strNumber( /* "(Please type a command or say `end')" */ 651)) 17171 } 17172 // \xref[Please type...] 17173 prg.printLn() 17174 prg.first = prg.curInput.startField 17175 { 17176 prg.print('*') 17177 prg.termInput() 17178 } // input on-line into |buffer| 17179 // \xref[*\relax] 17180 prg.curInput.limitField = prg.last 17181 prg.buffer[prg.curInput.limitField] = '%' 17182 prg.first = uint16(int32(prg.curInput.limitField) + 1) 17183 prg.curInput.locField = prg.curInput.startField 17184 } else { 17185 prg.fatalError(strNumber( /* "*** (job aborted, no legal end found)" */ 652)) 17186 } 17187 // \xref[job aborted] 17188 // nonstop mode, which is intended for overnight batch processing, 17189 // never waits for on-line input 17190 17191 } 17192 { 17193 if prg.interrupt != 0 { 17194 prg.pauseForInstructions() 17195 } 17196 } 17197 17198 goto switch1 17199 17200 case stringClass: 17201 // Get a string token and |return| 17202 if int32(prg.buffer[prg.curInput.locField]) == '"' { 17203 prg.curMod = /* "" */ 285 17204 } else { 17205 k = prg.curInput.locField 17206 prg.buffer[int32(prg.curInput.limitField)+1] = '"' 17207 for { 17208 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 17209 if int32(prg.buffer[prg.curInput.locField]) == '"' { 17210 break 17211 } 17212 } 17213 if int32(prg.curInput.locField) > int32(prg.curInput.limitField) { 17214 prg.curInput.locField = prg.curInput.limitField // the next character to be read on this line will be |"%"| 17215 { 17216 if int32(prg.interaction) == errorStopMode { 17217 } 17218 prg.printNl(strNumber( /* "! " */ 261)) 17219 prg.print( /* "Incomplete string token has been flushed" */ 644) /* \xref[!\relax] */ 17220 } 17221 // \xref[Incomplete string token...] 17222 { 17223 prg.helpPtr = 3 17224 prg.helpLine[2] = /* "Strings should finish on the same line as they began." */ 645 17225 prg.helpLine[1] = /* "I've deleted the partial string; you might want to" */ 646 17226 prg.helpLine[0] = /* "insert another by typing, e.g., `I\"new string\"'." */ 647 17227 } 17228 17229 prg.deletionsAllowed = false 17230 prg.error1() 17231 prg.deletionsAllowed = true 17232 goto restart 17233 } 17234 if int32(prg.curInput.locField) == int32(k)+1 && int32(prg.strStart[int32(prg.buffer[k])+1])-int32(prg.strStart[prg.buffer[k]]) == 1 { 17235 prg.curMod = int32(prg.buffer[k]) 17236 } else { 17237 { 17238 if int32(prg.poolPtr)+int32(prg.curInput.locField)-int32(k) > int32(prg.maxPoolPtr) { 17239 if int32(prg.poolPtr)+int32(prg.curInput.locField)-int32(k) > poolSize { 17240 prg.overflow(strNumber( /* "pool size" */ 257), poolSize-int32(prg.initPoolPtr)) 17241 } /* \xref[METAFONT capacity exceeded pool size][\quad pool size] */ 17242 prg.maxPoolPtr = uint16(int32(prg.poolPtr) + int32(prg.curInput.locField) - int32(k)) 17243 } 17244 } 17245 for { 17246 { 17247 prg.strPool[prg.poolPtr] = prg.buffer[k] 17248 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 17249 } 17250 k = uint16(int32(k) + 1) 17251 if int32(k) == int32(prg.curInput.locField) { 17252 break 17253 } 17254 } 17255 prg.curMod = int32(prg.makeString()) 17256 } 17257 } 17258 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 17259 prg.curCmd = byte(stringToken) 17260 goto exit 17261 17262 case 5, 6, 7, 8: 17263 k = uint16(int32(prg.curInput.locField) - 1) 17264 goto found 17265 17266 case invalidClass: 17267 // Decry the invalid character and |goto restart| 17268 { 17269 if int32(prg.interaction) == errorStopMode { 17270 } 17271 prg.printNl(strNumber( /* "! " */ 261)) 17272 prg.print( /* "Text line contains an invalid character" */ 641) /* \xref[!\relax] */ 17273 } 17274 // \xref[Text line contains...] 17275 { 17276 prg.helpPtr = 2 17277 prg.helpLine[1] = /* "A funny symbol that I can't read has just been input." */ 642 17278 prg.helpLine[0] = /* "Continue, and I'll forget that it ever happened." */ 643 17279 } 17280 17281 prg.deletionsAllowed = false 17282 prg.error1() 17283 prg.deletionsAllowed = true 17284 17285 goto restart 17286 17287 default: // letters, etc. 17288 } 17289 17290 k = uint16(int32(prg.curInput.locField) - 1) 17291 for int32(prg.charClass[prg.buffer[prg.curInput.locField]]) == int32(class) { 17292 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 17293 } 17294 17295 goto found 17296 17297 startNumericToken: 17298 n = int32(c) - '0' 17299 for int32(prg.charClass[prg.buffer[prg.curInput.locField]]) == digitClass { 17300 if n < 4096 { 17301 n = 10*n + int32(prg.buffer[prg.curInput.locField]) - '0' 17302 } 17303 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 17304 } 17305 if int32(prg.buffer[prg.curInput.locField]) == '.' { 17306 if int32(prg.charClass[prg.buffer[int32(prg.curInput.locField)+1]]) == digitClass { 17307 goto done 17308 } 17309 } 17310 f = 0 17311 goto finNumericToken 17312 17313 done: 17314 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 17315 17316 startDecimalToken: 17317 k = 0 17318 for { 17319 if int32(k) < 17 { 17320 prg.dig[k] = byte(int32(prg.buffer[prg.curInput.locField]) - '0') 17321 k = uint16(int32(k) + 1) 17322 } 17323 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 17324 if int32(prg.charClass[prg.buffer[prg.curInput.locField]]) != digitClass { 17325 break 17326 } 17327 } 17328 f = prg.roundDecimals(smallNumber(k)) 17329 if f == 0200000 { 17330 n = n + 1 17331 f = 0 17332 } 17333 17334 finNumericToken: 17335 if n < 4096 { 17336 prg.curMod = n*0200000 + f 17337 } else { 17338 { 17339 if int32(prg.interaction) == errorStopMode { 17340 } 17341 prg.printNl(strNumber( /* "! " */ 261)) 17342 prg.print( /* "Enormous number has been reduced" */ 648) /* \xref[!\relax] */ 17343 } 17344 // \xref[Enormous number...] 17345 { 17346 prg.helpPtr = 2 17347 prg.helpLine[1] = /* "I can't handle numbers bigger than about 4095.99998;" */ 649 17348 prg.helpLine[0] = /* "so I've changed your constant to that maximum amount." */ 650 17349 } 17350 17351 prg.deletionsAllowed = false 17352 prg.error1() 17353 prg.deletionsAllowed = true 17354 prg.curMod = 01777777777 17355 } 17356 prg.curCmd = byte(numericToken) 17357 goto exit 17358 17359 found: 17360 prg.curSym = prg.idLookup(int32(k), int32(prg.curInput.locField)-int32(k)) 17361 } else if int32(prg.curInput.locField) >= int32(prg.hiMemMin) { 17362 prg.curSym = *(*prg.mem[prg.curInput.locField].hh()).lh() 17363 prg.curInput.locField = *(*prg.mem[prg.curInput.locField].hh()).rh() // move to next 17364 if int32(prg.curSym) >= hashBase+hashSize+12+1 { 17365 if int32(prg.curSym) >= hashBase+hashSize+12+1+paramSize { 17366 if int32(prg.curSym) >= hashBase+hashSize+12+1+paramSize+paramSize { 17367 prg.curSym = uint16(int32(prg.curSym) - paramSize) 17368 } 17369 // |param_size=text_base-suffix_base| 17370 prg.beginTokenList(prg.paramStack[int32(prg.curInput.limitField)+int32(prg.curSym)-(hashBase+hashSize+12+1+paramSize)], quarterword(parameter)) 17371 17372 goto restart 17373 } else { 17374 prg.curCmd = byte(capsuleToken) 17375 prg.curMod = int32(prg.paramStack[int32(prg.curInput.limitField)+int32(prg.curSym)-(hashBase+hashSize+12+1)]) 17376 prg.curSym = 0 17377 goto exit 17378 } 17379 } 17380 } else if int32(prg.curInput.locField) > memMin { 17381 if int32(*(*prg.mem[prg.curInput.locField].hh()).b1()) == token { 17382 prg.curMod = *prg.mem[int32(prg.curInput.locField)+1].int() 17383 if int32(*(*prg.mem[prg.curInput.locField].hh()).b0()) == known { 17384 prg.curCmd = byte(numericToken) 17385 } else { 17386 prg.curCmd = byte(stringToken) 17387 { 17388 if int32(prg.strRef[prg.curMod]) < maxStrRef { 17389 prg.strRef[prg.curMod] = byte(int32(prg.strRef[prg.curMod]) + 1) 17390 } 17391 } 17392 } 17393 } else { 17394 prg.curMod = int32(prg.curInput.locField) 17395 prg.curCmd = byte(capsuleToken) 17396 } 17397 prg.curInput.locField = *(*prg.mem[prg.curInput.locField].hh()).rh() 17398 goto exit 17399 } else { 17400 prg.endTokenList() 17401 goto restart // resume previous level 17402 } 17403 17404 // Finish getting the symbolic token in |cur_sym|; |goto restart| if it is illegal 17405 prg.curCmd = byte(*prg.eqtb[prg.curSym-1].lh()) 17406 prg.curMod = int32(*prg.eqtb[prg.curSym-1].rh()) 17407 if int32(prg.curCmd) >= outerTag { 17408 if prg.checkOuterValidity() { 17409 prg.curCmd = byte(int32(prg.curCmd) - outerTag) 17410 } else { 17411 goto restart 17412 } 17413 } 17414 17415 exit: 17416 } 17417 17418 // 666. 17419 17420 // tangle:pos ../../mf.web:13950:3: 17421 17422 // We need to mention a procedure that may be called by |get_next|. 17423 func (prg *prg) firmUpTheLine() { 17424 var ( 17425 k /* 0..bufSize */ uint16 // an index into |buffer| 17426 ) 17427 prg.curInput.limitField = prg.last 17428 if prg.internal[pausing-1] > 0 { 17429 if int32(prg.interaction) > nonstopMode { 17430 prg.printLn() 17431 if int32(prg.curInput.startField) < int32(prg.curInput.limitField) { 17432 for ii := int32(prg.curInput.startField); ii <= int32(prg.curInput.limitField)-1; ii++ { 17433 k = uint16(ii) 17434 _ = k 17435 prg.print(int32(prg.buffer[k])) 17436 } 17437 } 17438 prg.first = prg.curInput.limitField 17439 { 17440 prg.print( /* "=>" */ 653) 17441 prg.termInput() 17442 } // wait for user response 17443 // \xref[=>] 17444 if int32(prg.last) > int32(prg.first) { 17445 for ii := int32(prg.first); ii <= int32(prg.last)-1; ii++ { 17446 k = uint16(ii) 17447 _ = k // move line down in buffer 17448 prg.buffer[int32(k)+int32(prg.curInput.startField)-int32(prg.first)] = prg.buffer[k] 17449 } 17450 prg.curInput.limitField = uint16(int32(prg.curInput.startField) + int32(prg.last) - int32(prg.first)) 17451 } 17452 } 17453 } 17454 } 17455 17456 // 685. 17457 17458 // tangle:pos ../../mf.web:14273:3: 17459 17460 // Different macro-absorbing operations have different syntaxes, but they 17461 // also have a lot in common. There is a list of special symbols that are to 17462 // be replaced by parameter tokens; there is a special command code that 17463 // ends the definition; the quotation conventions are identical. Therefore 17464 // it makes sense to have most of the work done by a single subroutine. That 17465 // subroutine is called |scan_toks|. 17466 // 17467 // The first parameter to |scan_toks| is the command code that will 17468 // terminate scanning (either |macro_def| or |iteration|). 17469 // 17470 // The second parameter, |subst_list|, points to a (possibly empty) list 17471 // of two-word nodes whose |info| and |value| fields specify symbol tokens 17472 // before and after replacement. The list will be returned to free storage 17473 // by |scan_toks|. 17474 // 17475 // The third parameter is simply appended to the token list that is built. 17476 // And the final parameter tells how many of the special operations 17477 // \.[\#\AT!], \.[\AT!], and \.[\AT!\#] are to be replaced by suffix parameters. 17478 // When such parameters are present, they are called \.[(SUFFIX0)], 17479 // \.[(SUFFIX1)], and \.[(SUFFIX2)]. 17480 func (prg *prg) scanToks(terminator commandCode, 17481 substList, tailEnd halfword, suffixCount smallNumber) (r halfword) { 17482 var ( 17483 p halfword // tail of the token list being built 17484 q halfword // temporary for link management 17485 balance int32 // left delimiters minus right delimiters 17486 ) 17487 p = uint16(3000 - 2) 17488 balance = 1 17489 *(*prg.mem[3000-2].hh()).rh() = uint16(memMin) 17490 for true { 17491 prg.getNext() 17492 if int32(prg.curSym) > 0 { 17493 { 17494 q = substList 17495 for int32(q) != memMin { 17496 if int32(*(*prg.mem[q].hh()).lh()) == int32(prg.curSym) { 17497 prg.curSym = uint16(*prg.mem[int32(q)+1].int()) 17498 prg.curCmd = byte(relax) 17499 goto found 17500 } 17501 q = *(*prg.mem[q].hh()).rh() 17502 } 17503 17504 found: 17505 } 17506 if int32(prg.curCmd) == int32(terminator) { 17507 if prg.curMod > 0 { 17508 balance = balance + 1 17509 } else { 17510 balance = balance - 1 17511 if balance == 0 { 17512 goto done 17513 } 17514 } 17515 } else if int32(prg.curCmd) == macroSpecial { 17516 if prg.curMod == quote { 17517 prg.getNext() 17518 } else if prg.curMod <= int32(suffixCount) { 17519 prg.curSym = uint16(hashBase + hashSize + 12 + 1 + paramSize - 1 + prg.curMod) 17520 } 17521 } 17522 } 17523 *(*prg.mem[p].hh()).rh() = prg.curTok() 17524 p = *(*prg.mem[p].hh()).rh() 17525 } 17526 17527 done: 17528 *(*prg.mem[p].hh()).rh() = tailEnd 17529 prg.flushNodeList(substList) 17530 r = *(*prg.mem[3000-2].hh()).rh() 17531 return r 17532 } 17533 17534 // 691. 17535 17536 // tangle:pos ../../mf.web:14363:3: 17537 17538 // Here is a routine that's used whenever a token will be redefined. If 17539 // the user's token is unredefinable, the `|frozen_inaccessible|' token is 17540 // substituted; the latter is redefinable but essentially impossible to use, 17541 // hence \MF's tables won't get fouled up. 17542 func (prg *prg) getSymbol() { 17543 restart: 17544 prg.getNext() 17545 if int32(prg.curSym) == 0 || int32(prg.curSym) > hashBase+hashSize { 17546 { 17547 if int32(prg.interaction) == errorStopMode { 17548 } 17549 prg.printNl(strNumber( /* "! " */ 261)) 17550 prg.print( /* "Missing symbolic token inserted" */ 665) /* \xref[!\relax] */ 17551 } 17552 // \xref[Missing symbolic token...] 17553 { 17554 prg.helpPtr = 3 17555 prg.helpLine[2] = /* "Sorry: You can't redefine a number, string, or expr." */ 666 17556 prg.helpLine[1] = /* "I've inserted an inaccessible symbol so that your" */ 667 17557 prg.helpLine[0] = /* "definition will be completed without mixing me up too badly." */ 668 17558 } 17559 if int32(prg.curSym) > 0 { 17560 prg.helpLine[2] = /* "Sorry: You can't redefine my error-recovery tokens." */ 669 17561 } else if int32(prg.curCmd) == stringToken { 17562 if int32(prg.strRef[prg.curMod]) < maxStrRef { 17563 if int32(prg.strRef[prg.curMod]) > 1 { 17564 prg.strRef[prg.curMod] = byte(int32(prg.strRef[prg.curMod]) - 1) 17565 } else { 17566 prg.flushString(strNumber(prg.curMod)) 17567 } 17568 } 17569 } 17570 prg.curSym = uint16(hashBase + hashSize) 17571 prg.insError() 17572 goto restart 17573 } 17574 } 17575 17576 // 692. 17577 17578 // tangle:pos ../../mf.web:14384:3: 17579 17580 // Before we actually redefine a symbolic token, we need to clear away its 17581 // former value, if it was a variable. The following stronger version of 17582 // |get_symbol| does that. 17583 func (prg *prg) getClearSymbol() { 17584 prg.getSymbol() 17585 prg.clearSymbol(prg.curSym, false) 17586 } 17587 17588 // 693. 17589 17590 // tangle:pos ../../mf.web:14392:3: 17591 17592 // Here's another little subroutine; it checks that an equals sign 17593 // or assignment sign comes along at the proper place in a macro definition. 17594 func (prg *prg) checkEquals() { 17595 if int32(prg.curCmd) != equals { 17596 if int32(prg.curCmd) != assignment { 17597 prg.missingErr(strNumber('=')) 17598 17599 // \xref[Missing `='] 17600 { 17601 prg.helpPtr = 5 17602 prg.helpLine[4] = /* "The next thing in this `def' should have been `='," */ 670 17603 prg.helpLine[3] = /* "because I've already looked at the definition heading." */ 671 17604 prg.helpLine[2] = /* "But don't worry; I'll pretend that an equals sign" */ 672 17605 prg.helpLine[1] = /* "was present. Everything from here to `enddef'" */ 673 17606 prg.helpLine[0] = /* "will be the replacement text of this macro." */ 674 17607 } 17608 prg.backError() 17609 } 17610 } 17611 } 17612 17613 // 694. 17614 17615 // tangle:pos ../../mf.web:14408:3: 17616 17617 // A \&[primarydef], \&[secondarydef], or \&[tertiarydef] is rather easily 17618 // handled now that we have |scan_toks|. In this case there are 17619 // two parameters, which will be \.[EXPR0] and \.[EXPR1] (i.e., 17620 // |expr_base| and |expr_base+1|). 17621 func (prg *prg) makeOpDef() { 17622 var ( 17623 m commandCode // the type of definition 17624 p, q, r1 halfword // for list manipulation 17625 ) 17626 m = byte(prg.curMod) 17627 17628 prg.getSymbol() 17629 q = prg.getNode(tokenNodeSize) 17630 *(*prg.mem[q].hh()).lh() = prg.curSym 17631 *prg.mem[int32(q)+1].int() = hashBase + hashSize + 12 + 1 17632 17633 prg.getClearSymbol() 17634 prg.warningInfo = int32(prg.curSym) 17635 17636 prg.getSymbol() 17637 p = prg.getNode(tokenNodeSize) 17638 *(*prg.mem[p].hh()).lh() = prg.curSym 17639 *prg.mem[int32(p)+1].int() = hashBase + hashSize + 12 + 1 + 1 17640 *(*prg.mem[p].hh()).rh() = q 17641 17642 prg.getNext() 17643 prg.checkEquals() 17644 17645 prg.scannerStatus = byte(opDefining) 17646 q = prg.getAvail() 17647 *(*prg.mem[q].hh()).lh() = uint16(memMin) 17648 r1 = prg.getAvail() 17649 *(*prg.mem[q].hh()).rh() = r1 17650 *(*prg.mem[r1].hh()).lh() = uint16(generalMacro) 17651 *(*prg.mem[r1].hh()).rh() = prg.scanToks(commandCode(macroDef), p, halfword(memMin), smallNumber(0)) 17652 prg.scannerStatus = byte(normal) 17653 *prg.eqtb[prg.warningInfo-1].lh() = uint16(m) 17654 *prg.eqtb[prg.warningInfo-1].rh() = q 17655 prg.getXNext() 17656 } 17657 17658 // 697. 17659 17660 // tangle:pos ../../mf.web:14456:3: 17661 17662 // Let's turn next to the more complex processing associated with \&[def] 17663 // and \&[vardef]. When the following procedure is called, |cur_mod| 17664 // should be either |start_def| or |var_def|. 17665 // \4 17666 // Declare the procedure called |check_delimiter| 17667 func (prg *prg) checkDelimiter(lDelim, rDelim halfword) { 17668 if int32(prg.curCmd) == rightDelimiter { 17669 if prg.curMod == int32(lDelim) { 17670 goto exit 17671 } 17672 } 17673 if int32(prg.curSym) != int32(rDelim) { 17674 prg.missingErr(*prg.hash[rDelim-1].rh()) 17675 17676 // \xref[Missing `)'] 17677 { 17678 prg.helpPtr = 2 17679 prg.helpLine[1] = /* "I found no right delimiter to match a left one. So I've" */ 922 17680 prg.helpLine[0] = /* "put one in, behind the scenes; this may fix the problem." */ 923 17681 } 17682 prg.backError() 17683 } else { 17684 { 17685 if int32(prg.interaction) == errorStopMode { 17686 } 17687 prg.printNl(strNumber( /* "! " */ 261)) 17688 prg.print( /* "The token `" */ 924) /* \xref[!\relax] */ 17689 } 17690 prg.slowPrint(int32(*prg.hash[rDelim-1].rh())) 17691 // \xref[The token...delimiter] 17692 prg.print( /* "' is no longer a right delimiter" */ 925) 17693 { 17694 prg.helpPtr = 3 17695 prg.helpLine[2] = /* "Strange: This token has lost its former meaning!" */ 926 17696 prg.helpLine[1] = /* "I'll read it as a right delimiter this time;" */ 927 17697 prg.helpLine[0] = /* "but watch out, I'll probably miss it later." */ 928 17698 } 17699 prg.error1() 17700 } 17701 17702 exit: 17703 } 17704 17705 // \4 17706 // Declare the function called |scan_declared_variable| 17707 func (prg *prg) scanDeclaredVariable() (r halfword) { 17708 var ( 17709 x halfword // hash address of the variable's root 17710 h, t halfword // head and tail of the token list to be returned 17711 l halfword // hash address of left bracket 17712 ) 17713 prg.getSymbol() 17714 x = prg.curSym 17715 if int32(prg.curCmd) != tagToken { 17716 prg.clearSymbol(x, false) 17717 } 17718 h = prg.getAvail() 17719 *(*prg.mem[h].hh()).lh() = x 17720 t = h 17721 17722 for true { 17723 prg.getXNext() 17724 if int32(prg.curSym) == 0 { 17725 goto done 17726 } 17727 if int32(prg.curCmd) != tagToken { 17728 if int32(prg.curCmd) != internalQuantity { 17729 if int32(prg.curCmd) == leftBracket { 17730 l = prg.curSym 17731 prg.getXNext() 17732 if int32(prg.curCmd) != rightBracket { 17733 prg.backInput() 17734 prg.curSym = l 17735 prg.curCmd = byte(leftBracket) 17736 goto done 17737 } else { 17738 prg.curSym = uint16(collectiveSubscript) 17739 } 17740 } else { 17741 goto done 17742 } 17743 } 17744 } 17745 *(*prg.mem[t].hh()).rh() = prg.getAvail() 17746 t = *(*prg.mem[t].hh()).rh() 17747 *(*prg.mem[t].hh()).lh() = prg.curSym 17748 } 17749 17750 done: 17751 if int32(*prg.eqtb[x-1].lh())%outerTag != tagToken { 17752 prg.clearSymbol(x, false) 17753 } 17754 if int32(*prg.eqtb[x-1].rh()) == memMin { 17755 prg.newRoot(x) 17756 } 17757 r = h 17758 return r 17759 } 17760 17761 func (prg *prg) scanDef() { 17762 var ( 17763 m/* startDef..varDef */ byte // the type of definition 17764 n/* 0..3 */ byte // the number of special suffix parameters 17765 k/* 0..paramSize */ byte // the total number of parameters 17766 c/* generalMacro..textMacro */ byte // the kind of macro we're defining 17767 r1 halfword // parameter-substitution list 17768 q halfword // tail of the macro token list 17769 p halfword // temporary storage 17770 base halfword // |expr_base|, |suffix_base|, or |text_base| 17771 lDelim, rDelim halfword // matching delimiters 17772 ) 17773 m = byte(prg.curMod) 17774 c = byte(generalMacro) 17775 *(*prg.mem[3000-2].hh()).rh() = uint16(memMin) 17776 17777 q = prg.getAvail() 17778 *(*prg.mem[q].hh()).lh() = uint16(memMin) 17779 r1 = uint16(memMin) 17780 17781 // Scan the token or variable to be defined; set |n|, |scanner_status|, and |warning_info| 17782 if int32(m) == startDef { 17783 prg.getClearSymbol() 17784 prg.warningInfo = int32(prg.curSym) 17785 prg.getNext() 17786 prg.scannerStatus = byte(opDefining) 17787 n = 0 17788 *prg.eqtb[prg.warningInfo-1].lh() = uint16(definedMacro) 17789 *prg.eqtb[prg.warningInfo-1].rh() = q 17790 } else { 17791 p = prg.scanDeclaredVariable() 17792 prg.flushVariable(*prg.eqtb[*(*prg.mem[p].hh()).lh()-1].rh(), *(*prg.mem[p].hh()).rh(), true) 17793 prg.warningInfo = int32(prg.findVariable(p)) 17794 prg.flushList(p) 17795 if prg.warningInfo == memMin { 17796 { 17797 if int32(prg.interaction) == errorStopMode { 17798 } 17799 prg.printNl(strNumber( /* "! " */ 261)) 17800 prg.print( /* "This variable already starts with a macro" */ 681) /* \xref[!\relax] */ 17801 } 17802 // \xref[This variable already...] 17803 { 17804 prg.helpPtr = 2 17805 prg.helpLine[1] = /* "After `vardef a' you can't say `vardef a.b'." */ 682 17806 prg.helpLine[0] = /* "So I'll have to discard this definition." */ 683 17807 } 17808 prg.error1() 17809 prg.warningInfo = memMin + 3 + 10 + 2 + 2 + 2 + 2 17810 } 17811 prg.scannerStatus = byte(varDefining) 17812 n = 2 17813 if int32(prg.curCmd) == macroSpecial { 17814 if prg.curMod == macroSuffix { 17815 n = 3 17816 prg.getNext() 17817 } 17818 } 17819 *(*prg.mem[prg.warningInfo].hh()).b0() = byte(unsuffixedMacro - 2 + int32(n)) 17820 *prg.mem[prg.warningInfo+1].int() = int32(q) 17821 } 17822 k = n 17823 if int32(prg.curCmd) == leftDelimiter { 17824 for { 17825 lDelim = prg.curSym 17826 rDelim = uint16(prg.curMod) 17827 prg.getNext() 17828 if int32(prg.curCmd) == paramType && prg.curMod >= hashBase+hashSize+12+1 { 17829 base = uint16(prg.curMod) 17830 } else { 17831 { 17832 if int32(prg.interaction) == errorStopMode { 17833 } 17834 prg.printNl(strNumber( /* "! " */ 261)) 17835 prg.print( /* "Missing parameter type; `expr' will be assumed" */ 684) /* \xref[!\relax] */ 17836 } 17837 // \xref[Missing parameter type] 17838 { 17839 prg.helpPtr = 1 17840 prg.helpLine[0] = /* "You should've had `expr' or `suffix' or `text' here." */ 685 17841 } 17842 prg.backError() 17843 base = uint16(hashBase + hashSize + 12 + 1) 17844 } 17845 17846 // Absorb parameter tokens for type |base| 17847 for { 17848 *(*prg.mem[q].hh()).rh() = prg.getAvail() 17849 q = *(*prg.mem[q].hh()).rh() 17850 *(*prg.mem[q].hh()).lh() = uint16(int32(base) + int32(k)) 17851 17852 prg.getSymbol() 17853 p = prg.getNode(tokenNodeSize) 17854 *prg.mem[int32(p)+1].int() = int32(base) + int32(k) 17855 *(*prg.mem[p].hh()).lh() = prg.curSym 17856 if int32(k) == paramSize { 17857 prg.overflow(strNumber( /* "parameter stack size" */ 686), paramSize) 17858 } 17859 // \xref[METAFONT capacity exceeded parameter stack size][\quad parameter stack size] 17860 k = byte(int32(k) + 1) 17861 *(*prg.mem[p].hh()).rh() = r1 17862 r1 = p 17863 prg.getNext() 17864 if int32(prg.curCmd) != comma { 17865 break 17866 } 17867 } 17868 prg.checkDelimiter(lDelim, rDelim) 17869 prg.getNext() 17870 if int32(prg.curCmd) != leftDelimiter { 17871 break 17872 } 17873 } 17874 } 17875 if int32(prg.curCmd) == paramType { 17876 p = prg.getNode(tokenNodeSize) 17877 if prg.curMod < hashBase+hashSize+12+1 { 17878 c = byte(prg.curMod) 17879 *prg.mem[int32(p)+1].int() = hashBase + hashSize + 12 + 1 + int32(k) 17880 } else { 17881 *prg.mem[int32(p)+1].int() = prg.curMod + int32(k) 17882 if prg.curMod == hashBase+hashSize+12+1 { 17883 c = byte(exprMacro) 17884 } else if prg.curMod == hashBase+hashSize+12+1+paramSize { 17885 c = byte(suffixMacro) 17886 } else { 17887 c = byte(textMacro) 17888 } 17889 } 17890 if int32(k) == paramSize { 17891 prg.overflow(strNumber( /* "parameter stack size" */ 686), paramSize) 17892 } 17893 k = byte(int32(k) + 1) 17894 prg.getSymbol() 17895 *(*prg.mem[p].hh()).lh() = prg.curSym 17896 *(*prg.mem[p].hh()).rh() = r1 17897 r1 = p 17898 prg.getNext() 17899 if int32(c) == exprMacro { 17900 if int32(prg.curCmd) == ofToken { 17901 c = byte(ofMacro) 17902 p = prg.getNode(tokenNodeSize) 17903 if int32(k) == paramSize { 17904 prg.overflow(strNumber( /* "parameter stack size" */ 686), paramSize) 17905 } 17906 *prg.mem[int32(p)+1].int() = hashBase + hashSize + 12 + 1 + int32(k) 17907 prg.getSymbol() 17908 *(*prg.mem[p].hh()).lh() = prg.curSym 17909 *(*prg.mem[p].hh()).rh() = r1 17910 r1 = p 17911 prg.getNext() 17912 } 17913 } 17914 } 17915 prg.checkEquals() 17916 p = prg.getAvail() 17917 *(*prg.mem[p].hh()).lh() = uint16(c) 17918 *(*prg.mem[q].hh()).rh() = p 17919 17920 // Attach the replacement text to the tail of node |p| 17921 if int32(m) == startDef { 17922 *(*prg.mem[p].hh()).rh() = prg.scanToks(commandCode(macroDef), r1, halfword(memMin), n) 17923 } else { 17924 q = prg.getAvail() 17925 *(*prg.mem[q].hh()).lh() = prg.bgLoc 17926 *(*prg.mem[p].hh()).rh() = q 17927 p = prg.getAvail() 17928 *(*prg.mem[p].hh()).lh() = prg.egLoc 17929 *(*prg.mem[q].hh()).rh() = prg.scanToks(commandCode(macroDef), r1, p, n) 17930 } 17931 if prg.warningInfo == memMin+3+10+2+2+2+2 { 17932 prg.flushTokenList(halfword(*prg.mem[memMin+3+10+2+2+2+2+1].int())) 17933 } 17934 prg.scannerStatus = byte(normal) 17935 prg.getXNext() 17936 } // \2 17937 17938 // \4 17939 // Declare the procedure called |macro_call| 17940 // \4 17941 // Declare the procedure called |print_macro_name| 17942 func (prg *prg) printMacroName(a, n halfword) { 17943 var ( 17944 p, q halfword // they traverse the first part of |a| 17945 ) 17946 if int32(n) != memMin { 17947 prg.slowPrint(int32(*prg.hash[n-1].rh())) 17948 } else { 17949 p = *(*prg.mem[a].hh()).lh() 17950 if int32(p) == memMin { 17951 prg.slowPrint(int32(*prg.hash[*(*prg.mem[*(*prg.mem[*(*prg.mem[a].hh()).rh()].hh()).lh()].hh()).lh()-1].rh())) 17952 } else { 17953 q = p 17954 for int32(*(*prg.mem[q].hh()).rh()) != memMin { 17955 q = *(*prg.mem[q].hh()).rh() 17956 } 17957 *(*prg.mem[q].hh()).rh() = *(*prg.mem[*(*prg.mem[a].hh()).rh()].hh()).lh() 17958 prg.showTokenList(int32(p), memMin, 1000, 0) 17959 *(*prg.mem[q].hh()).rh() = uint16(memMin) 17960 } 17961 } 17962 } 17963 17964 // \4 17965 // Declare the procedure called |print_arg| 17966 func (prg *prg) printArg(q halfword, n int32, b halfword) { 17967 if int32(*(*prg.mem[q].hh()).rh()) == memMin+1 { 17968 prg.printNl(strNumber( /* "(EXPR" */ 498)) 17969 } else if int32(b) < hashBase+hashSize+12+1+paramSize+paramSize && int32(b) != textMacro { 17970 prg.printNl(strNumber( /* "(SUFFIX" */ 499)) 17971 } else { 17972 prg.printNl(strNumber( /* "(TEXT" */ 500)) 17973 } 17974 prg.printInt(n) 17975 prg.print( /* ")<-" */ 702) 17976 if int32(*(*prg.mem[q].hh()).rh()) == memMin+1 { 17977 prg.printExp(q, smallNumber(1)) 17978 } else { 17979 prg.showTokenList(int32(q), memMin, 1000, 0) 17980 } 17981 } 17982 17983 // \4 17984 // Declare the procedure called |scan_text_arg| 17985 func (prg *prg) scanTextArg(lDelim, rDelim halfword) { 17986 var ( 17987 balance int32 // excess of |l_delim| over |r_delim| 17988 p halfword // list tail 17989 ) 17990 prg.warningInfo = int32(lDelim) 17991 prg.scannerStatus = byte(absorbing) 17992 p = uint16(3000 - 2) 17993 balance = 1 17994 *(*prg.mem[3000-2].hh()).rh() = uint16(memMin) 17995 for true { 17996 prg.getNext() 17997 if int32(lDelim) == 0 { 17998 if int32(prg.curCmd) > comma { 17999 if balance == 1 { 18000 goto done 18001 } else if int32(prg.curCmd) == endGroup { 18002 balance = balance - 1 18003 } 18004 } else if int32(prg.curCmd) == beginGroup { 18005 balance = balance + 1 18006 } 18007 } else { 18008 // Adjust the balance for a delimited argument; |goto done| if done 18009 if int32(prg.curCmd) == rightDelimiter { 18010 if prg.curMod == int32(lDelim) { 18011 balance = balance - 1 18012 if balance == 0 { 18013 goto done 18014 } 18015 } 18016 } else if int32(prg.curCmd) == leftDelimiter { 18017 if prg.curMod == int32(rDelim) { 18018 balance = balance + 1 18019 } 18020 } 18021 } 18022 *(*prg.mem[p].hh()).rh() = prg.curTok() 18023 p = *(*prg.mem[p].hh()).rh() 18024 } 18025 18026 done: 18027 prg.curExp = int32(*(*prg.mem[3000-2].hh()).rh()) 18028 prg.curType = byte(tokenList) 18029 prg.scannerStatus = byte(normal) 18030 } 18031 18032 func (prg *prg) macroCall(defRef, argList, macroName halfword) { 18033 var ( 18034 r1 halfword // current node in the macro's token list 18035 p, q halfword // for list manipulation 18036 n int32 // the number of arguments 18037 lDelim, rDelim halfword // a delimiter pair 18038 tail halfword // tail of the argument list 18039 ) 18040 r1 = *(*prg.mem[defRef].hh()).rh() 18041 *(*prg.mem[defRef].hh()).lh() = uint16(int32(*(*prg.mem[defRef].hh()).lh()) + 1) 18042 if int32(argList) == memMin { 18043 n = 0 18044 } else { 18045 // Determine the number |n| of arguments already supplied, and set |tail| to the tail of |arg_list| 18046 n = 1 18047 tail = argList 18048 for int32(*(*prg.mem[tail].hh()).rh()) != memMin { 18049 n = n + 1 18050 tail = *(*prg.mem[tail].hh()).rh() 18051 } 18052 } 18053 if prg.internal[tracingMacros-1] > 0 { 18054 prg.beginDiagnostic() 18055 prg.printLn() 18056 prg.printMacroName(argList, macroName) 18057 if n == 3 { 18058 prg.print( /* "@#" */ 664) 18059 } // indicate a suffixed macro 18060 prg.showMacro(defRef, memMin, 100000) 18061 if int32(argList) != memMin { 18062 n = 0 18063 p = argList 18064 for { 18065 q = *(*prg.mem[p].hh()).lh() 18066 prg.printArg(q, n, halfword(0)) 18067 n = n + 1 18068 p = *(*prg.mem[p].hh()).rh() 18069 if int32(p) == memMin { 18070 break 18071 } 18072 } 18073 } 18074 prg.endDiagnostic(false) 18075 } 18076 18077 // Scan the remaining arguments, if any; set |r| to the first token of the replacement text 18078 prg.curCmd = byte(comma + 1) // anything |<>comma| will do 18079 for int32(*(*prg.mem[r1].hh()).lh()) >= hashBase+hashSize+12+1 { 18080 if int32(prg.curCmd) != comma { 18081 prg.getXNext() 18082 if int32(prg.curCmd) != leftDelimiter { 18083 { 18084 if int32(prg.interaction) == errorStopMode { 18085 } 18086 prg.printNl(strNumber( /* "! " */ 261)) 18087 prg.print( /* "Missing argument to " */ 708) /* \xref[!\relax] */ 18088 } 18089 // \xref[Missing argument...] 18090 prg.printMacroName(argList, macroName) 18091 { 18092 prg.helpPtr = 3 18093 prg.helpLine[2] = /* "That macro has more parameters than you thought." */ 709 18094 prg.helpLine[1] = /* "I'll continue by pretending that each missing argument" */ 710 18095 prg.helpLine[0] = /* "is either zero or null." */ 711 18096 } 18097 if int32(*(*prg.mem[r1].hh()).lh()) >= hashBase+hashSize+12+1+paramSize { 18098 prg.curExp = memMin 18099 prg.curType = byte(tokenList) 18100 } else { 18101 prg.curExp = 0 18102 prg.curType = byte(known) 18103 } 18104 prg.backError() 18105 prg.curCmd = byte(rightDelimiter) 18106 goto found 18107 } 18108 lDelim = prg.curSym 18109 rDelim = uint16(prg.curMod) 18110 } 18111 18112 // Scan the argument represented by |info(r)| 18113 if int32(*(*prg.mem[r1].hh()).lh()) >= hashBase+hashSize+12+1+paramSize+paramSize { 18114 prg.scanTextArg(lDelim, rDelim) 18115 } else { 18116 prg.getXNext() 18117 if int32(*(*prg.mem[r1].hh()).lh()) >= hashBase+hashSize+12+1+paramSize { 18118 prg.scanSuffix() 18119 } else { 18120 prg.scanExpression() 18121 } 18122 } 18123 if int32(prg.curCmd) != comma { 18124 if int32(prg.curCmd) != rightDelimiter || prg.curMod != int32(lDelim) { 18125 if int32(*(*prg.mem[*(*prg.mem[r1].hh()).rh()].hh()).lh()) >= hashBase+hashSize+12+1 { 18126 prg.missingErr(strNumber(',')) 18127 // \xref[Missing `,'] 18128 { 18129 prg.helpPtr = 3 18130 prg.helpLine[2] = /* "I've finished reading a macro argument and am about to" */ 712 18131 prg.helpLine[1] = /* "read another; the arguments weren't delimited correctly." */ 713 18132 prg.helpLine[0] = /* "You might want to delete some tokens before continuing." */ 707 18133 } 18134 prg.backError() 18135 prg.curCmd = byte(comma) 18136 } else { 18137 prg.missingErr(*prg.hash[rDelim-1].rh()) 18138 // \xref[Missing `)'] 18139 { 18140 prg.helpPtr = 2 18141 prg.helpLine[1] = /* "I've gotten to the end of the macro parameter list." */ 714 18142 prg.helpLine[0] = /* "You might want to delete some tokens before continuing." */ 707 18143 } 18144 prg.backError() 18145 } 18146 } 18147 } 18148 18149 found: 18150 { 18151 p = prg.getAvail() 18152 if int32(prg.curType) == tokenList { 18153 *(*prg.mem[p].hh()).lh() = uint16(prg.curExp) 18154 } else { 18155 *(*prg.mem[p].hh()).lh() = prg.stashCurExp() 18156 } 18157 if prg.internal[tracingMacros-1] > 0 { 18158 prg.beginDiagnostic() 18159 prg.printArg(*(*prg.mem[p].hh()).lh(), n, *(*prg.mem[r1].hh()).lh()) 18160 prg.endDiagnostic(false) 18161 } 18162 if int32(argList) == memMin { 18163 argList = p 18164 } else { 18165 *(*prg.mem[tail].hh()).rh() = p 18166 } 18167 tail = p 18168 n = n + 1 18169 } 18170 r1 = *(*prg.mem[r1].hh()).rh() 18171 } 18172 if int32(prg.curCmd) == comma { 18173 { 18174 if int32(prg.interaction) == errorStopMode { 18175 } 18176 prg.printNl(strNumber( /* "! " */ 261)) 18177 prg.print( /* "Too many arguments to " */ 703) /* \xref[!\relax] */ 18178 } 18179 // \xref[Too many arguments...] 18180 prg.printMacroName(argList, macroName) 18181 prg.printChar(asciiCode(';')) 18182 prg.printNl(strNumber( /* " Missing `" */ 704)) 18183 prg.slowPrint(int32(*prg.hash[rDelim-1].rh())) 18184 // \xref[Missing `)'...] 18185 prg.print( /* "' has been inserted" */ 300) 18186 { 18187 prg.helpPtr = 3 18188 prg.helpLine[2] = /* "I'm going to assume that the comma I just read was a" */ 705 18189 prg.helpLine[1] = /* "right delimiter, and then I'll begin expanding the macro." */ 706 18190 prg.helpLine[0] = /* "You might want to delete some tokens before continuing." */ 707 18191 } 18192 prg.error1() 18193 } 18194 if int32(*(*prg.mem[r1].hh()).lh()) != generalMacro { 18195 if int32(*(*prg.mem[r1].hh()).lh()) < textMacro { 18196 prg.getXNext() 18197 if int32(*(*prg.mem[r1].hh()).lh()) != suffixMacro { 18198 if int32(prg.curCmd) == equals || int32(prg.curCmd) == assignment { 18199 prg.getXNext() 18200 } 18201 } 18202 } 18203 switch *(*prg.mem[r1].hh()).lh() { 18204 case primaryMacro: 18205 prg.scanPrimary() 18206 case secondaryMacro: 18207 prg.scanSecondary() 18208 case tertiaryMacro: 18209 prg.scanTertiary() 18210 case exprMacro: 18211 prg.scanExpression() 18212 case ofMacro: 18213 // Scan an expression followed by `\&[of] $\langle$primary$\rangle$' 18214 prg.scanExpression() 18215 p = prg.getAvail() 18216 *(*prg.mem[p].hh()).lh() = prg.stashCurExp() 18217 if prg.internal[tracingMacros-1] > 0 { 18218 prg.beginDiagnostic() 18219 prg.printArg(*(*prg.mem[p].hh()).lh(), n, halfword(0)) 18220 prg.endDiagnostic(false) 18221 } 18222 if int32(argList) == memMin { 18223 argList = p 18224 } else { 18225 *(*prg.mem[tail].hh()).rh() = p 18226 } 18227 tail = p 18228 n = n + 1 18229 if int32(prg.curCmd) != ofToken { 18230 prg.missingErr(strNumber( /* "of" */ 479)) 18231 prg.print( /* " for " */ 715) 18232 // \xref[Missing `of'] 18233 prg.printMacroName(argList, macroName) 18234 { 18235 prg.helpPtr = 1 18236 prg.helpLine[0] = /* "I've got the first argument; will look now for the other." */ 716 18237 } 18238 prg.backError() 18239 } 18240 prg.getXNext() 18241 prg.scanPrimary() 18242 18243 case suffixMacro: 18244 // Scan a suffix with optional delimiters 18245 if int32(prg.curCmd) != leftDelimiter { 18246 lDelim = uint16(memMin) 18247 } else { 18248 lDelim = prg.curSym 18249 rDelim = uint16(prg.curMod) 18250 prg.getXNext() 18251 } 18252 prg.scanSuffix() 18253 if int32(lDelim) != memMin { 18254 if int32(prg.curCmd) != rightDelimiter || prg.curMod != int32(lDelim) { 18255 prg.missingErr(*prg.hash[rDelim-1].rh()) 18256 // \xref[Missing `)'] 18257 { 18258 prg.helpPtr = 2 18259 prg.helpLine[1] = /* "I've gotten to the end of the macro parameter list." */ 714 18260 prg.helpLine[0] = /* "You might want to delete some tokens before continuing." */ 707 18261 } 18262 prg.backError() 18263 } 18264 prg.getXNext() 18265 } 18266 18267 case textMacro: 18268 prg.scanTextArg(halfword(0), halfword(0)) 18269 } // there are no other cases 18270 prg.backInput() 18271 // Append the current expression to |arg_list| 18272 { 18273 p = prg.getAvail() 18274 if int32(prg.curType) == tokenList { 18275 *(*prg.mem[p].hh()).lh() = uint16(prg.curExp) 18276 } else { 18277 *(*prg.mem[p].hh()).lh() = prg.stashCurExp() 18278 } 18279 if prg.internal[tracingMacros-1] > 0 { 18280 prg.beginDiagnostic() 18281 prg.printArg(*(*prg.mem[p].hh()).lh(), n, *(*prg.mem[r1].hh()).lh()) 18282 prg.endDiagnostic(false) 18283 } 18284 if int32(argList) == memMin { 18285 argList = p 18286 } else { 18287 *(*prg.mem[tail].hh()).rh() = p 18288 } 18289 tail = p 18290 n = n + 1 18291 } 18292 } 18293 r1 = *(*prg.mem[r1].hh()).rh() 18294 18295 // Feed the arguments and replacement text to the scanner 18296 for int32(prg.curInput.indexField) > maxInOpen && int32(prg.curInput.locField) == memMin { 18297 prg.endTokenList() 18298 } // conserve stack space 18299 if int32(prg.paramPtr)+n > prg.maxParamStack { 18300 prg.maxParamStack = int32(prg.paramPtr) + n 18301 if prg.maxParamStack > paramSize { 18302 prg.overflow(strNumber( /* "parameter stack size" */ 686), paramSize) 18303 } 18304 // \xref[METAFONT capacity exceeded parameter stack size][\quad parameter stack size] 18305 } 18306 prg.beginTokenList(defRef, quarterword(macro)) 18307 prg.curInput.nameField = macroName 18308 prg.curInput.locField = r1 18309 if n > 0 { 18310 p = argList 18311 for { 18312 prg.paramStack[prg.paramPtr] = *(*prg.mem[p].hh()).lh() 18313 prg.paramPtr = byte(int32(prg.paramPtr) + 1) 18314 p = *(*prg.mem[p].hh()).rh() 18315 if int32(p) == memMin { 18316 break 18317 } 18318 } 18319 prg.flushList(argList) 18320 } 18321 } // \2 18322 18323 // 707. 18324 18325 // tangle:pos ../../mf.web:14608:3: 18326 18327 // An auxiliary subroutine called |expand| is used by |get_x_next| 18328 // when it has to do exotic expansion commands. 18329 func (prg *prg) expand() { 18330 var ( 18331 p halfword // for list manipulation 18332 k int32 // something that we hope is |<=buf_size| 18333 j poolPointer // index into |str_pool| 18334 ) 18335 if prg.internal[tracingCommands-1] > 0200000 { 18336 if int32(prg.curCmd) != definedMacro { 18337 prg.showCmdMod(int32(prg.curCmd), prg.curMod) 18338 } 18339 } 18340 switch prg.curCmd { 18341 case ifTest: 18342 prg.conditional() // this procedure is discussed in Part 36 below 18343 case fiOrElse: 18344 // Terminate the current conditional and skip to \&[fi] 18345 if prg.curMod > int32(prg.ifLimit) { 18346 if int32(prg.ifLimit) == ifCode { 18347 prg.missingErr(strNumber(':')) 18348 // \xref[Missing `:'] 18349 prg.backInput() 18350 prg.curSym = uint16(hashBase + hashSize + 5) 18351 prg.insError() 18352 } else { 18353 { 18354 if int32(prg.interaction) == errorStopMode { 18355 } 18356 prg.printNl(strNumber( /* "! " */ 261)) 18357 prg.print( /* "Extra " */ 723) /* \xref[!\relax] */ 18358 } 18359 prg.printCmdMod(fiOrElse, prg.curMod) 18360 // \xref[Extra else] 18361 // \xref[Extra elseif] 18362 // \xref[Extra fi] 18363 { 18364 prg.helpPtr = 1 18365 prg.helpLine[0] = /* "I'm ignoring this; it doesn't match any if." */ 724 18366 } 18367 prg.error1() 18368 } 18369 } else { 18370 for prg.curMod != fiCode { 18371 prg.passText() 18372 } // skip to \&[fi] 18373 18374 // Pop the condition stack 18375 { 18376 p = prg.condPtr 18377 prg.ifLine = *prg.mem[int32(p)+1].int() 18378 prg.curIf = *(*prg.mem[p].hh()).b1() 18379 prg.ifLimit = *(*prg.mem[p].hh()).b0() 18380 prg.condPtr = *(*prg.mem[p].hh()).rh() 18381 prg.freeNode(p, halfword(ifNodeSize)) 18382 } 18383 } 18384 18385 case input: 18386 // Initiate or terminate input from a file 18387 if prg.curMod > 0 { 18388 prg.forceEof = true 18389 } else { 18390 prg.startInput() 18391 } 18392 18393 case iteration: 18394 if prg.curMod == endFor { 18395 { 18396 if int32(prg.interaction) == errorStopMode { 18397 } 18398 prg.printNl(strNumber( /* "! " */ 261)) 18399 prg.print( /* "Extra `endfor'" */ 687) /* \xref[!\relax] */ 18400 } 18401 // \xref[Extra `endfor'] 18402 { 18403 prg.helpPtr = 2 18404 prg.helpLine[1] = /* "I'm not currently working on a for loop," */ 688 18405 prg.helpLine[0] = /* "so I had better not try to end anything." */ 689 18406 } 18407 18408 prg.error1() 18409 } else { 18410 prg.beginIteration() 18411 } // this procedure is discussed in Part 37 below 18412 case repeatLoop: 18413 // Repeat a loop 18414 for int32(prg.curInput.indexField) > maxInOpen && int32(prg.curInput.locField) == memMin { 18415 prg.endTokenList() 18416 } // conserve stack space 18417 if int32(prg.loopPtr) == memMin { 18418 { 18419 if int32(prg.interaction) == errorStopMode { 18420 } 18421 prg.printNl(strNumber( /* "! " */ 261)) 18422 prg.print( /* "Lost loop" */ 691) /* \xref[!\relax] */ 18423 } 18424 // \xref[Lost loop] 18425 { 18426 prg.helpPtr = 2 18427 prg.helpLine[1] = /* "I'm confused; after exiting from a loop, I still seem" */ 692 18428 prg.helpLine[0] = /* "to want to repeat it. I'll try to forget the problem." */ 693 18429 } 18430 18431 prg.error1() 18432 } else { 18433 prg.resumeIteration() 18434 } // this procedure is in Part 37 below 18435 18436 case exitTest: 18437 // Exit a loop if the proper time has come 18438 prg.getBoolean() 18439 if prg.internal[tracingCommands-1] > 0200000 { 18440 prg.showCmdMod(nullary, prg.curExp) 18441 } 18442 if prg.curExp == trueCode { 18443 if int32(prg.loopPtr) == memMin { 18444 { 18445 if int32(prg.interaction) == errorStopMode { 18446 } 18447 prg.printNl(strNumber( /* "! " */ 261)) 18448 prg.print( /* "No loop is in progress" */ 694) /* \xref[!\relax] */ 18449 } 18450 // \xref[No loop is in progress] 18451 { 18452 prg.helpPtr = 1 18453 prg.helpLine[0] = /* "Why say `exitif' when there's nothing to exit from?" */ 695 18454 } 18455 if int32(prg.curCmd) == semicolon { 18456 prg.error1() 18457 } else { 18458 prg.backError() 18459 } 18460 } else { 18461 // Exit prematurely from an iteration 18462 p = uint16(memMin) 18463 for { 18464 if int32(prg.curInput.indexField) <= maxInOpen { 18465 prg.endFileReading() 18466 } else { 18467 if int32(prg.curInput.indexField) <= loopText { 18468 p = prg.curInput.startField 18469 } 18470 prg.endTokenList() 18471 } 18472 if int32(p) != memMin { 18473 break 18474 } 18475 } 18476 if int32(p) != int32(*(*prg.mem[prg.loopPtr].hh()).lh()) { 18477 prg.fatalError(strNumber( /* "*** (loop confusion)" */ 698)) 18478 } 18479 // \xref[loop confusion] 18480 prg.stopIteration() // this procedure is in Part 37 below 18481 } 18482 } else if int32(prg.curCmd) != semicolon { 18483 prg.missingErr(strNumber(';')) 18484 18485 // \xref[Missing `;'] 18486 { 18487 prg.helpPtr = 2 18488 prg.helpLine[1] = /* "After `exitif <boolean expr>' I expect to see a semicolon." */ 696 18489 prg.helpLine[0] = /* "I shall pretend that one was there." */ 697 18490 } 18491 prg.backError() 18492 } 18493 18494 case relax: 18495 case expandAfter: 18496 // Expand the token after the next token 18497 prg.getNext() 18498 p = prg.curTok() 18499 prg.getNext() 18500 if int32(prg.curCmd) < minCommand { 18501 prg.expand() 18502 } else { 18503 prg.backInput() 18504 } 18505 prg.beginTokenList(p, quarterword(backedUp)) 18506 18507 case scanTokens: 18508 // Put a string into the input buffer 18509 prg.getXNext() 18510 prg.scanPrimary() 18511 if int32(prg.curType) != stringType { 18512 prg.dispErr(halfword(memMin), strNumber( /* "Not a string" */ 699)) 18513 // \xref[Not a string] 18514 { 18515 prg.helpPtr = 2 18516 prg.helpLine[1] = /* "I'm going to flush this expression, since" */ 700 18517 prg.helpLine[0] = /* "scantokens should be followed by a known string." */ 701 18518 } 18519 prg.putGetFlushError(scaled(0)) 18520 } else { 18521 prg.backInput() 18522 if int32(prg.strStart[prg.curExp+1])-int32(prg.strStart[prg.curExp]) > 0 { 18523 prg.beginFileReading() 18524 prg.curInput.nameField = 2 18525 k = int32(prg.first) + (int32(prg.strStart[prg.curExp+1]) - int32(prg.strStart[prg.curExp])) 18526 if k >= int32(prg.maxBufStack) { 18527 if k >= bufSize { 18528 prg.maxBufStack = uint16(bufSize) 18529 prg.overflow(strNumber( /* "buffer size" */ 256), bufSize) 18530 // \xref[METAFONT capacity exceeded buffer size][\quad buffer size] 18531 } 18532 prg.maxBufStack = uint16(k + 1) 18533 } 18534 j = prg.strStart[prg.curExp] 18535 prg.curInput.limitField = uint16(k) 18536 for int32(prg.first) < int32(prg.curInput.limitField) { 18537 prg.buffer[prg.first] = prg.strPool[j] 18538 j = uint16(int32(j) + 1) 18539 prg.first = uint16(int32(prg.first) + 1) 18540 } 18541 prg.buffer[prg.curInput.limitField] = '%' 18542 prg.first = uint16(int32(prg.curInput.limitField) + 1) 18543 prg.curInput.locField = prg.curInput.startField 18544 prg.flushCurExp(scaled(0)) 18545 } 18546 } 18547 18548 case definedMacro: 18549 prg.macroCall(halfword(prg.curMod), halfword(memMin), prg.curSym) 18550 } // there are no other cases 18551 } // \2 18552 18553 func (prg *prg) getXNext() { 18554 var ( 18555 saveExp halfword // a capsule to save |cur_type| and |cur_exp| 18556 ) 18557 prg.getNext() 18558 if int32(prg.curCmd) < minCommand { 18559 saveExp = prg.stashCurExp() 18560 for { 18561 if int32(prg.curCmd) == definedMacro { 18562 prg.macroCall(halfword(prg.curMod), halfword(memMin), prg.curSym) 18563 } else { 18564 prg.expand() 18565 } 18566 prg.getNext() 18567 if int32(prg.curCmd) >= minCommand { 18568 break 18569 } 18570 } 18571 prg.unstashCurExp(saveExp) // that restores |cur_type| and |cur_exp| 18572 } 18573 } 18574 18575 // 719. 18576 18577 // tangle:pos ../../mf.web:14767:3: 18578 18579 // Now let's consider the |macro_call| procedure, which is used to start up 18580 // all user-defined macros. Since the arguments to a macro might be expressions, 18581 // |macro_call| is recursive. 18582 // \xref[recursion] 18583 // 18584 // The first parameter to |macro_call| points to the reference count of the 18585 // token list that defines the macro. The second parameter contains any 18586 // arguments that have already been parsed (see below). The third parameter 18587 // points to the symbolic token that names the macro. If the third parameter 18588 // is |null|, the macro was defined by \&[vardef], so its name can be 18589 // reconstructed from the prefix and ``at'' arguments found within the 18590 // second parameter. 18591 // 18592 // What is this second parameter? It's simply a linked list of one-word items, 18593 // whose |info| fields point to the arguments. In other words, if |arg_list=null|, 18594 // no arguments have been scanned yet; otherwise |info(arg_list)| points to 18595 // the first scanned argument, and |link(arg_list)| points to the list of 18596 // further arguments (if any). 18597 // 18598 // Arguments of type \&[expr] are so-called capsules, which we will 18599 // discuss later when we concentrate on expressions; they can be 18600 // recognized easily because their |link| field is |void|. Arguments of type 18601 // \&[suffix] and \&[text] are token lists without reference counts. 18602 18603 // 737. 18604 18605 // tangle:pos ../../mf.web:15073:3: 18606 18607 // It's sometimes necessary to put a single argument onto |param_stack|. 18608 // The |stack_argument| subroutine does this. 18609 func (prg *prg) stackArgument(p halfword) { 18610 if int32(prg.paramPtr) == prg.maxParamStack { 18611 prg.maxParamStack = prg.maxParamStack + 1 18612 if prg.maxParamStack > paramSize { 18613 prg.overflow(strNumber( /* "parameter stack size" */ 686), paramSize) 18614 } 18615 // \xref[METAFONT capacity exceeded parameter stack size][\quad parameter stack size] 18616 } 18617 prg.paramStack[prg.paramPtr] = p 18618 prg.paramPtr = byte(int32(prg.paramPtr) + 1) 18619 } // \2 18620 func (prg *prg) passText() { 18621 var ( 18622 l int32 18623 ) 18624 prg.scannerStatus = byte(skipping) 18625 l = 0 18626 prg.warningInfo = prg.line 18627 for true { 18628 prg.getNext() 18629 if int32(prg.curCmd) <= fiOrElse { 18630 if int32(prg.curCmd) < fiOrElse { 18631 l = l + 1 18632 } else { 18633 if l == 0 { 18634 goto done 18635 } 18636 if prg.curMod == fiCode { 18637 l = l - 1 18638 } 18639 } 18640 } else if int32(prg.curCmd) == stringToken { 18641 if int32(prg.strRef[prg.curMod]) < maxStrRef { 18642 if int32(prg.strRef[prg.curMod]) > 1 { 18643 prg.strRef[prg.curMod] = byte(int32(prg.strRef[prg.curMod]) - 1) 18644 } else { 18645 prg.flushString(strNumber(prg.curMod)) 18646 } 18647 } 18648 } 18649 } 18650 18651 done: 18652 prg.scannerStatus = byte(normal) 18653 } 18654 18655 // 746. 18656 18657 // tangle:pos ../../mf.web:15182:3: 18658 18659 // Here's a procedure that changes the |if_limit| code corresponding to 18660 // a given value of |cond_ptr|. 18661 func (prg *prg) changeIfLimit(l smallNumber, p halfword) { 18662 var ( 18663 q halfword 18664 ) 18665 if int32(p) == int32(prg.condPtr) { 18666 prg.ifLimit = l 18667 } else { 18668 q = prg.condPtr 18669 for true { 18670 if int32(q) == memMin { 18671 prg.confusion(strNumber( /* "if" */ 717)) 18672 } 18673 // \xref[this can't happen if][\quad if] 18674 if int32(*(*prg.mem[q].hh()).rh()) == int32(p) { 18675 *(*prg.mem[q].hh()).b0() = l 18676 goto exit 18677 } 18678 q = *(*prg.mem[q].hh()).rh() 18679 } 18680 } 18681 18682 exit: 18683 } 18684 18685 // 747. 18686 18687 // tangle:pos ../../mf.web:15200:3: 18688 18689 // The user is supposed to put colons into the proper parts of conditional 18690 // statements. Therefore, \MF\ has to check for their presence. 18691 func (prg *prg) checkColon() { 18692 if int32(prg.curCmd) != colon { 18693 prg.missingErr(strNumber(':')) 18694 18695 // \xref[Missing `:'] 18696 { 18697 prg.helpPtr = 2 18698 prg.helpLine[1] = /* "There should've been a colon after the condition." */ 720 18699 prg.helpLine[0] = /* "I shall pretend that one was there." */ 697 18700 } 18701 prg.backError() 18702 } 18703 } // \2 18704 func (prg *prg) conditional() { 18705 var ( 18706 saveCondPtr halfword // |cond_ptr| corresponding to this conditional 18707 newIfLimit/* fiCode..elseIfCode */ byte // future value of |if_limit| 18708 p halfword // temporary register 18709 ) 18710 { 18711 p = prg.getNode(ifNodeSize) 18712 *(*prg.mem[p].hh()).rh() = prg.condPtr 18713 *(*prg.mem[p].hh()).b0() = prg.ifLimit 18714 *(*prg.mem[p].hh()).b1() = prg.curIf 18715 *prg.mem[int32(p)+1].int() = prg.ifLine 18716 prg.condPtr = p 18717 prg.ifLimit = byte(ifCode) 18718 prg.ifLine = prg.line 18719 prg.curIf = byte(ifCode) 18720 } 18721 saveCondPtr = prg.condPtr 18722 18723 reswitch: 18724 prg.getBoolean() 18725 newIfLimit = byte(elseIfCode) 18726 if prg.internal[tracingCommands-1] > 0200000 { 18727 prg.beginDiagnostic() 18728 if prg.curExp == trueCode { 18729 prg.print( /* "[true]" */ 721) 18730 } else { 18731 prg.print( /* "[false]" */ 722) 18732 } 18733 prg.endDiagnostic(false) 18734 } 18735 18736 found: 18737 prg.checkColon() 18738 if prg.curExp == trueCode { 18739 prg.changeIfLimit(newIfLimit, saveCondPtr) 18740 18741 goto exit // wait for \&[elseif], \&[else], or \&[fi] 18742 } 18743 18744 // Skip to \&[elseif] or \&[else] or \&[fi], then |goto done| 18745 for true { 18746 prg.passText() 18747 if int32(prg.condPtr) == int32(saveCondPtr) { 18748 goto done 18749 } else if prg.curMod == fiCode { 18750 p = prg.condPtr 18751 prg.ifLine = *prg.mem[int32(p)+1].int() 18752 prg.curIf = *(*prg.mem[p].hh()).b1() 18753 prg.ifLimit = *(*prg.mem[p].hh()).b0() 18754 prg.condPtr = *(*prg.mem[p].hh()).rh() 18755 prg.freeNode(p, halfword(ifNodeSize)) 18756 } 18757 } 18758 18759 done: 18760 prg.curIf = byte(prg.curMod) 18761 prg.ifLine = prg.line 18762 if prg.curMod == fiCode { 18763 p = prg.condPtr 18764 prg.ifLine = *prg.mem[int32(p)+1].int() 18765 prg.curIf = *(*prg.mem[p].hh()).b1() 18766 prg.ifLimit = *(*prg.mem[p].hh()).b0() 18767 prg.condPtr = *(*prg.mem[p].hh()).rh() 18768 prg.freeNode(p, halfword(ifNodeSize)) 18769 } else if prg.curMod == elseIfCode { 18770 goto reswitch 18771 } else { 18772 prg.curExp = trueCode 18773 newIfLimit = byte(fiCode) 18774 prg.getXNext() 18775 goto found 18776 } 18777 18778 exit: 18779 } 18780 18781 // 754. 18782 18783 // tangle:pos ../../mf.web:15322:3: 18784 18785 // If the expressions that define an arithmetic progression in 18786 // a \&[for] loop don't have known numeric values, the |bad_for| 18787 // subroutine screams at the user. 18788 func (prg *prg) badFor(s strNumber) { 18789 prg.dispErr(halfword(memMin), strNumber( /* "Improper " */ 725)) // show the bad expression above the message 18790 // \xref[Improper...replaced by 0] 18791 prg.print(int32(s)) 18792 prg.print( /* " has been replaced by 0" */ 307) 18793 { 18794 prg.helpPtr = 4 18795 prg.helpLine[3] = /* "When you say `for x=a step b until c'," */ 726 18796 prg.helpLine[2] = /* "the initial value `a' and the step size `b'" */ 727 18797 prg.helpLine[1] = /* "and the final value `c' must have known numeric values." */ 728 18798 prg.helpLine[0] = /* "I'm zeroing this one. Proceed, with fingers crossed." */ 309 18799 } 18800 prg.putGetFlushError(scaled(0)) 18801 } // \2 18802 func (prg *prg) beginIteration() { 18803 var ( 18804 m halfword // |expr_base| (\&[for]) or |suffix_base| (\&[forsuffixes]) 18805 n halfword // hash address of the current symbol 18806 p, q, s, pp halfword // link manipulation registers 18807 ) 18808 m = uint16(prg.curMod) 18809 n = prg.curSym 18810 s = prg.getNode(loopNodeSize) 18811 if int32(m) == startForever { 18812 *(*prg.mem[int32(s)+1].hh()).lh() = uint16(memMin + 1) 18813 p = uint16(memMin) 18814 prg.getXNext() 18815 goto found 18816 } 18817 prg.getSymbol() 18818 p = prg.getNode(tokenNodeSize) 18819 *(*prg.mem[p].hh()).lh() = prg.curSym 18820 *prg.mem[int32(p)+1].int() = int32(m) 18821 18822 prg.getXNext() 18823 if int32(prg.curCmd) != equals && int32(prg.curCmd) != assignment { 18824 prg.missingErr(strNumber('=')) 18825 18826 // \xref[Missing `='] 18827 { 18828 prg.helpPtr = 3 18829 prg.helpLine[2] = /* "The next thing in this loop should have been `=' or `:='." */ 729 18830 prg.helpLine[1] = /* "But don't worry; I'll pretend that an equals sign" */ 672 18831 prg.helpLine[0] = /* "was present, and I'll look for the values next." */ 730 18832 } 18833 18834 prg.backError() 18835 } 18836 18837 // Scan the values to be used in the loop 18838 *(*prg.mem[int32(s)+1].hh()).lh() = uint16(memMin) 18839 q = uint16(int32(s) + 1) 18840 *(*prg.mem[q].hh()).rh() = uint16(memMin) // |link(q)=loop_list(s)| 18841 for { 18842 prg.getXNext() 18843 if int32(m) != hashBase+hashSize+12+1 { 18844 prg.scanSuffix() 18845 } else { 18846 if int32(prg.curCmd) >= colon { 18847 if int32(prg.curCmd) <= comma { 18848 goto continue1 18849 } 18850 } 18851 prg.scanExpression() 18852 if int32(prg.curCmd) == stepToken { 18853 if int32(q) == int32(s)+1 { 18854 if int32(prg.curType) != known { 18855 prg.badFor(strNumber( /* "initial value" */ 736)) 18856 } 18857 pp = prg.getNode(progressionNodeSize) 18858 *prg.mem[int32(pp)+1].int() = prg.curExp 18859 18860 prg.getXNext() 18861 prg.scanExpression() 18862 if int32(prg.curType) != known { 18863 prg.badFor(strNumber( /* "step size" */ 737)) 18864 } 18865 *prg.mem[int32(pp)+2].int() = prg.curExp 18866 if int32(prg.curCmd) != untilToken { 18867 prg.missingErr(strNumber( /* "until" */ 490)) 18868 18869 // \xref[Missing `until'] 18870 { 18871 prg.helpPtr = 2 18872 prg.helpLine[1] = /* "I assume you meant to say `until' after `step'." */ 738 18873 prg.helpLine[0] = /* "So I'll look for the final value and colon next." */ 739 18874 } 18875 prg.backError() 18876 } 18877 prg.getXNext() 18878 prg.scanExpression() 18879 if int32(prg.curType) != known { 18880 prg.badFor(strNumber( /* "final value" */ 740)) 18881 } 18882 *prg.mem[int32(pp)+3].int() = prg.curExp 18883 *(*prg.mem[int32(s)+1].hh()).lh() = pp 18884 goto done 18885 } 18886 } 18887 prg.curExp = int32(prg.stashCurExp()) 18888 } 18889 *(*prg.mem[q].hh()).rh() = prg.getAvail() 18890 q = *(*prg.mem[q].hh()).rh() 18891 *(*prg.mem[q].hh()).lh() = uint16(prg.curExp) 18892 prg.curType = byte(vacuous) 18893 18894 continue1: 18895 ; 18896 if int32(prg.curCmd) != comma { 18897 break 18898 } 18899 } 18900 18901 done: 18902 ; 18903 18904 found: 18905 if int32(prg.curCmd) != colon { 18906 prg.missingErr(strNumber(':')) 18907 18908 // \xref[Missing `:'] 18909 { 18910 prg.helpPtr = 3 18911 prg.helpLine[2] = /* "The next thing in this loop should have been a `:'." */ 731 18912 prg.helpLine[1] = /* "So I'll pretend that a colon was present;" */ 732 18913 prg.helpLine[0] = /* "everything from here to `endfor' will be iterated." */ 733 18914 } 18915 prg.backError() 18916 } 18917 18918 // Scan the loop text and put it on the loop control stack 18919 q = prg.getAvail() 18920 *(*prg.mem[q].hh()).lh() = uint16(hashBase + hashSize + 1) 18921 prg.scannerStatus = byte(loopDefining) 18922 prg.warningInfo = int32(n) 18923 *(*prg.mem[s].hh()).lh() = prg.scanToks(commandCode(iteration), p, q, smallNumber(0)) 18924 prg.scannerStatus = byte(normal) 18925 18926 *(*prg.mem[s].hh()).rh() = prg.loopPtr 18927 prg.loopPtr = s 18928 prg.resumeIteration() 18929 } // \2 18930 func (prg *prg) resumeIteration() { 18931 var ( 18932 p, q halfword // link registers 18933 ) 18934 p = *(*prg.mem[int32(prg.loopPtr)+1].hh()).lh() 18935 if int32(p) > memMin+1 { 18936 prg.curExp = *prg.mem[int32(p)+1].int() 18937 if *prg.mem[int32(p)+2].int() > 0 && prg.curExp > *prg.mem[int32(p)+3].int() || *prg.mem[int32(p)+2].int() < 0 && prg.curExp < *prg.mem[int32(p)+3].int() { 18938 // The arithmetic progression has ended 18939 goto notFound 18940 } 18941 prg.curType = byte(known) 18942 q = prg.stashCurExp() // make |q| an \&[expr] argument 18943 *prg.mem[int32(p)+1].int() = prg.curExp + *prg.mem[int32(p)+2].int() // set |value(p)| for the next iteration 18944 } else if int32(p) < memMin+1 { 18945 p = *(*prg.mem[int32(prg.loopPtr)+1].hh()).rh() 18946 if int32(p) == memMin { 18947 goto notFound 18948 } 18949 *(*prg.mem[int32(prg.loopPtr)+1].hh()).rh() = *(*prg.mem[p].hh()).rh() 18950 q = *(*prg.mem[p].hh()).lh() 18951 { 18952 *(*prg.mem[p].hh()).rh() = prg.avail 18953 prg.avail = p 18954 prg.dynUsed = prg.dynUsed - 1 18955 } 18956 } else { 18957 prg.beginTokenList(*(*prg.mem[prg.loopPtr].hh()).lh(), quarterword(foreverText)) 18958 goto exit 18959 } 18960 prg.beginTokenList(*(*prg.mem[prg.loopPtr].hh()).lh(), quarterword(loopText)) 18961 prg.stackArgument(q) 18962 if prg.internal[tracingCommands-1] > 0200000 { 18963 prg.beginDiagnostic() 18964 prg.printNl(strNumber( /* "[loop value=" */ 735)) 18965 // \xref[loop value=n] 18966 if int32(q) != memMin && int32(*(*prg.mem[q].hh()).rh()) == memMin+1 { 18967 prg.printExp(q, smallNumber(1)) 18968 } else { 18969 prg.showTokenList(int32(q), memMin, 50, 0) 18970 } 18971 prg.printChar(asciiCode('}')) 18972 prg.endDiagnostic(false) 18973 } 18974 18975 goto exit 18976 18977 notFound: 18978 prg.stopIteration() 18979 18980 exit: 18981 } // \2 18982 func (prg *prg) stopIteration() { 18983 var ( 18984 p, q halfword // the usual 18985 ) 18986 p = *(*prg.mem[int32(prg.loopPtr)+1].hh()).lh() 18987 if int32(p) > memMin+1 { 18988 prg.freeNode(p, halfword(progressionNodeSize)) 18989 } else if int32(p) < memMin+1 { 18990 q = *(*prg.mem[int32(prg.loopPtr)+1].hh()).rh() 18991 for int32(q) != memMin { 18992 p = *(*prg.mem[q].hh()).lh() 18993 if int32(p) != memMin { 18994 if int32(*(*prg.mem[p].hh()).rh()) == memMin+1 { 18995 prg.recycleValue(p) 18996 prg.freeNode(p, halfword(valueNodeSize)) 18997 } else { 18998 prg.flushTokenList(p) 18999 } 19000 } // it's a \&[suffix] or \&[text] parameter 19001 p = q 19002 q = *(*prg.mem[q].hh()).rh() 19003 { 19004 *(*prg.mem[p].hh()).rh() = prg.avail 19005 prg.avail = p 19006 prg.dynUsed = prg.dynUsed - 1 19007 } 19008 } 19009 } 19010 p = prg.loopPtr 19011 prg.loopPtr = *(*prg.mem[p].hh()).rh() 19012 prg.flushTokenList(*(*prg.mem[p].hh()).lh()) 19013 prg.freeNode(p, halfword(loopNodeSize)) 19014 } 19015 19016 // 766. \[38] File names 19017 19018 // tangle:pos ../../mf.web:15499:21: 19019 19020 // It's time now to fret about file names. Besides the fact that different 19021 // operating systems treat files in different ways, we must cope with the 19022 // fact that completely different naming conventions are used by different 19023 // groups of people. The following programs show what is required for one 19024 // particular operating system; similar routines for other systems are not 19025 // difficult to devise. 19026 // \xref[system dependencies] 19027 // 19028 // \MF\ assumes that a file name has three parts: the name proper; its 19029 // ``extension''; and a ``file area'' where it is found in an external file 19030 // system. The extension of an input file is assumed to be 19031 // `\.[.mf]' unless otherwise specified; it is `\.[.log]' on the 19032 // transcript file that records each run of \MF; it is `\.[.tfm]' on the font 19033 // metric files that describe characters in the fonts \MF\ creates; it is 19034 // `\.[.gf]' on the output files that specify generic font information; and it 19035 // is `\.[.base]' on the base files written by \.[INIMF] to initialize \MF. 19036 // The file area can be arbitrary on input files, but files are usually 19037 // output to the user's current area. If an input file cannot be 19038 // found on the specified area, \MF\ will look for it on a special system 19039 // area; this special area is intended for commonly used input files. 19040 // 19041 // Simple uses of \MF\ refer only to file names that have no explicit 19042 // extension or area. For example, a person usually says `\.[input] \.[cmr10]' 19043 // instead of `\.[input] \.[cmr10.new]'. Simple file 19044 // names are best, because they make the \MF\ source files portable; 19045 // whenever a file name consists entirely of letters and digits, it should be 19046 // treated in the same way by all implementations of \MF. However, users 19047 // need the ability to refer to other files in their environment, especially 19048 // when responding to error messages concerning unopenable files; therefore 19049 // we want to let them use the syntax that appears in their favorite 19050 // operating system. 19051 19052 // 769. 19053 19054 // tangle:pos ../../mf.web:15579:3: 19055 19056 // Input files that can't be found in the user's area may appear in a standard 19057 // system area called |MF_area|. 19058 // This system area name will, of course, vary from place to place. 19059 // \xref[system dependencies] 19060 19061 // 770. 19062 19063 // tangle:pos ../../mf.web:15587:3: 19064 19065 // Here now is the first of the system-dependent routines for file name scanning. 19066 // \xref[system dependencies] 19067 func (prg *prg) beginName() { 19068 prg.areaDelimiter = 0 19069 prg.extDelimiter = 0 19070 } 19071 19072 // 771. 19073 19074 // tangle:pos ../../mf.web:15594:3: 19075 19076 // And here's the second. 19077 // \xref[system dependencies] 19078 func (prg *prg) moreName(c asciiCode) (r bool) { 19079 if int32(c) == ' ' { 19080 r = false 19081 } else { 19082 if int32(c) == '>' || int32(c) == ':' { 19083 prg.areaDelimiter = prg.poolPtr 19084 prg.extDelimiter = 0 19085 } else if int32(c) == '.' && int32(prg.extDelimiter) == 0 { 19086 prg.extDelimiter = prg.poolPtr 19087 } 19088 { 19089 if int32(prg.poolPtr)+1 > int32(prg.maxPoolPtr) { 19090 if int32(prg.poolPtr)+1 > poolSize { 19091 prg.overflow(strNumber( /* "pool size" */ 257), poolSize-int32(prg.initPoolPtr)) 19092 } /* \xref[METAFONT capacity exceeded pool size][\quad pool size] */ 19093 prg.maxPoolPtr = uint16(int32(prg.poolPtr) + 1) 19094 } 19095 } 19096 { 19097 prg.strPool[prg.poolPtr] = c 19098 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 19099 } // contribute |c| to the current string 19100 r = true 19101 } 19102 return r 19103 } 19104 19105 // 772. 19106 19107 // tangle:pos ../../mf.web:15608:3: 19108 19109 // The third. 19110 // \xref[system dependencies] 19111 func (prg *prg) endName() { 19112 if int32(prg.strPtr)+3 > int32(prg.maxStrPtr) { 19113 if int32(prg.strPtr)+3 > maxStrings { 19114 prg.overflow(strNumber( /* "number of strings" */ 258), maxStrings-int32(prg.initStrPtr)) 19115 } 19116 // \xref[METAFONT capacity exceeded number of strings][\quad number of strings] 19117 prg.maxStrPtr = uint16(int32(prg.strPtr) + 3) 19118 } 19119 if int32(prg.areaDelimiter) == 0 { 19120 prg.curArea = /* "" */ 285 19121 } else { 19122 prg.curArea = prg.strPtr 19123 prg.strPtr = uint16(int32(prg.strPtr) + 1) 19124 prg.strStart[prg.strPtr] = uint16(int32(prg.areaDelimiter) + 1) 19125 } 19126 if int32(prg.extDelimiter) == 0 { 19127 prg.curExt = /* "" */ 285 19128 prg.curName = prg.makeString() 19129 } else { 19130 prg.curName = prg.strPtr 19131 prg.strPtr = uint16(int32(prg.strPtr) + 1) 19132 prg.strStart[prg.strPtr] = prg.extDelimiter 19133 prg.curExt = prg.makeString() 19134 } 19135 } 19136 19137 // 774. 19138 19139 // tangle:pos ../../mf.web:15640:3: 19140 19141 // Another system-dependent routine is needed to convert three internal 19142 // \MF\ strings 19143 // to the |name_of_file| value that is used to open files. The present code 19144 // allows both lowercase and uppercase letters in the file name. 19145 // \xref[system dependencies] 19146 func (prg *prg) packFileName(n, a, e strNumber) { 19147 var ( 19148 k int32 // number of positions filled in |name_of_file| 19149 c asciiCode // character being packed 19150 j poolPointer // index into |str_pool| 19151 ) 19152 k = 0 19153 for ii := int32(prg.strStart[a]); ii <= int32(prg.strStart[int32(a)+1])-1; ii++ { 19154 j = poolPointer(ii) 19155 _ = j 19156 c = prg.strPool[j] 19157 k = k + 1 19158 if k <= fileNameSize { 19159 prg.nameOfFile[k-1] = prg.xchr[c] 19160 } 19161 } 19162 for ii := int32(prg.strStart[n]); ii <= int32(prg.strStart[int32(n)+1])-1; ii++ { 19163 j = poolPointer(ii) 19164 _ = j 19165 c = prg.strPool[j] 19166 k = k + 1 19167 if k <= fileNameSize { 19168 prg.nameOfFile[k-1] = prg.xchr[c] 19169 } 19170 } 19171 for ii := int32(prg.strStart[e]); ii <= int32(prg.strStart[int32(e)+1])-1; ii++ { 19172 j = poolPointer(ii) 19173 _ = j 19174 c = prg.strPool[j] 19175 k = k + 1 19176 if k <= fileNameSize { 19177 prg.nameOfFile[k-1] = prg.xchr[c] 19178 } 19179 } 19180 if k <= fileNameSize { 19181 prg.nameLength = byte(k) 19182 } else { 19183 prg.nameLength = byte(fileNameSize) 19184 } 19185 for ii := int32(prg.nameLength) + 1; ii <= fileNameSize; ii++ { 19186 k = ii 19187 _ = k 19188 prg.nameOfFile[k-1] = ' ' 19189 } 19190 } 19191 19192 // 778. 19193 19194 // tangle:pos ../../mf.web:15685:3: 19195 19196 // Here is the messy routine that was just mentioned. It sets |name_of_file| 19197 // from the first |n| characters of |MF_base_default|, followed by 19198 // |buffer[a..b]|, followed by the last |base_ext_length| characters of 19199 // |MF_base_default|. 19200 // 19201 // We dare not give error messages here, since \MF\ calls this routine before 19202 // the |error| routine is ready to roll. Instead, we simply drop excess characters, 19203 // since the error will be detected in another way when a strange file name 19204 // isn't found. 19205 // \xref[system dependencies] 19206 func (prg *prg) packBufferedName(n smallNumber, a, b int32) { 19207 var ( 19208 k int32 // number of positions filled in |name_of_file| 19209 c asciiCode // character being packed 19210 j int32 // index into |buffer| or |MF_base_default| 19211 ) 19212 if int32(n)+b-a+1+baseExtLength > fileNameSize { 19213 b = a + fileNameSize - int32(n) - 1 - baseExtLength 19214 } 19215 k = 0 19216 for ii := int32(1); ii <= int32(n); ii++ { 19217 j = ii 19218 _ = j 19219 c = prg.xord[prg.mfBaseDefault[j-1]] 19220 k = k + 1 19221 if k <= fileNameSize { 19222 prg.nameOfFile[k-1] = prg.xchr[c] 19223 } 19224 } 19225 for ii := a; ii <= b; ii++ { 19226 j = ii 19227 _ = j 19228 c = prg.buffer[j] 19229 k = k + 1 19230 if k <= fileNameSize { 19231 prg.nameOfFile[k-1] = prg.xchr[c] 19232 } 19233 } 19234 for ii := int32(baseDefaultLength - baseExtLength + 1); ii <= baseDefaultLength; ii++ { 19235 j = ii 19236 _ = j 19237 c = prg.xord[prg.mfBaseDefault[j-1]] 19238 k = k + 1 19239 if k <= fileNameSize { 19240 prg.nameOfFile[k-1] = prg.xchr[c] 19241 } 19242 } 19243 if k <= fileNameSize { 19244 prg.nameLength = byte(k) 19245 } else { 19246 prg.nameLength = byte(fileNameSize) 19247 } 19248 for ii := int32(prg.nameLength) + 1; ii <= fileNameSize; ii++ { 19249 k = ii 19250 _ = k 19251 prg.nameOfFile[k-1] = ' ' 19252 } 19253 } 19254 19255 // 780. 19256 19257 // tangle:pos ../../mf.web:15748:3: 19258 19259 // Operating systems often make it possible to determine the exact name (and 19260 // possible version number) of a file that has been opened. The following routine, 19261 // which simply makes a \MF\ string from the value of |name_of_file|, should 19262 // ideally be changed to deduce the full name of file~|f|, which is the file 19263 // most recently opened, if it is possible to do this in a \PASCAL\ program. 19264 // \xref[system dependencies] 19265 // 19266 // This routine might be called after string memory has overflowed, hence 19267 // we dare not use `|str_room|'. 19268 func (prg *prg) makeNameString() (r strNumber) { 19269 var ( 19270 k /* 1..fileNameSize */ byte // index into |name_of_file| 19271 ) 19272 if int32(prg.poolPtr)+int32(prg.nameLength) > poolSize || int32(prg.strPtr) == maxStrings { 19273 r = '?' 19274 } else { 19275 for ii := int32(1); ii <= int32(prg.nameLength); ii++ { 19276 k = byte(ii) 19277 _ = k 19278 prg.strPool[prg.poolPtr] = prg.xord[prg.nameOfFile[k-1]] 19279 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 19280 } 19281 r = prg.makeString() 19282 } 19283 return r 19284 } 19285 func (prg *prg) aMakeNameString(f alphaFile) (r strNumber) { 19286 r = prg.makeNameString() 19287 return r 19288 } 19289 func (prg *prg) bMakeNameString(f byteFile) (r strNumber) { 19290 r = prg.makeNameString() 19291 return r 19292 } 19293 func (prg *prg) wMakeNameString(f wordFile) (r strNumber) { 19294 r = prg.makeNameString() 19295 return r 19296 } 19297 19298 // 781. 19299 19300 // tangle:pos ../../mf.web:15776:3: 19301 19302 // Now let's consider the ``driver'' 19303 // routines by which \MF\ deals with file names 19304 // in a system-independent manner. First comes a procedure that looks for a 19305 // file name in the input by taking the information from the input buffer. 19306 // (We can't use |get_next|, because the conversion to tokens would 19307 // destroy necessary information.) 19308 // 19309 // This procedure doesn't allow semicolons or percent signs to be part of 19310 // file names, because of other conventions of \MF. The manual doesn't 19311 // use semicolons or percents immediately after file names, but some users 19312 // no doubt will find it natural to do so; therefore system-dependent 19313 // changes to allow such characters in file names should probably 19314 // be made with reluctance, and only when an entire file name that 19315 // includes special characters is ``quoted'' somehow. 19316 // \xref[system dependencies] 19317 func (prg *prg) scanFileName() { 19318 prg.beginName() 19319 for int32(prg.buffer[prg.curInput.locField]) == ' ' { 19320 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 19321 } 19322 for true { 19323 if int32(prg.buffer[prg.curInput.locField]) == ';' || int32(prg.buffer[prg.curInput.locField]) == '%' { 19324 goto done 19325 } 19326 if !prg.moreName(prg.buffer[prg.curInput.locField]) { 19327 goto done 19328 } 19329 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 19330 } 19331 19332 done: 19333 prg.endName() 19334 } 19335 19336 // 784. 19337 19338 // tangle:pos ../../mf.web:15818:3: 19339 19340 // Here is a routine that manufactures the output file names, assuming that 19341 // |job_name<>0|. It ignores and changes the current settings of |cur_area| 19342 // and |cur_ext|. 19343 func (prg *prg) packJobName(s strNumber) { 19344 prg.curArea = /* "" */ 285 19345 prg.curExt = s 19346 prg.curName = prg.jobName 19347 prg.packFileName(prg.curName, prg.curArea, prg.curExt) 19348 } 19349 19350 // 786. 19351 19352 // tangle:pos ../../mf.web:15838:3: 19353 19354 // If some trouble arises when \MF\ tries to open a file, the following 19355 // routine calls upon the user to supply another file name. Parameter~|s| 19356 // is used in the error message to identify the type of file; parameter~|e| 19357 // is the default extension if none is given. Upon exit from the routine, 19358 // variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are 19359 // ready for another attempt at file opening. 19360 func (prg *prg) promptFileName(s, e strNumber) { 19361 var ( 19362 k /* 0..bufSize */ uint16 // index into |buffer| 19363 ) 19364 if int32(prg.interaction) == scrollMode { 19365 } 19366 if int32(s) == 743 { 19367 if int32(prg.interaction) == errorStopMode { 19368 } 19369 prg.printNl(strNumber( /* "! " */ 261)) 19370 prg.print( /* "I can't find file `" */ 744) /* \xref[!\relax] */ 19371 } else { 19372 if int32(prg.interaction) == errorStopMode { 19373 } 19374 prg.printNl(strNumber( /* "! " */ 261)) 19375 prg.print( /* "I can't write on file `" */ 745) /* \xref[!\relax] */ 19376 } 19377 // \xref[I can't write on file x] 19378 prg.printFileName(int32(prg.curName), int32(prg.curArea), int32(prg.curExt)) 19379 prg.print( /* "'." */ 746) 19380 if int32(e) == 747 { 19381 prg.showContext() 19382 } 19383 prg.printNl(strNumber( /* "Please type another " */ 748)) 19384 prg.print(int32(s)) 19385 // \xref[Please type...] 19386 if int32(prg.interaction) < scrollMode { 19387 prg.fatalError(strNumber( /* "*** (job aborted, file error in nonstop mode)" */ 749)) 19388 } 19389 // \xref[job aborted, file error...] 19390 { 19391 prg.print( /* ": " */ 750) 19392 prg.termInput() 19393 } 19394 // Scan file name in the buffer 19395 { 19396 prg.beginName() 19397 k = prg.first 19398 for int32(prg.buffer[k]) == ' ' && int32(k) < int32(prg.last) { 19399 k = uint16(int32(k) + 1) 19400 } 19401 for true { 19402 if int32(k) == int32(prg.last) { 19403 goto done 19404 } 19405 if !prg.moreName(prg.buffer[k]) { 19406 goto done 19407 } 19408 k = uint16(int32(k) + 1) 19409 } 19410 19411 done: 19412 prg.endName() 19413 } 19414 if int32(prg.curExt) == 285 { 19415 prg.curExt = e 19416 } 19417 prg.packFileName(prg.curName, prg.curArea, prg.curExt) 19418 } // \2 19419 19420 func (prg *prg) openLogFile() { 19421 var ( 19422 oldSetting/* 0..maxSelector */ byte // previous |selector| setting 19423 k/* 0..bufSize */ uint16 // index into |months| and |buffer| 19424 l/* 0..bufSize */ uint16 // end of first input line 19425 months [36]char // abbreviations of month names 19426 ) 19427 oldSetting = prg.selector 19428 if int32(prg.jobName) == 0 { 19429 prg.jobName = /* "mfput" */ 751 19430 } 19431 // \xref[mfput] 19432 prg.packJobName(strNumber( /* ".log" */ 752)) 19433 for !prg.aOpenOut(prg.logFile) { 19434 // Try to get a different log file name 19435 prg.selector = byte(termOnly) 19436 prg.promptFileName(strNumber( /* "transcript file name" */ 754), strNumber( /* ".log" */ 752)) 19437 } 19438 prg.logName = prg.aMakeNameString(prg.logFile) 19439 prg.selector = byte(logOnly) 19440 prg.logOpened = true 19441 19442 // Print the banner line, including the date and time 19443 { 19444 prg.logFile.Write("This is METAFONT, Version 2.71828182 (TRAP)") 19445 prg.slowPrint(int32(prg.baseIdent)) 19446 prg.print( /* " " */ 755) 19447 prg.printInt(prg.sysDay) 19448 prg.printChar(asciiCode(' ')) 19449 strcopy(months[:], "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC") 19450 for ii := 3*prg.sysMonth - 2; ii <= 3*prg.sysMonth; ii++ { 19451 k = uint16(ii) 19452 _ = k 19453 prg.logFile.Write(string(rune(months[k-1]))) 19454 } 19455 prg.printChar(asciiCode(' ')) 19456 prg.printInt(prg.sysYear) 19457 prg.printChar(asciiCode(' ')) 19458 prg.printDd(prg.sysTime / 60) 19459 prg.printChar(asciiCode(':')) 19460 prg.printDd(prg.sysTime % 60) 19461 } 19462 prg.inputStack[prg.inputPtr] = prg.curInput // make sure bottom level is in memory 19463 prg.printNl(strNumber( /* "**" */ 753)) 19464 // \xref[**] 19465 l = uint16(int32(prg.inputStack[0].limitField) - 1) // last position of first line 19466 for ii := int32(1); ii <= int32(l); ii++ { 19467 k = uint16(ii) 19468 _ = k 19469 prg.print(int32(prg.buffer[k])) 19470 } 19471 prg.printLn() // now the transcript file contains the first line of input 19472 prg.selector = byte(int32(oldSetting) + 2) // |log_only| or |term_and_log| 19473 } // \2 19474 func (prg *prg) startInput() { 19475 for int32(prg.curInput.indexField) > maxInOpen && int32(prg.curInput.locField) == memMin { 19476 prg.endTokenList() 19477 } 19478 if int32(prg.curInput.indexField) > maxInOpen { 19479 { 19480 if int32(prg.interaction) == errorStopMode { 19481 } 19482 prg.printNl(strNumber( /* "! " */ 261)) 19483 prg.print( /* "File names can't appear within macros" */ 757) /* \xref[!\relax] */ 19484 } 19485 // \xref[File names can't...] 19486 { 19487 prg.helpPtr = 3 19488 prg.helpLine[2] = /* "Sorry...I've converted what follows to tokens," */ 758 19489 prg.helpLine[1] = /* "possibly garbaging the name you gave." */ 759 19490 prg.helpLine[0] = /* "Please delete the tokens and insert the name again." */ 760 19491 } 19492 19493 prg.error1() 19494 } 19495 if int32(prg.curInput.indexField) <= maxInOpen { 19496 prg.scanFileName() 19497 } else { 19498 prg.curName = /* "" */ 285 19499 prg.curExt = /* "" */ 285 19500 prg.curArea = /* "" */ 285 19501 } 19502 if int32(prg.curExt) == 285 { 19503 prg.curExt = /* ".mf" */ 747 19504 } 19505 prg.packFileName(prg.curName, prg.curArea, prg.curExt) 19506 for true { 19507 prg.beginFileReading() // set up |cur_file| and new level of input 19508 if prg.aOpenIn(prg.inputFile[prg.curInput.indexField-1]) { 19509 goto done 19510 } 19511 if int32(prg.curArea) == 285 { 19512 prg.packFileName(prg.curName, strNumber( /* "MFinputs:" */ 741), prg.curExt) 19513 if prg.aOpenIn(prg.inputFile[prg.curInput.indexField-1]) { 19514 goto done 19515 } 19516 } 19517 prg.endFileReading() // remove the level that didn't work 19518 prg.promptFileName(strNumber( /* "input file name" */ 743), strNumber( /* ".mf" */ 747)) 19519 } 19520 19521 done: 19522 prg.curInput.nameField = prg.aMakeNameString(prg.inputFile[prg.curInput.indexField-1]) 19523 prg.strRef[prg.curName] = byte(maxStrRef) 19524 if int32(prg.jobName) == 0 { 19525 prg.jobName = prg.curName 19526 prg.openLogFile() 19527 } // |open_log_file| doesn't |show_context|, so |limit| 19528 // and |loc| needn't be set to meaningful values yet 19529 19530 if int32(prg.termOffset)+(int32(prg.strStart[int32(prg.curInput.nameField)+1])-int32(prg.strStart[prg.curInput.nameField])) > maxPrintLine-2 { 19531 prg.printLn() 19532 } else if int32(prg.termOffset) > 0 || int32(prg.fileOffset) > 0 { 19533 prg.printChar(asciiCode(' ')) 19534 } 19535 prg.printChar(asciiCode('(')) 19536 prg.openParens = byte(int32(prg.openParens) + 1) 19537 prg.slowPrint(int32(prg.curInput.nameField)) 19538 if int32(prg.curInput.nameField) == int32(prg.strPtr)-1 { 19539 prg.flushString(prg.curInput.nameField) 19540 prg.curInput.nameField = prg.curName 19541 } 19542 19543 // Read the first line of the new file 19544 { 19545 prg.line = 1 19546 if prg.inputLn(prg.inputFile[prg.curInput.indexField-1], false) { 19547 } 19548 prg.firmUpTheLine() 19549 prg.buffer[prg.curInput.limitField] = '%' 19550 prg.first = uint16(int32(prg.curInput.limitField) + 1) 19551 prg.curInput.locField = prg.curInput.startField 19552 } 19553 } 19554 19555 // 798. 19556 19557 // tangle:pos ../../mf.web:16035:3: 19558 19559 // Many different kinds of expressions are possible, so it is wise to have 19560 // precise descriptions of what |cur_type| and |cur_exp| mean in all cases: 19561 // 19562 // \smallskip\hang 19563 // |cur_type=vacuous| means that this expression didn't turn out to have a 19564 // value at all, because it arose from a \&[begingroup]$\,\ldots\,$\&[endgroup] 19565 // construction in which there was no expression before the \&[endgroup]. 19566 // In this case |cur_exp| has some irrelevant value. 19567 // 19568 // \smallskip\hang 19569 // |cur_type=boolean_type| means that |cur_exp| is either |true_code| 19570 // or |false_code|. 19571 // 19572 // \smallskip\hang 19573 // |cur_type=unknown_boolean| means that |cur_exp| points to a capsule 19574 // node that is in 19575 // a ring of equivalent booleans whose value has not yet been defined. 19576 // 19577 // \smallskip\hang 19578 // |cur_type=string_type| means that |cur_exp| is a string number (i.e., an 19579 // integer in the range |0<=cur_exp<str_ptr|). That string's reference count 19580 // includes this particular reference. 19581 // 19582 // \smallskip\hang 19583 // |cur_type=unknown_string| means that |cur_exp| points to a capsule 19584 // node that is in 19585 // a ring of equivalent strings whose value has not yet been defined. 19586 // 19587 // \smallskip\hang 19588 // |cur_type=pen_type| means that |cur_exp| points to a pen header node. This 19589 // node contains a reference count, which takes account of this particular 19590 // reference. 19591 // 19592 // \smallskip\hang 19593 // |cur_type=unknown_pen| means that |cur_exp| points to a capsule 19594 // node that is in 19595 // a ring of equivalent pens whose value has not yet been defined. 19596 // 19597 // \smallskip\hang 19598 // |cur_type=future_pen| means that |cur_exp| points to a knot list that 19599 // should eventually be made into a pen. Nobody else points to this particular 19600 // knot list. The |future_pen| option occurs only as an output of |scan_primary| 19601 // and |scan_secondary|, not as an output of |scan_tertiary| or |scan_expression|. 19602 // 19603 // \smallskip\hang 19604 // |cur_type=path_type| means that |cur_exp| points to the first node of 19605 // a path; nobody else points to this particular path. The control points of 19606 // the path will have been chosen. 19607 // 19608 // \smallskip\hang 19609 // |cur_type=unknown_path| means that |cur_exp| points to a capsule 19610 // node that is in 19611 // a ring of equivalent paths whose value has not yet been defined. 19612 // 19613 // \smallskip\hang 19614 // |cur_type=picture_type| means that |cur_exp| points to an edges header node. 19615 // Nobody else points to this particular set of edges. 19616 // 19617 // \smallskip\hang 19618 // |cur_type=unknown_picture| means that |cur_exp| points to a capsule 19619 // node that is in 19620 // a ring of equivalent pictures whose value has not yet been defined. 19621 // 19622 // \smallskip\hang 19623 // |cur_type=transform_type| means that |cur_exp| points to a |transform_type| 19624 // capsule node. The |value| part of this capsule 19625 // points to a transform node that contains six numeric values, 19626 // each of which is |independent|, |dependent|, |proto_dependent|, or |known|. 19627 // 19628 // \smallskip\hang 19629 // |cur_type=pair_type| means that |cur_exp| points to a capsule 19630 // node whose type is |pair_type|. The |value| part of this capsule 19631 // points to a pair node that contains two numeric values, 19632 // each of which is |independent|, |dependent|, |proto_dependent|, or |known|. 19633 // 19634 // \smallskip\hang 19635 // |cur_type=known| means that |cur_exp| is a |scaled| value. 19636 // 19637 // \smallskip\hang 19638 // |cur_type=dependent| means that |cur_exp| points to a capsule node whose type 19639 // is |dependent|. The |dep_list| field in this capsule points to the associated 19640 // dependency list. 19641 // 19642 // \smallskip\hang 19643 // |cur_type=proto_dependent| means that |cur_exp| points to a |proto_dependent| 19644 // capsule node. The |dep_list| field in this capsule 19645 // points to the associated dependency list. 19646 // 19647 // \smallskip\hang 19648 // |cur_type=independent| means that |cur_exp| points to a capsule node 19649 // whose type is |independent|. This somewhat unusual case can arise, for 19650 // example, in the expression 19651 // `$x+\&[begingroup]\penalty0\,\&[string]\,x; 0\,\&[endgroup]$'. 19652 // 19653 // \smallskip\hang 19654 // |cur_type=token_list| means that |cur_exp| points to a linked list of 19655 // tokens. 19656 // 19657 // \smallskip\noindent 19658 // The possible settings of |cur_type| have been listed here in increasing 19659 // numerical order. Notice that |cur_type| will never be |numeric_type| or 19660 // |suffixed_macro| or |unsuffixed_macro|, although variables of those types 19661 // are allowed. Conversely, \MF\ has no variables of type |vacuous| or 19662 // |token_list|. 19663 19664 // 824. 19665 19666 // tangle:pos ../../mf.web:16652:3: 19667 19668 // Errors at the beginning of expressions are flagged by |bad_exp|. 19669 func (prg *prg) badExp(s strNumber) { 19670 var ( 19671 saveFlag /* 0..maxCommandCode */ byte 19672 ) 19673 { 19674 if int32(prg.interaction) == errorStopMode { 19675 } 19676 prg.printNl(strNumber( /* "! " */ 261)) 19677 prg.print(int32(s)) /* \xref[!\relax] */ 19678 } 19679 prg.print( /* " expression can't begin with `" */ 770) 19680 prg.printCmdMod(int32(prg.curCmd), prg.curMod) 19681 prg.printChar(asciiCode('\'')) 19682 { 19683 prg.helpPtr = 4 19684 prg.helpLine[3] = /* "I'm afraid I need some sort of value in order to continue," */ 771 19685 prg.helpLine[2] = /* "so I've tentatively inserted `0'. You may want to" */ 772 19686 prg.helpLine[1] = /* "delete this zero and insert something else;" */ 773 19687 prg.helpLine[0] = /* "see Chapter 27 of The METAFONTbook for an example." */ 774 19688 } 19689 // \xref[METAFONTbook][\sl The [\logos METAFONT\/]book] 19690 prg.backInput() 19691 prg.curSym = 0 19692 prg.curCmd = byte(numericToken) 19693 prg.curMod = 0 19694 prg.insError() 19695 19696 saveFlag = prg.varFlag 19697 prg.varFlag = 0 19698 prg.getXNext() 19699 prg.varFlag = saveFlag 19700 } 19701 19702 // 827. 19703 19704 // tangle:pos ../../mf.web:16681:3: 19705 19706 // The |stash_in| subroutine puts the current (numeric) expression into a field 19707 // within a ``big node.'' 19708 func (prg *prg) stashIn(p halfword) { 19709 var ( 19710 q halfword // temporary register 19711 ) 19712 *(*prg.mem[p].hh()).b0() = prg.curType 19713 if int32(prg.curType) == known { 19714 *prg.mem[int32(p)+1].int() = prg.curExp 19715 } else { 19716 if int32(prg.curType) == independent { 19717 q = prg.singleDependency(halfword(prg.curExp)) 19718 if int32(q) == int32(prg.depFinal) { 19719 *(*prg.mem[p].hh()).b0() = byte(known) 19720 *prg.mem[int32(p)+1].int() = 0 19721 prg.freeNode(q, halfword(depNodeSize)) 19722 } else { 19723 *(*prg.mem[p].hh()).b0() = byte(dependent) 19724 prg.newDep(p, q) 19725 } 19726 prg.recycleValue(halfword(prg.curExp)) 19727 } else { 19728 prg.mem[int32(p)+1] = prg.mem[prg.curExp+1] 19729 // |dep_list(p):=dep_list(cur_exp)| and |prev_dep(p):=prev_dep(cur_exp)| 19730 *(*prg.mem[*(*prg.mem[int32(p)+1].hh()).lh()].hh()).rh() = p 19731 } 19732 prg.freeNode(halfword(prg.curExp), halfword(valueNodeSize)) 19733 } 19734 prg.curType = byte(vacuous) 19735 } 19736 19737 // 828. 19738 19739 // tangle:pos ../../mf.web:16699:3: 19740 19741 // In rare cases the current expression can become |independent|. There 19742 // may be many dependency lists pointing to such an independent capsule, 19743 // so we can't simply move it into place within a big node. Instead, 19744 // we copy it, then recycle it. 19745 19746 // 842. 19747 19748 // tangle:pos ../../mf.web:16865:3: 19749 19750 // The most difficult part of |scan_primary| has been saved for last, since 19751 // it was necessary to build up some confidence first. We can now face the task 19752 // of scanning a variable. 19753 // 19754 // As we scan a variable, we build a token list containing the relevant 19755 // names and subscript values, simultaneously following along in the 19756 // ``collective'' structure to see if we are actually dealing with a macro 19757 // instead of a value. 19758 // 19759 // The local variables |pre_head| and |post_head| will point to the beginning 19760 // of the prefix and suffix lists; |tail| will point to the end of the list 19761 // that is currently growing. 19762 // 19763 // Another local variable, |tt|, contains partial information about the 19764 // declared type of the variable-so-far. If |tt>=unsuffixed_macro|, the 19765 // relation |tt=type(q)| will always hold. If |tt=undefined|, the routine 19766 // doesn't bother to update its information about type. And if 19767 // |undefined<tt<unsuffixed_macro|, the precise value of |tt| isn't critical. 19768 19769 // 848. 19770 19771 // tangle:pos ../../mf.web:16939:3: 19772 19773 // Here's a routine that puts the current expression back to be read again. 19774 func (prg *prg) backExpr() { 19775 var ( 19776 p halfword // capsule token 19777 ) 19778 p = prg.stashCurExp() 19779 *(*prg.mem[p].hh()).rh() = uint16(memMin) 19780 prg.beginTokenList(p, quarterword(backedUp)) 19781 } 19782 19783 // 849. 19784 19785 // tangle:pos ../../mf.web:16946:3: 19786 19787 // Unknown subscripts lead to the following error message. 19788 func (prg *prg) badSubscript() { 19789 prg.dispErr(halfword(memMin), strNumber( /* "Improper subscript has been replaced by zero" */ 786)) 19790 // \xref[Improper subscript...] 19791 { 19792 prg.helpPtr = 3 19793 prg.helpLine[2] = /* "A bracketed subscript must have a known numeric value;" */ 787 19794 prg.helpLine[1] = /* "unfortunately, what I found was the value that appears just" */ 788 19795 prg.helpLine[0] = /* "above this error message. So I'll try a zero subscript." */ 789 19796 } 19797 prg.flushError(scaled(0)) 19798 } 19799 19800 // 851. 19801 19802 // tangle:pos ../../mf.web:16982:3: 19803 19804 // How do things stand now? Well, we have scanned an entire variable name, 19805 // including possible subscripts and/or attributes; |cur_cmd|, |cur_mod|, and 19806 // |cur_sym| represent the token that follows. If |post_head=null|, a 19807 // token list for this variable name starts at |link(pre_head)|, with all 19808 // subscripts evaluated. But if |post_head<>null|, the variable turned out 19809 // to be a suffixed macro; |pre_head| is the head of the prefix list, while 19810 // |post_head| is the head of a token list containing both `\.[\AT!]' and 19811 // the suffix. 19812 // 19813 // Our immediate problem is to see if this variable still exists. (Variable 19814 // structures can change drastically whenever we call |get_x_next|; users 19815 // aren't supposed to do this, but the fact that it is possible means that 19816 // we must be cautious.) 19817 // 19818 // The following procedure prints an error message when a variable 19819 // unexpectedly disappears. Its help message isn't quite right for 19820 // our present purposes, but we'll be able to fix that up. 19821 func (prg *prg) obliterated(q halfword) { 19822 { 19823 if int32(prg.interaction) == errorStopMode { 19824 } 19825 prg.printNl(strNumber( /* "! " */ 261)) 19826 prg.print( /* "Variable " */ 790) /* \xref[!\relax] */ 19827 } 19828 prg.showTokenList(int32(q), memMin, 1000, 0) 19829 prg.print( /* " has been obliterated" */ 791) 19830 // \xref[Variable...obliterated] 19831 { 19832 prg.helpPtr = 5 19833 prg.helpLine[4] = /* "It seems you did a nasty thing---probably by accident," */ 792 19834 prg.helpLine[3] = /* "but nevertheless you nearly hornswoggled me..." */ 793 19835 prg.helpLine[2] = /* "While I was evaluating the right-hand side of this" */ 794 19836 prg.helpLine[1] = /* "command, something happened, and the left-hand side" */ 795 19837 prg.helpLine[0] = /* "is no longer a variable! So I won't change anything." */ 796 19838 } 19839 } 19840 19841 // 863. 19842 19843 // tangle:pos ../../mf.web:17227:3: 19844 19845 // The following procedure calls a macro that has two parameters, 19846 // |p| and |cur_exp|. 19847 func (prg *prg) binaryMac(p, c, n halfword) { 19848 var ( 19849 q, r1 halfword // nodes in the parameter list 19850 ) 19851 q = prg.getAvail() 19852 r1 = prg.getAvail() 19853 *(*prg.mem[q].hh()).rh() = r1 19854 19855 *(*prg.mem[q].hh()).lh() = p 19856 *(*prg.mem[r1].hh()).lh() = prg.stashCurExp() 19857 19858 prg.macroCall(c, q, n) 19859 } 19860 19861 // 865. 19862 19863 // tangle:pos ../../mf.web:17266:3: 19864 19865 // A |future_pen| becomes a full-fledged pen here. 19866 func (prg *prg) materializePen() { 19867 var ( 19868 aMinusB, aPlusB, majorAxis, minorAxis scaled // ellipse variables 19869 theta angle // amount by which the ellipse has been rotated 19870 p halfword // path traverser 19871 q halfword // the knot list to be made into a pen 19872 ) 19873 q = uint16(prg.curExp) 19874 if int32(*(*prg.mem[q].hh()).b0()) == endpoint { 19875 { 19876 if int32(prg.interaction) == errorStopMode { 19877 } 19878 prg.printNl(strNumber( /* "! " */ 261)) 19879 prg.print( /* "Pen path must be a cycle" */ 806) /* \xref[!\relax] */ 19880 } 19881 // \xref[Pen path must be a cycle] 19882 { 19883 prg.helpPtr = 2 19884 prg.helpLine[1] = /* "I can't make a pen from the given path." */ 807 19885 prg.helpLine[0] = /* "So I've replaced it by the trivial path `(0,0)..cycle'." */ 575 19886 } 19887 prg.putGetError() 19888 prg.curExp = memMin + 3 19889 goto commonEnding 19890 } else if int32(*(*prg.mem[q].hh()).b0()) == open { 19891 prg.tx = *prg.mem[int32(q)+1].int() 19892 prg.ty = *prg.mem[int32(q)+2].int() 19893 prg.txx = *prg.mem[int32(q)+3].int() - prg.tx 19894 prg.tyx = *prg.mem[int32(q)+4].int() - prg.ty 19895 prg.txy = *prg.mem[int32(q)+5].int() - prg.tx 19896 prg.tyy = *prg.mem[int32(q)+6].int() - prg.ty 19897 aMinusB = prg.pythAdd(prg.txx-prg.tyy, prg.tyx+prg.txy) 19898 aPlusB = prg.pythAdd(prg.txx+prg.tyy, prg.tyx-prg.txy) 19899 majorAxis = (aMinusB + aPlusB) / 2 19900 minorAxis = abs(aPlusB-aMinusB) / 2 19901 if majorAxis == minorAxis { 19902 theta = 0 19903 } else { 19904 theta = (prg.nArg(prg.txx-prg.tyy, prg.tyx+prg.txy) + prg.nArg(prg.txx+prg.tyy, prg.tyx-prg.txy)) / 2 19905 } 19906 prg.freeNode(q, halfword(knotNodeSize)) 19907 q = prg.makeEllipse(majorAxis, minorAxis, theta) 19908 if prg.tx != 0 || prg.ty != 0 { 19909 p = q 19910 for { 19911 *prg.mem[int32(p)+1].int() = *prg.mem[int32(p)+1].int() + prg.tx 19912 *prg.mem[int32(p)+2].int() = *prg.mem[int32(p)+2].int() + prg.ty 19913 p = *(*prg.mem[p].hh()).rh() 19914 if int32(p) == int32(q) { 19915 break 19916 } 19917 } 19918 } 19919 } 19920 prg.curExp = int32(prg.makePen(q)) 19921 19922 commonEnding: 19923 prg.tossKnotList(q) 19924 prg.curType = byte(penType) 19925 } 19926 19927 // 871. 19928 19929 // tangle:pos ../../mf.web:17413:3: 19930 19931 // A pair of numeric values is changed into a knot node for a one-point path 19932 // when \MF\ discovers that the pair is part of a path. 19933 // \4 19934 // Declare the procedure called |known_pair| 19935 func (prg *prg) knownPair() { 19936 var ( 19937 p halfword // the pair node 19938 ) 19939 if int32(prg.curType) != pairType { 19940 prg.dispErr(halfword(memMin), strNumber( /* "Undefined coordinates have been replaced by (0,0)" */ 809)) 19941 // \xref[Undefined coordinates...] 19942 { 19943 prg.helpPtr = 5 19944 prg.helpLine[4] = /* "I need x and y numbers for this part of the path." */ 810 19945 prg.helpLine[3] = /* "The value I found (see above) was no good;" */ 811 19946 prg.helpLine[2] = /* "so I'll try to keep going by using zero instead." */ 812 19947 prg.helpLine[1] = /* "(Chapter 27 of The METAFONTbook explains that" */ 813 19948 prg.helpLine[0] = /* "you might want to type `I ???' now.)" */ 814 19949 } 19950 prg.putGetFlushError(scaled(0)) 19951 prg.curX = 0 19952 prg.curY = 0 19953 } else { 19954 p = uint16(*prg.mem[prg.curExp+1].int()) 19955 19956 // Make sure that both |x| and |y| parts of |p| are known; copy them into |cur_x| and |cur_y| 19957 if int32(*(*prg.mem[p].hh()).b0()) == known { 19958 prg.curX = *prg.mem[int32(p)+1].int() 19959 } else { 19960 prg.dispErr(p, strNumber( 19961 /* "Undefined x coordinate has been replaced by 0" */ 815)) 19962 // \xref[Undefined coordinates...] 19963 { 19964 prg.helpPtr = 5 19965 prg.helpLine[4] = /* "I need a `known' x value for this part of the path." */ 816 19966 prg.helpLine[3] = /* "The value I found (see above) was no good;" */ 811 19967 prg.helpLine[2] = /* "so I'll try to keep going by using zero instead." */ 812 19968 prg.helpLine[1] = /* "(Chapter 27 of The METAFONTbook explains that" */ 813 19969 prg.helpLine[0] = /* "you might want to type `I ???' now.)" */ 814 19970 } 19971 prg.putGetError() 19972 prg.recycleValue(p) 19973 prg.curX = 0 19974 } 19975 if int32(*(*prg.mem[int32(p)+2].hh()).b0()) == known { 19976 prg.curY = *prg.mem[int32(p)+2+1].int() 19977 } else { 19978 prg.dispErr(halfword(int32(p)+2), strNumber( 19979 /* "Undefined y coordinate has been replaced by 0" */ 817)) 19980 { 19981 prg.helpPtr = 5 19982 prg.helpLine[4] = /* "I need a `known' y value for this part of the path." */ 818 19983 prg.helpLine[3] = /* "The value I found (see above) was no good;" */ 811 19984 prg.helpLine[2] = /* "so I'll try to keep going by using zero instead." */ 812 19985 prg.helpLine[1] = /* "(Chapter 27 of The METAFONTbook explains that" */ 813 19986 prg.helpLine[0] = /* "you might want to type `I ???' now.)" */ 814 19987 } 19988 prg.putGetError() 19989 prg.recycleValue(halfword(int32(p) + 2)) 19990 prg.curY = 0 19991 } 19992 prg.flushCurExp(scaled(0)) 19993 } 19994 } 19995 19996 func (prg *prg) newKnot() (r halfword) { // convert a pair to a knot with two endpoints 19997 var ( 19998 q halfword // the new node 19999 ) 20000 q = prg.getNode(knotNodeSize) 20001 *(*prg.mem[q].hh()).b0() = byte(endpoint) 20002 *(*prg.mem[q].hh()).b1() = byte(endpoint) 20003 *(*prg.mem[q].hh()).rh() = q 20004 20005 prg.knownPair() 20006 *prg.mem[int32(q)+1].int() = prg.curX 20007 *prg.mem[int32(q)+2].int() = prg.curY 20008 r = q 20009 return r 20010 } 20011 20012 // 875. 20013 20014 // tangle:pos ../../mf.web:17490:3: 20015 20016 // The |scan_direction| subroutine looks at the directional information 20017 // that is enclosed in braces, and also scans ahead to the following character. 20018 // A type code is returned, either |open| (if the direction was $(0,0)$), 20019 // or |curl| (if the direction was a curl of known value |cur_exp|), or 20020 // |given| (if the direction is given by the |angle| value that now 20021 // appears in |cur_exp|). 20022 // 20023 // There's nothing difficult about this subroutine, but the program is rather 20024 // lengthy because a variety of potential errors need to be nipped in the bud. 20025 func (prg *prg) scanDirection() (r smallNumber) { 20026 var ( 20027 t/* given..open */ byte // the type of information found 20028 x scaled // an |x| coordinate 20029 ) 20030 prg.getXNext() 20031 if int32(prg.curCmd) == curlCommand { 20032 prg.getXNext() 20033 prg.scanExpression() 20034 if int32(prg.curType) != known || prg.curExp < 0 { 20035 prg.dispErr(halfword(memMin), strNumber( /* "Improper curl has been replaced by 1" */ 821)) 20036 // \xref[Improper curl] 20037 { 20038 prg.helpPtr = 1 20039 prg.helpLine[0] = /* "A curl must be a known, nonnegative number." */ 822 20040 } 20041 prg.putGetFlushError(scaled(0200000)) 20042 } 20043 t = byte(curl) 20044 } else { 20045 // Scan a given direction 20046 prg.scanExpression() 20047 if int32(prg.curType) > pairType { 20048 if int32(prg.curType) != known { 20049 prg.dispErr(halfword(memMin), strNumber( /* "Undefined x coordinate has been replaced by 0" */ 815)) 20050 // \xref[Undefined coordinates...] 20051 { 20052 prg.helpPtr = 5 20053 prg.helpLine[4] = /* "I need a `known' x value for this part of the path." */ 816 20054 prg.helpLine[3] = /* "The value I found (see above) was no good;" */ 811 20055 prg.helpLine[2] = /* "so I'll try to keep going by using zero instead." */ 812 20056 prg.helpLine[1] = /* "(Chapter 27 of The METAFONTbook explains that" */ 813 20057 prg.helpLine[0] = /* "you might want to type `I ???' now.)" */ 814 20058 } 20059 prg.putGetFlushError(scaled(0)) 20060 } 20061 x = prg.curExp 20062 if int32(prg.curCmd) != comma { 20063 prg.missingErr(strNumber(',')) 20064 20065 // \xref[Missing `,'] 20066 { 20067 prg.helpPtr = 2 20068 prg.helpLine[1] = /* "I've got the x coordinate of a path direction;" */ 823 20069 prg.helpLine[0] = /* "will look for the y coordinate next." */ 824 20070 } 20071 prg.backError() 20072 } 20073 prg.getXNext() 20074 prg.scanExpression() 20075 if int32(prg.curType) != known { 20076 prg.dispErr(halfword(memMin), strNumber( /* "Undefined y coordinate has been replaced by 0" */ 817)) 20077 { 20078 prg.helpPtr = 5 20079 prg.helpLine[4] = /* "I need a `known' y value for this part of the path." */ 818 20080 prg.helpLine[3] = /* "The value I found (see above) was no good;" */ 811 20081 prg.helpLine[2] = /* "so I'll try to keep going by using zero instead." */ 812 20082 prg.helpLine[1] = /* "(Chapter 27 of The METAFONTbook explains that" */ 813 20083 prg.helpLine[0] = /* "you might want to type `I ???' now.)" */ 814 20084 } 20085 prg.putGetFlushError(scaled(0)) 20086 } 20087 prg.curY = prg.curExp 20088 prg.curX = x 20089 } else { 20090 prg.knownPair() 20091 } 20092 if prg.curX == 0 && prg.curY == 0 { 20093 t = byte(open) 20094 } else { 20095 t = byte(given) 20096 prg.curExp = prg.nArg(prg.curX, prg.curY) 20097 } 20098 } 20099 if int32(prg.curCmd) != rightBrace { 20100 prg.missingErr(strNumber('}')) 20101 20102 // \xref[Missing `\char`\]'] 20103 { 20104 prg.helpPtr = 3 20105 prg.helpLine[2] = /* "I've scanned a direction spec for part of a path," */ 819 20106 prg.helpLine[1] = /* "so a right brace should have come next." */ 820 20107 prg.helpLine[0] = /* "I shall pretend that one was there." */ 697 20108 } 20109 20110 prg.backError() 20111 } 20112 prg.getXNext() 20113 r = t 20114 return r 20115 } 20116 20117 // 895. 20118 20119 // tangle:pos ../../mf.web:17914:3: 20120 20121 // OK, let's look at the simplest \\[do] procedure first. 20122 func (prg *prg) doNullary(c quarterword) { 20123 var ( 20124 k int32 // all-purpose loop index 20125 ) 20126 { 20127 if prg.arithError { 20128 prg.clearArith() 20129 } 20130 } 20131 if prg.internal[tracingCommands-1] > 0400000 { 20132 prg.showCmdMod(nullary, int32(c)) 20133 } 20134 switch c { 20135 case trueCode, falseCode: 20136 prg.curType = byte(booleanType) 20137 prg.curExp = int32(c) 20138 20139 case nullPictureCode: 20140 prg.curType = byte(pictureType) 20141 prg.curExp = int32(prg.getNode(edgeHeaderSize)) 20142 prg.initEdges(halfword(prg.curExp)) 20143 20144 case nullPenCode: 20145 prg.curType = byte(penType) 20146 prg.curExp = memMin + 3 20147 20148 case normalDeviate: 20149 prg.curType = byte(known) 20150 prg.curExp = prg.normRand() 20151 20152 case penCircle: 20153 // Make a special knot node for \&[pencircle] 20154 prg.curType = byte(futurePen) 20155 prg.curExp = int32(prg.getNode(knotNodeSize)) 20156 *(*prg.mem[prg.curExp].hh()).b0() = byte(open) 20157 *(*prg.mem[prg.curExp].hh()).b1() = byte(open) 20158 *(*prg.mem[prg.curExp].hh()).rh() = uint16(prg.curExp) 20159 20160 *prg.mem[prg.curExp+1].int() = 0 20161 *prg.mem[prg.curExp+2].int() = 0 20162 20163 *prg.mem[prg.curExp+3].int() = 0200000 20164 *prg.mem[prg.curExp+4].int() = 0 20165 20166 *prg.mem[prg.curExp+5].int() = 0 20167 *prg.mem[prg.curExp+6].int() = 0200000 20168 20169 case jobNameOp: 20170 if int32(prg.jobName) == 0 { 20171 prg.openLogFile() 20172 } 20173 prg.curType = byte(stringType) 20174 prg.curExp = int32(prg.jobName) 20175 20176 case readStringOp: 20177 // Read a string from the terminal 20178 if int32(prg.interaction) <= nonstopMode { 20179 prg.fatalError(strNumber( /* "*** (cannot readstring in nonstop modes)" */ 835)) 20180 } 20181 prg.beginFileReading() 20182 prg.curInput.nameField = 1 20183 { 20184 prg.print( /* "" */ 285) 20185 prg.termInput() 20186 } 20187 { 20188 if int32(prg.poolPtr)+int32(prg.last)-int32(prg.curInput.startField) > int32(prg.maxPoolPtr) { 20189 if int32(prg.poolPtr)+int32(prg.last)-int32(prg.curInput.startField) > poolSize { 20190 prg.overflow(strNumber( /* "pool size" */ 257), poolSize-int32(prg.initPoolPtr)) 20191 } /* \xref[METAFONT capacity exceeded pool size][\quad pool size] */ 20192 prg.maxPoolPtr = uint16(int32(prg.poolPtr) + int32(prg.last) - int32(prg.curInput.startField)) 20193 } 20194 } 20195 for ii := int32(prg.curInput.startField); ii <= int32(prg.last)-1; ii++ { 20196 k = ii 20197 _ = k 20198 prg.strPool[prg.poolPtr] = prg.buffer[k] 20199 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 20200 } 20201 prg.endFileReading() 20202 prg.curType = byte(stringType) 20203 prg.curExp = int32(prg.makeString()) 20204 20205 } // there are no other cases 20206 { 20207 if prg.arithError { 20208 prg.clearArith() 20209 } 20210 } 20211 } 20212 20213 // 898. 20214 20215 // tangle:pos ../../mf.web:17958:3: 20216 20217 // Things get a bit more interesting when there's an operand. The 20218 // operand to |do_unary| appears in |cur_type| and |cur_exp|. 20219 // \4 20220 // Declare unary action procedures 20221 func (prg *prg) nicePair(p int32, t quarterword) (r bool) { 20222 if int32(t) == pairType { 20223 p = *prg.mem[p+1].int() 20224 if int32(*(*prg.mem[p].hh()).b0()) == known { 20225 if int32(*(*prg.mem[p+2].hh()).b0()) == known { 20226 r = true 20227 goto exit 20228 } 20229 } 20230 } 20231 r = false 20232 20233 exit: 20234 ; 20235 return r 20236 } 20237 20238 func (prg *prg) printKnownOrUnknownType(t smallNumber, v int32) { 20239 prg.printChar(asciiCode('(')) 20240 if int32(t) < dependent { 20241 if int32(t) != pairType { 20242 prg.printType(t) 20243 } else if prg.nicePair(v, quarterword(pairType)) { 20244 prg.print( /* "pair" */ 337) 20245 } else { 20246 prg.print( /* "unknown pair" */ 836) 20247 } 20248 } else { 20249 prg.print( /* "unknown numeric" */ 837) 20250 } 20251 prg.printChar(asciiCode(')')) 20252 } 20253 20254 func (prg *prg) badUnary(c quarterword) { 20255 prg.dispErr(halfword(memMin), strNumber( /* "Not implemented: " */ 838)) 20256 prg.printOp(c) 20257 // \xref[Not implemented...] 20258 prg.printKnownOrUnknownType(prg.curType, prg.curExp) 20259 { 20260 prg.helpPtr = 3 20261 prg.helpLine[2] = /* "I'm afraid I don't know how to apply that operation to that" */ 839 20262 prg.helpLine[1] = /* "particular type. Continue, and I'll simply return the" */ 840 20263 prg.helpLine[0] = /* "argument (shown above) as the result of the operation." */ 841 20264 } 20265 prg.putGetError() 20266 } 20267 20268 func (prg *prg) negateDepList(p halfword) { 20269 for true { 20270 *prg.mem[int32(p)+1].int() = -*prg.mem[int32(p)+1].int() 20271 if int32(*(*prg.mem[p].hh()).lh()) == memMin { 20272 goto exit 20273 } 20274 p = *(*prg.mem[p].hh()).rh() 20275 } 20276 20277 exit: 20278 } 20279 20280 func (prg *prg) pairToPath() { 20281 prg.curExp = int32(prg.newKnot()) 20282 prg.curType = byte(pathType) 20283 } 20284 20285 func (prg *prg) takePart(c quarterword) { 20286 var ( 20287 p halfword // the big node 20288 ) 20289 p = uint16(*prg.mem[prg.curExp+1].int()) 20290 *prg.mem[memMin+3+10+2+2+1].int() = int32(p) 20291 *(*prg.mem[memMin+3+10+2+2].hh()).b0() = prg.curType 20292 *(*prg.mem[p].hh()).rh() = uint16(memMin + 3 + 10 + 2 + 2) 20293 prg.freeNode(halfword(prg.curExp), halfword(valueNodeSize)) 20294 prg.makeExpCopy(halfword(int32(p) + 2*(int32(c)-xPart))) 20295 prg.recycleValue(halfword(memMin + 3 + 10 + 2 + 2)) 20296 } 20297 20298 func (prg *prg) strToNum(c quarterword) { // converts a string to a number 20299 var ( 20300 n int32 // accumulator 20301 m asciiCode // current character 20302 k poolPointer // index into |str_pool| 20303 b/* 8..16 */ byte // radix of conversion 20304 badChar bool // did the string contain an invalid digit? 20305 ) 20306 if int32(c) == asciiOp { 20307 if int32(prg.strStart[prg.curExp+1])-int32(prg.strStart[prg.curExp]) == 0 { 20308 n = -1 20309 } else { 20310 n = int32(prg.strPool[prg.strStart[prg.curExp]]) 20311 } 20312 } else { 20313 if int32(c) == octOp { 20314 b = 8 20315 } else { 20316 b = 16 20317 } 20318 n = 0 20319 badChar = false 20320 for ii := int32(prg.strStart[prg.curExp]); ii <= int32(prg.strStart[prg.curExp+1])-1; ii++ { 20321 k = poolPointer(ii) 20322 _ = k 20323 m = prg.strPool[k] 20324 if int32(m) >= '0' && int32(m) <= '9' { 20325 m = byte(int32(m) - '0') 20326 } else if int32(m) >= 'A' && int32(m) <= 'F' { 20327 m = byte(int32(m) - 'A' + 10) 20328 } else if int32(m) >= 'a' && int32(m) <= 'f' { 20329 m = byte(int32(m) - 'a' + 10) 20330 } else { 20331 badChar = true 20332 m = 0 20333 } 20334 if int32(m) >= int32(b) { 20335 badChar = true 20336 m = 0 20337 } 20338 if n < 32768/int32(b) { 20339 n = n*int32(b) + int32(m) 20340 } else { 20341 n = 32767 20342 } 20343 } 20344 20345 // Give error messages if |bad_char| or |n>=4096| 20346 if badChar { 20347 prg.dispErr(halfword(memMin), strNumber( /* "String contains illegal digits" */ 843)) 20348 // \xref[String contains illegal digits] 20349 if int32(c) == octOp { 20350 prg.helpPtr = 1 20351 prg.helpLine[0] = /* "I zeroed out characters that weren't in the range 0..7." */ 844 20352 } else { 20353 prg.helpPtr = 1 20354 prg.helpLine[0] = /* "I zeroed out characters that weren't hex digits." */ 845 20355 } 20356 prg.putGetError() 20357 } 20358 if n > 4095 { 20359 { 20360 if int32(prg.interaction) == errorStopMode { 20361 } 20362 prg.printNl(strNumber( /* "! " */ 261)) 20363 prg.print( /* "Number too large (" */ 846) /* \xref[!\relax] */ 20364 } 20365 prg.printInt(n) 20366 prg.printChar(asciiCode(')')) 20367 // \xref[Number too large] 20368 { 20369 prg.helpPtr = 1 20370 prg.helpLine[0] = /* "I have trouble with numbers greater than 4095; watch out." */ 847 20371 } 20372 prg.putGetError() 20373 } 20374 } 20375 prg.flushCurExp(n * 0200000) 20376 } 20377 20378 func (prg *prg) pathLength() (r scaled) { // computes the length of the current path 20379 var ( 20380 n scaled // the path length so far 20381 p halfword // traverser 20382 ) 20383 p = uint16(prg.curExp) 20384 if int32(*(*prg.mem[p].hh()).b0()) == endpoint { 20385 n = -0200000 20386 } else { 20387 n = 0 20388 } 20389 for { 20390 p = *(*prg.mem[p].hh()).rh() 20391 n = n + 0200000 20392 if int32(p) == prg.curExp { 20393 break 20394 } 20395 } 20396 r = n 20397 return r 20398 } 20399 20400 func (prg *prg) testKnown(c quarterword) { 20401 var ( 20402 b/* trueCode..falseCode */ byte // is the current expression known? 20403 p, q halfword // locations in a big node 20404 ) 20405 b = byte(falseCode) 20406 switch prg.curType { 20407 case vacuous, booleanType, stringType, penType, 20408 futurePen, pathType, pictureType, known: 20409 b = byte(trueCode) 20410 case transformType, pairType: 20411 p = uint16(*prg.mem[prg.curExp+1].int()) 20412 q = uint16(int32(p) + int32(prg.bigNodeSize[prg.curType-13])) 20413 for { 20414 q = uint16(int32(q) - 2) 20415 if int32(*(*prg.mem[q].hh()).b0()) != known { 20416 goto done 20417 } 20418 if int32(q) == int32(p) { 20419 break 20420 } 20421 } 20422 b = byte(trueCode) 20423 20424 done: 20425 ; 20426 20427 default: 20428 } 20429 if int32(c) == knownOp { 20430 prg.flushCurExp(scaled(b)) 20431 } else { 20432 prg.flushCurExp(trueCode + falseCode - int32(b)) 20433 } 20434 prg.curType = byte(booleanType) 20435 } 20436 20437 func (prg *prg) doUnary(c quarterword) { 20438 var ( 20439 p, q halfword // for list manipulation 20440 x int32 // a temporary register 20441 ) 20442 { 20443 if prg.arithError { 20444 prg.clearArith() 20445 } 20446 } 20447 if prg.internal[tracingCommands-1] > 0400000 { 20448 prg.beginDiagnostic() 20449 prg.printNl(strNumber('{')) 20450 prg.printOp(c) 20451 prg.printChar(asciiCode('(')) 20452 20453 prg.printExp(halfword(memMin), smallNumber(0)) // show the operand, but not verbosely 20454 prg.print( /* ")]" */ 842) 20455 prg.endDiagnostic(false) 20456 } 20457 switch c { 20458 case plus: 20459 if int32(prg.curType) < pairType { 20460 if int32(prg.curType) != pictureType { 20461 prg.badUnary(quarterword(plus)) 20462 } 20463 } 20464 case minus: 20465 // Negate the current expression 20466 switch prg.curType { 20467 case pairType, independent: 20468 q = uint16(prg.curExp) 20469 prg.makeExpCopy(q) 20470 if int32(prg.curType) == dependent { 20471 prg.negateDepList(*(*prg.mem[prg.curExp+1].hh()).rh()) 20472 } else if int32(prg.curType) == pairType { 20473 p = uint16(*prg.mem[prg.curExp+1].int()) 20474 if int32(*(*prg.mem[p].hh()).b0()) == known { 20475 *prg.mem[int32(p)+1].int() = -*prg.mem[int32(p)+1].int() 20476 } else { 20477 prg.negateDepList(*(*prg.mem[int32(p)+1].hh()).rh()) 20478 } 20479 if int32(*(*prg.mem[int32(p)+2].hh()).b0()) == known { 20480 *prg.mem[int32(p)+2+1].int() = -*prg.mem[int32(p)+2+1].int() 20481 } else { 20482 prg.negateDepList(*(*prg.mem[int32(p)+2+1].hh()).rh()) 20483 } 20484 } // if |cur_type=known| then |cur_exp=0| 20485 prg.recycleValue(q) 20486 prg.freeNode(q, halfword(valueNodeSize)) 20487 20488 case dependent, protoDependent: 20489 prg.negateDepList(*(*prg.mem[prg.curExp+1].hh()).rh()) 20490 case known: 20491 prg.curExp = -prg.curExp 20492 case pictureType: 20493 prg.negateEdges(halfword(prg.curExp)) 20494 20495 default: 20496 prg.badUnary(quarterword(minus)) 20497 } 20498 20499 // \4 20500 // Additional cases of unary operators 20501 case notOp: 20502 if int32(prg.curType) != booleanType { 20503 prg.badUnary(quarterword(notOp)) 20504 } else { 20505 prg.curExp = trueCode + falseCode - prg.curExp 20506 } 20507 20508 case sqrtOp, mExpOp, mLogOp, sinDOp, 20509 cosDOp, floorOp, uniformDeviate, oddOp, 20510 charExistsOp: // 20511 20512 if int32(prg.curType) != known { 20513 prg.badUnary(c) 20514 } else { 20515 switch c { 20516 case sqrtOp: 20517 prg.curExp = prg.squareRt(prg.curExp) 20518 case mExpOp: 20519 prg.curExp = prg.mExp(prg.curExp) 20520 case mLogOp: 20521 prg.curExp = prg.mLog(prg.curExp) 20522 case sinDOp, cosDOp: 20523 prg.nSinCos(prg.curExp % 23592960 * 16) 20524 if int32(c) == sinDOp { 20525 prg.curExp = prg.roundFraction(prg.nSin) 20526 } else { 20527 prg.curExp = prg.roundFraction(prg.nCos) 20528 } 20529 20530 case floorOp: 20531 prg.curExp = prg.floorScaled(prg.curExp) 20532 case uniformDeviate: 20533 prg.curExp = prg.unifRand(prg.curExp) 20534 case oddOp: 20535 if prg.roundUnscaled(prg.curExp)&1 != 0 { 20536 prg.curExp = trueCode 20537 } else { 20538 prg.curExp = falseCode 20539 } 20540 prg.curType = byte(booleanType) 20541 20542 case charExistsOp: 20543 // Determine if a character has been shipped out 20544 prg.curExp = prg.roundUnscaled(prg.curExp) % 256 20545 if prg.curExp < 0 { 20546 prg.curExp = prg.curExp + 256 20547 } 20548 if prg.charExists[prg.curExp] { 20549 prg.curExp = trueCode 20550 } else { 20551 prg.curExp = falseCode 20552 } 20553 prg.curType = byte(booleanType) 20554 20555 } 20556 } // there are no other cases 20557 20558 case angleOp: 20559 if prg.nicePair(prg.curExp, prg.curType) { 20560 p = uint16(*prg.mem[prg.curExp+1].int()) 20561 x = prg.nArg(*prg.mem[int32(p)+1].int(), *prg.mem[int32(p)+2+1].int()) 20562 if x >= 0 { 20563 prg.flushCurExp((x + 8) / 16) 20564 } else { 20565 prg.flushCurExp(-((-x + 8) / 16)) 20566 } 20567 } else { 20568 prg.badUnary(quarterword(angleOp)) 20569 } 20570 20571 case xPart, yPart: 20572 if int32(prg.curType) <= pairType && int32(prg.curType) >= transformType { 20573 prg.takePart(c) 20574 } else { 20575 prg.badUnary(c) 20576 } 20577 case xxPart, xyPart, yxPart, yyPart: 20578 if int32(prg.curType) == transformType { 20579 prg.takePart(c) 20580 } else { 20581 prg.badUnary(c) 20582 } 20583 20584 case charOp: 20585 if int32(prg.curType) != known { 20586 prg.badUnary(quarterword(charOp)) 20587 } else { 20588 prg.curExp = prg.roundUnscaled(prg.curExp) % 256 20589 prg.curType = byte(stringType) 20590 if prg.curExp < 0 { 20591 prg.curExp = prg.curExp + 256 20592 } 20593 if int32(prg.strStart[prg.curExp+1])-int32(prg.strStart[prg.curExp]) != 1 { 20594 { 20595 if int32(prg.poolPtr)+1 > int32(prg.maxPoolPtr) { 20596 if int32(prg.poolPtr)+1 > poolSize { 20597 prg.overflow(strNumber( /* "pool size" */ 257), poolSize-int32(prg.initPoolPtr)) 20598 } /* \xref[METAFONT capacity exceeded pool size][\quad pool size] */ 20599 prg.maxPoolPtr = uint16(int32(prg.poolPtr) + 1) 20600 } 20601 } 20602 { 20603 prg.strPool[prg.poolPtr] = byte(prg.curExp) 20604 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 20605 } 20606 prg.curExp = int32(prg.makeString()) 20607 } 20608 } 20609 case decimal: 20610 if int32(prg.curType) != known { 20611 prg.badUnary(quarterword(decimal)) 20612 } else { 20613 prg.oldSetting = prg.selector 20614 prg.selector = byte(newString) 20615 prg.printScaled(prg.curExp) 20616 prg.curExp = int32(prg.makeString()) 20617 prg.selector = prg.oldSetting 20618 prg.curType = byte(stringType) 20619 } 20620 case octOp, hexOp, asciiOp: 20621 if int32(prg.curType) != stringType { 20622 prg.badUnary(c) 20623 } else { 20624 prg.strToNum(c) 20625 } 20626 20627 case lengthOp: 20628 if int32(prg.curType) == stringType { 20629 prg.flushCurExp((int32(prg.strStart[prg.curExp+1]) - int32(prg.strStart[prg.curExp])) * 0200000) 20630 } else if int32(prg.curType) == pathType { 20631 prg.flushCurExp(prg.pathLength()) 20632 } else if int32(prg.curType) == known { 20633 prg.curExp = abs(prg.curExp) 20634 } else if prg.nicePair(prg.curExp, prg.curType) { 20635 prg.flushCurExp(prg.pythAdd(*prg.mem[*prg.mem[prg.curExp+1].int()+1].int(), *prg.mem[*prg.mem[prg.curExp+1].int()+2+1].int())) 20636 } else { 20637 prg.badUnary(c) 20638 } 20639 20640 case turningOp: 20641 if int32(prg.curType) == pairType { 20642 prg.flushCurExp(scaled(0)) 20643 } else if int32(prg.curType) != pathType { 20644 prg.badUnary(quarterword(turningOp)) 20645 } else if int32(*(*prg.mem[prg.curExp].hh()).b0()) == endpoint { 20646 prg.flushCurExp(scaled(0)) 20647 } else { 20648 prg.curPen = uint16(memMin + 3) 20649 prg.curPathType = byte(contourCode) 20650 prg.curExp = int32(prg.makeSpec(halfword(prg.curExp), 20651 02000000000-0100000-1-017777777777, 0)) 20652 prg.flushCurExp(prg.turningNumber * 0200000) // convert to |scaled| 20653 } 20654 20655 case booleanType: 20656 if int32(prg.curType) >= booleanType && int32(prg.curType) <= unknownBoolean { 20657 prg.flushCurExp(trueCode) 20658 } else { 20659 prg.flushCurExp(falseCode) 20660 } 20661 prg.curType = byte(booleanType) 20662 case stringType: 20663 if int32(prg.curType) >= stringType && int32(prg.curType) <= unknownString { 20664 prg.flushCurExp(trueCode) 20665 } else { 20666 prg.flushCurExp(falseCode) 20667 } 20668 prg.curType = byte(booleanType) 20669 case penType: 20670 if int32(prg.curType) >= penType && int32(prg.curType) <= futurePen { 20671 prg.flushCurExp(trueCode) 20672 } else { 20673 prg.flushCurExp(falseCode) 20674 } 20675 prg.curType = byte(booleanType) 20676 case pathType: 20677 if int32(prg.curType) >= pathType && int32(prg.curType) <= unknownPath { 20678 prg.flushCurExp(trueCode) 20679 } else { 20680 prg.flushCurExp(falseCode) 20681 } 20682 prg.curType = byte(booleanType) 20683 case pictureType: 20684 if int32(prg.curType) >= pictureType && int32(prg.curType) <= unknownPicture { 20685 prg.flushCurExp(trueCode) 20686 } else { 20687 prg.flushCurExp(falseCode) 20688 } 20689 prg.curType = byte(booleanType) 20690 case transformType, pairType: 20691 if int32(prg.curType) == int32(c) { 20692 prg.flushCurExp(trueCode) 20693 } else { 20694 prg.flushCurExp(falseCode) 20695 } 20696 prg.curType = byte(booleanType) 20697 case numericType: 20698 if int32(prg.curType) >= known && int32(prg.curType) <= independent { 20699 prg.flushCurExp(trueCode) 20700 } else { 20701 prg.flushCurExp(falseCode) 20702 } 20703 prg.curType = byte(booleanType) 20704 case knownOp, unknownOp: 20705 prg.testKnown(c) 20706 20707 case cycleOp: 20708 if int32(prg.curType) != pathType { 20709 prg.flushCurExp(falseCode) 20710 } else if int32(*(*prg.mem[prg.curExp].hh()).b0()) != endpoint { 20711 prg.flushCurExp(trueCode) 20712 } else { 20713 prg.flushCurExp(falseCode) 20714 } 20715 prg.curType = byte(booleanType) 20716 20717 case makePenOp: 20718 if int32(prg.curType) == pairType { 20719 prg.pairToPath() 20720 } 20721 if int32(prg.curType) == pathType { 20722 prg.curType = byte(futurePen) 20723 } else { 20724 prg.badUnary(quarterword(makePenOp)) 20725 } 20726 20727 case makePathOp: 20728 if int32(prg.curType) == futurePen { 20729 prg.materializePen() 20730 } 20731 if int32(prg.curType) != penType { 20732 prg.badUnary(quarterword(makePathOp)) 20733 } else { 20734 prg.flushCurExp(scaled(prg.makePath(halfword(prg.curExp)))) 20735 prg.curType = byte(pathType) 20736 } 20737 20738 case totalWeightOp: 20739 if int32(prg.curType) != pictureType { 20740 prg.badUnary(quarterword(totalWeightOp)) 20741 } else { 20742 prg.flushCurExp(prg.totalWeight(halfword(prg.curExp))) 20743 } 20744 case reverse: 20745 if int32(prg.curType) == pathType { 20746 p = prg.htapYpoc(halfword(prg.curExp)) 20747 if int32(*(*prg.mem[p].hh()).b1()) == endpoint { 20748 p = *(*prg.mem[p].hh()).rh() 20749 } 20750 prg.tossKnotList(halfword(prg.curExp)) 20751 prg.curExp = int32(p) 20752 } else if int32(prg.curType) == pairType { 20753 prg.pairToPath() 20754 } else { 20755 prg.badUnary(quarterword(reverse)) 20756 } 20757 20758 } // there are no other cases 20759 { 20760 if prg.arithError { 20761 prg.clearArith() 20762 } 20763 } 20764 } 20765 20766 // 922. 20767 20768 // tangle:pos ../../mf.web:18295:3: 20769 20770 // Finally, we have the operations that combine a capsule~|p| 20771 // with the current expression. 20772 // \4 20773 // Declare binary action procedures 20774 func (prg *prg) badBinary(p halfword, c quarterword) { 20775 prg.dispErr(p, strNumber( /* "" */ 285)) 20776 prg.dispErr(halfword(memMin), strNumber( /* "Not implemented: " */ 838)) 20777 // \xref[Not implemented...] 20778 if int32(c) >= minOf { 20779 prg.printOp(c) 20780 } 20781 prg.printKnownOrUnknownType(*(*prg.mem[p].hh()).b0(), int32(p)) 20782 if int32(c) >= minOf { 20783 prg.print( /* "of" */ 479) 20784 } else { 20785 prg.printOp(c) 20786 } 20787 prg.printKnownOrUnknownType(prg.curType, prg.curExp) 20788 20789 { 20790 prg.helpPtr = 3 20791 prg.helpLine[2] = /* "I'm afraid I don't know how to apply that operation to that" */ 839 20792 prg.helpLine[1] = /* "combination of types. Continue, and I'll return the second" */ 848 20793 prg.helpLine[0] = /* "argument (see above) as the result of the operation." */ 849 20794 } 20795 prg.putGetError() 20796 } 20797 20798 func (prg *prg) tarnished(p halfword) (r halfword) { 20799 var ( 20800 q halfword // beginning of the big node 20801 r1 halfword // current position in the big node 20802 ) 20803 q = uint16(*prg.mem[int32(p)+1].int()) 20804 r1 = uint16(int32(q) + int32(prg.bigNodeSize[*(*prg.mem[p].hh()).b0()-13])) 20805 for { 20806 r1 = uint16(int32(r1) - 2) 20807 if int32(*(*prg.mem[r1].hh()).b0()) == independent { 20808 r = uint16(memMin + 1) 20809 goto exit 20810 } 20811 if int32(r1) == int32(q) { 20812 break 20813 } 20814 } 20815 r = uint16(memMin) 20816 20817 exit: 20818 ; 20819 return r 20820 } 20821 20822 // \4 20823 // Declare the procedure called |dep_finish| 20824 func (prg *prg) depFinish(v, q halfword, t smallNumber) { 20825 var ( 20826 p halfword // the destination 20827 vv scaled // the value, if it is |known| 20828 ) 20829 if int32(q) == memMin { 20830 p = uint16(prg.curExp) 20831 } else { 20832 p = q 20833 } 20834 *(*prg.mem[int32(p)+1].hh()).rh() = v 20835 *(*prg.mem[p].hh()).b0() = t 20836 if int32(*(*prg.mem[v].hh()).lh()) == memMin { 20837 vv = *prg.mem[int32(v)+1].int() 20838 if int32(q) == memMin { 20839 prg.flushCurExp(vv) 20840 } else { 20841 prg.recycleValue(p) 20842 *(*prg.mem[q].hh()).b0() = byte(known) 20843 *prg.mem[int32(q)+1].int() = vv 20844 } 20845 } else if int32(q) == memMin { 20846 prg.curType = t 20847 } 20848 if prg.fixNeeded { 20849 prg.fixDependencies() 20850 } 20851 } 20852 20853 func (prg *prg) addOrSubtract(p, q halfword, c quarterword) { 20854 var ( 20855 s, t smallNumber // operand types 20856 r1 halfword // list traverser 20857 v int32 // second operand value 20858 ) 20859 if int32(q) == memMin { 20860 t = prg.curType 20861 if int32(t) < dependent { 20862 v = prg.curExp 20863 } else { 20864 v = int32(*(*prg.mem[prg.curExp+1].hh()).rh()) 20865 } 20866 } else { 20867 t = *(*prg.mem[q].hh()).b0() 20868 if int32(t) < dependent { 20869 v = *prg.mem[int32(q)+1].int() 20870 } else { 20871 v = int32(*(*prg.mem[int32(q)+1].hh()).rh()) 20872 } 20873 } 20874 if int32(t) == known { 20875 if int32(c) == minus { 20876 v = -v 20877 } 20878 if int32(*(*prg.mem[p].hh()).b0()) == known { 20879 v = prg.slowAdd(*prg.mem[int32(p)+1].int(), v) 20880 if int32(q) == memMin { 20881 prg.curExp = v 20882 } else { 20883 *prg.mem[int32(q)+1].int() = v 20884 } 20885 20886 goto exit 20887 } 20888 20889 // Add a known value to the constant term of |dep_list(p)| 20890 r1 = *(*prg.mem[int32(p)+1].hh()).rh() 20891 for int32(*(*prg.mem[r1].hh()).lh()) != memMin { 20892 r1 = *(*prg.mem[r1].hh()).rh() 20893 } 20894 *prg.mem[int32(r1)+1].int() = prg.slowAdd(*prg.mem[int32(r1)+1].int(), v) 20895 if int32(q) == memMin { 20896 q = prg.getNode(valueNodeSize) 20897 prg.curExp = int32(q) 20898 prg.curType = *(*prg.mem[p].hh()).b0() 20899 *(*prg.mem[q].hh()).b1() = byte(capsule) 20900 } 20901 *(*prg.mem[int32(q)+1].hh()).rh() = *(*prg.mem[int32(p)+1].hh()).rh() 20902 *(*prg.mem[q].hh()).b0() = *(*prg.mem[p].hh()).b0() 20903 *(*prg.mem[int32(q)+1].hh()).lh() = *(*prg.mem[int32(p)+1].hh()).lh() 20904 *(*prg.mem[*(*prg.mem[int32(p)+1].hh()).lh()].hh()).rh() = q 20905 *(*prg.mem[p].hh()).b0() = byte(known) // this will keep the recycler from collecting non-garbage 20906 20907 } else { 20908 if int32(c) == minus { 20909 prg.negateDepList(halfword(v)) 20910 } 20911 20912 // Add operand |p| to the dependency list |v| 20913 if int32(*(*prg.mem[p].hh()).b0()) == known { 20914 for int32(*(*prg.mem[v].hh()).lh()) != memMin { 20915 v = int32(*(*prg.mem[v].hh()).rh()) 20916 } 20917 *prg.mem[v+1].int() = prg.slowAdd(*prg.mem[int32(p)+1].int(), *prg.mem[v+1].int()) 20918 } else { 20919 s = *(*prg.mem[p].hh()).b0() 20920 r1 = *(*prg.mem[int32(p)+1].hh()).rh() 20921 if int32(t) == dependent { 20922 if int32(s) == dependent { 20923 if prg.maxCoef(r1)+prg.maxCoef(halfword(v)) < 04525252525 { 20924 v = int32(prg.pPlusQ(halfword(v), r1, smallNumber(dependent))) 20925 goto done 20926 } 20927 } // |fix_needed| will necessarily be false 20928 t = byte(protoDependent) 20929 v = int32(prg.pOverV(halfword(v), scaled(0200000), smallNumber(dependent), smallNumber(protoDependent))) 20930 } 20931 if int32(s) == protoDependent { 20932 v = int32(prg.pPlusQ(halfword(v), r1, smallNumber(protoDependent))) 20933 } else { 20934 v = int32(prg.pPlusFq(halfword(v), 0200000, r1, smallNumber(protoDependent), smallNumber(dependent))) 20935 } 20936 20937 done: 20938 if int32(q) != memMin { 20939 prg.depFinish(halfword(v), q, t) 20940 } else { 20941 prg.curType = t 20942 prg.depFinish(halfword(v), halfword(memMin), t) 20943 } 20944 } 20945 } 20946 20947 exit: 20948 } 20949 20950 func (prg *prg) depMult(p halfword, v int32, vIsScaled bool) { 20951 var ( 20952 q halfword // the dependency list being multiplied by |v| 20953 s, t smallNumber // its type, before and after 20954 ) 20955 if int32(p) == memMin { 20956 q = uint16(prg.curExp) 20957 } else if int32(*(*prg.mem[p].hh()).b0()) != known { 20958 q = p 20959 } else { 20960 if vIsScaled { 20961 *prg.mem[int32(p)+1].int() = prg.takeScaled(*prg.mem[int32(p)+1].int(), v) 20962 } else { 20963 *prg.mem[int32(p)+1].int() = prg.takeFraction(*prg.mem[int32(p)+1].int(), v) 20964 } 20965 20966 goto exit 20967 } 20968 t = *(*prg.mem[q].hh()).b0() 20969 q = *(*prg.mem[int32(q)+1].hh()).rh() 20970 s = t 20971 if int32(t) == dependent { 20972 if vIsScaled { 20973 if prg.abVsCd(prg.maxCoef(q), abs(v), 04525252525-1, 0200000) >= 0 { 20974 t = byte(protoDependent) 20975 } 20976 } 20977 } 20978 q = prg.pTimesV(q, v, s, t, vIsScaled) 20979 prg.depFinish(q, p, t) 20980 20981 exit: 20982 } 20983 20984 func (prg *prg) hardTimes(p halfword) { 20985 var ( 20986 q halfword // a copy of the dependent variable |p| 20987 r1 halfword // the big node for the nice pair 20988 u, v scaled // the known values of the nice pair 20989 ) 20990 if int32(*(*prg.mem[p].hh()).b0()) == pairType { 20991 q = prg.stashCurExp() 20992 prg.unstashCurExp(p) 20993 p = q 20994 } // now |cur_type=pair_type| 20995 r1 = uint16(*prg.mem[prg.curExp+1].int()) 20996 u = *prg.mem[int32(r1)+1].int() 20997 v = *prg.mem[int32(r1)+2+1].int() 20998 20999 // Move the dependent variable |p| into both parts of the pair node |r| 21000 *(*prg.mem[int32(r1)+2].hh()).b0() = *(*prg.mem[p].hh()).b0() 21001 prg.newDep(halfword(int32(r1)+2), prg.copyDepList(*(*prg.mem[int32(p)+1].hh()).rh())) 21002 21003 *(*prg.mem[r1].hh()).b0() = *(*prg.mem[p].hh()).b0() 21004 prg.mem[int32(r1)+1] = prg.mem[int32(p)+1] 21005 *(*prg.mem[*(*prg.mem[int32(p)+1].hh()).lh()].hh()).rh() = r1 21006 prg.freeNode(p, halfword(valueNodeSize)) 21007 prg.depMult(r1, u, true) 21008 prg.depMult(halfword(int32(r1)+2), v, true) 21009 } 21010 21011 func (prg *prg) depDiv(p halfword, v scaled) { 21012 var ( 21013 q halfword // the dependency list being divided by |v| 21014 s, t smallNumber // its type, before and after 21015 ) 21016 if int32(p) == memMin { 21017 q = uint16(prg.curExp) 21018 } else if int32(*(*prg.mem[p].hh()).b0()) != known { 21019 q = p 21020 } else { 21021 *prg.mem[int32(p)+1].int() = prg.makeScaled(*prg.mem[int32(p)+1].int(), v) 21022 goto exit 21023 } 21024 t = *(*prg.mem[q].hh()).b0() 21025 q = *(*prg.mem[int32(q)+1].hh()).rh() 21026 s = t 21027 if int32(t) == dependent { 21028 if prg.abVsCd(prg.maxCoef(q), 0200000, 04525252525-1, abs(v)) >= 0 { 21029 t = byte(protoDependent) 21030 } 21031 } 21032 q = prg.pOverV(q, v, s, t) 21033 prg.depFinish(q, p, t) 21034 21035 exit: 21036 } 21037 21038 func (prg *prg) setUpTrans(c quarterword) { 21039 var ( 21040 p, q, r1 halfword // list manipulation registers 21041 ) 21042 if int32(c) != transformedBy || int32(prg.curType) != transformType { 21043 p = prg.stashCurExp() 21044 prg.curExp = int32(prg.idTransform()) 21045 prg.curType = byte(transformType) 21046 q = uint16(*prg.mem[prg.curExp+1].int()) 21047 switch c { 21048 case rotatedBy: 21049 if int32(*(*prg.mem[p].hh()).b0()) == known { 21050 prg.nSinCos(*prg.mem[int32(p)+1].int() % 23592960 * 16) 21051 *prg.mem[int32(q)+4+1].int() = prg.roundFraction(prg.nCos) 21052 *prg.mem[int32(q)+8+1].int() = prg.roundFraction(prg.nSin) 21053 *prg.mem[int32(q)+6+1].int() = -*prg.mem[int32(q)+8+1].int() 21054 *prg.mem[int32(q)+10+1].int() = *prg.mem[int32(q)+4+1].int() 21055 21056 goto done 21057 } 21058 21059 case slantedBy: 21060 if int32(*(*prg.mem[p].hh()).b0()) > pairType { 21061 prg.install(halfword(int32(q)+6), p) 21062 goto done 21063 } 21064 case scaledBy: 21065 if int32(*(*prg.mem[p].hh()).b0()) > pairType { 21066 prg.install(halfword(int32(q)+4), p) 21067 prg.install(halfword(int32(q)+10), p) 21068 goto done 21069 } 21070 case shiftedBy: 21071 if int32(*(*prg.mem[p].hh()).b0()) == pairType { 21072 r1 = uint16(*prg.mem[int32(p)+1].int()) 21073 prg.install(q, r1) 21074 prg.install(halfword(int32(q)+2), halfword(int32(r1)+2)) 21075 goto done 21076 } 21077 case xScaled: 21078 if int32(*(*prg.mem[p].hh()).b0()) > pairType { 21079 prg.install(halfword(int32(q)+4), p) 21080 goto done 21081 } 21082 case yScaled: 21083 if int32(*(*prg.mem[p].hh()).b0()) > pairType { 21084 prg.install(halfword(int32(q)+10), p) 21085 goto done 21086 } 21087 case zScaled: 21088 if int32(*(*prg.mem[p].hh()).b0()) == pairType { 21089 r1 = uint16(*prg.mem[int32(p)+1].int()) 21090 prg.install(halfword(int32(q)+4), r1) 21091 prg.install(halfword(int32(q)+10), r1) 21092 prg.install(halfword(int32(q)+8), halfword(int32(r1)+2)) 21093 if int32(*(*prg.mem[int32(r1)+2].hh()).b0()) == known { 21094 *prg.mem[int32(r1)+2+1].int() = -*prg.mem[int32(r1)+2+1].int() 21095 } else { 21096 prg.negateDepList(*(*prg.mem[int32(r1)+2+1].hh()).rh()) 21097 } 21098 prg.install(halfword(int32(q)+6), halfword(int32(r1)+2)) 21099 21100 goto done 21101 } 21102 21103 case transformedBy: 21104 21105 } // there are no other cases 21106 prg.dispErr(p, strNumber( /* "Improper transformation argument" */ 858)) 21107 // \xref[Improper transformation argument] 21108 { 21109 prg.helpPtr = 3 21110 prg.helpLine[2] = /* "The expression shown above has the wrong type," */ 859 21111 prg.helpLine[1] = /* "so I can't transform anything using it." */ 860 21112 prg.helpLine[0] = /* "Proceed, and I'll omit the transformation." */ 538 21113 } 21114 prg.putGetError() 21115 21116 done: 21117 prg.recycleValue(p) 21118 prg.freeNode(p, halfword(valueNodeSize)) 21119 } 21120 21121 // If the current transform is entirely known, stash it in global variables; otherwise |return| 21122 q = uint16(*prg.mem[prg.curExp+1].int()) 21123 r1 = uint16(int32(q) + transformNodeSize) 21124 for { 21125 r1 = uint16(int32(r1) - 2) 21126 if int32(*(*prg.mem[r1].hh()).b0()) != known { 21127 goto exit 21128 } 21129 if int32(r1) == int32(q) { 21130 break 21131 } 21132 } 21133 prg.txx = *prg.mem[int32(q)+4+1].int() 21134 prg.txy = *prg.mem[int32(q)+6+1].int() 21135 prg.tyx = *prg.mem[int32(q)+8+1].int() 21136 prg.tyy = *prg.mem[int32(q)+10+1].int() 21137 prg.tx = *prg.mem[int32(q)+1].int() 21138 prg.ty = *prg.mem[int32(q)+2+1].int() 21139 prg.flushCurExp(scaled(0)) 21140 21141 exit: 21142 } 21143 21144 func (prg *prg) setUpKnownTrans(c quarterword) { 21145 prg.setUpTrans(c) 21146 if int32(prg.curType) != known { 21147 prg.dispErr(halfword(memMin), strNumber( /* "Transform components aren't all known" */ 861)) 21148 // \xref[Transform components...] 21149 { 21150 prg.helpPtr = 3 21151 prg.helpLine[2] = /* "I'm unable to apply a partially specified transformation" */ 862 21152 prg.helpLine[1] = /* "except to a fully known pair or transform." */ 863 21153 prg.helpLine[0] = /* "Proceed, and I'll omit the transformation." */ 538 21154 } 21155 prg.putGetFlushError(scaled(0)) 21156 prg.txx = 0200000 21157 prg.txy = 0 21158 prg.tyx = 0 21159 prg.tyy = 0200000 21160 prg.tx = 0 21161 prg.ty = 0 21162 } 21163 } 21164 21165 func (prg *prg) trans(p, q halfword) { 21166 var ( 21167 v scaled // the new |x| value 21168 ) 21169 v = prg.takeScaled(*prg.mem[p].int(), prg.txx) + prg.takeScaled(*prg.mem[q].int(), prg.txy) + prg.tx 21170 *prg.mem[q].int() = prg.takeScaled(*prg.mem[p].int(), prg.tyx) + prg.takeScaled(*prg.mem[q].int(), prg.tyy) + prg.ty 21171 *prg.mem[p].int() = v 21172 } 21173 21174 func (prg *prg) pathTrans(p halfword, c quarterword) { 21175 var ( 21176 q halfword // list traverser 21177 ) 21178 prg.setUpKnownTrans(c) 21179 prg.unstashCurExp(p) 21180 if int32(prg.curType) == penType { 21181 if *prg.mem[prg.curExp+9].int() == 0 { 21182 if prg.tx == 0 { 21183 if prg.ty == 0 { 21184 goto exit 21185 } 21186 } 21187 } 21188 prg.flushCurExp(scaled(prg.makePath(halfword(prg.curExp)))) 21189 prg.curType = byte(futurePen) 21190 } 21191 q = uint16(prg.curExp) 21192 for { 21193 if int32(*(*prg.mem[q].hh()).b0()) != endpoint { 21194 prg.trans(halfword(int32(q)+3), halfword(int32(q)+4)) 21195 } // that's |left_x| and |left_y| 21196 prg.trans(halfword(int32(q)+1), halfword(int32(q)+2)) // that's |x_coord| and |y_coord| 21197 if int32(*(*prg.mem[q].hh()).b1()) != endpoint { 21198 prg.trans(halfword(int32(q)+5), halfword(int32(q)+6)) 21199 } // that's |right_x| and |right_y| 21200 q = *(*prg.mem[q].hh()).rh() 21201 if int32(q) == prg.curExp { 21202 break 21203 } 21204 } 21205 21206 exit: 21207 } 21208 21209 func (prg *prg) edgesTrans(p halfword, c quarterword) { 21210 prg.setUpKnownTrans(c) 21211 prg.unstashCurExp(p) 21212 prg.curEdges = uint16(prg.curExp) 21213 if int32(*(*prg.mem[prg.curEdges].hh()).rh()) == int32(prg.curEdges) { 21214 goto exit 21215 } // the empty set is easy to transform 21216 if prg.txx == 0 { 21217 if prg.tyy == 0 { 21218 if prg.txy%0200000 == 0 { 21219 if prg.tyx%0200000 == 0 { 21220 prg.xySwapEdges() 21221 prg.txx = prg.txy 21222 prg.tyy = prg.tyx 21223 prg.txy = 0 21224 prg.tyx = 0 21225 if int32(*(*prg.mem[prg.curEdges].hh()).rh()) == int32(prg.curEdges) { 21226 goto exit 21227 } 21228 } 21229 } 21230 } 21231 } 21232 if prg.txy == 0 { 21233 if prg.tyx == 0 { 21234 if prg.txx%0200000 == 0 { 21235 if prg.tyy%0200000 == 0 { 21236 if prg.txx == 0 || prg.tyy == 0 { 21237 prg.tossEdges(prg.curEdges) 21238 prg.curExp = int32(prg.getNode(edgeHeaderSize)) 21239 prg.initEdges(halfword(prg.curExp)) 21240 } else { 21241 if prg.txx < 0 { 21242 prg.xReflectEdges() 21243 prg.txx = -prg.txx 21244 } 21245 if prg.tyy < 0 { 21246 prg.yReflectEdges() 21247 prg.tyy = -prg.tyy 21248 } 21249 if prg.txx != 0200000 { 21250 prg.xScaleEdges(prg.txx / 0200000) 21251 } 21252 if prg.tyy != 0200000 { 21253 prg.yScaleEdges(prg.tyy / 0200000) 21254 } 21255 21256 // Shift the edges by |(tx,ty)|, rounded 21257 prg.tx = prg.roundUnscaled(prg.tx) 21258 prg.ty = prg.roundUnscaled(prg.ty) 21259 if int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh())+prg.tx <= 0 || int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh())+prg.tx >= 8192 || int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh())+prg.ty <= 0 || int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh())+prg.ty >= 8191 || abs(prg.tx) >= 4096 || abs(prg.ty) >= 4096 { 21260 { 21261 if int32(prg.interaction) == errorStopMode { 21262 } 21263 prg.printNl(strNumber( /* "! " */ 261)) 21264 prg.print( /* "Too far to shift" */ 867) /* \xref[!\relax] */ 21265 } 21266 // \xref[Too far to shift] 21267 { 21268 prg.helpPtr = 3 21269 prg.helpLine[2] = /* "I can't shift the picture as requested---it would" */ 868 21270 prg.helpLine[1] = /* "make some coordinates too large or too small." */ 537 21271 prg.helpLine[0] = /* "Proceed, and I'll omit the transformation." */ 538 21272 } 21273 prg.putGetError() 21274 } else { 21275 if prg.tx != 0 { 21276 if !(abs(int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())-prg.tx-4096) < 4096) { 21277 prg.fixOffset() 21278 } 21279 *(*prg.mem[int32(prg.curEdges)+2].hh()).lh() = uint16(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh()) + prg.tx) 21280 *(*prg.mem[int32(prg.curEdges)+2].hh()).rh() = uint16(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh()) + prg.tx) 21281 *(*prg.mem[int32(prg.curEdges)+3].hh()).lh() = uint16(int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) - prg.tx) 21282 *prg.mem[int32(prg.curEdges)+4].int() = 0 21283 } 21284 if prg.ty != 0 { 21285 *(*prg.mem[int32(prg.curEdges)+1].hh()).lh() = uint16(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh()) + prg.ty) 21286 *(*prg.mem[int32(prg.curEdges)+1].hh()).rh() = uint16(int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh()) + prg.ty) 21287 *(*prg.mem[int32(prg.curEdges)+5].hh()).lh() = uint16(int32(*(*prg.mem[int32(prg.curEdges)+5].hh()).lh()) + prg.ty) 21288 *prg.mem[int32(prg.curEdges)+4].int() = 0 21289 } 21290 } 21291 } 21292 21293 goto exit 21294 } 21295 } 21296 } 21297 } 21298 { 21299 if int32(prg.interaction) == errorStopMode { 21300 } 21301 prg.printNl(strNumber( /* "! " */ 261)) 21302 prg.print( /* "That transformation is too hard" */ 864) /* \xref[!\relax] */ 21303 } 21304 // \xref[That transformation...] 21305 { 21306 prg.helpPtr = 3 21307 prg.helpLine[2] = /* "I can apply complicated transformations to paths," */ 865 21308 prg.helpLine[1] = /* "but I can only do integer operations on pictures." */ 866 21309 prg.helpLine[0] = /* "Proceed, and I'll omit the transformation." */ 538 21310 } 21311 prg.putGetError() 21312 21313 exit: 21314 } 21315 21316 // \4 21317 // Declare subroutines needed by |big_trans| 21318 func (prg *prg) bilin1(p halfword, t scaled, q halfword, u, delta scaled) { 21319 var ( 21320 r1 halfword // list traverser 21321 ) 21322 if t != 0200000 { 21323 prg.depMult(p, t, true) 21324 } 21325 if u != 0 { 21326 if int32(*(*prg.mem[q].hh()).b0()) == known { 21327 delta = delta + prg.takeScaled(*prg.mem[int32(q)+1].int(), u) 21328 } else { 21329 if int32(*(*prg.mem[p].hh()).b0()) != protoDependent { 21330 if int32(*(*prg.mem[p].hh()).b0()) == known { 21331 prg.newDep(p, prg.constDependency(*prg.mem[int32(p)+1].int())) 21332 } else { 21333 *(*prg.mem[int32(p)+1].hh()).rh() = prg.pTimesV(*(*prg.mem[int32(p)+1].hh()).rh(), 0200000, smallNumber(dependent), smallNumber(protoDependent), true) 21334 } 21335 *(*prg.mem[p].hh()).b0() = byte(protoDependent) 21336 } 21337 *(*prg.mem[int32(p)+1].hh()).rh() = prg.pPlusFq(*(*prg.mem[int32(p)+1].hh()).rh(), u, *(*prg.mem[int32(q)+1].hh()).rh(), smallNumber(protoDependent), *(*prg.mem[q].hh()).b0()) 21338 } 21339 } 21340 if int32(*(*prg.mem[p].hh()).b0()) == known { 21341 *prg.mem[int32(p)+1].int() = *prg.mem[int32(p)+1].int() + delta 21342 } else { 21343 r1 = *(*prg.mem[int32(p)+1].hh()).rh() 21344 for int32(*(*prg.mem[r1].hh()).lh()) != memMin { 21345 r1 = *(*prg.mem[r1].hh()).rh() 21346 } 21347 delta = *prg.mem[int32(r1)+1].int() + delta 21348 if int32(r1) != int32(*(*prg.mem[int32(p)+1].hh()).rh()) { 21349 *prg.mem[int32(r1)+1].int() = delta 21350 } else { 21351 prg.recycleValue(p) 21352 *(*prg.mem[p].hh()).b0() = byte(known) 21353 *prg.mem[int32(p)+1].int() = delta 21354 } 21355 } 21356 if prg.fixNeeded { 21357 prg.fixDependencies() 21358 } 21359 } 21360 21361 func (prg *prg) addMultDep(p halfword, v scaled, r1 halfword) { 21362 if int32(*(*prg.mem[r1].hh()).b0()) == known { 21363 *prg.mem[int32(prg.depFinal)+1].int() = *prg.mem[int32(prg.depFinal)+1].int() + prg.takeScaled(*prg.mem[int32(r1)+1].int(), v) 21364 } else { 21365 *(*prg.mem[int32(p)+1].hh()).rh() = prg.pPlusFq(*(*prg.mem[int32(p)+1].hh()).rh(), v, *(*prg.mem[int32(r1)+1].hh()).rh(), smallNumber(protoDependent), *(*prg.mem[r1].hh()).b0()) 21366 if prg.fixNeeded { 21367 prg.fixDependencies() 21368 } 21369 } 21370 } 21371 21372 func (prg *prg) bilin2(p, t halfword, v scaled, u, q halfword) { 21373 var ( 21374 vv scaled // temporary storage for |value(p)| 21375 ) 21376 vv = *prg.mem[int32(p)+1].int() 21377 *(*prg.mem[p].hh()).b0() = byte(protoDependent) 21378 prg.newDep(p, prg.constDependency(scaled(0))) // this sets |dep_final| 21379 if vv != 0 { 21380 prg.addMultDep(p, vv, t) 21381 } // |dep_final| doesn't change 21382 if v != 0 { 21383 prg.addMultDep(p, v, u) 21384 } 21385 if int32(q) != memMin { 21386 prg.addMultDep(p, scaled(0200000), q) 21387 } 21388 if int32(*(*prg.mem[int32(p)+1].hh()).rh()) == int32(prg.depFinal) { 21389 vv = *prg.mem[int32(prg.depFinal)+1].int() 21390 prg.recycleValue(p) 21391 *(*prg.mem[p].hh()).b0() = byte(known) 21392 *prg.mem[int32(p)+1].int() = vv 21393 } 21394 } 21395 21396 func (prg *prg) bilin3(p halfword, t, v, u, delta scaled) { 21397 if t != 0200000 { 21398 delta = delta + prg.takeScaled(*prg.mem[int32(p)+1].int(), t) 21399 } else { 21400 delta = delta + *prg.mem[int32(p)+1].int() 21401 } 21402 if u != 0 { 21403 *prg.mem[int32(p)+1].int() = delta + prg.takeScaled(v, u) 21404 } else { 21405 *prg.mem[int32(p)+1].int() = delta 21406 } 21407 } 21408 21409 func (prg *prg) bigTrans(p halfword, c quarterword) { 21410 var ( 21411 q, r1, pp, qq halfword // list manipulation registers 21412 s smallNumber // size of a big node 21413 ) 21414 s = prg.bigNodeSize[*(*prg.mem[p].hh()).b0()-13] 21415 q = uint16(*prg.mem[int32(p)+1].int()) 21416 r1 = uint16(int32(q) + int32(s)) 21417 for { 21418 r1 = uint16(int32(r1) - 2) 21419 if int32(*(*prg.mem[r1].hh()).b0()) != known { 21420 prg.setUpKnownTrans(c) 21421 prg.makeExpCopy(p) 21422 r1 = uint16(*prg.mem[prg.curExp+1].int()) 21423 if int32(prg.curType) == transformType { 21424 prg.bilin1(halfword(int32(r1)+10), prg.tyy, halfword(int32(q)+6), prg.tyx, scaled(0)) 21425 prg.bilin1(halfword(int32(r1)+8), prg.tyy, halfword(int32(q)+4), prg.tyx, scaled(0)) 21426 prg.bilin1(halfword(int32(r1)+6), prg.txx, halfword(int32(q)+10), prg.txy, scaled(0)) 21427 prg.bilin1(halfword(int32(r1)+4), prg.txx, halfword(int32(q)+8), prg.txy, scaled(0)) 21428 } 21429 prg.bilin1(halfword(int32(r1)+2), prg.tyy, q, prg.tyx, prg.ty) 21430 prg.bilin1(r1, prg.txx, halfword(int32(q)+2), prg.txy, prg.tx) 21431 21432 goto exit 21433 } 21434 if int32(r1) == int32(q) { 21435 break 21436 } 21437 } 21438 21439 // Transform a known big node 21440 prg.setUpTrans(c) 21441 if int32(prg.curType) == known { 21442 prg.makeExpCopy(p) 21443 r1 = uint16(*prg.mem[prg.curExp+1].int()) 21444 if int32(prg.curType) == transformType { 21445 prg.bilin3(halfword(int32(r1)+10), prg.tyy, *prg.mem[int32(q)+6+1].int(), prg.tyx, scaled(0)) 21446 prg.bilin3(halfword(int32(r1)+8), prg.tyy, *prg.mem[int32(q)+4+1].int(), prg.tyx, scaled(0)) 21447 prg.bilin3(halfword(int32(r1)+6), prg.txx, *prg.mem[int32(q)+10+1].int(), prg.txy, scaled(0)) 21448 prg.bilin3(halfword(int32(r1)+4), prg.txx, *prg.mem[int32(q)+8+1].int(), prg.txy, scaled(0)) 21449 } 21450 prg.bilin3(halfword(int32(r1)+2), prg.tyy, *prg.mem[int32(q)+1].int(), prg.tyx, prg.ty) 21451 prg.bilin3(r1, prg.txx, *prg.mem[int32(q)+2+1].int(), prg.txy, prg.tx) 21452 } else { 21453 pp = prg.stashCurExp() 21454 qq = uint16(*prg.mem[int32(pp)+1].int()) 21455 prg.makeExpCopy(p) 21456 r1 = uint16(*prg.mem[prg.curExp+1].int()) 21457 if int32(prg.curType) == transformType { 21458 prg.bilin2(halfword(int32(r1)+10), halfword(int32(qq)+10), *prg.mem[int32(q)+6+1].int(), halfword(int32(qq)+8), halfword(memMin)) 21459 prg.bilin2(halfword(int32(r1)+8), halfword(int32(qq)+10), *prg.mem[int32(q)+4+1].int(), halfword(int32(qq)+8), halfword(memMin)) 21460 prg.bilin2(halfword(int32(r1)+6), halfword(int32(qq)+4), *prg.mem[int32(q)+10+1].int(), halfword(int32(qq)+6), halfword(memMin)) 21461 prg.bilin2(halfword(int32(r1)+4), halfword(int32(qq)+4), *prg.mem[int32(q)+8+1].int(), halfword(int32(qq)+6), halfword(memMin)) 21462 } 21463 prg.bilin2(halfword(int32(r1)+2), halfword(int32(qq)+10), *prg.mem[int32(q)+1].int(), halfword(int32(qq)+8), halfword(int32(qq)+2)) 21464 prg.bilin2(r1, halfword(int32(qq)+4), *prg.mem[int32(q)+2+1].int(), halfword(int32(qq)+6), qq) 21465 prg.recycleValue(pp) 21466 prg.freeNode(pp, halfword(valueNodeSize)) 21467 } 21468 21469 exit: 21470 } // node |p| will now be recycled by |do_binary| 21471 21472 func (prg *prg) cat(p halfword) { 21473 var ( 21474 a, b strNumber // the strings being concatenated 21475 k poolPointer // index into |str_pool| 21476 ) 21477 a = uint16(*prg.mem[int32(p)+1].int()) 21478 b = uint16(prg.curExp) 21479 { 21480 if int32(prg.poolPtr)+(int32(prg.strStart[int32(a)+1])-int32(prg.strStart[a]))+(int32(prg.strStart[int32(b)+1])-int32(prg.strStart[b])) > int32(prg.maxPoolPtr) { 21481 if int32(prg.poolPtr)+(int32(prg.strStart[int32(a)+1])-int32(prg.strStart[a]))+(int32(prg.strStart[int32(b)+1])-int32(prg.strStart[b])) > poolSize { 21482 prg.overflow(strNumber( /* "pool size" */ 257), poolSize-int32(prg.initPoolPtr)) 21483 } /* \xref[METAFONT capacity exceeded pool size][\quad pool size] */ 21484 prg.maxPoolPtr = uint16(int32(prg.poolPtr) + (int32(prg.strStart[int32(a)+1]) - int32(prg.strStart[a])) + (int32(prg.strStart[int32(b)+1]) - int32(prg.strStart[b]))) 21485 } 21486 } 21487 for ii := int32(prg.strStart[a]); ii <= int32(prg.strStart[int32(a)+1])-1; ii++ { 21488 k = poolPointer(ii) 21489 _ = k 21490 prg.strPool[prg.poolPtr] = prg.strPool[k] 21491 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 21492 } 21493 for ii := int32(prg.strStart[b]); ii <= int32(prg.strStart[int32(b)+1])-1; ii++ { 21494 k = poolPointer(ii) 21495 _ = k 21496 prg.strPool[prg.poolPtr] = prg.strPool[k] 21497 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 21498 } 21499 prg.curExp = int32(prg.makeString()) 21500 { 21501 if int32(prg.strRef[b]) < maxStrRef { 21502 if int32(prg.strRef[b]) > 1 { 21503 prg.strRef[b] = byte(int32(prg.strRef[b]) - 1) 21504 } else { 21505 prg.flushString(b) 21506 } 21507 } 21508 } 21509 } 21510 21511 func (prg *prg) chopString(p halfword) { 21512 var ( 21513 a, b int32 // start and stop points 21514 l int32 // length of the original string 21515 k int32 // runs from |a| to |b| 21516 s strNumber // the original string 21517 reversed bool // was |a>b|? 21518 ) 21519 a = prg.roundUnscaled(*prg.mem[int32(p)+1].int()) 21520 b = prg.roundUnscaled(*prg.mem[int32(p)+2+1].int()) 21521 if a <= b { 21522 reversed = false 21523 } else { 21524 reversed = true 21525 k = a 21526 a = b 21527 b = k 21528 } 21529 s = uint16(prg.curExp) 21530 l = int32(prg.strStart[int32(s)+1]) - int32(prg.strStart[s]) 21531 if a < 0 { 21532 a = 0 21533 if b < 0 { 21534 b = 0 21535 } 21536 } 21537 if b > l { 21538 b = l 21539 if a > l { 21540 a = l 21541 } 21542 } 21543 { 21544 if int32(prg.poolPtr)+b-a > int32(prg.maxPoolPtr) { 21545 if int32(prg.poolPtr)+b-a > poolSize { 21546 prg.overflow(strNumber( /* "pool size" */ 257), poolSize-int32(prg.initPoolPtr)) 21547 } /* \xref[METAFONT capacity exceeded pool size][\quad pool size] */ 21548 prg.maxPoolPtr = uint16(int32(prg.poolPtr) + b - a) 21549 } 21550 } 21551 if reversed { 21552 for ii := int32(prg.strStart[s]) + b - 1; ii >= int32(prg.strStart[s])+a; ii-- { 21553 k = ii 21554 _ = k 21555 prg.strPool[prg.poolPtr] = prg.strPool[k] 21556 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 21557 } 21558 } else { 21559 for ii := int32(prg.strStart[s]) + a; ii <= int32(prg.strStart[s])+b-1; ii++ { 21560 k = ii 21561 _ = k 21562 prg.strPool[prg.poolPtr] = prg.strPool[k] 21563 prg.poolPtr = uint16(int32(prg.poolPtr) + 1) 21564 } 21565 } 21566 prg.curExp = int32(prg.makeString()) 21567 { 21568 if int32(prg.strRef[s]) < maxStrRef { 21569 if int32(prg.strRef[s]) > 1 { 21570 prg.strRef[s] = byte(int32(prg.strRef[s]) - 1) 21571 } else { 21572 prg.flushString(s) 21573 } 21574 } 21575 } 21576 } 21577 21578 func (prg *prg) chopPath(p halfword) { 21579 var ( 21580 q halfword // a knot in the original path 21581 pp, qq, rr, ss halfword // link variables for copies of path nodes 21582 a, b, k, l scaled // indices for chopping 21583 reversed bool // was |a>b|? 21584 ) 21585 l = prg.pathLength() 21586 a = *prg.mem[int32(p)+1].int() 21587 b = *prg.mem[int32(p)+2+1].int() 21588 if a <= b { 21589 reversed = false 21590 } else { 21591 reversed = true 21592 k = a 21593 a = b 21594 b = k 21595 } 21596 21597 // Dispense with the cases |a<0| and/or |b>l| 21598 if a < 0 { 21599 if int32(*(*prg.mem[prg.curExp].hh()).b0()) == endpoint { 21600 a = 0 21601 if b < 0 { 21602 b = 0 21603 } 21604 } else { 21605 for { 21606 a = a + l 21607 b = b + l 21608 if a >= 0 { 21609 break 21610 } 21611 } 21612 } 21613 } // a cycle always has length |l>0| 21614 if b > l { 21615 if int32(*(*prg.mem[prg.curExp].hh()).b0()) == endpoint { 21616 b = l 21617 if a > l { 21618 a = l 21619 } 21620 } else { 21621 for a >= l { 21622 a = a - l 21623 b = b - l 21624 } 21625 } 21626 } 21627 q = uint16(prg.curExp) 21628 for a >= 0200000 { 21629 q = *(*prg.mem[q].hh()).rh() 21630 a = a - 0200000 21631 b = b - 0200000 21632 } 21633 if b == a { 21634 if a > 0 { 21635 qq = *(*prg.mem[q].hh()).rh() 21636 prg.splitCubic(q, a*010000, *prg.mem[int32(qq)+1].int(), *prg.mem[int32(qq)+2].int()) 21637 q = *(*prg.mem[q].hh()).rh() 21638 } 21639 pp = prg.copyKnot(q) 21640 qq = pp 21641 } else { 21642 // Construct a path from |pp| to |qq| of length $\lceil b\rceil$ 21643 pp = prg.copyKnot(q) 21644 qq = pp 21645 for { 21646 q = *(*prg.mem[q].hh()).rh() 21647 rr = qq 21648 qq = prg.copyKnot(q) 21649 *(*prg.mem[rr].hh()).rh() = qq 21650 b = b - 0200000 21651 if b <= 0 { 21652 break 21653 } 21654 } 21655 if a > 0 { 21656 ss = pp 21657 pp = *(*prg.mem[pp].hh()).rh() 21658 prg.splitCubic(ss, a*010000, *prg.mem[int32(pp)+1].int(), *prg.mem[int32(pp)+2].int()) 21659 pp = *(*prg.mem[ss].hh()).rh() 21660 prg.freeNode(ss, halfword(knotNodeSize)) 21661 if int32(rr) == int32(ss) { 21662 b = prg.makeScaled(b, 0200000-a) 21663 rr = pp 21664 } 21665 } 21666 if b < 0 { 21667 prg.splitCubic(rr, (b+0200000)*010000, *prg.mem[int32(qq)+1].int(), *prg.mem[int32(qq)+2].int()) 21668 prg.freeNode(qq, halfword(knotNodeSize)) 21669 qq = *(*prg.mem[rr].hh()).rh() 21670 } 21671 } 21672 *(*prg.mem[pp].hh()).b0() = byte(endpoint) 21673 *(*prg.mem[qq].hh()).b1() = byte(endpoint) 21674 *(*prg.mem[qq].hh()).rh() = pp 21675 prg.tossKnotList(halfword(prg.curExp)) 21676 if reversed { 21677 prg.curExp = int32(*(*prg.mem[prg.htapYpoc(pp)].hh()).rh()) 21678 prg.tossKnotList(pp) 21679 } else { 21680 prg.curExp = int32(pp) 21681 } 21682 } 21683 21684 func (prg *prg) pairValue(x, y scaled) { 21685 var ( 21686 p halfword // a pair node 21687 ) 21688 p = prg.getNode(valueNodeSize) 21689 prg.flushCurExp(scaled(p)) 21690 prg.curType = byte(pairType) 21691 *(*prg.mem[p].hh()).b0() = byte(pairType) 21692 *(*prg.mem[p].hh()).b1() = byte(capsule) 21693 prg.initBigNode(p) 21694 p = uint16(*prg.mem[int32(p)+1].int()) 21695 21696 *(*prg.mem[p].hh()).b0() = byte(known) 21697 *prg.mem[int32(p)+1].int() = x 21698 21699 *(*prg.mem[int32(p)+2].hh()).b0() = byte(known) 21700 *prg.mem[int32(p)+2+1].int() = y 21701 21702 } 21703 21704 func (prg *prg) setUpOffset(p halfword) { 21705 prg.findOffset(*prg.mem[int32(p)+1].int(), *prg.mem[int32(p)+2+1].int(), halfword(prg.curExp)) 21706 prg.pairValue(prg.curX, prg.curY) 21707 } 21708 21709 func (prg *prg) setUpDirectionTime(p halfword) { 21710 prg.flushCurExp(prg.findDirectionTime(*prg.mem[int32(p)+1].int(), *prg.mem[int32(p)+2+1].int(), halfword(prg.curExp))) 21711 } 21712 21713 func (prg *prg) findPoint(v scaled, c quarterword) { 21714 var ( 21715 p halfword // the path 21716 n scaled // its length 21717 q halfword // successor of |p| 21718 ) 21719 p = uint16(prg.curExp) 21720 21721 if int32(*(*prg.mem[p].hh()).b0()) == endpoint { 21722 n = -0200000 21723 } else { 21724 n = 0 21725 } 21726 for { 21727 p = *(*prg.mem[p].hh()).rh() 21728 n = n + 0200000 21729 if int32(p) == prg.curExp { 21730 break 21731 } 21732 } 21733 if n == 0 { 21734 v = 0 21735 } else if v < 0 { 21736 if int32(*(*prg.mem[p].hh()).b0()) == endpoint { 21737 v = 0 21738 } else { 21739 v = n - 1 - (-v-1)%n 21740 } 21741 } else if v > n { 21742 if int32(*(*prg.mem[p].hh()).b0()) == endpoint { 21743 v = n 21744 } else { 21745 v = v % n 21746 } 21747 } 21748 p = uint16(prg.curExp) 21749 for v >= 0200000 { 21750 p = *(*prg.mem[p].hh()).rh() 21751 v = v - 0200000 21752 } 21753 if v != 0 { 21754 q = *(*prg.mem[p].hh()).rh() 21755 prg.splitCubic(p, v*010000, *prg.mem[int32(q)+1].int(), *prg.mem[int32(q)+2].int()) 21756 p = *(*prg.mem[p].hh()).rh() 21757 } 21758 21759 // Set the current expression to the desired path coordinates 21760 switch c { 21761 case pointOf: 21762 prg.pairValue(*prg.mem[int32(p)+1].int(), *prg.mem[int32(p)+2].int()) 21763 case precontrolOf: 21764 if int32(*(*prg.mem[p].hh()).b0()) == endpoint { 21765 prg.pairValue(*prg.mem[int32(p)+1].int(), *prg.mem[int32(p)+2].int()) 21766 } else { 21767 prg.pairValue(*prg.mem[int32(p)+3].int(), *prg.mem[int32(p)+4].int()) 21768 } 21769 case postcontrolOf: 21770 if int32(*(*prg.mem[p].hh()).b1()) == endpoint { 21771 prg.pairValue(*prg.mem[int32(p)+1].int(), *prg.mem[int32(p)+2].int()) 21772 } else { 21773 prg.pairValue(*prg.mem[int32(p)+5].int(), *prg.mem[int32(p)+6].int()) 21774 } 21775 } 21776 } 21777 21778 func (prg *prg) doBinary(p halfword, c quarterword) { 21779 var ( 21780 q, r1, rr halfword // for list manipulation 21781 oldP, oldExp halfword // capsules to recycle 21782 v int32 // for numeric manipulation 21783 ) 21784 { 21785 if prg.arithError { 21786 prg.clearArith() 21787 } 21788 } 21789 if prg.internal[tracingCommands-1] > 0400000 { 21790 prg.beginDiagnostic() 21791 prg.printNl(strNumber( /* "[(" */ 850)) 21792 prg.printExp(p, smallNumber(0)) // show the operand, but not verbosely 21793 prg.printChar(asciiCode(')')) 21794 prg.printOp(c) 21795 prg.printChar(asciiCode('(')) 21796 21797 prg.printExp(halfword(memMin), smallNumber(0)) 21798 prg.print( /* ")]" */ 842) 21799 prg.endDiagnostic(false) 21800 } 21801 21802 // Sidestep |independent| cases in capsule |p| 21803 switch *(*prg.mem[p].hh()).b0() { 21804 case transformType, pairType: 21805 oldP = prg.tarnished(p) 21806 case independent: 21807 oldP = uint16(memMin + 1) 21808 21809 default: 21810 oldP = uint16(memMin) 21811 } 21812 if int32(oldP) != memMin { 21813 q = prg.stashCurExp() 21814 oldP = p 21815 prg.makeExpCopy(oldP) 21816 p = prg.stashCurExp() 21817 prg.unstashCurExp(q) 21818 } 21819 21820 // Sidestep |independent| cases in the current expression 21821 switch prg.curType { 21822 case transformType, pairType: 21823 oldExp = prg.tarnished(halfword(prg.curExp)) 21824 case independent: 21825 oldExp = uint16(memMin + 1) 21826 21827 default: 21828 oldExp = uint16(memMin) 21829 } 21830 if int32(oldExp) != memMin { 21831 oldExp = uint16(prg.curExp) 21832 prg.makeExpCopy(oldExp) 21833 } 21834 switch c { 21835 case plus, minus: 21836 // Add or subtract the current expression from |p| 21837 if int32(prg.curType) < pairType || int32(*(*prg.mem[p].hh()).b0()) < pairType { 21838 if int32(prg.curType) == pictureType && int32(*(*prg.mem[p].hh()).b0()) == pictureType { 21839 if int32(c) == minus { 21840 prg.negateEdges(halfword(prg.curExp)) 21841 } 21842 prg.curEdges = uint16(prg.curExp) 21843 prg.mergeEdges(halfword(*prg.mem[int32(p)+1].int())) 21844 } else { 21845 prg.badBinary(p, c) 21846 } 21847 } else if int32(prg.curType) == pairType { 21848 if int32(*(*prg.mem[p].hh()).b0()) != pairType { 21849 prg.badBinary(p, c) 21850 } else { 21851 q = uint16(*prg.mem[int32(p)+1].int()) 21852 r1 = uint16(*prg.mem[prg.curExp+1].int()) 21853 prg.addOrSubtract(q, r1, c) 21854 prg.addOrSubtract(halfword(int32(q)+2), halfword(int32(r1)+2), c) 21855 } 21856 } else if int32(*(*prg.mem[p].hh()).b0()) == pairType { 21857 prg.badBinary(p, c) 21858 } else { 21859 prg.addOrSubtract(p, halfword(memMin), c) 21860 } 21861 21862 // \4 21863 // Additional cases of binary operators 21864 case lessThan, lessOrEqual, greaterThan, greaterOrEqual, 21865 equalTo, unequalTo: 21866 if int32(prg.curType) > pairType && int32(*(*prg.mem[p].hh()).b0()) > pairType { 21867 prg.addOrSubtract(p, halfword(memMin), quarterword(minus)) 21868 } else if int32(prg.curType) != int32(*(*prg.mem[p].hh()).b0()) { 21869 prg.badBinary(p, c) 21870 goto done 21871 } else if int32(prg.curType) == stringType { 21872 prg.flushCurExp(prg.strVsStr(strNumber(*prg.mem[int32(p)+1].int()), strNumber(prg.curExp))) 21873 } else if int32(prg.curType) == unknownString || int32(prg.curType) == unknownBoolean { 21874 q = uint16(*prg.mem[prg.curExp+1].int()) 21875 for int32(q) != prg.curExp && int32(q) != int32(p) { 21876 q = uint16(*prg.mem[int32(q)+1].int()) 21877 } 21878 if int32(q) == int32(p) { 21879 prg.flushCurExp(scaled(0)) 21880 } 21881 } else if int32(prg.curType) == pairType || int32(prg.curType) == transformType { 21882 q = uint16(*prg.mem[int32(p)+1].int()) 21883 r1 = uint16(*prg.mem[prg.curExp+1].int()) 21884 rr = uint16(int32(r1) + int32(prg.bigNodeSize[prg.curType-13]) - 2) 21885 for true { 21886 prg.addOrSubtract(q, r1, quarterword(minus)) 21887 if int32(*(*prg.mem[r1].hh()).b0()) != known { 21888 goto done1 21889 } 21890 if *prg.mem[int32(r1)+1].int() != 0 { 21891 goto done1 21892 } 21893 if int32(r1) == int32(rr) { 21894 goto done1 21895 } 21896 q = uint16(int32(q) + 2) 21897 r1 = uint16(int32(r1) + 2) 21898 } 21899 21900 done1: 21901 prg.takePart(quarterword(xPart + (int32(r1)-*prg.mem[prg.curExp+1].int())/2)) 21902 } else if int32(prg.curType) == booleanType { 21903 prg.flushCurExp(prg.curExp - *prg.mem[int32(p)+1].int()) 21904 } else { 21905 prg.badBinary(p, c) 21906 goto done 21907 } 21908 21909 // Compare the current expression with zero 21910 if int32(prg.curType) != known { 21911 if int32(prg.curType) < known { 21912 prg.dispErr(p, strNumber( /* "" */ 285)) 21913 { 21914 prg.helpPtr = 1 21915 prg.helpLine[0] = /* "The quantities shown above have not been equated." */ 851 21916 } 21917 } else { 21918 prg.helpPtr = 2 21919 prg.helpLine[1] = /* "Oh dear. I can't decide if the expression above is positive," */ 852 21920 prg.helpLine[0] = /* "negative, or zero. So this comparison test won't be `true'." */ 853 21921 } 21922 prg.dispErr(halfword(memMin), strNumber( /* "Unknown relation will be considered false" */ 854)) 21923 // \xref[Unknown relation...] 21924 prg.putGetFlushError(falseCode) 21925 } else { 21926 switch c { 21927 case lessThan: 21928 if prg.curExp < 0 { 21929 prg.curExp = trueCode 21930 } else { 21931 prg.curExp = falseCode 21932 } 21933 case lessOrEqual: 21934 if prg.curExp <= 0 { 21935 prg.curExp = trueCode 21936 } else { 21937 prg.curExp = falseCode 21938 } 21939 case greaterThan: 21940 if prg.curExp > 0 { 21941 prg.curExp = trueCode 21942 } else { 21943 prg.curExp = falseCode 21944 } 21945 case greaterOrEqual: 21946 if prg.curExp >= 0 { 21947 prg.curExp = trueCode 21948 } else { 21949 prg.curExp = falseCode 21950 } 21951 case equalTo: 21952 if prg.curExp == 0 { 21953 prg.curExp = trueCode 21954 } else { 21955 prg.curExp = falseCode 21956 } 21957 case unequalTo: 21958 if prg.curExp != 0 { 21959 prg.curExp = trueCode 21960 } else { 21961 prg.curExp = falseCode 21962 } 21963 } 21964 } // there are no other cases 21965 prg.curType = byte(booleanType) 21966 21967 done: 21968 ; 21969 21970 case andOp, orOp: 21971 if int32(*(*prg.mem[p].hh()).b0()) != booleanType || int32(prg.curType) != booleanType { 21972 prg.badBinary(p, c) 21973 } else if *prg.mem[int32(p)+1].int() == int32(c)+falseCode-andOp { 21974 prg.curExp = *prg.mem[int32(p)+1].int() 21975 } 21976 21977 case times: 21978 if int32(prg.curType) < pairType || int32(*(*prg.mem[p].hh()).b0()) < pairType { 21979 prg.badBinary(p, quarterword(times)) 21980 } else if int32(prg.curType) == known || int32(*(*prg.mem[p].hh()).b0()) == known { 21981 if int32(*(*prg.mem[p].hh()).b0()) == known { 21982 v = *prg.mem[int32(p)+1].int() 21983 prg.freeNode(p, halfword(valueNodeSize)) 21984 } else { 21985 v = prg.curExp 21986 prg.unstashCurExp(p) 21987 } 21988 if int32(prg.curType) == known { 21989 prg.curExp = prg.takeScaled(prg.curExp, v) 21990 } else if int32(prg.curType) == pairType { 21991 p = uint16(*prg.mem[prg.curExp+1].int()) 21992 prg.depMult(p, v, true) 21993 prg.depMult(halfword(int32(p)+2), v, true) 21994 } else { 21995 prg.depMult(halfword(memMin), v, true) 21996 } 21997 21998 goto exit 21999 } else if prg.nicePair(int32(p), *(*prg.mem[p].hh()).b0()) && int32(prg.curType) > pairType || prg.nicePair(prg.curExp, prg.curType) && int32(*(*prg.mem[p].hh()).b0()) > pairType { 22000 prg.hardTimes(p) 22001 goto exit 22002 } else { 22003 prg.badBinary(p, quarterword(times)) 22004 } 22005 22006 case over: 22007 if int32(prg.curType) != known || int32(*(*prg.mem[p].hh()).b0()) < pairType { 22008 prg.badBinary(p, quarterword(over)) 22009 } else { 22010 v = prg.curExp 22011 prg.unstashCurExp(p) 22012 if v == 0 { 22013 prg.dispErr(halfword(memMin), strNumber( /* "Division by zero" */ 784)) 22014 // \xref[Division by zero] 22015 { 22016 prg.helpPtr = 2 22017 prg.helpLine[1] = /* "You're trying to divide the quantity shown above the error" */ 856 22018 prg.helpLine[0] = /* "message by zero. I'm going to divide it by one instead." */ 857 22019 } 22020 prg.putGetError() 22021 } else { 22022 if int32(prg.curType) == known { 22023 prg.curExp = prg.makeScaled(prg.curExp, v) 22024 } else if int32(prg.curType) == pairType { 22025 p = uint16(*prg.mem[prg.curExp+1].int()) 22026 prg.depDiv(p, v) 22027 prg.depDiv(halfword(int32(p)+2), v) 22028 } else { 22029 prg.depDiv(halfword(memMin), v) 22030 } 22031 } 22032 22033 goto exit 22034 } 22035 22036 case pythagAdd, pythagSub: 22037 if int32(prg.curType) == known && int32(*(*prg.mem[p].hh()).b0()) == known { 22038 if int32(c) == pythagAdd { 22039 prg.curExp = prg.pythAdd(*prg.mem[int32(p)+1].int(), prg.curExp) 22040 } else { 22041 prg.curExp = prg.pythSub(*prg.mem[int32(p)+1].int(), prg.curExp) 22042 } 22043 } else { 22044 prg.badBinary(p, c) 22045 } 22046 22047 case rotatedBy, slantedBy, scaledBy, shiftedBy, 22048 transformedBy, xScaled, yScaled, zScaled: // 22049 22050 if int32(*(*prg.mem[p].hh()).b0()) == pathType || int32(*(*prg.mem[p].hh()).b0()) == futurePen || int32(*(*prg.mem[p].hh()).b0()) == penType { 22051 prg.pathTrans(p, c) 22052 goto exit 22053 } else if int32(*(*prg.mem[p].hh()).b0()) == pairType || int32(*(*prg.mem[p].hh()).b0()) == transformType { 22054 prg.bigTrans(p, c) 22055 } else if int32(*(*prg.mem[p].hh()).b0()) == pictureType { 22056 prg.edgesTrans(p, c) 22057 goto exit 22058 } else { 22059 prg.badBinary(p, c) 22060 } 22061 22062 case concatenate: 22063 if int32(prg.curType) == stringType && int32(*(*prg.mem[p].hh()).b0()) == stringType { 22064 prg.cat(p) 22065 } else { 22066 prg.badBinary(p, quarterword(concatenate)) 22067 } 22068 case substringOf: 22069 if prg.nicePair(int32(p), *(*prg.mem[p].hh()).b0()) && int32(prg.curType) == stringType { 22070 prg.chopString(halfword(*prg.mem[int32(p)+1].int())) 22071 } else { 22072 prg.badBinary(p, quarterword(substringOf)) 22073 } 22074 case subpathOf: 22075 if int32(prg.curType) == pairType { 22076 prg.pairToPath() 22077 } 22078 if prg.nicePair(int32(p), *(*prg.mem[p].hh()).b0()) && int32(prg.curType) == pathType { 22079 prg.chopPath(halfword(*prg.mem[int32(p)+1].int())) 22080 } else { 22081 prg.badBinary(p, quarterword(subpathOf)) 22082 } 22083 22084 case pointOf, precontrolOf, postcontrolOf: 22085 if int32(prg.curType) == pairType { 22086 prg.pairToPath() 22087 } 22088 if int32(prg.curType) == pathType && int32(*(*prg.mem[p].hh()).b0()) == known { 22089 prg.findPoint(*prg.mem[int32(p)+1].int(), c) 22090 } else { 22091 prg.badBinary(p, c) 22092 } 22093 22094 case penOffsetOf: 22095 if int32(prg.curType) == futurePen { 22096 prg.materializePen() 22097 } 22098 if int32(prg.curType) == penType && prg.nicePair(int32(p), *(*prg.mem[p].hh()).b0()) { 22099 prg.setUpOffset(halfword(*prg.mem[int32(p)+1].int())) 22100 } else { 22101 prg.badBinary(p, quarterword(penOffsetOf)) 22102 } 22103 22104 case directionTimeOf: 22105 if int32(prg.curType) == pairType { 22106 prg.pairToPath() 22107 } 22108 if int32(prg.curType) == pathType && prg.nicePair(int32(p), *(*prg.mem[p].hh()).b0()) { 22109 prg.setUpDirectionTime(halfword(*prg.mem[int32(p)+1].int())) 22110 } else { 22111 prg.badBinary(p, quarterword(directionTimeOf)) 22112 } 22113 22114 case intersect: 22115 if int32(*(*prg.mem[p].hh()).b0()) == pairType { 22116 q = prg.stashCurExp() 22117 prg.unstashCurExp(p) 22118 prg.pairToPath() 22119 p = prg.stashCurExp() 22120 prg.unstashCurExp(q) 22121 } 22122 if int32(prg.curType) == pairType { 22123 prg.pairToPath() 22124 } 22125 if int32(prg.curType) == pathType && int32(*(*prg.mem[p].hh()).b0()) == pathType { 22126 prg.pathIntersection(halfword(*prg.mem[int32(p)+1].int()), halfword(prg.curExp)) 22127 prg.pairValue(prg.curT, prg.curTt) 22128 } else { 22129 prg.badBinary(p, quarterword(intersect)) 22130 } 22131 22132 } // there are no other cases 22133 prg.recycleValue(p) 22134 prg.freeNode(p, halfword(valueNodeSize)) // |return| to avoid this 22135 // |return| to avoid this 22136 exit: 22137 { 22138 if prg.arithError { 22139 prg.clearArith() 22140 } 22141 } 22142 // Recycle any sidestepped |independent| capsules 22143 if int32(oldP) != memMin { 22144 prg.recycleValue(oldP) 22145 prg.freeNode(oldP, halfword(valueNodeSize)) 22146 } 22147 if int32(oldExp) != memMin { 22148 prg.recycleValue(oldExp) 22149 prg.freeNode(oldExp, halfword(valueNodeSize)) 22150 } 22151 } 22152 22153 // 944. 22154 22155 // tangle:pos ../../mf.web:18630:3: 22156 22157 // Here is a routine that is similar to |times|; but it is invoked only 22158 // internally, when |v| is a |fraction| whose magnitude is at most~1, 22159 // and when |cur_type>=pair_type|. 22160 func (prg *prg) fracMult(n, d scaled) { // multiplies |cur_exp| by |n/d| 22161 var ( 22162 p halfword // a pair node 22163 oldExp halfword // a capsule to recycle 22164 v fraction // |n/d| 22165 ) 22166 if prg.internal[tracingCommands-1] > 0400000 { 22167 prg.beginDiagnostic() 22168 prg.printNl(strNumber( /* "[(" */ 850)) 22169 prg.printScaled(n) 22170 prg.printChar(asciiCode('/')) 22171 prg.printScaled(d) 22172 prg.print( /* ")*(" */ 855) 22173 prg.printExp(halfword(memMin), smallNumber(0)) 22174 prg.print( /* ")]" */ 842) 22175 prg.endDiagnostic(false) 22176 } 22177 switch prg.curType { 22178 case transformType, pairType: 22179 oldExp = prg.tarnished(halfword(prg.curExp)) 22180 case independent: 22181 oldExp = uint16(memMin + 1) 22182 22183 default: 22184 oldExp = uint16(memMin) 22185 } 22186 if int32(oldExp) != memMin { 22187 oldExp = uint16(prg.curExp) 22188 prg.makeExpCopy(oldExp) 22189 } 22190 v = prg.makeFraction(n, d) 22191 if int32(prg.curType) == known { 22192 prg.curExp = prg.takeFraction(prg.curExp, v) 22193 } else if int32(prg.curType) == pairType { 22194 p = uint16(*prg.mem[prg.curExp+1].int()) 22195 prg.depMult(p, v, false) 22196 prg.depMult(halfword(int32(p)+2), v, false) 22197 } else { 22198 prg.depMult(halfword(memMin), v, false) 22199 } 22200 if int32(oldExp) != memMin { 22201 prg.recycleValue(oldExp) 22202 prg.freeNode(oldExp, halfword(valueNodeSize)) 22203 } 22204 } 22205 22206 // 989. \[43] Statements and commands 22207 22208 // tangle:pos ../../mf.web:19313:34: 22209 22210 // The chief executive of \MF\ is the |do_statement| routine, which 22211 // contains the master switch that causes all the various pieces of \MF\ 22212 // to do their things, in the right order. 22213 // 22214 // In a sense, this is the grand climax of the program: It applies all the 22215 // tools that we have worked so hard to construct. In another sense, this is 22216 // the messiest part of the program: It necessarily refers to other pieces 22217 // of code all over the place, so that a person can't fully understand what is 22218 // going on without paging back and forth to be reminded of conventions that 22219 // are defined elsewhere. We are now at the hub of the web. 22220 // 22221 // The structure of |do_statement| itself is quite simple. The first token 22222 // of the statement is fetched using |get_x_next|. If it can be the first 22223 // token of an expression, we look for an equation, an assignment, or a 22224 // title. Otherwise we use a \&[case] construction to branch at high speed to 22225 // the appropriate routine for various and sundry other types of commands, 22226 // each of which has an “action procedure” that does the necessary work. 22227 // 22228 // The program uses the fact that 22229 // $$\hbox[|min_primary_command=max_statement_command=type_name|]$$ 22230 // to interpret a statement that starts with, e.g., `\&[string]', 22231 // as a type declaration rather than a boolean expression. 22232 // \4 22233 // Declare generic font output procedures 22234 func (prg *prg) writeGf(a, b gfIndex) { 22235 var ( 22236 k gfIndex 22237 ) 22238 for ii := int32(a); ii <= int32(b); ii++ { 22239 k = gfIndex(ii) 22240 _ = k 22241 prg.gfFile.Write(prg.gfBuf[k]) 22242 } 22243 } 22244 22245 func (prg *prg) gfSwap() { 22246 if int32(prg.gfLimit) == gfBufSize { 22247 prg.writeGf(gfIndex(0), gfIndex(int32(prg.halfBuf)-1)) 22248 prg.gfLimit = prg.halfBuf 22249 prg.gfOffset = prg.gfOffset + gfBufSize 22250 prg.gfPtr = 0 22251 } else { 22252 prg.writeGf(prg.halfBuf, gfIndex(gfBufSize-1)) 22253 prg.gfLimit = byte(gfBufSize) 22254 } 22255 } 22256 22257 func (prg *prg) gfFour(x int32) { 22258 if x >= 0 { 22259 prg.gfBuf[prg.gfPtr] = byte(x / 0100000000) 22260 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22261 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22262 prg.gfSwap() 22263 } 22264 } else { 22265 x = x + 010000000000 22266 x = x + 010000000000 22267 { 22268 prg.gfBuf[prg.gfPtr] = byte(x/0100000000 + 128) 22269 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22270 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22271 prg.gfSwap() 22272 } 22273 } 22274 } 22275 x = x % 0100000000 22276 { 22277 prg.gfBuf[prg.gfPtr] = byte(x / 0200000) 22278 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22279 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22280 prg.gfSwap() 22281 } 22282 } 22283 x = x % 0200000 22284 { 22285 prg.gfBuf[prg.gfPtr] = byte(x / 0400) 22286 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22287 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22288 prg.gfSwap() 22289 } 22290 } 22291 { 22292 prg.gfBuf[prg.gfPtr] = byte(x % 0400) 22293 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22294 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22295 prg.gfSwap() 22296 } 22297 } 22298 } 22299 22300 func (prg *prg) gfTwo(x int32) { 22301 { 22302 prg.gfBuf[prg.gfPtr] = byte(x / 0400) 22303 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22304 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22305 prg.gfSwap() 22306 } 22307 } 22308 { 22309 prg.gfBuf[prg.gfPtr] = byte(x % 0400) 22310 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22311 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22312 prg.gfSwap() 22313 } 22314 } 22315 } 22316 22317 func (prg *prg) gfThree(x int32) { 22318 { 22319 prg.gfBuf[prg.gfPtr] = byte(x / 0200000) 22320 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22321 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22322 prg.gfSwap() 22323 } 22324 } 22325 { 22326 prg.gfBuf[prg.gfPtr] = byte(x % 0200000 / 0400) 22327 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22328 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22329 prg.gfSwap() 22330 } 22331 } 22332 { 22333 prg.gfBuf[prg.gfPtr] = byte(x % 0400) 22334 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22335 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22336 prg.gfSwap() 22337 } 22338 } 22339 } 22340 22341 func (prg *prg) gfPaint(d int32) { 22342 if d < 64 { 22343 prg.gfBuf[prg.gfPtr] = byte(paint0 + d) 22344 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22345 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22346 prg.gfSwap() 22347 } 22348 } else if d < 256 { 22349 { 22350 prg.gfBuf[prg.gfPtr] = byte(paint1) 22351 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22352 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22353 prg.gfSwap() 22354 } 22355 } 22356 { 22357 prg.gfBuf[prg.gfPtr] = byte(d) 22358 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22359 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22360 prg.gfSwap() 22361 } 22362 } 22363 } else { 22364 { 22365 prg.gfBuf[prg.gfPtr] = byte(paint1 + 1) 22366 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22367 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22368 prg.gfSwap() 22369 } 22370 } 22371 prg.gfTwo(d) 22372 } 22373 } 22374 22375 func (prg *prg) gfString(s, t strNumber) { 22376 var ( 22377 k poolPointer 22378 l int32 // length of the strings to output 22379 ) 22380 if int32(s) != 0 { 22381 l = int32(prg.strStart[int32(s)+1]) - int32(prg.strStart[s]) 22382 if int32(t) != 0 { 22383 l = l + (int32(prg.strStart[int32(t)+1]) - int32(prg.strStart[t])) 22384 } 22385 if l <= 255 { 22386 { 22387 prg.gfBuf[prg.gfPtr] = byte(xxx1) 22388 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22389 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22390 prg.gfSwap() 22391 } 22392 } 22393 { 22394 prg.gfBuf[prg.gfPtr] = byte(l) 22395 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22396 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22397 prg.gfSwap() 22398 } 22399 } 22400 } else { 22401 { 22402 prg.gfBuf[prg.gfPtr] = byte(xxx3) 22403 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22404 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22405 prg.gfSwap() 22406 } 22407 } 22408 prg.gfThree(l) 22409 } 22410 for ii := int32(prg.strStart[s]); ii <= int32(prg.strStart[int32(s)+1])-1; ii++ { 22411 k = poolPointer(ii) 22412 _ = k 22413 prg.gfBuf[prg.gfPtr] = prg.strPool[k] 22414 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22415 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22416 prg.gfSwap() 22417 } 22418 } 22419 } 22420 if int32(t) != 0 { 22421 for ii := int32(prg.strStart[t]); ii <= int32(prg.strStart[int32(t)+1])-1; ii++ { 22422 k = poolPointer(ii) 22423 _ = k 22424 prg.gfBuf[prg.gfPtr] = prg.strPool[k] 22425 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22426 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22427 prg.gfSwap() 22428 } 22429 } 22430 } 22431 } 22432 22433 func (prg *prg) gfBoc(minM, maxM, minN, maxN int32) { 22434 if minM < prg.gfMinM { 22435 prg.gfMinM = minM 22436 } 22437 if maxN > prg.gfMaxN { 22438 prg.gfMaxN = maxN 22439 } 22440 if prg.bocP == -1 { 22441 if prg.bocC >= 0 { 22442 if prg.bocC < 256 { 22443 if maxM-minM >= 0 { 22444 if maxM-minM < 256 { 22445 if maxM >= 0 { 22446 if maxM < 256 { 22447 if maxN-minN >= 0 { 22448 if maxN-minN < 256 { 22449 if maxN >= 0 { 22450 if maxN < 256 { 22451 { 22452 prg.gfBuf[prg.gfPtr] = byte(boc1) 22453 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22454 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22455 prg.gfSwap() 22456 } 22457 } 22458 { 22459 prg.gfBuf[prg.gfPtr] = byte(prg.bocC) 22460 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22461 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22462 prg.gfSwap() 22463 } 22464 } 22465 22466 { 22467 prg.gfBuf[prg.gfPtr] = byte(maxM - minM) 22468 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22469 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22470 prg.gfSwap() 22471 } 22472 } 22473 { 22474 prg.gfBuf[prg.gfPtr] = byte(maxM) 22475 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22476 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22477 prg.gfSwap() 22478 } 22479 } 22480 { 22481 prg.gfBuf[prg.gfPtr] = byte(maxN - minN) 22482 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22483 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22484 prg.gfSwap() 22485 } 22486 } 22487 { 22488 prg.gfBuf[prg.gfPtr] = byte(maxN) 22489 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22490 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22491 prg.gfSwap() 22492 } 22493 } 22494 goto exit 22495 } 22496 } 22497 } 22498 } 22499 } 22500 } 22501 } 22502 } 22503 } 22504 } 22505 } 22506 { 22507 prg.gfBuf[prg.gfPtr] = byte(boc) 22508 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22509 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22510 prg.gfSwap() 22511 } 22512 } 22513 prg.gfFour(prg.bocC) 22514 prg.gfFour(prg.bocP) 22515 22516 prg.gfFour(minM) 22517 prg.gfFour(maxM) 22518 prg.gfFour(minN) 22519 prg.gfFour(maxN) 22520 22521 exit: 22522 } 22523 22524 func (prg *prg) initGf() { 22525 var ( 22526 k eightBits // runs through all possible character codes 22527 t int32 // the time of this run 22528 ) 22529 prg.gfMinM = 4096 22530 prg.gfMaxM = -4096 22531 prg.gfMinN = 4096 22532 prg.gfMaxN = -4096 22533 for ii := int32(0); ii <= 255; ii++ { 22534 k = eightBits(ii) 22535 _ = k 22536 prg.charPtr[k] = -1 22537 } 22538 22539 // Determine the file extension, |gf_ext| 22540 if prg.internal[hppp-1] <= 0 { 22541 prg.gfExt = /* ".gf" */ 1054 22542 } else { 22543 prg.oldSetting = prg.selector 22544 prg.selector = byte(newString) 22545 prg.printChar(asciiCode('.')) 22546 prg.printInt(prg.makeScaled(prg.internal[hppp-1], 59429463)) 22547 // $2^[32]/72.27\approx59429463.07$ 22548 prg.print( /* "gf" */ 1055) 22549 prg.gfExt = prg.makeString() 22550 prg.selector = prg.oldSetting 22551 } 22552 { 22553 if int32(prg.jobName) == 0 { 22554 prg.openLogFile() 22555 } 22556 prg.packJobName(prg.gfExt) 22557 for !prg.bOpenOut(prg.gfFile) { 22558 prg.promptFileName(strNumber( /* "file name for output" */ 756), prg.gfExt) 22559 } 22560 prg.outputFileName = prg.bMakeNameString(prg.gfFile) 22561 } 22562 { 22563 prg.gfBuf[prg.gfPtr] = byte(pre) 22564 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22565 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22566 prg.gfSwap() 22567 } 22568 } 22569 { 22570 prg.gfBuf[prg.gfPtr] = byte(gfIdByte) 22571 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22572 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22573 prg.gfSwap() 22574 } 22575 } // begin to output the preamble 22576 prg.oldSetting = prg.selector 22577 prg.selector = byte(newString) 22578 prg.print( /* " METAFONT output " */ 1053) 22579 prg.printInt(prg.roundUnscaled(prg.internal[year-1])) 22580 prg.printChar(asciiCode('.')) 22581 prg.printDd(prg.roundUnscaled(prg.internal[month-1])) 22582 prg.printChar(asciiCode('.')) 22583 prg.printDd(prg.roundUnscaled(prg.internal[day-1])) 22584 prg.printChar(asciiCode(':')) 22585 22586 t = prg.roundUnscaled(prg.internal[time-1]) 22587 prg.printDd(t / 60) 22588 prg.printDd(t % 60) 22589 22590 prg.selector = prg.oldSetting 22591 { 22592 prg.gfBuf[prg.gfPtr] = byte(int32(prg.poolPtr) - int32(prg.strStart[prg.strPtr])) 22593 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22594 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22595 prg.gfSwap() 22596 } 22597 } 22598 prg.gfString(strNumber(0), prg.makeString()) 22599 prg.strPtr = uint16(int32(prg.strPtr) - 1) 22600 prg.poolPtr = prg.strStart[prg.strPtr] // flush that string from memory 22601 prg.gfPrevPtr = prg.gfOffset + int32(prg.gfPtr) 22602 } 22603 22604 func (prg *prg) shipOut(c eightBits) { 22605 var ( 22606 f int32 // current character extension 22607 prevM, m, mm int32 // previous and current pixel column numbers 22608 prevN, n int32 // previous and current pixel row numbers 22609 p, q halfword // for list traversal 22610 prevW, w, ww int32 // old and new weights 22611 d int32 // data from edge-weight node 22612 delta int32 // number of rows to skip 22613 curMinM int32 // starting column, relative to the current offset 22614 xOff, yOff int32 // offsets, rounded to integers 22615 ) 22616 if int32(prg.outputFileName) == 0 { 22617 prg.initGf() 22618 } 22619 f = prg.roundUnscaled(prg.internal[charExt-1]) 22620 22621 xOff = prg.roundUnscaled(prg.internal[xOffset-1]) 22622 yOff = prg.roundUnscaled(prg.internal[yOffset-1]) 22623 if int32(prg.termOffset) > maxPrintLine-9 { 22624 prg.printLn() 22625 } else if int32(prg.termOffset) > 0 || int32(prg.fileOffset) > 0 { 22626 prg.printChar(asciiCode(' ')) 22627 } 22628 prg.printChar(asciiCode('[')) 22629 prg.printInt(int32(c)) 22630 if f != 0 { 22631 prg.printChar(asciiCode('.')) 22632 prg.printInt(f) 22633 } 22634 22635 prg.bocC = 256*f + int32(c) 22636 prg.bocP = prg.charPtr[c] 22637 prg.charPtr[c] = prg.gfPrevPtr 22638 22639 if prg.internal[proofing-1] > 0 { 22640 if xOff != 0 { 22641 prg.gfString(strNumber( /* "xoffset" */ 438), strNumber(0)) 22642 { 22643 prg.gfBuf[prg.gfPtr] = byte(yyy) 22644 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22645 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22646 prg.gfSwap() 22647 } 22648 } 22649 prg.gfFour(xOff * 0200000) 22650 } 22651 if yOff != 0 { 22652 prg.gfString(strNumber( /* "yoffset" */ 439), strNumber(0)) 22653 { 22654 prg.gfBuf[prg.gfPtr] = byte(yyy) 22655 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22656 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22657 prg.gfSwap() 22658 } 22659 } 22660 prg.gfFour(yOff * 0200000) 22661 } 22662 } 22663 22664 // Output the character represented in |cur_edges| 22665 prevN = 4096 22666 p = *(*prg.mem[prg.curEdges].hh()).lh() 22667 n = int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).rh()) - zeroField 22668 for int32(p) != int32(prg.curEdges) { 22669 if int32(*(*prg.mem[int32(p)+1].hh()).lh()) > memMin+1 { 22670 prg.sortEdges(p) 22671 } 22672 q = *(*prg.mem[int32(p)+1].hh()).rh() 22673 w = 0 22674 prevM = -02000000000 // $|fraction_one|\approx\infty$ 22675 ww = 0 22676 prevW = 0 22677 m = prevM 22678 for { 22679 if int32(q) == 3000 { 22680 mm = 02000000000 22681 } else { 22682 d = int32(*(*prg.mem[q].hh()).lh()) - 0 22683 mm = d / 8 22684 ww = ww + d%8 - zeroW 22685 } 22686 if mm != m { 22687 if prevW <= 0 { 22688 if w > 0 { 22689 if prevM == -02000000000 { 22690 if prevN == 4096 { 22691 prg.gfBoc(int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh())+xOff-zeroField, int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).rh())+xOff-zeroField, int32(*(*prg.mem[int32(prg.curEdges)+1].hh()).lh())+yOff-zeroField, n+yOff) 22692 curMinM = int32(*(*prg.mem[int32(prg.curEdges)+2].hh()).lh()) - zeroField + int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) 22693 } else if prevN > n+1 { 22694 delta = prevN - n - 1 22695 if delta < 0400 { 22696 { 22697 prg.gfBuf[prg.gfPtr] = byte(skip1) 22698 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22699 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22700 prg.gfSwap() 22701 } 22702 } 22703 { 22704 prg.gfBuf[prg.gfPtr] = byte(delta) 22705 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22706 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22707 prg.gfSwap() 22708 } 22709 } 22710 } else { 22711 { 22712 prg.gfBuf[prg.gfPtr] = byte(skip1 + 1) 22713 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22714 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22715 prg.gfSwap() 22716 } 22717 } 22718 prg.gfTwo(delta) 22719 } 22720 } else { 22721 // Skip to column $m$ in the next row and |goto done|, or skip zero rows 22722 delta = m - curMinM 22723 if delta > maxNewRow { 22724 prg.gfBuf[prg.gfPtr] = byte(skip0) 22725 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22726 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22727 prg.gfSwap() 22728 } 22729 } else { 22730 { 22731 prg.gfBuf[prg.gfPtr] = byte(newRow0 + delta) 22732 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22733 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22734 prg.gfSwap() 22735 } 22736 } 22737 goto done 22738 } 22739 } 22740 prg.gfPaint(m - curMinM) // skip to column $m$, painting white 22741 // skip to column $m$, painting white 22742 done: 22743 prevN = n 22744 } else { 22745 prg.gfPaint(m - prevM) 22746 } 22747 prevM = m 22748 prevW = w 22749 } 22750 } else if w <= 0 { 22751 prg.gfPaint(m - prevM) 22752 prevM = m 22753 prevW = w 22754 } 22755 m = mm 22756 } 22757 w = ww 22758 q = *(*prg.mem[q].hh()).rh() 22759 if mm == 02000000000 { 22760 break 22761 } 22762 } 22763 if w != 0 { 22764 prg.printNl(strNumber( /* "(There's unbounded black in character shipped out!)" */ 1057)) 22765 } 22766 // \xref[There's unbounded black...] 22767 if prevM-int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh())+xOff > prg.gfMaxM { 22768 prg.gfMaxM = prevM - int32(*(*prg.mem[int32(prg.curEdges)+3].hh()).lh()) + xOff 22769 } 22770 p = *(*prg.mem[p].hh()).lh() 22771 n = n - 1 22772 } 22773 if prevN == 4096 { 22774 prg.gfBoc(0, 0, 0, 0) 22775 if prg.gfMaxM < 0 { 22776 prg.gfMaxM = 0 22777 } 22778 if prg.gfMinN > 0 { 22779 prg.gfMinN = 0 22780 } 22781 } else if prevN+yOff < prg.gfMinN { 22782 prg.gfMinN = prevN + yOff 22783 } 22784 { 22785 prg.gfBuf[prg.gfPtr] = byte(eoc) 22786 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 22787 if int32(prg.gfPtr) == int32(prg.gfLimit) { 22788 prg.gfSwap() 22789 } 22790 } 22791 prg.gfPrevPtr = prg.gfOffset + int32(prg.gfPtr) 22792 prg.totalChars = prg.totalChars + 1 22793 prg.printChar(asciiCode(']')) // progress report 22794 if prg.internal[tracingOutput-1] > 0 { 22795 prg.printEdges(strNumber( /* " (just shipped out)" */ 1056), true, xOff, yOff) 22796 } 22797 } 22798 22799 // \4 22800 // Declare action procedures for use by |do_statement| 22801 // \4 22802 // Declare the procedure called |try_eq| 22803 func (prg *prg) tryEq(l, r1 halfword) { 22804 var ( 22805 p halfword // dependency list for right operand minus left operand 22806 t/* known..independent */ byte // the type of list |p| 22807 q halfword // the constant term of |p| is here 22808 pp halfword // dependency list for right operand 22809 tt/* dependent..independent */ byte // the type of list |pp| 22810 copied bool // have we copied a list that ought to be recycled? 22811 ) 22812 t = *(*prg.mem[l].hh()).b0() 22813 if int32(t) == known { 22814 t = byte(dependent) 22815 p = prg.constDependency(-*prg.mem[int32(l)+1].int()) 22816 q = p 22817 } else if int32(t) == independent { 22818 t = byte(dependent) 22819 p = prg.singleDependency(l) 22820 *prg.mem[int32(p)+1].int() = -*prg.mem[int32(p)+1].int() 22821 q = prg.depFinal 22822 } else { 22823 p = *(*prg.mem[int32(l)+1].hh()).rh() 22824 q = p 22825 for true { 22826 *prg.mem[int32(q)+1].int() = -*prg.mem[int32(q)+1].int() 22827 if int32(*(*prg.mem[q].hh()).lh()) == memMin { 22828 goto done 22829 } 22830 q = *(*prg.mem[q].hh()).rh() 22831 } 22832 22833 done: 22834 *(*prg.mem[*(*prg.mem[int32(l)+1].hh()).lh()].hh()).rh() = *(*prg.mem[q].hh()).rh() 22835 *(*prg.mem[int32(*(*prg.mem[q].hh()).rh())+1].hh()).lh() = *(*prg.mem[int32(l)+1].hh()).lh() 22836 *(*prg.mem[l].hh()).b0() = byte(known) 22837 } 22838 22839 // Add the right operand to list |p| 22840 if int32(r1) == memMin { 22841 if int32(prg.curType) == known { 22842 *prg.mem[int32(q)+1].int() = *prg.mem[int32(q)+1].int() + prg.curExp 22843 goto done1 22844 } else { 22845 tt = prg.curType 22846 if int32(tt) == independent { 22847 pp = prg.singleDependency(halfword(prg.curExp)) 22848 } else { 22849 pp = *(*prg.mem[prg.curExp+1].hh()).rh() 22850 } 22851 } 22852 } else if int32(*(*prg.mem[r1].hh()).b0()) == known { 22853 *prg.mem[int32(q)+1].int() = *prg.mem[int32(q)+1].int() + *prg.mem[int32(r1)+1].int() 22854 goto done1 22855 } else { 22856 tt = *(*prg.mem[r1].hh()).b0() 22857 if int32(tt) == independent { 22858 pp = prg.singleDependency(r1) 22859 } else { 22860 pp = *(*prg.mem[int32(r1)+1].hh()).rh() 22861 } 22862 } 22863 if int32(tt) != independent { 22864 copied = false 22865 } else { 22866 copied = true 22867 tt = byte(dependent) 22868 } 22869 22870 // Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t| 22871 prg.watchCoefs = false 22872 if int32(t) == int32(tt) { 22873 p = prg.pPlusQ(p, pp, t) 22874 } else if int32(t) == protoDependent { 22875 p = prg.pPlusFq(p, 0200000, pp, smallNumber(protoDependent), smallNumber(dependent)) 22876 } else { 22877 q = p 22878 for int32(*(*prg.mem[q].hh()).lh()) != memMin { 22879 *prg.mem[int32(q)+1].int() = prg.roundFraction(*prg.mem[int32(q)+1].int()) 22880 q = *(*prg.mem[q].hh()).rh() 22881 } 22882 t = byte(protoDependent) 22883 p = prg.pPlusQ(p, pp, t) 22884 } 22885 prg.watchCoefs = true 22886 22887 if copied { 22888 prg.flushNodeList(pp) 22889 } 22890 22891 done1: 22892 ; 22893 if int32(*(*prg.mem[p].hh()).lh()) == memMin { 22894 if abs(*prg.mem[int32(p)+1].int()) > 64 { 22895 { 22896 if int32(prg.interaction) == errorStopMode { 22897 } 22898 prg.printNl(strNumber( /* "! " */ 261)) 22899 prg.print( /* "Inconsistent equation" */ 897) /* \xref[!\relax] */ 22900 } 22901 22902 // \xref[Inconsistent equation] 22903 prg.print( /* " (off by " */ 899) 22904 prg.printScaled(*prg.mem[int32(p)+1].int()) 22905 prg.printChar(asciiCode(')')) 22906 { 22907 prg.helpPtr = 2 22908 prg.helpLine[1] = /* "The equation I just read contradicts what was said before." */ 898 22909 prg.helpLine[0] = /* "But don't worry; continue and I'll just ignore it." */ 896 22910 } 22911 prg.putGetError() 22912 } else if int32(r1) == memMin { 22913 { 22914 if int32(prg.interaction) == errorStopMode { 22915 } 22916 prg.printNl(strNumber( /* "! " */ 261)) 22917 prg.print( /* "Redundant equation" */ 599) /* \xref[!\relax] */ 22918 } 22919 22920 // \xref[Redundant equation] 22921 { 22922 prg.helpPtr = 2 22923 prg.helpLine[1] = /* "I already knew that this equation was true." */ 600 22924 prg.helpLine[0] = /* "But perhaps no harm has been done; let's continue." */ 601 22925 } 22926 22927 prg.putGetError() 22928 } 22929 prg.freeNode(p, halfword(depNodeSize)) 22930 } else { 22931 prg.linearEq(p, t) 22932 if int32(r1) == memMin { 22933 if int32(prg.curType) != known { 22934 if int32(*(*prg.mem[prg.curExp].hh()).b0()) == known { 22935 pp = uint16(prg.curExp) 22936 prg.curExp = *prg.mem[prg.curExp+1].int() 22937 prg.curType = byte(known) 22938 prg.freeNode(pp, halfword(valueNodeSize)) 22939 } 22940 } 22941 } 22942 } 22943 } 22944 22945 // \4 22946 // Declare the procedure called |make_eq| 22947 func (prg *prg) makeEq(lhs halfword) { 22948 var ( 22949 t smallNumber // type of the left-hand side 22950 v int32 // value of the left-hand side 22951 p, q halfword // pointers inside of big nodes 22952 ) 22953 restart: 22954 t = *(*prg.mem[lhs].hh()).b0() 22955 if int32(t) <= pairType { 22956 v = *prg.mem[int32(lhs)+1].int() 22957 } 22958 switch t { 22959 case booleanType, stringType, penType, pathType, 22960 pictureType: 22961 if int32(prg.curType) == int32(t)+unknownTag { 22962 prg.nonlinearEq(v, halfword(prg.curExp), false) 22963 prg.unstashCurExp(halfword(prg.curExp)) 22964 goto done 22965 } else if int32(prg.curType) == int32(t) { 22966 if int32(prg.curType) <= stringType { 22967 if int32(prg.curType) == stringType { 22968 if prg.strVsStr(strNumber(v), strNumber(prg.curExp)) != 0 { 22969 goto notFound 22970 } 22971 } else if v != prg.curExp { 22972 goto notFound 22973 } 22974 22975 // Exclaim about a redundant equation 22976 { 22977 { 22978 if int32(prg.interaction) == errorStopMode { 22979 } 22980 prg.printNl(strNumber( /* "! " */ 261)) 22981 prg.print( /* "Redundant equation" */ 599) /* \xref[!\relax] */ 22982 } 22983 22984 // \xref[Redundant equation] 22985 { 22986 prg.helpPtr = 2 22987 prg.helpLine[1] = /* "I already knew that this equation was true." */ 600 22988 prg.helpLine[0] = /* "But perhaps no harm has been done; let's continue." */ 601 22989 } 22990 22991 prg.putGetError() 22992 } 22993 goto done 22994 } 22995 { 22996 if int32(prg.interaction) == errorStopMode { 22997 } 22998 prg.printNl(strNumber( /* "! " */ 261)) 22999 prg.print( /* "Redundant or inconsistent equation" */ 894) /* \xref[!\relax] */ 23000 } 23001 // \xref[Redundant or inconsistent equation] 23002 { 23003 prg.helpPtr = 2 23004 prg.helpLine[1] = /* "An equation between already-known quantities can't help." */ 895 23005 prg.helpLine[0] = /* "But don't worry; continue and I'll just ignore it." */ 896 23006 } 23007 prg.putGetError() 23008 goto done 23009 23010 notFound: 23011 { 23012 if int32(prg.interaction) == errorStopMode { 23013 } 23014 prg.printNl(strNumber( /* "! " */ 261)) 23015 prg.print( /* "Inconsistent equation" */ 897) /* \xref[!\relax] */ 23016 } 23017 // \xref[Inconsistent equation] 23018 { 23019 prg.helpPtr = 2 23020 prg.helpLine[1] = /* "The equation I just read contradicts what was said before." */ 898 23021 prg.helpLine[0] = /* "But don't worry; continue and I'll just ignore it." */ 896 23022 } 23023 prg.putGetError() 23024 goto done 23025 } 23026 23027 case unknownBoolean, unknownString, unknownPen, unknownPicture, 23028 unknownPath: 23029 if int32(prg.curType) == int32(t)-unknownTag { 23030 prg.nonlinearEq(prg.curExp, lhs, true) 23031 goto done 23032 } else if int32(prg.curType) == int32(t) { 23033 prg.ringMerge(lhs, halfword(prg.curExp)) 23034 goto done 23035 } else if int32(prg.curType) == pairType { 23036 if int32(t) == unknownPath { 23037 prg.pairToPath() 23038 goto restart 23039 } 23040 } 23041 case transformType, pairType: 23042 if int32(prg.curType) == int32(t) { 23043 p = uint16(v + int32(prg.bigNodeSize[t-13])) 23044 q = uint16(*prg.mem[prg.curExp+1].int() + int32(prg.bigNodeSize[t-13])) 23045 for { 23046 p = uint16(int32(p) - 2) 23047 q = uint16(int32(q) - 2) 23048 prg.tryEq(p, q) 23049 if int32(p) == v { 23050 break 23051 } 23052 } 23053 23054 goto done 23055 } 23056 23057 case known, dependent, protoDependent, independent: 23058 if int32(prg.curType) >= known { 23059 prg.tryEq(lhs, halfword(memMin)) 23060 goto done 23061 } 23062 case vacuous: 23063 23064 } // all cases have been listed 23065 23066 // Announce that the equation cannot be performed 23067 prg.dispErr(lhs, strNumber( /* "" */ 285)) 23068 prg.dispErr(halfword(memMin), strNumber( /* "Equation cannot be performed (" */ 891)) 23069 // \xref[Equation cannot be performed] 23070 if int32(*(*prg.mem[lhs].hh()).b0()) <= pairType { 23071 prg.printType(*(*prg.mem[lhs].hh()).b0()) 23072 } else { 23073 prg.print( /* "numeric" */ 341) 23074 } 23075 prg.printChar(asciiCode('=')) 23076 if int32(prg.curType) <= pairType { 23077 prg.printType(prg.curType) 23078 } else { 23079 prg.print( /* "numeric" */ 341) 23080 } 23081 prg.printChar(asciiCode(')')) 23082 23083 { 23084 prg.helpPtr = 2 23085 prg.helpLine[1] = /* "I'm sorry, but I don't know how to make such things equal." */ 892 23086 prg.helpLine[0] = /* "(See the two expressions just above the error message.)" */ 893 23087 } 23088 prg.putGetError() 23089 23090 done: 23091 { 23092 if prg.arithError { 23093 prg.clearArith() 23094 } 23095 } 23096 prg.recycleValue(lhs) 23097 prg.freeNode(lhs, halfword(valueNodeSize)) 23098 } // \2 23099 23100 func (prg *prg) doEquation() { 23101 var ( 23102 lhs halfword // capsule for the left-hand side 23103 p halfword // temporary register 23104 ) 23105 lhs = prg.stashCurExp() 23106 prg.getXNext() 23107 prg.varFlag = byte(assignment) 23108 prg.scanExpression() 23109 if int32(prg.curCmd) == equals { 23110 prg.doEquation() 23111 } else if int32(prg.curCmd) == assignment { 23112 prg.doAssignment() 23113 } 23114 if prg.internal[tracingCommands-1] > 0400000 { 23115 prg.beginDiagnostic() 23116 prg.printNl(strNumber( /* "[(" */ 850)) 23117 prg.printExp(lhs, smallNumber(0)) 23118 prg.print( /* ")=(" */ 886) 23119 prg.printExp(halfword(memMin), smallNumber(0)) 23120 prg.print( /* ")]" */ 842) 23121 prg.endDiagnostic(false) 23122 } 23123 if int32(prg.curType) == unknownPath { 23124 if int32(*(*prg.mem[lhs].hh()).b0()) == pairType { 23125 p = prg.stashCurExp() 23126 prg.unstashCurExp(lhs) 23127 lhs = p 23128 } 23129 } // in this case |make_eq| will change the pair to a path 23130 prg.makeEq(lhs) // equate |lhs| to |(cur_type,cur_exp)| 23131 } 23132 23133 func (prg *prg) doAssignment() { 23134 var ( 23135 lhs halfword // token list for the left-hand side 23136 p halfword // where the left-hand value is stored 23137 q halfword // temporary capsule for the right-hand value 23138 ) 23139 if int32(prg.curType) != tokenList { 23140 prg.dispErr(halfword(memMin), strNumber( /* "Improper `:=' will be changed to `='" */ 883)) 23141 // \xref[Improper `:='] 23142 { 23143 prg.helpPtr = 2 23144 prg.helpLine[1] = /* "I didn't find a variable name at the left of the `:='," */ 884 23145 prg.helpLine[0] = /* "so I'm going to pretend that you said `=' instead." */ 885 23146 } 23147 23148 prg.error1() 23149 prg.doEquation() 23150 } else { 23151 lhs = uint16(prg.curExp) 23152 prg.curType = byte(vacuous) 23153 23154 prg.getXNext() 23155 prg.varFlag = byte(assignment) 23156 prg.scanExpression() 23157 if int32(prg.curCmd) == equals { 23158 prg.doEquation() 23159 } else if int32(prg.curCmd) == assignment { 23160 prg.doAssignment() 23161 } 23162 if prg.internal[tracingCommands-1] > 0400000 { 23163 prg.beginDiagnostic() 23164 prg.printNl(strNumber('{')) 23165 if int32(*(*prg.mem[lhs].hh()).lh()) > hashBase+hashSize+12 { 23166 prg.slowPrint(int32(prg.intName[int32(*(*prg.mem[lhs].hh()).lh())-(hashBase+hashSize+12)-1])) 23167 } else { 23168 prg.showTokenList(int32(lhs), memMin, 1000, 0) 23169 } 23170 prg.print( /* ":=" */ 461) 23171 prg.printExp(halfword(memMin), smallNumber(0)) 23172 prg.printChar(asciiCode('}')) 23173 prg.endDiagnostic(false) 23174 } 23175 if int32(*(*prg.mem[lhs].hh()).lh()) > hashBase+hashSize+12 { 23176 if int32(prg.curType) == known { 23177 prg.internal[int32(*(*prg.mem[lhs].hh()).lh())-(hashBase+hashSize+12)-1] = prg.curExp 23178 } else { 23179 prg.dispErr(halfword(memMin), strNumber( /* "Internal quantity `" */ 887)) 23180 // \xref[Internal quantity...] 23181 prg.slowPrint(int32(prg.intName[int32(*(*prg.mem[lhs].hh()).lh())-(hashBase+hashSize+12)-1])) 23182 prg.print( /* "' must receive a known value" */ 888) 23183 { 23184 prg.helpPtr = 2 23185 prg.helpLine[1] = /* "I can't set an internal quantity to anything but a known" */ 889 23186 prg.helpLine[0] = /* "numeric value, so I'll have to ignore this assignment." */ 890 23187 } 23188 prg.putGetError() 23189 } 23190 } else { 23191 // Assign the current expression to the variable |lhs| 23192 p = prg.findVariable(lhs) 23193 if int32(p) != memMin { 23194 q = prg.stashCurExp() 23195 prg.curType = prg.undType(p) 23196 prg.recycleValue(p) 23197 *(*prg.mem[p].hh()).b0() = prg.curType 23198 *prg.mem[int32(p)+1].int() = memMin 23199 prg.makeExpCopy(p) 23200 p = prg.stashCurExp() 23201 prg.unstashCurExp(q) 23202 prg.makeEq(p) 23203 } else { 23204 prg.obliterated(lhs) 23205 prg.putGetError() 23206 } 23207 } 23208 prg.flushNodeList(lhs) 23209 } 23210 } 23211 23212 func (prg *prg) doTypeDeclaration() { 23213 var ( 23214 t smallNumber // the type being declared 23215 p halfword // token list for a declared variable 23216 q halfword // value node for the variable 23217 ) 23218 if prg.curMod >= transformType { 23219 t = byte(prg.curMod) 23220 } else { 23221 t = byte(prg.curMod + unknownTag) 23222 } 23223 for { 23224 p = prg.scanDeclaredVariable() 23225 prg.flushVariable(*prg.eqtb[*(*prg.mem[p].hh()).lh()-1].rh(), *(*prg.mem[p].hh()).rh(), false) 23226 23227 q = prg.findVariable(p) 23228 if int32(q) != memMin { 23229 *(*prg.mem[q].hh()).b0() = t 23230 *prg.mem[int32(q)+1].int() = memMin 23231 } else { 23232 { 23233 if int32(prg.interaction) == errorStopMode { 23234 } 23235 prg.printNl(strNumber( /* "! " */ 261)) 23236 prg.print( /* "Declared variable conflicts with previous vardef" */ 900) /* \xref[!\relax] */ 23237 } 23238 // \xref[Declared variable conflicts...] 23239 { 23240 prg.helpPtr = 2 23241 prg.helpLine[1] = /* "You can't use, e.g., `numeric foo[]' after `vardef foo'." */ 901 23242 prg.helpLine[0] = /* "Proceed, and I'll ignore the illegal redeclaration." */ 902 23243 } 23244 prg.putGetError() 23245 } 23246 prg.flushList(p) 23247 if int32(prg.curCmd) < comma { 23248 { 23249 if int32(prg.interaction) == errorStopMode { 23250 } 23251 prg.printNl(strNumber( /* "! " */ 261)) 23252 prg.print( /* "Illegal suffix of declared variable will be flushed" */ 903) /* \xref[!\relax] */ 23253 } 23254 // \xref[Illegal suffix...flushed] 23255 { 23256 prg.helpPtr = 5 23257 prg.helpLine[4] = /* "Variables in declarations must consist entirely of" */ 904 23258 prg.helpLine[3] = /* "names and collective subscripts, e.g., `x[]a'." */ 905 23259 prg.helpLine[2] = /* "Are you trying to use a reserved word in a variable name?" */ 906 23260 prg.helpLine[1] = /* "I'm going to discard the junk I found here," */ 907 23261 prg.helpLine[0] = /* "up to the next comma or the end of the declaration." */ 908 23262 } 23263 if int32(prg.curCmd) == numericToken { 23264 prg.helpLine[2] = /* "Explicit subscripts like `x15a' aren't permitted." */ 909 23265 } 23266 prg.putGetError() 23267 prg.scannerStatus = byte(flushing) 23268 for { 23269 prg.getNext() 23270 23271 // Decrease the string reference count... 23272 if int32(prg.curCmd) == stringToken { 23273 if int32(prg.strRef[prg.curMod]) < maxStrRef { 23274 if int32(prg.strRef[prg.curMod]) > 1 { 23275 prg.strRef[prg.curMod] = byte(int32(prg.strRef[prg.curMod]) - 1) 23276 } else { 23277 prg.flushString(strNumber(prg.curMod)) 23278 } 23279 } 23280 } 23281 if int32(prg.curCmd) >= comma { 23282 break 23283 } 23284 } // either |end_of_statement| or |cur_cmd=comma| 23285 prg.scannerStatus = byte(normal) 23286 } 23287 if int32(prg.curCmd) > comma { 23288 break 23289 } 23290 } 23291 } 23292 23293 func (prg *prg) doRandomSeed() { 23294 prg.getXNext() 23295 if int32(prg.curCmd) != assignment { 23296 prg.missingErr(strNumber( /* ":=" */ 461)) 23297 // \xref[Missing `:='] 23298 { 23299 prg.helpPtr = 1 23300 prg.helpLine[0] = /* "Always say `randomseed:=<numeric expression>'." */ 914 23301 } 23302 prg.backError() 23303 } 23304 prg.getXNext() 23305 prg.scanExpression() 23306 if int32(prg.curType) != known { 23307 prg.dispErr(halfword(memMin), strNumber( /* "Unknown value will be ignored" */ 915)) 23308 // \xref[Unknown value...ignored] 23309 { 23310 prg.helpPtr = 2 23311 prg.helpLine[1] = /* "Your expression was too random for me to handle," */ 916 23312 prg.helpLine[0] = /* "so I won't change the random seed just now." */ 917 23313 } 23314 23315 prg.putGetFlushError(scaled(0)) 23316 } else { 23317 // Initialize the random seed to |cur_exp| 23318 prg.initRandoms(prg.curExp) 23319 if int32(prg.selector) >= logOnly { 23320 prg.oldSetting = prg.selector 23321 prg.selector = byte(logOnly) 23322 prg.printNl(strNumber( /* "[randomseed:=" */ 918)) 23323 prg.printScaled(prg.curExp) 23324 prg.printChar(asciiCode('}')) 23325 prg.printNl(strNumber( /* "" */ 285)) 23326 prg.selector = prg.oldSetting 23327 } 23328 } 23329 } 23330 23331 func (prg *prg) doProtection() { 23332 var ( 23333 m/* 0..1 */ byte // 0 to unprotect, 1 to protect 23334 t halfword // the |eq_type| before we change it 23335 ) 23336 m = byte(prg.curMod) 23337 for { 23338 prg.getSymbol() 23339 t = *prg.eqtb[prg.curSym-1].lh() 23340 if int32(m) == 0 { 23341 if int32(t) >= outerTag { 23342 *prg.eqtb[prg.curSym-1].lh() = uint16(int32(t) - outerTag) 23343 } 23344 } else if int32(t) < outerTag { 23345 *prg.eqtb[prg.curSym-1].lh() = uint16(int32(t) + outerTag) 23346 } 23347 prg.getXNext() 23348 if int32(prg.curCmd) != comma { 23349 break 23350 } 23351 } 23352 } 23353 23354 func (prg *prg) defDelims() { 23355 var ( 23356 lDelim, rDelim halfword // the new delimiter pair 23357 ) 23358 prg.getClearSymbol() 23359 lDelim = prg.curSym 23360 23361 prg.getClearSymbol() 23362 rDelim = prg.curSym 23363 23364 *prg.eqtb[lDelim-1].lh() = uint16(leftDelimiter) 23365 *prg.eqtb[lDelim-1].rh() = rDelim 23366 23367 *prg.eqtb[rDelim-1].lh() = uint16(rightDelimiter) 23368 *prg.eqtb[rDelim-1].rh() = lDelim 23369 23370 prg.getXNext() 23371 } // \2 23372 23373 func (prg *prg) doInterim() { 23374 prg.getXNext() 23375 if int32(prg.curCmd) != internalQuantity { 23376 { 23377 if int32(prg.interaction) == errorStopMode { 23378 } 23379 prg.printNl(strNumber( /* "! " */ 261)) 23380 prg.print( /* "The token `" */ 924) /* \xref[!\relax] */ 23381 } 23382 // \xref[The token...quantity] 23383 if int32(prg.curSym) == 0 { 23384 prg.print( /* "(%CAPSULE)" */ 929) 23385 } else { 23386 prg.slowPrint(int32(*prg.hash[prg.curSym-1].rh())) 23387 } 23388 prg.print( /* "' isn't an internal quantity" */ 930) 23389 { 23390 prg.helpPtr = 1 23391 prg.helpLine[0] = /* "Something like `tracingonline' should follow `interim'." */ 931 23392 } 23393 prg.backError() 23394 } else { 23395 prg.saveInternal(halfword(prg.curMod)) 23396 prg.backInput() 23397 } 23398 prg.doStatement() 23399 } 23400 23401 func (prg *prg) doLet() { 23402 var ( 23403 l halfword // hash location of the left-hand symbol 23404 ) 23405 prg.getSymbol() 23406 l = prg.curSym 23407 prg.getXNext() 23408 if int32(prg.curCmd) != equals { 23409 if int32(prg.curCmd) != assignment { 23410 prg.missingErr(strNumber('=')) 23411 // \xref[Missing `='] 23412 { 23413 prg.helpPtr = 3 23414 prg.helpLine[2] = /* "You should have said `let symbol = something'." */ 932 23415 prg.helpLine[1] = /* "But don't worry; I'll pretend that an equals sign" */ 672 23416 prg.helpLine[0] = /* "was present. The next token I read will be `something'." */ 933 23417 } 23418 prg.backError() 23419 } 23420 } 23421 prg.getSymbol() 23422 switch prg.curCmd { 23423 case definedMacro, secondaryPrimaryMacro, tertiarySecondaryMacro, expressionTertiaryMacro: 23424 *(*prg.mem[prg.curMod].hh()).lh() = uint16(int32(*(*prg.mem[prg.curMod].hh()).lh()) + 1) 23425 23426 default: 23427 } 23428 23429 prg.clearSymbol(l, false) 23430 *prg.eqtb[l-1].lh() = uint16(prg.curCmd) 23431 if int32(prg.curCmd) == tagToken { 23432 *prg.eqtb[l-1].rh() = uint16(memMin) 23433 } else { 23434 *prg.eqtb[l-1].rh() = uint16(prg.curMod) 23435 } 23436 prg.getXNext() 23437 } 23438 23439 func (prg *prg) doNewInternal() { 23440 for { 23441 if int32(prg.intPtr) == maxInternal { 23442 prg.overflow(strNumber( /* "number of internals" */ 934), maxInternal) 23443 } 23444 // \xref[METAFONT capacity exceeded number of int][\quad number of internals] 23445 prg.getClearSymbol() 23446 prg.intPtr = byte(int32(prg.intPtr) + 1) 23447 *prg.eqtb[prg.curSym-1].lh() = uint16(internalQuantity) 23448 *prg.eqtb[prg.curSym-1].rh() = uint16(prg.intPtr) 23449 prg.intName[prg.intPtr-1] = *prg.hash[prg.curSym-1].rh() 23450 prg.internal[prg.intPtr-1] = 0 23451 prg.getXNext() 23452 if int32(prg.curCmd) != comma { 23453 break 23454 } 23455 } 23456 } 23457 23458 func (prg *prg) doShow() { 23459 for { 23460 prg.getXNext() 23461 prg.scanExpression() 23462 prg.printNl(strNumber( /* ">> " */ 765)) 23463 // \xref[>>] 23464 prg.printExp(halfword(memMin), smallNumber(2)) 23465 prg.flushCurExp(scaled(0)) 23466 if int32(prg.curCmd) != comma { 23467 break 23468 } 23469 } 23470 } 23471 23472 func (prg *prg) dispToken() { 23473 prg.printNl(strNumber( /* "> " */ 940)) 23474 // \xref[>\relax] 23475 if int32(prg.curSym) == 0 { 23476 if int32(prg.curCmd) == numericToken { 23477 prg.printScaled(prg.curMod) 23478 } else if int32(prg.curCmd) == capsuleToken { 23479 prg.gPointer = uint16(prg.curMod) 23480 prg.printCapsule() 23481 } else { 23482 prg.printChar(asciiCode('"')) 23483 prg.slowPrint(prg.curMod) 23484 prg.printChar(asciiCode('"')) 23485 { 23486 if int32(prg.strRef[prg.curMod]) < maxStrRef { 23487 if int32(prg.strRef[prg.curMod]) > 1 { 23488 prg.strRef[prg.curMod] = byte(int32(prg.strRef[prg.curMod]) - 1) 23489 } else { 23490 prg.flushString(strNumber(prg.curMod)) 23491 } 23492 } 23493 } 23494 } 23495 } else { 23496 prg.slowPrint(int32(*prg.hash[prg.curSym-1].rh())) 23497 prg.printChar(asciiCode('=')) 23498 if int32(*prg.eqtb[prg.curSym-1].lh()) >= outerTag { 23499 prg.print( /* "(outer) " */ 941) 23500 } 23501 prg.printCmdMod(int32(prg.curCmd), prg.curMod) 23502 if int32(prg.curCmd) == definedMacro { 23503 prg.printLn() 23504 prg.showMacro(halfword(prg.curMod), memMin, 100000) 23505 } // this avoids recursion between |show_macro| and |print_cmd_mod| 23506 // \xref[recursion] 23507 } 23508 } 23509 23510 func (prg *prg) doShowToken() { 23511 for { 23512 prg.getNext() 23513 prg.dispToken() 23514 prg.getXNext() 23515 if int32(prg.curCmd) != comma { 23516 break 23517 } 23518 } 23519 } 23520 23521 func (prg *prg) doShowStats() { 23522 prg.printNl(strNumber( /* "Memory usage " */ 950)) 23523 // \xref[Memory usage...] 23524 prg.printInt(prg.varUsed) 23525 prg.printChar(asciiCode('&')) 23526 prg.printInt(prg.dynUsed) 23527 if false { 23528 prg.print( /* "unknown" */ 358) 23529 } 23530 prg.print( /* " (" */ 558) 23531 prg.printInt(int32(prg.hiMemMin) - int32(prg.loMemMax) - 1) 23532 prg.print( /* " still untouched)" */ 951) 23533 prg.printLn() 23534 prg.printNl(strNumber( /* "String usage " */ 952)) 23535 prg.printInt(int32(prg.strPtr) - int32(prg.initStrPtr)) 23536 prg.printChar(asciiCode('&')) 23537 prg.printInt(int32(prg.poolPtr) - int32(prg.initPoolPtr)) 23538 prg.print( /* " (" */ 558) 23539 prg.printInt(maxStrings - int32(prg.maxStrPtr)) 23540 prg.printChar(asciiCode('&')) 23541 prg.printInt(poolSize - int32(prg.maxPoolPtr)) 23542 prg.print( /* " still untouched)" */ 951) 23543 prg.printLn() 23544 prg.getXNext() 23545 } 23546 23547 func (prg *prg) dispVar(p halfword) { 23548 var ( 23549 q halfword // traverses attributes and subscripts 23550 n/* 0..maxPrintLine */ byte // amount of macro text to show 23551 ) 23552 if int32(*(*prg.mem[p].hh()).b0()) == structured { 23553 q = *(*prg.mem[int32(p)+1].hh()).lh() 23554 for { 23555 prg.dispVar(q) 23556 q = *(*prg.mem[q].hh()).rh() 23557 if int32(q) == memMin+3+10+2+2 { 23558 break 23559 } 23560 } 23561 q = *(*prg.mem[int32(p)+1].hh()).rh() 23562 for int32(*(*prg.mem[q].hh()).b1()) == subscr { 23563 prg.dispVar(q) 23564 q = *(*prg.mem[q].hh()).rh() 23565 } 23566 } else if int32(*(*prg.mem[p].hh()).b0()) >= unsuffixedMacro { 23567 prg.printNl(strNumber( /* "" */ 285)) 23568 prg.printVariableName(p) 23569 if int32(*(*prg.mem[p].hh()).b0()) > unsuffixedMacro { 23570 prg.print( /* "@#" */ 664) 23571 } // |suffixed_macro| 23572 prg.print( /* "=macro:" */ 953) 23573 if int32(prg.fileOffset) >= maxPrintLine-20 { 23574 n = 5 23575 } else { 23576 n = byte(maxPrintLine - int32(prg.fileOffset) - 15) 23577 } 23578 prg.showMacro(halfword(*prg.mem[int32(p)+1].int()), memMin, int32(n)) 23579 } else if int32(*(*prg.mem[p].hh()).b0()) != undefined { 23580 prg.printNl(strNumber( /* "" */ 285)) 23581 prg.printVariableName(p) 23582 prg.printChar(asciiCode('=')) 23583 prg.printExp(p, smallNumber(0)) 23584 } 23585 } 23586 23587 func (prg *prg) doShowVar() { 23588 for { 23589 prg.getNext() 23590 if int32(prg.curSym) > 0 { 23591 if int32(prg.curSym) <= hashBase+hashSize+12 { 23592 if int32(prg.curCmd) == tagToken { 23593 if prg.curMod != memMin { 23594 prg.dispVar(halfword(prg.curMod)) 23595 goto done 23596 } 23597 } 23598 } 23599 } 23600 prg.dispToken() 23601 23602 done: 23603 prg.getXNext() 23604 if int32(prg.curCmd) != comma { 23605 break 23606 } 23607 } 23608 } 23609 23610 func (prg *prg) doShowDependencies() { 23611 var ( 23612 p halfword // link that runs through all dependencies 23613 ) 23614 p = *(*prg.mem[memMin+3+10].hh()).rh() 23615 for int32(p) != memMin+3+10 { 23616 if prg.interesting(p) { 23617 prg.printNl(strNumber( /* "" */ 285)) 23618 prg.printVariableName(p) 23619 if int32(*(*prg.mem[p].hh()).b0()) == dependent { 23620 prg.printChar(asciiCode('=')) 23621 } else { 23622 prg.print( /* " = " */ 768) 23623 } // extra spaces imply proto-dependency 23624 prg.printDependency(*(*prg.mem[int32(p)+1].hh()).rh(), *(*prg.mem[p].hh()).b0()) 23625 } 23626 p = *(*prg.mem[int32(p)+1].hh()).rh() 23627 for int32(*(*prg.mem[p].hh()).lh()) != memMin { 23628 p = *(*prg.mem[p].hh()).rh() 23629 } 23630 p = *(*prg.mem[p].hh()).rh() 23631 } 23632 prg.getXNext() 23633 } 23634 23635 func (prg *prg) doShowWhatever() { 23636 if int32(prg.interaction) == errorStopMode { 23637 } 23638 switch prg.curMod { 23639 case showTokenCode: 23640 prg.doShowToken() 23641 case showStatsCode: 23642 prg.doShowStats() 23643 case showCode: 23644 prg.doShow() 23645 case showVarCode: 23646 prg.doShowVar() 23647 case showDependenciesCode: 23648 prg.doShowDependencies() 23649 } // there are no other cases 23650 if prg.internal[showstopping-1] > 0 { 23651 { 23652 if int32(prg.interaction) == errorStopMode { 23653 } 23654 prg.printNl(strNumber( /* "! " */ 261)) 23655 prg.print( /* "OK" */ 954) /* \xref[!\relax] */ 23656 } 23657 // \xref[OK] 23658 if int32(prg.interaction) < errorStopMode { 23659 prg.helpPtr = 0 23660 prg.errorCount = int8(int32(prg.errorCount) - 1) 23661 } else { 23662 prg.helpPtr = 1 23663 prg.helpLine[0] = /* "This isn't an error message; I'm just showing something." */ 955 23664 } 23665 if int32(prg.curCmd) == semicolon { 23666 prg.error1() 23667 } else { 23668 prg.putGetError() 23669 } 23670 } 23671 } 23672 23673 func (prg *prg) scanWith() (r bool) { 23674 var ( 23675 t smallNumber // |known| or |pen_type| 23676 result bool // the value to return 23677 ) 23678 t = byte(prg.curMod) 23679 prg.curType = byte(vacuous) 23680 prg.getXNext() 23681 prg.scanExpression() 23682 result = false 23683 if int32(prg.curType) != int32(t) { 23684 prg.dispErr(halfword(memMin), strNumber( /* "Improper type" */ 963)) 23685 // \xref[Improper type] 23686 { 23687 prg.helpPtr = 2 23688 prg.helpLine[1] = /* "Next time say `withweight <known numeric expression>';" */ 964 23689 prg.helpLine[0] = /* "I'll ignore the bad `with' clause and look for another." */ 965 23690 } 23691 if int32(t) == penType { 23692 prg.helpLine[1] = /* "Next time say `withpen <known pen expression>';" */ 966 23693 } 23694 prg.putGetFlushError(scaled(0)) 23695 } else if int32(prg.curType) == penType { 23696 result = true 23697 } else { 23698 // Check the tentative weight 23699 prg.curExp = prg.roundUnscaled(prg.curExp) 23700 if abs(prg.curExp) < 4 && prg.curExp != 0 { 23701 result = true 23702 } else { 23703 { 23704 if int32(prg.interaction) == errorStopMode { 23705 } 23706 prg.printNl(strNumber( /* "! " */ 261)) 23707 prg.print( /* "Weight must be -3, -2, -1, +1, +2, or +3" */ 967) /* \xref[!\relax] */ 23708 } 23709 // \xref[Weight must be...] 23710 { 23711 prg.helpPtr = 1 23712 prg.helpLine[0] = /* "I'll ignore the bad `with' clause and look for another." */ 965 23713 } 23714 prg.putGetFlushError(scaled(0)) 23715 } 23716 } 23717 r = result 23718 return r 23719 } 23720 23721 func (prg *prg) findEdgesVar(t halfword) { 23722 var ( 23723 p halfword 23724 ) 23725 p = prg.findVariable(t) 23726 prg.curEdges = uint16(memMin) 23727 if int32(p) == memMin { 23728 prg.obliterated(t) 23729 prg.putGetError() 23730 } else if int32(*(*prg.mem[p].hh()).b0()) != pictureType { 23731 { 23732 if int32(prg.interaction) == errorStopMode { 23733 } 23734 prg.printNl(strNumber( /* "! " */ 261)) 23735 prg.print( /* "Variable " */ 790) /* \xref[!\relax] */ 23736 } 23737 prg.showTokenList(int32(t), memMin, 1000, 0) 23738 // \xref[Variable x is the wrong type] 23739 prg.print( /* " is the wrong type (" */ 968) 23740 prg.printType(*(*prg.mem[p].hh()).b0()) 23741 prg.printChar(asciiCode(')')) 23742 { 23743 prg.helpPtr = 2 23744 prg.helpLine[1] = /* "I was looking for a \"known\" picture variable." */ 969 23745 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 23746 } 23747 prg.putGetError() 23748 } else { 23749 prg.curEdges = uint16(*prg.mem[int32(p)+1].int()) 23750 } 23751 prg.flushNodeList(t) 23752 } 23753 23754 func (prg *prg) doAddTo() { 23755 var ( 23756 lhs, rhs halfword // variable on left, path on right 23757 w int32 // tentative weight 23758 p halfword // list manipulation register 23759 q halfword // beginning of second half of doubled path 23760 addToType/* doublePathCode..alsoCode */ byte // modifier of \&[addto] 23761 ) 23762 prg.getXNext() 23763 prg.varFlag = byte(thingToAdd) 23764 prg.scanPrimary() 23765 if int32(prg.curType) != tokenList { 23766 prg.dispErr(halfword(memMin), strNumber( /* "Not a suitable variable" */ 971)) 23767 // \xref[Not a suitable variable] 23768 { 23769 prg.helpPtr = 4 23770 prg.helpLine[3] = /* "At this point I needed to see the name of a picture variable." */ 972 23771 prg.helpLine[2] = /* "(Or perhaps you have indeed presented me with one; I might" */ 973 23772 prg.helpLine[1] = /* "have missed it, if it wasn't followed by the proper token.)" */ 974 23773 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 23774 } 23775 prg.putGetFlushError(scaled(0)) 23776 } else { 23777 lhs = uint16(prg.curExp) 23778 addToType = byte(prg.curMod) 23779 23780 prg.curType = byte(vacuous) 23781 prg.getXNext() 23782 prg.scanExpression() 23783 if int32(addToType) == alsoCode { 23784 prg.findEdgesVar(lhs) 23785 if int32(prg.curEdges) == memMin { 23786 prg.flushCurExp(scaled(0)) 23787 } else if int32(prg.curType) != pictureType { 23788 prg.dispErr(halfword(memMin), strNumber( /* "Improper `addto'" */ 975)) 23789 // \xref[Improper `addto'] 23790 { 23791 prg.helpPtr = 2 23792 prg.helpLine[1] = /* "This expression should have specified a known picture." */ 976 23793 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 23794 } 23795 prg.putGetFlushError(scaled(0)) 23796 } else { 23797 prg.mergeEdges(halfword(prg.curExp)) 23798 prg.flushCurExp(scaled(0)) 23799 } 23800 } else { 23801 // Get ready to fill a contour, and fill it 23802 if int32(prg.curType) == pairType { 23803 prg.pairToPath() 23804 } 23805 if int32(prg.curType) != pathType { 23806 prg.dispErr(halfword(memMin), strNumber( /* "Improper `addto'" */ 975)) 23807 // \xref[Improper `addto'] 23808 { 23809 prg.helpPtr = 2 23810 prg.helpLine[1] = /* "This expression should have been a known path." */ 977 23811 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 23812 } 23813 prg.putGetFlushError(scaled(0)) 23814 prg.flushTokenList(lhs) 23815 } else { 23816 rhs = uint16(prg.curExp) 23817 w = 1 23818 prg.curPen = uint16(memMin + 3) 23819 for int32(prg.curCmd) == withOption { 23820 if prg.scanWith() { 23821 if int32(prg.curType) == known { 23822 w = prg.curExp 23823 } else { 23824 // Change the tentative pen 23825 if int32(*(*prg.mem[prg.curPen].hh()).lh()) == memMin { 23826 prg.tossPen(prg.curPen) 23827 } else { 23828 *(*prg.mem[prg.curPen].hh()).lh() = uint16(int32(*(*prg.mem[prg.curPen].hh()).lh()) - 1) 23829 } 23830 prg.curPen = uint16(prg.curExp) 23831 } 23832 } 23833 } 23834 23835 // Complete the contour filling operation 23836 prg.findEdgesVar(lhs) 23837 if int32(prg.curEdges) == memMin { 23838 prg.tossKnotList(rhs) 23839 } else { 23840 lhs = uint16(memMin) 23841 prg.curPathType = addToType 23842 if int32(*(*prg.mem[rhs].hh()).b0()) == endpoint { 23843 if int32(prg.curPathType) == doublePathCode { 23844 if int32(*(*prg.mem[rhs].hh()).rh()) == int32(rhs) { 23845 *prg.mem[int32(rhs)+5].int() = *prg.mem[int32(rhs)+1].int() 23846 *prg.mem[int32(rhs)+6].int() = *prg.mem[int32(rhs)+2].int() 23847 *prg.mem[int32(rhs)+3].int() = *prg.mem[int32(rhs)+1].int() 23848 *prg.mem[int32(rhs)+4].int() = *prg.mem[int32(rhs)+2].int() 23849 *(*prg.mem[rhs].hh()).b0() = byte(explicit) 23850 *(*prg.mem[rhs].hh()).b1() = byte(explicit) 23851 } else { 23852 p = prg.htapYpoc(rhs) 23853 q = *(*prg.mem[p].hh()).rh() 23854 23855 *prg.mem[int32(prg.pathTail)+5].int() = *prg.mem[int32(q)+5].int() 23856 *prg.mem[int32(prg.pathTail)+6].int() = *prg.mem[int32(q)+6].int() 23857 *(*prg.mem[prg.pathTail].hh()).b1() = *(*prg.mem[q].hh()).b1() 23858 *(*prg.mem[prg.pathTail].hh()).rh() = *(*prg.mem[q].hh()).rh() 23859 prg.freeNode(q, halfword(knotNodeSize)) 23860 23861 *prg.mem[int32(p)+5].int() = *prg.mem[int32(rhs)+5].int() 23862 *prg.mem[int32(p)+6].int() = *prg.mem[int32(rhs)+6].int() 23863 *(*prg.mem[p].hh()).b1() = *(*prg.mem[rhs].hh()).b1() 23864 *(*prg.mem[p].hh()).rh() = *(*prg.mem[rhs].hh()).rh() 23865 prg.freeNode(rhs, halfword(knotNodeSize)) 23866 23867 rhs = p 23868 } 23869 } else { 23870 // Complain about non-cycle and |goto not_found| 23871 { 23872 if int32(prg.interaction) == errorStopMode { 23873 } 23874 prg.printNl(strNumber( /* "! " */ 261)) 23875 prg.print( /* "Not a cycle" */ 978) /* \xref[!\relax] */ 23876 } 23877 // \xref[Not a cycle] 23878 { 23879 prg.helpPtr = 2 23880 prg.helpLine[1] = /* "That contour should have ended with `..cycle' or `&cycle'." */ 979 23881 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 23882 } 23883 prg.putGetError() 23884 prg.tossKnotList(rhs) 23885 goto notFound 23886 } 23887 } else if int32(prg.curPathType) == doublePathCode { 23888 lhs = prg.htapYpoc(rhs) 23889 } 23890 prg.curWt = w 23891 rhs = prg.makeSpec(rhs, *prg.mem[int32(prg.curPen)+9].int(), prg.internal[tracingSpecs-1]) 23892 23893 // Check the turning number 23894 if prg.turningNumber <= 0 { 23895 if int32(prg.curPathType) != doublePathCode { 23896 if prg.internal[turningCheck-1] > 0 { 23897 if prg.turningNumber < 0 && int32(*(*prg.mem[prg.curPen].hh()).rh()) == memMin { 23898 prg.curWt = -prg.curWt 23899 } else { 23900 if prg.turningNumber == 0 { 23901 if prg.internal[turningCheck-1] <= 0200000 && int32(*(*prg.mem[prg.curPen].hh()).rh()) == memMin { 23902 goto done 23903 } else { 23904 prg.printStrange(strNumber( /* "Strange path (turning number is zero)" */ 980)) 23905 } 23906 } else { 23907 prg.printStrange(strNumber( /* "Backwards path (turning number is negative)" */ 981)) 23908 } 23909 // \xref[Backwards path...] 23910 { 23911 prg.helpPtr = 3 23912 prg.helpLine[2] = /* "The path doesn't have a counterclockwise orientation," */ 982 23913 prg.helpLine[1] = /* "so I'll probably have trouble drawing it." */ 983 23914 prg.helpLine[0] = /* "(See Chapter 27 of The METAFONTbook for more help.)" */ 984 23915 } 23916 // \xref[METAFONTbook][\sl The [\logos METAFONT\/]book] 23917 prg.putGetError() 23918 } 23919 } 23920 } 23921 } 23922 23923 done: 23924 ; 23925 if *prg.mem[int32(prg.curPen)+9].int() == 0 { 23926 prg.fillSpec(rhs) 23927 } else { 23928 prg.fillEnvelope(rhs) 23929 } 23930 if int32(lhs) != memMin { 23931 prg.revTurns = true 23932 lhs = prg.makeSpec(lhs, *prg.mem[int32(prg.curPen)+9].int(), prg.internal[tracingSpecs-1]) 23933 prg.revTurns = false 23934 if *prg.mem[int32(prg.curPen)+9].int() == 0 { 23935 prg.fillSpec(lhs) 23936 } else { 23937 prg.fillEnvelope(lhs) 23938 } 23939 } 23940 23941 notFound: 23942 } 23943 if int32(*(*prg.mem[prg.curPen].hh()).lh()) == memMin { 23944 prg.tossPen(prg.curPen) 23945 } else { 23946 *(*prg.mem[prg.curPen].hh()).lh() = uint16(int32(*(*prg.mem[prg.curPen].hh()).lh()) - 1) 23947 } 23948 } 23949 } 23950 } 23951 } 23952 23953 // \4 23954 // Declare the function called |tfm_check| 23955 func (prg *prg) tfmCheck(m smallNumber) (r scaled) { 23956 if abs(prg.internal[m-1]) >= 01000000000 { 23957 { 23958 if int32(prg.interaction) == errorStopMode { 23959 } 23960 prg.printNl(strNumber( /* "! " */ 261)) 23961 prg.print( /* "Enormous " */ 1001) /* \xref[!\relax] */ 23962 } 23963 prg.print(int32(prg.intName[m-1])) 23964 // \xref[Enormous charwd...] 23965 // \xref[Enormous chardp...] 23966 // \xref[Enormous charht...] 23967 // \xref[Enormous charic...] 23968 // \xref[Enormous designsize...] 23969 prg.print( /* " has been reduced" */ 1002) 23970 { 23971 prg.helpPtr = 1 23972 prg.helpLine[0] = /* "Font metric dimensions must be less than 2048pt." */ 1003 23973 } 23974 prg.putGetError() 23975 if prg.internal[m-1] > 0 { 23976 r = 01000000000 - 1 23977 } else { 23978 r = 1 - 01000000000 23979 } 23980 } else { 23981 r = prg.internal[m-1] 23982 } 23983 return r 23984 } 23985 23986 func (prg *prg) doShipOut() { 23987 var ( 23988 c int32 // the character code 23989 ) 23990 prg.getXNext() 23991 prg.varFlag = byte(semicolon) 23992 prg.scanExpression() 23993 if int32(prg.curType) != tokenList { 23994 if int32(prg.curType) == pictureType { 23995 prg.curEdges = uint16(prg.curExp) 23996 } else { 23997 { 23998 prg.dispErr(halfword(memMin), strNumber( /* "Not a suitable variable" */ 971)) 23999 // \xref[Not a suitable variable] 24000 { 24001 prg.helpPtr = 4 24002 prg.helpLine[3] = /* "At this point I needed to see the name of a picture variable." */ 972 24003 prg.helpLine[2] = /* "(Or perhaps you have indeed presented me with one; I might" */ 973 24004 prg.helpLine[1] = /* "have missed it, if it wasn't followed by the proper token.)" */ 974 24005 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 24006 } 24007 prg.putGetFlushError(scaled(0)) 24008 } 24009 24010 goto exit 24011 } 24012 } else { 24013 prg.findEdgesVar(halfword(prg.curExp)) 24014 prg.curType = byte(vacuous) 24015 } 24016 if int32(prg.curEdges) != memMin { 24017 c = prg.roundUnscaled(prg.internal[charCode-1]) % 256 24018 if c < 0 { 24019 c = c + 256 24020 } 24021 24022 // Store the width information for character code~|c| 24023 if c < int32(prg.bc) { 24024 prg.bc = byte(c) 24025 } 24026 if c > int32(prg.ec) { 24027 prg.ec = byte(c) 24028 } 24029 prg.charExists[c] = true 24030 prg.gfDx[c] = prg.internal[charDx-1] 24031 prg.gfDy[c] = prg.internal[charDy-1] 24032 prg.tfmWidth[c] = prg.tfmCheck(smallNumber(charWd)) 24033 prg.tfmHeight[c] = prg.tfmCheck(smallNumber(charHt)) 24034 prg.tfmDepth[c] = prg.tfmCheck(smallNumber(charDp)) 24035 prg.tfmItalCorr[c] = prg.tfmCheck(smallNumber(charIc)) 24036 if prg.internal[proofing-1] >= 0 { 24037 prg.shipOut(eightBits(c)) 24038 } 24039 } 24040 prg.flushCurExp(scaled(0)) 24041 24042 exit: 24043 } 24044 24045 func (prg *prg) doDisplay() { 24046 var ( 24047 e halfword // token list for a picture variable 24048 ) 24049 prg.getXNext() 24050 prg.varFlag = byte(inWindow) 24051 prg.scanPrimary() 24052 if int32(prg.curType) != tokenList { 24053 prg.dispErr(halfword(memMin), strNumber( /* "Not a suitable variable" */ 971)) 24054 // \xref[Not a suitable variable] 24055 { 24056 prg.helpPtr = 4 24057 prg.helpLine[3] = /* "At this point I needed to see the name of a picture variable." */ 972 24058 prg.helpLine[2] = /* "(Or perhaps you have indeed presented me with one; I might" */ 973 24059 prg.helpLine[1] = /* "have missed it, if it wasn't followed by the proper token.)" */ 974 24060 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 24061 } 24062 prg.putGetFlushError(scaled(0)) 24063 } else { 24064 e = uint16(prg.curExp) 24065 prg.curType = byte(vacuous) 24066 prg.getXNext() 24067 prg.scanExpression() 24068 if int32(prg.curType) != known { 24069 goto commonEnding 24070 } 24071 prg.curExp = prg.roundUnscaled(prg.curExp) 24072 if prg.curExp < 0 { 24073 goto notFound 24074 } 24075 if prg.curExp > 15 { 24076 goto notFound 24077 } 24078 if !prg.windowOpen[prg.curExp] { 24079 goto notFound 24080 } 24081 prg.findEdgesVar(e) 24082 if int32(prg.curEdges) != memMin { 24083 prg.dispEdges(windowNumber(prg.curExp)) 24084 } 24085 24086 goto exit 24087 24088 notFound: 24089 prg.curExp = prg.curExp * 0200000 24090 24091 commonEnding: 24092 prg.dispErr(halfword(memMin), strNumber( /* "Bad window number" */ 985)) 24093 // \xref[Bad window number] 24094 { 24095 prg.helpPtr = 1 24096 prg.helpLine[0] = /* "It should be the number of an open window." */ 986 24097 } 24098 prg.putGetFlushError(scaled(0)) 24099 prg.flushTokenList(e) 24100 } 24101 24102 exit: 24103 } 24104 24105 func (prg *prg) getPair(c commandCode) (r bool) { 24106 var ( 24107 p halfword // a pair of values that are known (we hope) 24108 b bool // did we find such a pair? 24109 ) 24110 if int32(prg.curCmd) != int32(c) { 24111 r = false 24112 } else { 24113 prg.getXNext() 24114 prg.scanExpression() 24115 if prg.nicePair(prg.curExp, prg.curType) { 24116 p = uint16(*prg.mem[prg.curExp+1].int()) 24117 prg.curX = *prg.mem[int32(p)+1].int() 24118 prg.curY = *prg.mem[int32(p)+2+1].int() 24119 b = true 24120 } else { 24121 b = false 24122 } 24123 prg.flushCurExp(scaled(0)) 24124 r = b 24125 } 24126 return r 24127 } 24128 24129 func (prg *prg) doOpenWindow() { 24130 var ( 24131 k int32 // the window number in question 24132 r0, c0, r11, c1 scaled // window coordinates 24133 ) 24134 prg.getXNext() 24135 prg.scanExpression() 24136 if int32(prg.curType) != known { 24137 goto notFound 24138 } 24139 k = prg.roundUnscaled(prg.curExp) 24140 if k < 0 { 24141 goto notFound 24142 } 24143 if k > 15 { 24144 goto notFound 24145 } 24146 if !prg.getPair(commandCode(fromToken)) { 24147 goto notFound 24148 } 24149 r0 = prg.curX 24150 c0 = prg.curY 24151 if !prg.getPair(commandCode(toToken)) { 24152 goto notFound 24153 } 24154 r11 = prg.curX 24155 c1 = prg.curY 24156 if !prg.getPair(commandCode(atToken)) { 24157 goto notFound 24158 } 24159 prg.openAWindow(windowNumber(k), r0, c0, r11, c1, prg.curX, prg.curY) 24160 goto exit 24161 24162 notFound: 24163 { 24164 if int32(prg.interaction) == errorStopMode { 24165 } 24166 prg.printNl(strNumber( /* "! " */ 261)) 24167 prg.print( /* "Improper `openwindow'" */ 987) /* \xref[!\relax] */ 24168 } 24169 // \xref[Improper `openwindow'] 24170 { 24171 prg.helpPtr = 2 24172 prg.helpLine[1] = /* "Say `openwindow k from (r0,c0) to (r1,c1) at (x,y)'," */ 988 24173 prg.helpLine[0] = /* "where all quantities are known and k is between 0 and 15." */ 989 24174 } 24175 prg.putGetError() 24176 24177 exit: 24178 } 24179 24180 func (prg *prg) doCull() { 24181 var ( 24182 e halfword // token list for a picture variable 24183 keeping/* dropCode..keepCode */ byte // modifier of |cull_op| 24184 w, wIn, wOut int32 // culling weights 24185 ) 24186 w = 1 24187 prg.getXNext() 24188 prg.varFlag = byte(cullOp) 24189 prg.scanPrimary() 24190 if int32(prg.curType) != tokenList { 24191 prg.dispErr(halfword(memMin), strNumber( /* "Not a suitable variable" */ 971)) 24192 // \xref[Not a suitable variable] 24193 { 24194 prg.helpPtr = 4 24195 prg.helpLine[3] = /* "At this point I needed to see the name of a picture variable." */ 972 24196 prg.helpLine[2] = /* "(Or perhaps you have indeed presented me with one; I might" */ 973 24197 prg.helpLine[1] = /* "have missed it, if it wasn't followed by the proper token.)" */ 974 24198 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 24199 } 24200 prg.putGetFlushError(scaled(0)) 24201 } else { 24202 e = uint16(prg.curExp) 24203 prg.curType = byte(vacuous) 24204 keeping = byte(prg.curMod) 24205 if !prg.getPair(commandCode(cullOp)) { 24206 goto notFound 24207 } 24208 for int32(prg.curCmd) == withOption && prg.curMod == known { 24209 if prg.scanWith() { 24210 w = prg.curExp 24211 } 24212 } 24213 24214 // Set up the culling weights, or |goto not_found| if the thresholds are bad 24215 if prg.curX > prg.curY { 24216 goto notFound 24217 } 24218 if int32(keeping) == dropCode { 24219 if prg.curX > 0 || prg.curY < 0 { 24220 goto notFound 24221 } 24222 wOut = w 24223 wIn = 0 24224 } else { 24225 if prg.curX <= 0 && prg.curY >= 0 { 24226 goto notFound 24227 } 24228 wOut = 0 24229 wIn = w 24230 } 24231 prg.findEdgesVar(e) 24232 if int32(prg.curEdges) != memMin { 24233 prg.cullEdges(prg.floorUnscaled(prg.curX+0200000-1), prg.floorUnscaled(prg.curY), wOut, wIn) 24234 } 24235 24236 goto exit 24237 24238 notFound: 24239 { 24240 if int32(prg.interaction) == errorStopMode { 24241 } 24242 prg.printNl(strNumber( /* "! " */ 261)) 24243 prg.print( /* "Bad culling amounts" */ 990) /* \xref[!\relax] */ 24244 } 24245 // \xref[Bad culling amounts] 24246 { 24247 prg.helpPtr = 1 24248 prg.helpLine[0] = /* "Always cull by known amounts that exclude 0." */ 991 24249 } 24250 prg.putGetError() 24251 prg.flushTokenList(e) 24252 } 24253 24254 exit: 24255 } 24256 24257 func (prg *prg) doMessage() { 24258 var ( 24259 m /* messageCode..errHelpCode */ byte // the type of message 24260 ) 24261 m = byte(prg.curMod) 24262 prg.getXNext() 24263 prg.scanExpression() 24264 if int32(prg.curType) != stringType { 24265 prg.dispErr(halfword(memMin), strNumber( /* "Not a string" */ 699)) 24266 // \xref[Not a string] 24267 { 24268 prg.helpPtr = 1 24269 prg.helpLine[0] = /* "A message should be a known string expression." */ 995 24270 } 24271 prg.putGetError() 24272 } else { 24273 switch m { 24274 case messageCode: 24275 prg.printNl(strNumber( /* "" */ 285)) 24276 prg.slowPrint(prg.curExp) 24277 24278 case errMessageCode: 24279 // Print string |cur_exp| as an error message 24280 { 24281 if int32(prg.interaction) == errorStopMode { 24282 } 24283 prg.printNl(strNumber( /* "! " */ 261)) 24284 prg.print( /* "" */ 285) /* \xref[!\relax] */ 24285 } 24286 prg.slowPrint(prg.curExp) 24287 if int32(prg.errHelp) != 0 { 24288 prg.useErrHelp = true 24289 } else if prg.longHelpSeen { 24290 prg.helpPtr = 1 24291 prg.helpLine[0] = /* "(That was another `errmessage'.)" */ 996 24292 } else { 24293 if int32(prg.interaction) < errorStopMode { 24294 prg.longHelpSeen = true 24295 } 24296 { 24297 prg.helpPtr = 4 24298 prg.helpLine[3] = /* "This error message was generated by an `errmessage'" */ 997 24299 prg.helpLine[2] = /* "command, so I can't give any explicit help." */ 998 24300 prg.helpLine[1] = /* "Pretend that you're Miss Marple: Examine all clues," */ 999 24301 prg.helpLine[0] = /* "and deduce the truth by inspired guesses." */ 1000 24302 } 24303 } 24304 prg.putGetError() 24305 prg.useErrHelp = false 24306 24307 case errHelpCode: 24308 // Save string |cur_exp| as the |err_help| 24309 if int32(prg.errHelp) != 0 { 24310 if int32(prg.strRef[prg.errHelp]) < maxStrRef { 24311 if int32(prg.strRef[prg.errHelp]) > 1 { 24312 prg.strRef[prg.errHelp] = byte(int32(prg.strRef[prg.errHelp]) - 1) 24313 } else { 24314 prg.flushString(prg.errHelp) 24315 } 24316 } 24317 } 24318 if int32(prg.strStart[prg.curExp+1])-int32(prg.strStart[prg.curExp]) == 0 { 24319 prg.errHelp = 0 24320 } else { 24321 prg.errHelp = uint16(prg.curExp) 24322 { 24323 if int32(prg.strRef[prg.errHelp]) < maxStrRef { 24324 prg.strRef[prg.errHelp] = byte(int32(prg.strRef[prg.errHelp]) + 1) 24325 } 24326 } 24327 } 24328 24329 } 24330 } // there are no other cases 24331 prg.flushCurExp(scaled(0)) 24332 } 24333 24334 func (prg *prg) getCode() (r eightBits) { 24335 var ( 24336 c int32 // the code value found 24337 ) 24338 prg.getXNext() 24339 prg.scanExpression() 24340 if int32(prg.curType) == known { 24341 c = prg.roundUnscaled(prg.curExp) 24342 if c >= 0 { 24343 if c < 256 { 24344 goto found 24345 } 24346 } 24347 } else if int32(prg.curType) == stringType { 24348 if int32(prg.strStart[prg.curExp+1])-int32(prg.strStart[prg.curExp]) == 1 { 24349 c = int32(prg.strPool[prg.strStart[prg.curExp]]) 24350 goto found 24351 } 24352 } 24353 prg.dispErr(halfword(memMin), strNumber( /* "Invalid code has been replaced by 0" */ 1009)) 24354 // \xref[Invalid code...] 24355 { 24356 prg.helpPtr = 2 24357 prg.helpLine[1] = /* "I was looking for a number between 0 and 255, or for a" */ 1010 24358 prg.helpLine[0] = /* "string of length 1. Didn't find it; will use 0 instead." */ 1011 24359 } 24360 prg.putGetFlushError(scaled(0)) 24361 c = 0 24362 24363 found: 24364 r = byte(c) 24365 return r 24366 } 24367 24368 func (prg *prg) setTag(c halfword, t smallNumber, r1 halfword) { 24369 if int32(prg.charTag[c]) == noTag { 24370 prg.charTag[c] = t 24371 prg.charRemainder[c] = r1 24372 if int32(t) == ligTag { 24373 prg.labelPtr = uint16(int32(prg.labelPtr) + 1) 24374 prg.labelLoc[prg.labelPtr] = int16(r1) 24375 prg.labelChar[prg.labelPtr-1] = byte(c) 24376 } 24377 } else { 24378 // Complain about a character tag conflict 24379 { 24380 if int32(prg.interaction) == errorStopMode { 24381 } 24382 prg.printNl(strNumber( /* "! " */ 261)) 24383 prg.print( /* "Character " */ 1012) /* \xref[!\relax] */ 24384 } 24385 if int32(c) > ' ' && int32(c) < 127 { 24386 prg.print(int32(c)) 24387 } else if int32(c) == 256 { 24388 prg.print( /* "||" */ 1013) 24389 } else { 24390 prg.print( /* "code " */ 1014) 24391 prg.printInt(int32(c)) 24392 } 24393 prg.print( /* " is already " */ 1015) 24394 // \xref[Character c is already...] 24395 switch prg.charTag[c] { 24396 case ligTag: 24397 prg.print( /* "in a ligtable" */ 1016) 24398 case listTag: 24399 prg.print( /* "in a charlist" */ 1017) 24400 case extTag: 24401 prg.print( /* "extensible" */ 1006) 24402 } // there are no other cases 24403 { 24404 prg.helpPtr = 2 24405 prg.helpLine[1] = /* "It's not legal to label a character more than once." */ 1018 24406 prg.helpLine[0] = /* "So I'll not change anything just now." */ 970 24407 } 24408 prg.putGetError() 24409 } 24410 } 24411 24412 func (prg *prg) doTfmCommand() { 24413 var ( 24414 c, cc/* 0..256 */ uint16 // character codes 24415 k/* 0..maxKerns */ uint16 // index into the |kern| array 24416 j int32 // index into |header_byte| or |param| 24417 ) 24418 switch prg.curMod { 24419 case charListCode: 24420 c = uint16(prg.getCode()) 24421 // we will store a list of character successors 24422 for int32(prg.curCmd) == colon { 24423 cc = uint16(prg.getCode()) 24424 prg.setTag(c, smallNumber(listTag), cc) 24425 c = cc 24426 } 24427 24428 case ligTableCode: 24429 // Store a list of ligature/kern steps 24430 prg.lkStarted = false 24431 24432 continue1: 24433 prg.getXNext() 24434 if int32(prg.curCmd) == skipTo && prg.lkStarted { 24435 c = uint16(prg.getCode()) 24436 if int32(prg.nl)-int32(prg.skipTable[c]) > 128 { 24437 { 24438 { 24439 if int32(prg.interaction) == errorStopMode { 24440 } 24441 prg.printNl(strNumber( /* "! " */ 261)) 24442 prg.print( /* "Too far to skip" */ 1035) /* \xref[!\relax] */ 24443 } /* \xref[Too far to skip] */ 24444 { 24445 prg.helpPtr = 1 24446 prg.helpLine[0] = /* "At most 127 lig/kern steps can separate skipto1 from 1::." */ 1036 24447 } 24448 prg.error1() 24449 prg.ll = prg.skipTable[c] 24450 for { 24451 prg.lll = uint16(int32(prg.ligKern[prg.ll].b0) - minQuarterword) 24452 prg.ligKern[prg.ll].b0 = byte(stopFlag) 24453 prg.ll = uint16(int32(prg.ll) - int32(prg.lll)) 24454 if int32(prg.lll) == 0 { 24455 break 24456 } 24457 } 24458 } 24459 prg.skipTable[c] = uint16(ligTableSize) 24460 } 24461 if int32(prg.skipTable[c]) == ligTableSize { 24462 prg.ligKern[int32(prg.nl)-1].b0 = byte(0 + minQuarterword) 24463 } else { 24464 prg.ligKern[int32(prg.nl)-1].b0 = byte(int32(prg.nl) - int32(prg.skipTable[c]) - 1 + minQuarterword) 24465 } 24466 prg.skipTable[c] = uint16(int32(prg.nl) - 1) 24467 goto done 24468 } 24469 if int32(prg.curCmd) == bcharLabel { 24470 c = 256 24471 prg.curCmd = byte(colon) 24472 } else { 24473 prg.backInput() 24474 c = uint16(prg.getCode()) 24475 } 24476 if int32(prg.curCmd) == colon || int32(prg.curCmd) == doubleColon { 24477 if int32(prg.curCmd) == colon { 24478 if int32(c) == 256 { 24479 prg.bchLabel = prg.nl 24480 } else { 24481 prg.setTag(c, smallNumber(ligTag), prg.nl) 24482 } 24483 } else if int32(prg.skipTable[c]) < ligTableSize { 24484 prg.ll = prg.skipTable[c] 24485 prg.skipTable[c] = uint16(ligTableSize) 24486 for { 24487 prg.lll = uint16(int32(prg.ligKern[prg.ll].b0) - minQuarterword) 24488 if int32(prg.nl)-int32(prg.ll) > 128 { 24489 { 24490 { 24491 if int32(prg.interaction) == errorStopMode { 24492 } 24493 prg.printNl(strNumber( /* "! " */ 261)) 24494 prg.print( /* "Too far to skip" */ 1035) /* \xref[!\relax] */ 24495 } /* \xref[Too far to skip] */ 24496 { 24497 prg.helpPtr = 1 24498 prg.helpLine[0] = /* "At most 127 lig/kern steps can separate skipto1 from 1::." */ 1036 24499 } 24500 prg.error1() 24501 prg.ll = prg.ll 24502 for { 24503 prg.lll = uint16(int32(prg.ligKern[prg.ll].b0) - minQuarterword) 24504 prg.ligKern[prg.ll].b0 = byte(stopFlag) 24505 prg.ll = uint16(int32(prg.ll) - int32(prg.lll)) 24506 if int32(prg.lll) == 0 { 24507 break 24508 } 24509 } 24510 } 24511 goto continue1 24512 } 24513 prg.ligKern[prg.ll].b0 = byte(int32(prg.nl) - int32(prg.ll) - 1 + minQuarterword) 24514 prg.ll = uint16(int32(prg.ll) - int32(prg.lll)) 24515 if int32(prg.lll) == 0 { 24516 break 24517 } 24518 } 24519 } 24520 24521 goto continue1 24522 } 24523 if int32(prg.curCmd) == ligKernToken { 24524 prg.ligKern[prg.nl].b1 = byte(int32(c) + minQuarterword) 24525 prg.ligKern[prg.nl].b0 = byte(0 + minQuarterword) 24526 if prg.curMod < 128 { 24527 prg.ligKern[prg.nl].b2 = byte(prg.curMod + minQuarterword) 24528 prg.ligKern[prg.nl].b3 = byte(int32(prg.getCode()) + minQuarterword) 24529 } else { 24530 prg.getXNext() 24531 prg.scanExpression() 24532 if int32(prg.curType) != known { 24533 prg.dispErr(halfword(memMin), strNumber( /* "Improper kern" */ 1037)) 24534 // \xref[Improper kern] 24535 { 24536 prg.helpPtr = 2 24537 prg.helpLine[1] = /* "The amount of kern should be a known numeric value." */ 1038 24538 prg.helpLine[0] = /* "I'm zeroing this one. Proceed, with fingers crossed." */ 309 24539 } 24540 prg.putGetFlushError(scaled(0)) 24541 } 24542 prg.kern[prg.nk] = prg.curExp 24543 k = 0 24544 for prg.kern[k] != prg.curExp { 24545 k = uint16(int32(k) + 1) 24546 } 24547 if int32(k) == int32(prg.nk) { 24548 if int32(prg.nk) == maxKerns { 24549 prg.overflow(strNumber( /* "kern" */ 1034), maxKerns) 24550 } 24551 // \xref[METAFONT capacity exceeded kern][\quad kern] 24552 prg.nk = uint16(int32(prg.nk) + 1) 24553 } 24554 prg.ligKern[prg.nl].b2 = byte(kernFlag + int32(k)/256) 24555 prg.ligKern[prg.nl].b3 = byte(int32(k)%256 + minQuarterword) 24556 } 24557 prg.lkStarted = true 24558 } else { 24559 { 24560 if int32(prg.interaction) == errorStopMode { 24561 } 24562 prg.printNl(strNumber( /* "! " */ 261)) 24563 prg.print( /* "Illegal ligtable step" */ 1023) /* \xref[!\relax] */ 24564 } 24565 // \xref[Illegal ligtable step] 24566 { 24567 prg.helpPtr = 1 24568 prg.helpLine[0] = /* "I was looking for `=:' or `kern' here." */ 1024 24569 } 24570 prg.backError() 24571 prg.ligKern[prg.nl].b1 = byte(0 + minQuarterword) 24572 prg.ligKern[prg.nl].b2 = byte(0 + minQuarterword) 24573 prg.ligKern[prg.nl].b3 = byte(0 + minQuarterword) 24574 24575 prg.ligKern[prg.nl].b0 = byte(stopFlag + 1) // this specifies an unconditional stop 24576 } 24577 if int32(prg.nl) == ligTableSize { 24578 prg.overflow(strNumber( /* "ligtable size" */ 1025), ligTableSize) 24579 } 24580 // \xref[METAFONT capacity exceeded ligtable size][\quad ligtable size] 24581 prg.nl = uint16(int32(prg.nl) + 1) 24582 if int32(prg.curCmd) == comma { 24583 goto continue1 24584 } 24585 if int32(prg.ligKern[int32(prg.nl)-1].b0) < stopFlag { 24586 prg.ligKern[int32(prg.nl)-1].b0 = byte(stopFlag) 24587 } 24588 24589 done: 24590 ; 24591 24592 case extensibleCode: 24593 // Define an extensible recipe 24594 if int32(prg.ne) == 256 { 24595 prg.overflow(strNumber( /* "extensible" */ 1006), 256) 24596 } 24597 // \xref[METAFONT capacity exceeded extensible][\quad extensible] 24598 c = uint16(prg.getCode()) 24599 prg.setTag(c, smallNumber(extTag), prg.ne) 24600 if int32(prg.curCmd) != colon { 24601 prg.missingErr(strNumber(':')) /* \xref[Missing `\char`\#'] */ 24602 { 24603 prg.helpPtr = 1 24604 prg.helpLine[0] = /* "I'm processing `extensible c: t,m,b,r'." */ 1039 24605 } 24606 prg.backError() 24607 } 24608 prg.exten[prg.ne].b0 = byte(int32(prg.getCode()) + minQuarterword) 24609 if int32(prg.curCmd) != comma { 24610 prg.missingErr(strNumber(',')) /* \xref[Missing `\char`\#'] */ 24611 { 24612 prg.helpPtr = 1 24613 prg.helpLine[0] = /* "I'm processing `extensible c: t,m,b,r'." */ 1039 24614 } 24615 prg.backError() 24616 } 24617 prg.exten[prg.ne].b1 = byte(int32(prg.getCode()) + minQuarterword) 24618 if int32(prg.curCmd) != comma { 24619 prg.missingErr(strNumber(',')) /* \xref[Missing `\char`\#'] */ 24620 { 24621 prg.helpPtr = 1 24622 prg.helpLine[0] = /* "I'm processing `extensible c: t,m,b,r'." */ 1039 24623 } 24624 prg.backError() 24625 } 24626 prg.exten[prg.ne].b2 = byte(int32(prg.getCode()) + minQuarterword) 24627 if int32(prg.curCmd) != comma { 24628 prg.missingErr(strNumber(',')) /* \xref[Missing `\char`\#'] */ 24629 { 24630 prg.helpPtr = 1 24631 prg.helpLine[0] = /* "I'm processing `extensible c: t,m,b,r'." */ 1039 24632 } 24633 prg.backError() 24634 } 24635 prg.exten[prg.ne].b3 = byte(int32(prg.getCode()) + minQuarterword) 24636 prg.ne = uint16(int32(prg.ne) + 1) 24637 24638 case headerByteCode, fontDimenCode: 24639 c = uint16(prg.curMod) 24640 prg.getXNext() 24641 prg.scanExpression() 24642 if int32(prg.curType) != known || prg.curExp < 0100000 { 24643 prg.dispErr(halfword(memMin), strNumber( /* "Improper location" */ 1019)) 24644 // \xref[Improper location] 24645 { 24646 prg.helpPtr = 2 24647 prg.helpLine[1] = /* "I was looking for a known, positive number." */ 1020 24648 prg.helpLine[0] = /* "For safety's sake I'll ignore the present command." */ 1021 24649 } 24650 prg.putGetError() 24651 } else { 24652 j = prg.roundUnscaled(prg.curExp) 24653 if int32(prg.curCmd) != colon { 24654 prg.missingErr(strNumber(':')) 24655 // \xref[Missing `:'] 24656 { 24657 prg.helpPtr = 1 24658 prg.helpLine[0] = /* "A colon should follow a headerbyte or fontdimen location." */ 1022 24659 } 24660 prg.backError() 24661 } 24662 if int32(c) == headerByteCode { 24663 for { 24664 if j > headerSize { 24665 prg.overflow(strNumber( /* "headerbyte" */ 1007), headerSize) 24666 } 24667 // \xref[METAFONT capacity exceeded headerbyte][\quad headerbyte] 24668 prg.headerByte[j-1] = int16(prg.getCode()) 24669 j = j + 1 24670 if int32(prg.curCmd) != comma { 24671 break 24672 } 24673 } 24674 } else { 24675 // Store a list of font dimensions 24676 for { 24677 if j > maxFontDimen { 24678 prg.overflow(strNumber( /* "fontdimen" */ 1008), maxFontDimen) 24679 } 24680 // \xref[METAFONT capacity exceeded fontdimen][\quad fontdimen] 24681 for j > int32(prg.np) { 24682 prg.np = byte(int32(prg.np) + 1) 24683 prg.param[prg.np-1] = 0 24684 } 24685 prg.getXNext() 24686 prg.scanExpression() 24687 if int32(prg.curType) != known { 24688 prg.dispErr(halfword(memMin), strNumber( /* "Improper font parameter" */ 1040)) 24689 // \xref[Improper font parameter] 24690 { 24691 prg.helpPtr = 1 24692 prg.helpLine[0] = /* "I'm zeroing this one. Proceed, with fingers crossed." */ 309 24693 } 24694 prg.putGetFlushError(scaled(0)) 24695 } 24696 prg.param[j-1] = prg.curExp 24697 j = j + 1 24698 if int32(prg.curCmd) != comma { 24699 break 24700 } 24701 } 24702 } 24703 } 24704 24705 } // there are no other cases 24706 } 24707 24708 func (prg *prg) doSpecial() { 24709 var ( 24710 m smallNumber // either |string_type| or |known| 24711 ) 24712 m = byte(prg.curMod) 24713 prg.getXNext() 24714 prg.scanExpression() 24715 if prg.internal[proofing-1] >= 0 { 24716 if int32(prg.curType) != int32(m) { 24717 prg.dispErr(halfword(memMin), strNumber( /* "Unsuitable expression" */ 1060)) 24718 // \xref[Unsuitable expression] 24719 { 24720 prg.helpPtr = 1 24721 prg.helpLine[0] = /* "The expression shown above has the wrong type to be output." */ 1061 24722 } 24723 prg.putGetError() 24724 } else { 24725 if int32(prg.outputFileName) == 0 { 24726 prg.initGf() 24727 } 24728 if int32(m) == stringType { 24729 prg.gfString(strNumber(prg.curExp), strNumber(0)) 24730 } else { 24731 { 24732 prg.gfBuf[prg.gfPtr] = byte(yyy) 24733 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 24734 if int32(prg.gfPtr) == int32(prg.gfLimit) { 24735 prg.gfSwap() 24736 } 24737 } 24738 prg.gfFour(prg.curExp) 24739 } 24740 } 24741 } 24742 prg.flushCurExp(scaled(0)) 24743 } 24744 24745 func (prg *prg) storeBaseFile() { 24746 var ( 24747 k int32 // all-purpose index 24748 p, q halfword // all-purpose pointers 24749 x int32 // something to dump 24750 w fourQuarters // four ASCII codes 24751 ) 24752 prg.selector = byte(newString) 24753 prg.print( /* " (preloaded base=" */ 1071) 24754 prg.print(int32(prg.jobName)) 24755 prg.printChar(asciiCode(' ')) 24756 prg.printInt(prg.roundUnscaled(prg.internal[year-1])) 24757 prg.printChar(asciiCode('.')) 24758 prg.printInt(prg.roundUnscaled(prg.internal[month-1])) 24759 prg.printChar(asciiCode('.')) 24760 prg.printInt(prg.roundUnscaled(prg.internal[day-1])) 24761 prg.printChar(asciiCode(')')) 24762 if int32(prg.interaction) == batchMode { 24763 prg.selector = byte(logOnly) 24764 } else { 24765 prg.selector = byte(termAndLog) 24766 } 24767 { 24768 if int32(prg.poolPtr)+1 > int32(prg.maxPoolPtr) { 24769 if int32(prg.poolPtr)+1 > poolSize { 24770 prg.overflow(strNumber( /* "pool size" */ 257), poolSize-int32(prg.initPoolPtr)) 24771 } /* \xref[METAFONT capacity exceeded pool size][\quad pool size] */ 24772 prg.maxPoolPtr = uint16(int32(prg.poolPtr) + 1) 24773 } 24774 } 24775 prg.baseIdent = prg.makeString() 24776 prg.strRef[prg.baseIdent] = byte(maxStrRef) 24777 24778 prg.packJobName(strNumber(baseExtension)) 24779 for !prg.wOpenOut(prg.baseFile) { 24780 prg.promptFileName(strNumber( /* "base file name" */ 1072), strNumber(baseExtension)) 24781 } 24782 prg.printNl(strNumber( /* "Beginning to dump on file " */ 1073)) 24783 // \xref[Beginning to dump...] 24784 prg.slowPrint(int32(prg.wMakeNameString(prg.baseFile))) 24785 prg.flushString(strNumber(int32(prg.strPtr) - 1)) 24786 prg.printNl(strNumber( /* "" */ 285)) 24787 prg.slowPrint(int32(prg.baseIdent)) 24788 24789 // Dump constants for consistency check 24790 { 24791 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = 461259239 24792 prg.baseFile.Put() 24793 } 24794 24795 { 24796 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = memMin 24797 prg.baseFile.Put() 24798 } 24799 24800 { 24801 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = 3000 24802 prg.baseFile.Put() 24803 } 24804 24805 { 24806 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = hashSize 24807 prg.baseFile.Put() 24808 } 24809 24810 { 24811 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = hashPrime 24812 prg.baseFile.Put() 24813 } 24814 24815 { 24816 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = maxInOpen 24817 prg.baseFile.Put() 24818 } 24819 24820 // Dump the string pool 24821 { 24822 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.poolPtr) 24823 prg.baseFile.Put() 24824 } 24825 { 24826 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.strPtr) 24827 prg.baseFile.Put() 24828 } 24829 for ii := int32(0); ii <= int32(prg.strPtr); ii++ { 24830 k = ii 24831 _ = k 24832 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.strStart[k]) 24833 prg.baseFile.Put() 24834 } 24835 k = 0 24836 for k+4 < int32(prg.poolPtr) { 24837 w.b0 = byte(int32(prg.strPool[k]) + minQuarterword) 24838 w.b1 = byte(int32(prg.strPool[k+1]) + minQuarterword) 24839 w.b2 = byte(int32(prg.strPool[k+2]) + minQuarterword) 24840 w.b3 = byte(int32(prg.strPool[k+3]) + minQuarterword) 24841 { 24842 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).qqqq() = w 24843 prg.baseFile.Put() 24844 } 24845 k = k + 4 24846 } 24847 k = int32(prg.poolPtr) - 4 24848 w.b0 = byte(int32(prg.strPool[k]) + minQuarterword) 24849 w.b1 = byte(int32(prg.strPool[k+1]) + minQuarterword) 24850 w.b2 = byte(int32(prg.strPool[k+2]) + minQuarterword) 24851 w.b3 = byte(int32(prg.strPool[k+3]) + minQuarterword) 24852 { 24853 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).qqqq() = w 24854 prg.baseFile.Put() 24855 } 24856 prg.printLn() 24857 prg.printInt(int32(prg.strPtr)) 24858 prg.print( /* " strings of total length " */ 1068) 24859 prg.printInt(int32(prg.poolPtr)) 24860 24861 // Dump the dynamic memory 24862 prg.sortAvail() 24863 prg.varUsed = 0 24864 { 24865 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.loMemMax) 24866 prg.baseFile.Put() 24867 } 24868 { 24869 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.rover) 24870 prg.baseFile.Put() 24871 } 24872 p = uint16(memMin) 24873 q = prg.rover 24874 x = 0 24875 for { 24876 for ii := int32(p); ii <= int32(q)+1; ii++ { 24877 k = ii 24878 _ = k 24879 *(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P())) = prg.mem[k] 24880 prg.baseFile.Put() 24881 } 24882 x = x + int32(q) + 2 - int32(p) 24883 prg.varUsed = prg.varUsed + int32(q) - int32(p) 24884 p = uint16(int32(q) + int32(*(*prg.mem[q].hh()).lh())) 24885 q = *(*prg.mem[int32(q)+1].hh()).rh() 24886 if int32(q) == int32(prg.rover) { 24887 break 24888 } 24889 } 24890 prg.varUsed = prg.varUsed + int32(prg.loMemMax) - int32(p) 24891 prg.dynUsed = int32(prg.memEnd) + 1 - int32(prg.hiMemMin) 24892 24893 for ii := int32(p); ii <= int32(prg.loMemMax); ii++ { 24894 k = ii 24895 _ = k 24896 *(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P())) = prg.mem[k] 24897 prg.baseFile.Put() 24898 } 24899 x = x + int32(prg.loMemMax) + 1 - int32(p) 24900 { 24901 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.hiMemMin) 24902 prg.baseFile.Put() 24903 } 24904 { 24905 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.avail) 24906 prg.baseFile.Put() 24907 } 24908 for ii := int32(prg.hiMemMin); ii <= int32(prg.memEnd); ii++ { 24909 k = ii 24910 _ = k 24911 *(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P())) = prg.mem[k] 24912 prg.baseFile.Put() 24913 } 24914 x = x + int32(prg.memEnd) + 1 - int32(prg.hiMemMin) 24915 p = prg.avail 24916 for int32(p) != memMin { 24917 prg.dynUsed = prg.dynUsed - 1 24918 p = *(*prg.mem[p].hh()).rh() 24919 } 24920 { 24921 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = prg.varUsed 24922 prg.baseFile.Put() 24923 } 24924 { 24925 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = prg.dynUsed 24926 prg.baseFile.Put() 24927 } 24928 prg.printLn() 24929 prg.printInt(x) 24930 prg.print( /* " memory locations dumped; current usage is " */ 1069) 24931 prg.printInt(prg.varUsed) 24932 prg.printChar(asciiCode('&')) 24933 prg.printInt(prg.dynUsed) 24934 24935 // Dump the table of equivalents and the hash table 24936 { 24937 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.hashUsed) 24938 prg.baseFile.Put() 24939 } 24940 prg.stCount = hashBase + hashSize - 1 - int32(prg.hashUsed) 24941 for ii := int32(1); ii <= int32(prg.hashUsed); ii++ { 24942 p = halfword(ii) 24943 _ = p 24944 if int32(*prg.hash[p-1].rh()) != 0 { 24945 { 24946 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(p) 24947 prg.baseFile.Put() 24948 } 24949 { 24950 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).hh() = prg.hash[p-1] 24951 prg.baseFile.Put() 24952 } 24953 { 24954 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).hh() = prg.eqtb[p-1] 24955 prg.baseFile.Put() 24956 } 24957 prg.stCount = prg.stCount + 1 24958 } 24959 } 24960 for ii := int32(prg.hashUsed) + 1; ii <= hashBase+hashSize+12; ii++ { 24961 p = halfword(ii) 24962 _ = p 24963 { 24964 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).hh() = prg.hash[p-1] 24965 prg.baseFile.Put() 24966 } 24967 { 24968 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).hh() = prg.eqtb[p-1] 24969 prg.baseFile.Put() 24970 } 24971 } 24972 { 24973 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = prg.stCount 24974 prg.baseFile.Put() 24975 } 24976 24977 prg.printLn() 24978 prg.printInt(prg.stCount) 24979 prg.print( /* " symbolic tokens" */ 1070) 24980 24981 // Dump a few more things and the closing check word 24982 { 24983 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.intPtr) 24984 prg.baseFile.Put() 24985 } 24986 for ii := int32(1); ii <= int32(prg.intPtr); ii++ { 24987 k = ii 24988 _ = k 24989 { 24990 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = prg.internal[k-1] 24991 prg.baseFile.Put() 24992 } 24993 { 24994 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.intName[k-1]) 24995 prg.baseFile.Put() 24996 } 24997 } 24998 { 24999 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.startSym) 25000 prg.baseFile.Put() 25001 } 25002 { 25003 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.interaction) 25004 prg.baseFile.Put() 25005 } 25006 { 25007 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.baseIdent) 25008 prg.baseFile.Put() 25009 } 25010 { 25011 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.bgLoc) 25012 prg.baseFile.Put() 25013 } 25014 { 25015 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = int32(prg.egLoc) 25016 prg.baseFile.Put() 25017 } 25018 { 25019 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = prg.serialNo 25020 prg.baseFile.Put() 25021 } 25022 { 25023 *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() = 69069 25024 prg.baseFile.Put() 25025 } 25026 prg.internal[tracingStats-1] = 0 25027 25028 // Close the base file 25029 prg.wClose(prg.baseFile) 25030 } 25031 25032 func (prg *prg) doStatement() { 25033 prg.curType = byte(vacuous) 25034 prg.getXNext() 25035 if int32(prg.curCmd) > maxPrimaryCommand { 25036 if int32(prg.curCmd) < semicolon { 25037 { 25038 if int32(prg.interaction) == errorStopMode { 25039 } 25040 prg.printNl(strNumber( /* "! " */ 261)) 25041 prg.print( /* "A statement can't begin with `" */ 869) /* \xref[!\relax] */ 25042 } 25043 // \xref[A statement can't begin with x] 25044 prg.printCmdMod(int32(prg.curCmd), prg.curMod) 25045 prg.printChar(asciiCode('\'')) 25046 { 25047 prg.helpPtr = 5 25048 prg.helpLine[4] = /* "I was looking for the beginning of a new statement." */ 870 25049 prg.helpLine[3] = /* "If you just proceed without changing anything, I'll ignore" */ 871 25050 prg.helpLine[2] = /* "everything up to the next `;'. Please insert a semicolon" */ 872 25051 prg.helpLine[1] = /* "now in front of anything that you don't want me to delete." */ 873 25052 prg.helpLine[0] = /* "(See Chapter 27 of The METAFONTbook for an example.)" */ 874 25053 } 25054 25055 // \xref[METAFONTbook][\sl The [\logos METAFONT\/]book] 25056 prg.backError() 25057 prg.getXNext() 25058 } 25059 } else if int32(prg.curCmd) > maxStatementCommand { 25060 prg.varFlag = byte(assignment) 25061 prg.scanExpression() 25062 if int32(prg.curCmd) < endGroup { 25063 if int32(prg.curCmd) == equals { 25064 prg.doEquation() 25065 } else if int32(prg.curCmd) == assignment { 25066 prg.doAssignment() 25067 } else if int32(prg.curType) == stringType { 25068 if prg.internal[tracingTitles-1] > 0 { 25069 prg.printNl(strNumber( /* "" */ 285)) 25070 prg.slowPrint(prg.curExp) 25071 } 25072 if prg.internal[proofing-1] > 0 { 25073 if int32(prg.outputFileName) == 0 { 25074 prg.initGf() 25075 } 25076 prg.gfString(strNumber( /* "title " */ 1062), strNumber(prg.curExp)) 25077 // \xref[title] 25078 } 25079 } else if int32(prg.curType) != vacuous { 25080 prg.dispErr(halfword(memMin), strNumber( /* "Isolated expression" */ 879)) 25081 // \xref[Isolated expression] 25082 { 25083 prg.helpPtr = 3 25084 prg.helpLine[2] = /* "I couldn't find an `=' or `:=' after the" */ 880 25085 prg.helpLine[1] = /* "expression that is shown above this error message," */ 881 25086 prg.helpLine[0] = /* "so I guess I'll just ignore it and carry on." */ 882 25087 } 25088 prg.putGetError() 25089 } 25090 prg.flushCurExp(scaled(0)) 25091 prg.curType = byte(vacuous) 25092 } 25093 } else { 25094 // Do a statement that doesn't begin with an expression 25095 if prg.internal[tracingCommands-1] > 0 { 25096 prg.showCmdMod(int32(prg.curCmd), prg.curMod) 25097 } 25098 switch prg.curCmd { 25099 case typeName: 25100 prg.doTypeDeclaration() 25101 case macroDef: 25102 if prg.curMod > varDef { 25103 prg.makeOpDef() 25104 } else if prg.curMod > endDef { 25105 prg.scanDef() 25106 } 25107 // \4 25108 // Cases of |do_statement| that invoke particular commands 25109 case randomSeed: 25110 prg.doRandomSeed() 25111 25112 case modeCommand: 25113 prg.printLn() 25114 prg.interaction = byte(prg.curMod) 25115 25116 // Initialize the print |selector| based on |interaction| 25117 if int32(prg.interaction) == batchMode { 25118 prg.selector = byte(noPrint) 25119 } else { 25120 prg.selector = byte(termOnly) 25121 } 25122 if prg.logOpened { 25123 prg.selector = byte(int32(prg.selector) + 2) 25124 } 25125 prg.getXNext() 25126 25127 case protectionCommand: 25128 prg.doProtection() 25129 25130 case delimiters: 25131 prg.defDelims() 25132 25133 case saveCommand: 25134 for { 25135 prg.getSymbol() 25136 prg.saveVariable(prg.curSym) 25137 prg.getXNext() 25138 if int32(prg.curCmd) != comma { 25139 break 25140 } 25141 } 25142 case interimCommand: 25143 prg.doInterim() 25144 case letCommand: 25145 prg.doLet() 25146 case newInternal: 25147 prg.doNewInternal() 25148 25149 case showCommand: 25150 prg.doShowWhatever() 25151 25152 case addToCommand: 25153 prg.doAddTo() 25154 25155 case shipOutCommand: 25156 prg.doShipOut() 25157 case displayCommand: 25158 prg.doDisplay() 25159 case openWindow: 25160 prg.doOpenWindow() 25161 case cullCommand: 25162 prg.doCull() 25163 25164 case everyJobCommand: 25165 prg.getSymbol() 25166 prg.startSym = prg.curSym 25167 prg.getXNext() 25168 25169 case messageCommand: 25170 prg.doMessage() 25171 25172 case tfmCommand: 25173 prg.doTfmCommand() 25174 25175 case specialCommand: 25176 prg.doSpecial() 25177 25178 } // there are no other cases 25179 prg.curType = byte(vacuous) 25180 } 25181 if int32(prg.curCmd) < semicolon { 25182 { 25183 if int32(prg.interaction) == errorStopMode { 25184 } 25185 prg.printNl(strNumber( /* "! " */ 261)) 25186 prg.print( /* "Extra tokens will be flushed" */ 875) /* \xref[!\relax] */ 25187 } 25188 // \xref[Extra tokens will be flushed] 25189 { 25190 prg.helpPtr = 6 25191 prg.helpLine[5] = /* "I've just read as much of that statement as I could fathom," */ 876 25192 prg.helpLine[4] = /* "so a semicolon should have been next. It's very puzzling..." */ 877 25193 prg.helpLine[3] = /* "but I'll try to get myself back together, by ignoring" */ 878 25194 prg.helpLine[2] = /* "everything up to the next `;'. Please insert a semicolon" */ 872 25195 prg.helpLine[1] = /* "now in front of anything that you don't want me to delete." */ 873 25196 prg.helpLine[0] = /* "(See Chapter 27 of The METAFONTbook for an example.)" */ 874 25197 } 25198 25199 // \xref[METAFONTbook][\sl The [\logos METAFONT\/]book] 25200 prg.backError() 25201 prg.scannerStatus = byte(flushing) 25202 for { 25203 prg.getNext() 25204 25205 // Decrease the string reference count... 25206 if int32(prg.curCmd) == stringToken { 25207 if int32(prg.strRef[prg.curMod]) < maxStrRef { 25208 if int32(prg.strRef[prg.curMod]) > 1 { 25209 prg.strRef[prg.curMod] = byte(int32(prg.strRef[prg.curMod]) - 1) 25210 } else { 25211 prg.flushString(strNumber(prg.curMod)) 25212 } 25213 } 25214 } 25215 if int32(prg.curCmd) > comma { 25216 break 25217 } 25218 } // |cur_cmd=semicolon|, |end_group|, or |stop| 25219 prg.scannerStatus = byte(normal) 25220 } 25221 prg.errorCount = 0 25222 } 25223 25224 // 1017. 25225 25226 // tangle:pos ../../mf.web:19802:3: 25227 25228 // \MF's |main_control| procedure just calls |do_statement| repeatedly 25229 // until coming to the end of the user's program. 25230 // Each execution of |do_statement| concludes with 25231 // |cur_cmd=semicolon|, |end_group|, or |stop|. 25232 func (prg *prg) mainControl() { 25233 for { 25234 prg.doStatement() 25235 if int32(prg.curCmd) == endGroup { 25236 { 25237 if int32(prg.interaction) == errorStopMode { 25238 } 25239 prg.printNl(strNumber( /* "! " */ 261)) 25240 prg.print( /* "Extra `endgroup'" */ 910) /* \xref[!\relax] */ 25241 } 25242 // \xref[Extra `endgroup'] 25243 { 25244 prg.helpPtr = 2 25245 prg.helpLine[1] = /* "I'm not currently working on a `begingroup'," */ 911 25246 prg.helpLine[0] = /* "so I had better not try to end anything." */ 689 25247 } 25248 prg.flushError(scaled(0)) 25249 } 25250 if int32(prg.curCmd) == stop { 25251 break 25252 } 25253 } 25254 } 25255 25256 // 1088. 25257 25258 // tangle:pos ../../mf.web:20697:3: 25259 25260 // The first 24 bytes (6 words) of a \.[TFM] file contain twelve 16-bit 25261 // integers that give the lengths of the various subsequent portions 25262 // of the file. These twelve integers are, in order: 25263 // $$\vbox[\halign[\hfil#&$\null=\null$#\hfil\cr 25264 // |lf|&length of the entire file, in words;\cr 25265 // |lh|&length of the header data, in words;\cr 25266 // |bc|&smallest character code in the font;\cr 25267 // |ec|&largest character code in the font;\cr 25268 // |nw|&number of words in the width table;\cr 25269 // |nh|&number of words in the height table;\cr 25270 // |nd|&number of words in the depth table;\cr 25271 // |ni|&number of words in the italic correction table;\cr 25272 // |nl|&number of words in the lig/kern table;\cr 25273 // |nk|&number of words in the kern table;\cr 25274 // |ne|&number of words in the extensible character table;\cr 25275 // |np|&number of font parameter words.\cr]]$$ 25276 // They are all nonnegative and less than $2^[15]$. We must have |bc-1<=ec<=255|, 25277 // |ne<=256|, and 25278 // $$\hbox[|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.]$$ 25279 // Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|), 25280 // and as few as 0 characters (if |bc=ec+1|). 25281 // 25282 // Incidentally, when two or more 8-bit bytes are combined to form an integer of 25283 // 16 or more bits, the most significant bytes appear first in the file. 25284 // This is called BigEndian order. 25285 // \xref[BigEndian order] 25286 25287 // 1089. 25288 25289 // tangle:pos ../../mf.web:20724:3: 25290 25291 // The rest of the \.[TFM] file may be regarded as a sequence of ten data 25292 // arrays having the informal specification 25293 // $$\def\arr$[#1]#2$[\&[array] $[#1]$ \&[of] #2] 25294 // \tabskip\centering 25295 // \halign to\displaywidth[\hfil\\[#]\tabskip=0pt&$\,:\,$\arr#\hfil 25296 // \tabskip\centering\cr 25297 // header&|[0..lh-1]\\[stuff]|\cr 25298 // char\_info&|[bc..ec]char_info_word|\cr 25299 // width&|[0..nw-1]fix_word|\cr 25300 // height&|[0..nh-1]fix_word|\cr 25301 // depth&|[0..nd-1]fix_word|\cr 25302 // italic&|[0..ni-1]fix_word|\cr 25303 // lig\_kern&|[0..nl-1]lig_kern_command|\cr 25304 // kern&|[0..nk-1]fix_word|\cr 25305 // exten&|[0..ne-1]extensible_recipe|\cr 25306 // param&|[1..np]fix_word|\cr]$$ 25307 // The most important data type used here is a | fix_word|, which is 25308 // a 32-bit representation of a binary fraction. A |fix_word| is a signed 25309 // quantity, with the two's complement of the entire word used to represent 25310 // negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the 25311 // binary point; thus, the largest |fix_word| value is $2048-2^[-20]$, and 25312 // the smallest is $-2048$. We will see below, however, that all but two of 25313 // the |fix_word| values must lie between $-16$ and $+16$. 25314 25315 // 1090. 25316 25317 // tangle:pos ../../mf.web:20748:3: 25318 25319 // The first data array is a block of header information, which contains 25320 // general facts about the font. The header must contain at least two words, 25321 // |header[0]| and |header[1]|, whose meaning is explained below. Additional 25322 // header information of use to other software routines might also be 25323 // included, and \MF\ will generate it if the \.[headerbyte] command occurs. 25324 // For example, 16 more words of header information are in use at the Xerox 25325 // Palo Alto Research Center; the first ten specify the character coding 25326 // scheme used (e.g., `\.[XEROX TEXT]' or `\.[TEX MATHSY]'), the next five 25327 // give the font family name (e.g., `\.[HELVETICA]' or `\.[CMSY]'), and the 25328 // last gives the ``face byte.'' 25329 // 25330 // \yskip\hang|header[0]| is a 32-bit check sum that \MF\ will copy into 25331 // the \.[GF] output file. This helps ensure consistency between files, 25332 // since \TeX\ records the check sums from the \.[TFM]'s it reads, and these 25333 // should match the check sums on actual fonts that are used. The actual 25334 // relation between this check sum and the rest of the \.[TFM] file is not 25335 // important; the check sum is simply an identification number with the 25336 // property that incompatible fonts almost always have distinct check sums. 25337 // \xref[check sum] 25338 // 25339 // \yskip\hang|header[1]| is a |fix_word| containing the design size of the 25340 // font, in units of \TeX\ points. This number must be at least 1.0; it is 25341 // fairly arbitrary, but usually the design size is 10.0 for a ``10 point'' 25342 // font, i.e., a font that was designed to look best at a 10-point size, 25343 // whatever that really means. When a \TeX\ user asks for a font `\.[at] 25344 // $\delta$ \.[pt]', the effect is to override the design size and replace it 25345 // by $\delta$, and to multiply the $x$ and~$y$ coordinates of the points in 25346 // the font image by a factor of $\delta$ divided by the design size. [\sl 25347 // All other dimensions in the\/ \.[TFM] file are |fix_word|\kern-1pt\ 25348 // numbers in design-size units.] Thus, for example, the value of |param[6]|, 25349 // which defines the \.[em] unit, is often the |fix_word| value $2^[20]=1.0$, 25350 // since many fonts have a design size equal to one em. The other dimensions 25351 // must be less than 16 design-size units in absolute value; thus, 25352 // |header[1]| and |param[1]| are the only |fix_word| entries in the whole 25353 // \.[TFM] file whose first byte might be something besides 0 or 255. 25354 // \xref[design size] 25355 25356 // 1091. 25357 25358 // tangle:pos ../../mf.web:20785:3: 25359 25360 // Next comes the |char_info| array, which contains one | char_info_word| 25361 // per character. Each word in this part of the file contains six fields 25362 // packed into four bytes as follows. 25363 // 25364 // \yskip\hang first byte: | width_index| (8 bits)\par 25365 // \hang second byte: | height_index| (4 bits) times 16, plus | depth_index| 25366 // (4~bits)\par 25367 // \hang third byte: | italic_index| (6 bits) times 4, plus | tag| 25368 // (2~bits)\par 25369 // \hang fourth byte: | remainder| (8 bits)\par 25370 // \yskip\noindent 25371 // The actual width of a character is \\[width]|[width_index]|, in design-size 25372 // units; this is a device for compressing information, since many characters 25373 // have the same width. Since it is quite common for many characters 25374 // to have the same height, depth, or italic correction, the \.[TFM] format 25375 // imposes a limit of 16 different heights, 16 different depths, and 25376 // 64 different italic corrections. 25377 // 25378 // Incidentally, the relation $\\[width][0]=\\[height][0]=\\[depth][0]= 25379 // \\[italic][0]=0$ should always hold, so that an index of zero implies a 25380 // value of zero. The |width_index| should never be zero unless the 25381 // character does not exist in the font, since a character is valid if and 25382 // only if it lies between |bc| and |ec| and has a nonzero |width_index|. 25383 25384 // 1092. 25385 25386 // tangle:pos ../../mf.web:20809:3: 25387 25388 // The |tag| field in a |char_info_word| has four values that explain how to 25389 // interpret the |remainder| field. 25390 // 25391 // \def\hangg#1 [\hang\hbox[#1 ]] 25392 // \yskip\hangg|tag=0| (|no_tag|) means that |remainder| is unused.\par 25393 // \hangg|tag=1| (|lig_tag|) means that this character has a ligature/kerning 25394 // program starting at location |remainder| in the |lig_kern| array.\par 25395 // \hangg|tag=2| (|list_tag|) means that this character is part of a chain of 25396 // characters of ascending sizes, and not the largest in the chain. The 25397 // |remainder| field gives the character code of the next larger character.\par 25398 // \hangg|tag=3| (|ext_tag|) means that this character code represents an 25399 // extensible character, i.e., a character that is built up of smaller pieces 25400 // so that it can be made arbitrarily large. The pieces are specified in 25401 // | exten[remainder]|.\par 25402 // \yskip\noindent 25403 // Characters with |tag=2| and |tag=3| are treated as characters with |tag=0| 25404 // unless they are used in special circumstances in math formulas. For example, 25405 // \TeX's \.[\\sum] operation looks for a |list_tag|, and the \.[\\left] 25406 // operation looks for both |list_tag| and |ext_tag|. 25407 25408 // 1093. 25409 25410 // tangle:pos ../../mf.web:20834:3: 25411 25412 // The |lig_kern| array contains instructions in a simple programming language 25413 // that explains what to do for special letter pairs. Each word in this array is a 25414 // | lig_kern_command| of four bytes. 25415 // 25416 // \yskip\hang first byte: |skip_byte|, indicates that this is the final program 25417 // step if the byte is 128 or more, otherwise the next step is obtained by 25418 // skipping this number of intervening steps.\par 25419 // \hang second byte: |next_char|, ``if |next_char| follows the current character, 25420 // then perform the operation and stop, otherwise continue.''\par 25421 // \hang third byte: |op_byte|, indicates a ligature step if less than~128, 25422 // a kern step otherwise.\par 25423 // \hang fourth byte: |remainder|.\par 25424 // \yskip\noindent 25425 // In a kern step, an 25426 // additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted 25427 // between the current character and |next_char|. This amount is 25428 // often negative, so that the characters are brought closer together 25429 // by kerning; but it might be positive. 25430 // 25431 // There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where 25432 // $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is 25433 // |remainder| is inserted between the current character and |next_char|; 25434 // then the current character is deleted if $b=0$, and |next_char| is 25435 // deleted if $c=0$; then we pass over $a$~characters to reach the next 25436 // current character (which may have a ligature/kerning program of its own). 25437 // 25438 // If the very first instruction of the |lig_kern| array has |skip_byte=255|, 25439 // the |next_char| byte is the so-called boundary character of this font; 25440 // the value of |next_char| need not lie between |bc| and~|ec|. 25441 // If the very last instruction of the |lig_kern| array has |skip_byte=255|, 25442 // there is a special ligature/kerning program for a boundary character at the 25443 // left, beginning at location |256*op_byte+remainder|. 25444 // The interpretation is that \TeX\ puts implicit boundary characters 25445 // before and after each consecutive string of characters from the same font. 25446 // These implicit characters do not appear in the output, but they can affect 25447 // ligatures and kerning. 25448 // 25449 // If the very first instruction of a character's |lig_kern| program has 25450 // |skip_byte>128|, the program actually begins in location 25451 // |256*op_byte+remainder|. This feature allows access to large |lig_kern| 25452 // arrays, because the first instruction must otherwise 25453 // appear in a location |<=255|. 25454 // 25455 // Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy 25456 // the condition 25457 // $$\hbox[|256*op_byte+remainder<nl|.]$$ 25458 // If such an instruction is encountered during 25459 // normal program execution, it denotes an unconditional halt; no ligature 25460 // or kerning command is performed. 25461 25462 // 1094. 25463 25464 // tangle:pos ../../mf.web:20892:3: 25465 25466 // Extensible characters are specified by an | extensible_recipe|, which 25467 // consists of four bytes called | top|, | mid|, | bot|, and | rep| (in this 25468 // order). These bytes are the character codes of individual pieces used to 25469 // build up a large symbol. If |top|, |mid|, or |bot| are zero, they are not 25470 // present in the built-up result. For example, an extensible vertical line is 25471 // like an extensible bracket, except that the top and bottom pieces are missing. 25472 // 25473 // Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box 25474 // if the piece isn't present. Then the extensible characters have the form 25475 // $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent; 25476 // in the latter case we can have $TR^kB$ for both even and odd values of~|k|. 25477 // The width of the extensible character is the width of $R$; and the 25478 // height-plus-depth is the sum of the individual height-plus-depths of the 25479 // components used, since the pieces are butted together in a vertical list. 25480 25481 // 1095. 25482 25483 // tangle:pos ../../mf.web:20912:3: 25484 25485 // The final portion of a \.[TFM] file is the |param| array, which is another 25486 // sequence of |fix_word| values. 25487 // 25488 // \yskip\hang|param[1]=slant| is the amount of italic slant, which is used 25489 // to help position accents. For example, |slant=.25| means that when you go 25490 // up one unit, you also go .25 units to the right. The |slant| is a pure 25491 // number; it is the only |fix_word| other than the design size itself that is 25492 // not scaled by the design size. 25493 // \xref[design size] 25494 // 25495 // \hang|param[2]=space| is the normal spacing between words in text. 25496 // Note that character @'40 in the font need not have anything to do with 25497 // blank spaces. 25498 // 25499 // \hang|param[3]=space_stretch| is the amount of glue stretching between words. 25500 // 25501 // \hang|param[4]=space_shrink| is the amount of glue shrinking between words. 25502 // 25503 // \hang|param[5]=x_height| is the size of one ex in the font; it is also 25504 // the height of letters for which accents don't have to be raised or lowered. 25505 // 25506 // \hang|param[6]=quad| is the size of one em in the font. 25507 // 25508 // \hang|param[7]=extra_space| is the amount added to |param[2]| at the 25509 // ends of sentences. 25510 // 25511 // \yskip\noindent 25512 // If fewer than seven parameters are present, \TeX\ sets the missing parameters 25513 // to zero. 25514 25515 // 1117. 25516 25517 // tangle:pos ../../mf.web:21341:3: 25518 25519 // Straight linear insertion is good enough for sorting, since the lists 25520 // are usually not terribly long. As we work on the data, the current list 25521 // will start at |link(temp_head)| and end at |inf_val|; the nodes in this 25522 // list will be in increasing order of their |value| fields. 25523 // 25524 // Given such a list, the |sort_in| function takes a value and returns a pointer 25525 // to where that value can be found in the list. The value is inserted in 25526 // the proper place, if necessary. 25527 // 25528 // At the time we need to do these operations, most of \MF's work has been 25529 // completed, so we will have plenty of memory to play with. The value nodes 25530 // that are allocated for sorting will never be returned to free storage. 25531 func (prg *prg) sortIn(v scaled) (r halfword) { 25532 var ( 25533 p, q, r1 halfword // list manipulation registers 25534 ) 25535 p = uint16(3000 - 1) 25536 for true { 25537 q = *(*prg.mem[p].hh()).rh() 25538 if v <= *prg.mem[int32(q)+1].int() { 25539 goto found 25540 } 25541 p = q 25542 } 25543 25544 found: 25545 if v < *prg.mem[int32(q)+1].int() { 25546 r1 = prg.getNode(valueNodeSize) 25547 *prg.mem[int32(r1)+1].int() = v 25548 *(*prg.mem[r1].hh()).rh() = q 25549 *(*prg.mem[p].hh()).rh() = r1 25550 } 25551 r = *(*prg.mem[p].hh()).rh() 25552 return r 25553 } 25554 25555 // 1118. 25556 25557 // tangle:pos ../../mf.web:21370:3: 25558 25559 // Now we come to the interesting part, where we reduce the list if necessary 25560 // until it has the required size. The |min_cover| routine is basic to this 25561 // process; it computes the minimum number~|m| such that the values of the 25562 // current sorted list can be covered by |m|~intervals of width~|d|. It 25563 // also sets the global value |perturbation| to the smallest value $d'>d$ 25564 // such that the covering found by this algorithm would be different. 25565 // 25566 // In particular, |min_cover(0)| returns the number of distinct values in the 25567 // current list and sets |perturbation| to the minimum distance between 25568 // adjacent values. 25569 func (prg *prg) minCover(d scaled) (r int32) { 25570 var ( 25571 p halfword // runs through the current list 25572 l scaled // the least element covered by the current interval 25573 m int32 // lower bound on the size of the minimum cover 25574 ) 25575 m = 0 25576 p = *(*prg.mem[3000-1].hh()).rh() 25577 prg.perturbation = 017777777777 25578 for int32(p) != memMin+3+10+2+2+2 { 25579 m = m + 1 25580 l = *prg.mem[int32(p)+1].int() 25581 for { 25582 p = *(*prg.mem[p].hh()).rh() 25583 if *prg.mem[int32(p)+1].int() > l+d { 25584 break 25585 } 25586 } 25587 if *prg.mem[int32(p)+1].int()-l < prg.perturbation { 25588 prg.perturbation = *prg.mem[int32(p)+1].int() - l 25589 } 25590 } 25591 r = m 25592 return r 25593 } 25594 25595 // 1120. 25596 25597 // tangle:pos ../../mf.web:21399:3: 25598 25599 // The smallest |d| such that a given list can be covered with |m| intervals 25600 // is determined by the |threshold| routine, which is sort of an inverse 25601 // to |min_cover|. The idea is to increase the interval size rapidly until 25602 // finding the range, then to go sequentially until the exact borderline has 25603 // been discovered. 25604 func (prg *prg) threshold(m int32) (r scaled) { 25605 var ( 25606 d scaled // lower bound on the smallest interval size 25607 ) 25608 prg.excess = prg.minCover(scaled(0)) - m 25609 if prg.excess <= 0 { 25610 r = 0 25611 } else { 25612 for { 25613 d = prg.perturbation 25614 if prg.minCover(d+d) <= m { 25615 break 25616 } 25617 } 25618 for prg.minCover(d) > m { 25619 d = prg.perturbation 25620 } 25621 r = d 25622 } 25623 return r 25624 } 25625 25626 // 1121. 25627 25628 // tangle:pos ../../mf.web:21416:3: 25629 25630 // The |skimp| procedure reduces the current list to at most |m| entries, 25631 // by changing values if necessary. It also sets |info(p):=k| if |value(p)| 25632 // is the |k|th distinct value on the resulting list, and it sets 25633 // |perturbation| to the maximum amount by which a |value| field has 25634 // been changed. The size of the resulting list is returned as the 25635 // value of |skimp|. 25636 func (prg *prg) skimp(m int32) (r int32) { 25637 var ( 25638 d scaled // the size of intervals being coalesced 25639 p, q, r1 halfword // list manipulation registers 25640 l scaled // the least value in the current interval 25641 v scaled // a compromise value 25642 ) 25643 d = prg.threshold(m) 25644 prg.perturbation = 0 25645 q = uint16(3000 - 1) 25646 m = 0 25647 p = *(*prg.mem[3000-1].hh()).rh() 25648 for int32(p) != memMin+3+10+2+2+2 { 25649 m = m + 1 25650 l = *prg.mem[int32(p)+1].int() 25651 *(*prg.mem[p].hh()).lh() = uint16(m) 25652 if *prg.mem[int32(*(*prg.mem[p].hh()).rh())+1].int() <= l+d { 25653 for { 25654 p = *(*prg.mem[p].hh()).rh() 25655 *(*prg.mem[p].hh()).lh() = uint16(m) 25656 prg.excess = prg.excess - 1 25657 if prg.excess == 0 { 25658 d = 0 25659 } 25660 if *prg.mem[int32(*(*prg.mem[p].hh()).rh())+1].int() > l+d { 25661 break 25662 } 25663 } 25664 v = l + (*prg.mem[int32(p)+1].int()-l)/2 25665 if *prg.mem[int32(p)+1].int()-v > prg.perturbation { 25666 prg.perturbation = *prg.mem[int32(p)+1].int() - v 25667 } 25668 r1 = q 25669 for { 25670 r1 = *(*prg.mem[r1].hh()).rh() 25671 *prg.mem[int32(r1)+1].int() = v 25672 if int32(r1) == int32(p) { 25673 break 25674 } 25675 } 25676 *(*prg.mem[q].hh()).rh() = p // remove duplicate values from the current list 25677 } 25678 q = p 25679 p = *(*prg.mem[p].hh()).rh() 25680 } 25681 r = m 25682 return r 25683 } 25684 25685 // 1123. 25686 25687 // tangle:pos ../../mf.web:21451:3: 25688 25689 // A warning message is issued whenever something is perturbed by 25690 // more than 1/16\thinspace pt. 25691 func (prg *prg) tfmWarning(m smallNumber) { 25692 prg.printNl(strNumber( /* "(some " */ 1041)) 25693 prg.print(int32(prg.intName[m-1])) 25694 // \xref[some charwds...] 25695 // \xref[some chardps...] 25696 // \xref[some charhts...] 25697 // \xref[some charics...] 25698 prg.print( /* " values had to be adjusted by as much as " */ 1042) 25699 prg.printScaled(prg.perturbation) 25700 prg.print( /* "pt)" */ 1043) 25701 } 25702 25703 // 1128. 25704 25705 // tangle:pos ../../mf.web:21510:3: 25706 25707 // Bytes 5--8 of the header are set to the design size, unless the user has 25708 // some crazy reason for specifying them differently. 25709 // \xref[design size] 25710 // 25711 // Error messages are not allowed at the time this procedure is called, 25712 // so a warning is printed instead. 25713 // 25714 // The value of |max_tfm_dimen| is calculated so that 25715 // $$\hbox[|make_scaled(16*max_tfm_dimen,internal[design_size])|] 25716 // < \\[three\_bytes].$$ 25717 func (prg *prg) fixDesignSize() { 25718 var ( 25719 d scaled // the design size 25720 ) 25721 d = prg.internal[designSize-1] 25722 if d < 0200000 || d >= 01000000000 { 25723 if d != 0 { 25724 prg.printNl(strNumber( /* "(illegal design size has been changed to 128pt)" */ 1044)) 25725 } 25726 // \xref[illegal design size...] 25727 d = 040000000 25728 prg.internal[designSize-1] = d 25729 } 25730 if int32(prg.headerByte[5-1]) < 0 { 25731 if int32(prg.headerByte[6-1]) < 0 { 25732 if int32(prg.headerByte[7-1]) < 0 { 25733 if int32(prg.headerByte[8-1]) < 0 { 25734 prg.headerByte[5-1] = int16(d / 04000000) 25735 prg.headerByte[6-1] = int16(d / 4096 % 256) 25736 prg.headerByte[7-1] = int16(d / 16 % 256) 25737 prg.headerByte[8-1] = int16(d % 16 * 16) 25738 } 25739 } 25740 } 25741 } 25742 prg.maxTfmDimen = 16*prg.internal[designSize-1] - 1 - prg.internal[designSize-1]/010000000 25743 if prg.maxTfmDimen >= 01000000000 { 25744 prg.maxTfmDimen = 01000000000 - 1 25745 } 25746 } 25747 25748 // 1129. 25749 25750 // tangle:pos ../../mf.web:21543:3: 25751 25752 // The |dimen_out| procedure computes a |fix_word| relative to the 25753 // design size. If the data was out of range, it is corrected and the 25754 // global variable |tfm_changed| is increased by~one. 25755 func (prg *prg) dimenOut(x scaled) (r int32) { 25756 if abs(x) > prg.maxTfmDimen { 25757 prg.tfmChanged = prg.tfmChanged + 1 25758 if x > 0 { 25759 x = prg.maxTfmDimen 25760 } else { 25761 x = -prg.maxTfmDimen 25762 } 25763 } 25764 x = prg.makeScaled(x*16, prg.internal[designSize-1]) 25765 r = x 25766 return r 25767 } 25768 25769 // 1131. 25770 25771 // tangle:pos ../../mf.web:21560:3: 25772 25773 // If the user has not specified any of the first four header bytes, 25774 // the |fix_check_sum| procedure replaces them by a ``check sum'' computed 25775 // from the |tfm_width| data relative to the design size. 25776 // \xref[check sum] 25777 func (prg *prg) fixCheckSum() { 25778 var ( 25779 k eightBits // runs through character codes 25780 b1, b2, b3, b4 eightBits // bytes of the check sum 25781 x int32 // hash value used in check sum computation 25782 ) 25783 if int32(prg.headerByte[1-1]) < 0 { 25784 if int32(prg.headerByte[2-1]) < 0 { 25785 if int32(prg.headerByte[3-1]) < 0 { 25786 if int32(prg.headerByte[4-1]) < 0 { 25787 b1 = prg.bc 25788 b2 = prg.ec 25789 b3 = prg.bc 25790 b4 = prg.ec 25791 prg.tfmChanged = 0 25792 for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ { 25793 k = eightBits(ii) 25794 _ = k 25795 if prg.charExists[k] { 25796 x = prg.dimenOut(*prg.mem[prg.tfmWidth[k]+1].int()) + (int32(k)+4)*020000000 // this is positive 25797 b1 = byte((int32(b1) + int32(b1) + x) % 255) 25798 b2 = byte((int32(b2) + int32(b2) + x) % 253) 25799 b3 = byte((int32(b3) + int32(b3) + x) % 251) 25800 b4 = byte((int32(b4) + int32(b4) + x) % 247) 25801 } 25802 } 25803 prg.headerByte[1-1] = int16(b1) 25804 prg.headerByte[2-1] = int16(b2) 25805 prg.headerByte[3-1] = int16(b3) 25806 prg.headerByte[4-1] = int16(b4) 25807 goto exit 25808 } 25809 } 25810 } 25811 } 25812 for ii := int32(1); ii <= 4; ii++ { 25813 k = eightBits(ii) 25814 _ = k 25815 if int32(prg.headerByte[k-1]) < 0 { 25816 prg.headerByte[k-1] = 0 25817 } 25818 } 25819 25820 exit: 25821 } 25822 25823 // 1133. 25824 25825 // tangle:pos ../../mf.web:21589:3: 25826 25827 // Finally we're ready to actually write the \.[TFM] information. 25828 // Here are some utility routines for this purpose. 25829 func (prg *prg) tfmTwo(x int32) { 25830 prg.tfmFile.Write(x / 256) 25831 prg.tfmFile.Write(x % 256) 25832 } 25833 25834 func (prg *prg) tfmFour(x int32) { 25835 if x >= 0 { 25836 prg.tfmFile.Write(x / 0100000000) 25837 } else { 25838 x = x + 010000000000 // use two's complement for negative values 25839 x = x + 010000000000 25840 prg.tfmFile.Write(x/0100000000 + 128) 25841 } 25842 x = x % 0100000000 25843 prg.tfmFile.Write(x / 0200000) 25844 x = x % 0200000 25845 prg.tfmFile.Write(x / 0400) 25846 prg.tfmFile.Write(x % 0400) 25847 } 25848 25849 func (prg *prg) tfmQqqq(x fourQuarters) { 25850 prg.tfmFile.Write(int32(x.b0) - minQuarterword) 25851 prg.tfmFile.Write(int32(x.b1) - minQuarterword) 25852 prg.tfmFile.Write(int32(x.b2) - minQuarterword) 25853 prg.tfmFile.Write(int32(x.b3) - minQuarterword) 25854 } 25855 25856 // 1142. \[46] Generic font file format 25857 25858 // tangle:pos ../../mf.web:21761:35: 25859 25860 // The most important output produced by a typical run of \MF\ is the 25861 // ``generic font'' (\.[GF]) file that specifies the bit patterns of the 25862 // characters that have been drawn. The term [\sl generic\/] indicates that 25863 // this file format doesn't match the conventions of any name-brand manufacturer; 25864 // but it is easy to convert \.[GF] files to the special format required by 25865 // almost all digital phototypesetting equipment. There's a strong analogy 25866 // between the \.[DVI] files written by \TeX\ and the \.[GF] files written 25867 // by \MF; and, in fact, the file formats have a lot in common. 25868 // 25869 // A \.[GF] file is a stream of 8-bit bytes that may be 25870 // regarded as a series of commands in a machine-like language. The first 25871 // byte of each command is the operation code, and this code is followed by 25872 // zero or more bytes that provide parameters to the command. The parameters 25873 // themselves may consist of several consecutive bytes; for example, the 25874 // `|boc|' (beginning of character) command has six parameters, each of 25875 // which is four bytes long. Parameters are usually regarded as nonnegative 25876 // integers; but four-byte-long parameters can be either positive or 25877 // negative, hence they range in value from $-2^[31]$ to $2^[31]-1$. 25878 // As in \.[TFM] files, numbers that occupy 25879 // more than one byte position appear in BigEndian order, 25880 // and negative numbers appear in two's complement notation. 25881 // 25882 // A \.[GF] file consists of a ``preamble,'' followed by a sequence of one or 25883 // more ``characters,'' followed by a ``postamble.'' The preamble is simply a 25884 // |pre| command, with its parameters that introduce the file; this must come 25885 // first. Each ``character'' consists of a |boc| command, followed by any 25886 // number of other commands that specify ``black'' pixels, 25887 // followed by an |eoc| command. The characters appear in the order that \MF\ 25888 // generated them. If we ignore no-op commands (which are allowed between any 25889 // two commands in the file), each |eoc| command is immediately followed by a 25890 // |boc| command, or by a |post| command; in the latter case, there are no 25891 // more characters in the file, and the remaining bytes form the postamble. 25892 // Further details about the postamble will be explained later. 25893 // 25894 // Some parameters in \.[GF] commands are ``pointers.'' These are four-byte 25895 // quantities that give the location number of some other byte in the file; 25896 // the first file byte is number~0, then comes number~1, and so on. 25897 25898 // 1143. 25899 25900 // tangle:pos ../../mf.web:21800:3: 25901 25902 // The \.[GF] format is intended to be both compact and easily interpreted 25903 // by a machine. Compactness is achieved by making most of the information 25904 // relative instead of absolute. When a \.[GF]-reading program reads the 25905 // commands for a character, it keeps track of two quantities: (a)~the current 25906 // column number,~|m|; and (b)~the current row number,~|n|. These are 32-bit 25907 // signed integers, although most actual font formats produced from \.[GF] 25908 // files will need to curtail this vast range because of practical 25909 // limitations. (\MF\ output will never allow $\vert m\vert$ or $\vert 25910 // n\vert$ to get extremely large, but the \.[GF] format tries to be more general.) 25911 // 25912 // How do \.[GF]'s row and column numbers correspond to the conventions 25913 // of \TeX\ and \MF? Well, the ``reference point'' of a character, in \TeX's 25914 // view, is considered to be at the lower left corner of the pixel in row~0 25915 // and column~0. This point is the intersection of the baseline with the left 25916 // edge of the type; it corresponds to location $(0,0)$ in \MF\ programs. 25917 // Thus the pixel in \.[GF] row~0 and column~0 is \MF's unit square, comprising the 25918 // region of the plane whose coordinates both lie between 0 and~1. The 25919 // pixel in \.[GF] row~|n| and column~|m| consists of the points whose \MF\ 25920 // coordinates |(x,y)| satisfy |m<=x<=m+1| and |n<=y<=n+1|. Negative values of 25921 // |m| and~|x| correspond to columns of pixels [\sl left\/] of the reference 25922 // point; negative values of |n| and~|y| correspond to rows of pixels [\sl 25923 // below\/] the baseline. 25924 // 25925 // Besides |m| and |n|, there's also a third aspect of the current 25926 // state, namely the |paint_switch|, which is always either |black| or 25927 // |white|. Each \\[paint] command advances |m| by a specified amount~|d|, 25928 // and blackens the intervening pixels if |paint_switch=black|; then 25929 // the |paint_switch| changes to the opposite state. \.[GF]'s commands are 25930 // designed so that |m| will never decrease within a row, and |n| will never 25931 // increase within a character; hence there is no way to whiten a pixel that 25932 // has been blackened. 25933 25934 // 1144. 25935 25936 // tangle:pos ../../mf.web:21832:3: 25937 25938 // Here is a list of all the commands that may appear in a \.[GF] file. Each 25939 // command is specified by its symbolic name (e.g., |boc|), its opcode byte 25940 // (e.g., 67), and its parameters (if any). The parameters are followed 25941 // by a bracketed number telling how many bytes they occupy; for example, 25942 // `|d[2]|' means that parameter |d| is two bytes long. 25943 // 25944 // \yskip\hang|paint_0| 0. This is a \\[paint] command with |d=0|; it does 25945 // nothing but change the |paint_switch| from \\[black] to \\[white] or vice~versa. 25946 // 25947 // \yskip\hang\\[paint\_1] through \\[paint\_63] (opcodes 1 to 63). 25948 // These are \\[paint] commands with |d=1| to~63, defined as follows: If 25949 // |paint_switch=black|, blacken |d|~pixels of the current row~|n|, 25950 // in columns |m| through |m+d-1| inclusive. Then, in any case, 25951 // complement the |paint_switch| and advance |m| by~|d|. 25952 // 25953 // \yskip\hang|paint1| 64 |d[1]|. This is a \\[paint] command with a specified 25954 // value of~|d|; \MF\ uses it to paint when |64<=d<256|. 25955 // 25956 // \yskip\hang| paint2| 65 |d[2]|. Same as |paint1|, but |d|~can be as high 25957 // as~65535. 25958 // 25959 // \yskip\hang| paint3| 66 |d[3]|. Same as |paint1|, but |d|~can be as high 25960 // as $2^[24]-1$. \MF\ never needs this command, and it is hard to imagine 25961 // anybody making practical use of it; surely a more compact encoding will be 25962 // desirable when characters can be this large. But the command is there, 25963 // anyway, just in case. 25964 // 25965 // \yskip\hang|boc| 67 |c[4]| |p[4]| |min_m[4]| |max_m[4]| |min_n[4]| 25966 // |max_n[4]|. Beginning of a character: Here |c| is the character code, and 25967 // |p| points to the previous character beginning (if any) for characters having 25968 // this code number modulo 256. (The pointer |p| is |-1| if there was no 25969 // prior character with an equivalent code.) The values of registers |m| and |n| 25970 // defined by the instructions that follow for this character must 25971 // satisfy |min_m<=m<=max_m| and |min_n<=n<=max_n|. (The values of |max_m| and 25972 // |min_n| need not be the tightest bounds possible.) When a \.[GF]-reading 25973 // program sees a |boc|, it can use |min_m|, |max_m|, |min_n|, and |max_n| to 25974 // initialize the bounds of an array. Then it sets |m:=min_m|, |n:=max_n|, and 25975 // |paint_switch:=white|. 25976 // 25977 // \yskip\hang|boc1| 68 |c[1]| | del_m[1]| |max_m[1]| | del_n[1]| |max_n[1]|. 25978 // Same as |boc|, but |p| is assumed to be~$-1$; also |del_m=max_m-min_m| 25979 // and |del_n=max_n-min_n| are given instead of |min_m| and |min_n|. 25980 // The one-byte parameters must be between 0 and 255, inclusive. 25981 // \ (This abbreviated |boc| saves 19~bytes per character, in common cases.) 25982 // 25983 // \yskip\hang|eoc| 69. End of character: All pixels blackened so far 25984 // constitute the pattern for this character. In particular, a completely 25985 // blank character might have |eoc| immediately following |boc|. 25986 // 25987 // \yskip\hang|skip0| 70. Decrease |n| by 1 and set |m:=min_m|, 25988 // |paint_switch:=white|. \ (This finishes one row and begins another, 25989 // ready to whiten the leftmost pixel in the new row.) 25990 // 25991 // \yskip\hang|skip1| 71 |d[1]|. Decrease |n| by |d+1|, set |m:=min_m|, and set 25992 // |paint_switch:=white|. This is a way to produce |d| all-white rows. 25993 // 25994 // \yskip\hang| skip2| 72 |d[2]|. Same as |skip1|, but |d| can be as large 25995 // as 65535. 25996 // 25997 // \yskip\hang| skip3| 73 |d[3]|. Same as |skip1|, but |d| can be as large 25998 // as $2^[24]-1$. \MF\ obviously never needs this command. 25999 // 26000 // \yskip\hang|new_row_0| 74. Decrease |n| by 1 and set |m:=min_m|, 26001 // |paint_switch:=black|. \ (This finishes one row and begins another, 26002 // ready to [\sl blacken\/] the leftmost pixel in the new row.) 26003 // 26004 // \yskip\hang| new_row_1| through | new_row_164| (opcodes 75 to 238). Same as 26005 // |new_row_0|, but with |m:=min_m+1| through |min_m+164|, respectively. 26006 // 26007 // \yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in 26008 // general; it functions as a $(k+2)$-byte |no_op| unless special \.[GF]-reading 26009 // programs are being used. \MF\ generates \\[xxx] commands when encountering 26010 // a \&[special] string; this occurs in the \.[GF] file only between 26011 // characters, after the preamble, and before the postamble. However, 26012 // \\[xxx] commands might appear within characters, 26013 // in \.[GF] files generated by other 26014 // processors. It is recommended that |x| be a string having the form of a 26015 // keyword followed by possible parameters relevant to that keyword. 26016 // 26017 // \yskip\hang| xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|. 26018 // 26019 // \yskip\hang|xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<$2^[24]$|. 26020 // \MF\ uses this when sending a \&[special] string whose length exceeds~255. 26021 // 26022 // \yskip\hang| xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be 26023 // ridiculously large; |k| mustn't be negative. 26024 // 26025 // \yskip\hang|yyy| 243 |y[4]|. This command is undefined in general; 26026 // it functions as a 5-byte |no_op| unless special \.[GF]-reading programs 26027 // are being used. \MF\ puts |scaled| numbers into |yyy|'s, as a 26028 // result of \&[numspecial] commands; the intent is to provide numeric 26029 // parameters to \\[xxx] commands that immediately precede. 26030 // 26031 // \yskip\hang| no_op| 244. No operation, do nothing. Any number of |no_op|'s 26032 // may occur between \.[GF] commands, but a |no_op| cannot be inserted between 26033 // a command and its parameters or between two parameters. 26034 // 26035 // \yskip\hang|char_loc| 245 |c[1]| |dx[4]| |dy[4]| |w[4]| |p[4]|. 26036 // This command will appear only in the postamble, which will be explained shortly. 26037 // 26038 // \yskip\hang| char_loc0| 246 |c[1]| | dm[1]| |w[4]| |p[4]|. 26039 // Same as |char_loc|, except that |dy| is assumed to be zero, and the value 26040 // of~|dx| is taken to be |65536*dm|, where |0<=dm<256|. 26041 // 26042 // \yskip\hang|pre| 247 |i[1]| |k[1]| |x[k]|. 26043 // Beginning of the preamble; this must come at the very beginning of the 26044 // file. Parameter |i| is an identifying number for \.[GF] format, currently 26045 // 131. The other information is merely commentary; it is not given 26046 // special interpretation like \\[xxx] commands are. (Note that \\[xxx] 26047 // commands may immediately follow the preamble, before the first |boc|.) 26048 // 26049 // \yskip\hang|post| 248. Beginning of the postamble, see below. 26050 // 26051 // \yskip\hang|post_post| 249. Ending of the postamble, see below. 26052 // 26053 // \yskip\noindent Commands 250--255 are undefined at the present time. 26054 26055 // 1145. 26056 26057 // tangle:pos ../../mf.web:21951:3: 26058 26059 // \MF\ refers to the following opcodes explicitly. 26060 26061 // 1146. 26062 26063 // tangle:pos ../../mf.web:21971:3: 26064 26065 // The last character in a \.[GF] file is followed by `|post|'; this command 26066 // introduces the postamble, which summarizes important facts that \MF\ has 26067 // accumulated. The postamble has the form 26068 // $$\vbox[\halign[\hbox[#\hfil]\cr 26069 // |post| |p[4]| | ds[4]| | cs[4]| | hppp[4]| | vppp[4]| 26070 // | min_m[4]| | max_m[4]| | min_n[4]| | max_n[4]|\cr 26071 // $\langle\,$character locators$\,\rangle$\cr 26072 // |post_post| |q[4]| |i[1]| 223's$[[\G]4]$\cr]]$$ 26073 // Here |p| is a pointer to the byte following the final |eoc| in the file 26074 // (or to the byte following the preamble, if there are no characters); 26075 // it can be used to locate the beginning of \\[xxx] commands 26076 // that might have preceded the postamble. The |ds| and |cs| parameters 26077 // \xref[design size] \xref[check sum] 26078 // give the design size and check sum, respectively, which are exactly the 26079 // values put into the header of the \.[TFM] file that \MF\ produces (or 26080 // would produce) on this run. Parameters |hppp| and |vppp| are the ratios of 26081 // pixels per point, horizontally and vertically, expressed as |scaled| integers 26082 // (i.e., multiplied by $2^[16]$); they can be used to correlate the font 26083 // with specific device resolutions, magnifications, and ``at sizes.'' Then 26084 // come |min_m|, |max_m|, |min_n|, and |max_n|, which bound the values that 26085 // registers |m| and~|n| assume in all characters in this \.[GF] file. 26086 // (These bounds need not be the best possible; |max_m| and |min_n| may, on the 26087 // other hand, be tighter than the similar bounds in |boc| commands. For 26088 // example, some character may have |min_n=-100| in its |boc|, but it might 26089 // turn out that |n| never gets lower than |-50| in any character; then 26090 // |min_n| can have any value |<=-50|. If there are no characters in the file, 26091 // it's possible to have |min_m>max_m| and/or |min_n>max_n|.) 26092 26093 // 1147. 26094 26095 // tangle:pos ../../mf.web:21999:3: 26096 26097 // Character locators are introduced by |char_loc| commands, 26098 // which specify a character residue~|c|, character escapements (|dx,dy|), 26099 // a character width~|w|, and a pointer~|p| 26100 // to the beginning of that character. (If two or more characters have the 26101 // same code~|c| modulo 256, only the last will be indicated; the others can be 26102 // located by following backpointers. Characters whose codes differ by a 26103 // multiple of 256 are assumed to share the same font metric information, 26104 // hence the \.[TFM] file contains only residues of character codes modulo~256. 26105 // This convention is intended for oriental languages, when there are many 26106 // character shapes but few distinct widths.) 26107 // \xref[oriental characters]\xref[Chinese characters]\xref[Japanese characters] 26108 // 26109 // The character escapements (|dx,dy|) are the values of \MF's \&[chardx] 26110 // and \&[chardy] parameters; they are in units of |scaled| pixels; 26111 // i.e., |dx| is in horizontal pixel units times $2^[16]$, and |dy| is in 26112 // vertical pixel units times $2^[16]$. This is the intended amount of 26113 // displacement after typesetting the character; for \.[DVI] files, |dy| 26114 // should be zero, but other document file formats allow nonzero vertical 26115 // escapement. 26116 // 26117 // The character width~|w| duplicates the information in the \.[TFM] file; it 26118 // is a |fix_word| value relative to the design size, and it should be 26119 // independent of magnification. 26120 // 26121 // The backpointer |p| points to the character's |boc|, or to the first of 26122 // a sequence of consecutive \\[xxx] or |yyy| or |no_op| commands that 26123 // immediately precede the |boc|, if such commands exist; such ``special'' 26124 // commands essentially belong to the characters, while the special commands 26125 // after the final character belong to the postamble (i.e., to the font 26126 // as a whole). This convention about |p| applies also to the backpointers 26127 // in |boc| commands, even though it wasn't explained in the description 26128 // of~|boc|. \xref[backpointers] 26129 // 26130 // Pointer |p| might be |-1| if the character exists in the \.[TFM] file 26131 // but not in the \.[GF] file. This unusual situation can arise in \MF\ output 26132 // if the user had |proofing<0| when the character was being shipped out, 26133 // but then made |proofing>=0| in order to get a \.[GF] file. 26134 26135 // 1148. 26136 26137 // tangle:pos ../../mf.web:22037:3: 26138 26139 // The last part of the postamble, following the |post_post| byte that 26140 // signifies the end of the character locators, contains |q|, a pointer to the 26141 // |post| command that started the postamble. An identification byte, |i|, 26142 // comes next; this currently equals~131, as in the preamble. 26143 // 26144 // The |i| byte is followed by four or more bytes that are all equal to 26145 // the decimal number 223 (i.e., @'337 in octal). \MF\ puts out four to seven of 26146 // these trailing bytes, until the total length of the file is a multiple of 26147 // four bytes, since this works out best on machines that pack four bytes per 26148 // word; but any number of 223's is allowed, as long as there are at least four 26149 // of them. In effect, 223 is a sort of signature that is added at the very end. 26150 // \xref[Fuchs, David Raymond] 26151 // 26152 // This curious way to finish off a \.[GF] file makes it feasible for 26153 // \.[GF]-reading programs to find the postamble first, on most computers, 26154 // even though \MF\ wants to write the postamble last. Most operating 26155 // systems permit random access to individual words or bytes of a file, so 26156 // the \.[GF] reader can start at the end and skip backwards over the 223's 26157 // until finding the identification byte. Then it can back up four bytes, read 26158 // |q|, and move to byte |q| of the file. This byte should, of course, 26159 // contain the value 248 (|post|); now the postamble can be read, so the 26160 // \.[GF] reader can discover all the information needed for individual characters. 26161 // 26162 // Unfortunately, however, standard \PASCAL\ does not include the ability to 26163 // \xref[system dependencies] 26164 // access a random position in a file, or even to determine the length of a file. 26165 // Almost all systems nowadays provide the necessary capabilities, so \.[GF] 26166 // format has been designed to work most efficiently with modern operating systems. 26167 // But if \.[GF] files have to be processed under the restrictions of standard 26168 // \PASCAL, one can simply read them from front to back. This will 26169 // be adequate for most applications. However, the postamble-first approach 26170 // would facilitate a program that merges two \.[GF] files, replacing data 26171 // from one that is overridden by corresponding data in the other. 26172 26173 // 1187. 26174 26175 // tangle:pos ../../mf.web:22552:3: 26176 26177 // Corresponding to the procedure that dumps a base file, we also have a function 26178 // that reads~one~in. The function returns |false| if the dumped base is 26179 // incompatible with the present \MF\ table sizes, etc. 26180 // \4 26181 // Declare the function called |open_base_file| 26182 func (prg *prg) openBaseFile() (r bool) { 26183 var ( 26184 j /* 0..bufSize */ uint16 // the first space after the file name 26185 ) 26186 j = prg.curInput.locField 26187 if int32(prg.buffer[prg.curInput.locField]) == '&' { 26188 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 26189 j = prg.curInput.locField 26190 prg.buffer[prg.last] = ' ' 26191 for int32(prg.buffer[j]) != ' ' { 26192 j = uint16(int32(j) + 1) 26193 } 26194 prg.packBufferedName(smallNumber(0), int32(prg.curInput.locField), int32(j)-1) // try first without the system file area 26195 if prg.wOpenIn(prg.baseFile) { 26196 goto found 26197 } 26198 prg.packBufferedName(smallNumber(baseAreaLength), int32(prg.curInput.locField), int32(j)-1) 26199 // now try the system base file area 26200 if prg.wOpenIn(prg.baseFile) { 26201 goto found 26202 } 26203 26204 prg.termOut.Writeln("Sorry, I can't find that base;", " will try PLAIN.") 26205 // \xref[Sorry, I can't find...] 26206 26207 } 26208 // now pull out all the stops: try for the system \.[plain] file 26209 prg.packBufferedName(smallNumber(baseDefaultLength-baseExtLength), 1, 0) 26210 if !prg.wOpenIn(prg.baseFile) { 26211 prg.termOut.Writeln("I can't find the PLAIN base file!") 26212 // \xref[I can't find PLAIN...] 26213 // \xref[plain] 26214 r = false 26215 goto exit 26216 } 26217 26218 found: 26219 prg.curInput.locField = j 26220 r = true 26221 26222 exit: 26223 ; 26224 return r 26225 } 26226 26227 func (prg *prg) loadBaseFile() (r bool) { 26228 var ( 26229 k int32 // all-purpose index 26230 p, q halfword // all-purpose pointers 26231 x int32 // something undumped 26232 w fourQuarters // four ASCII codes 26233 ) 26234 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26235 if x != 461259239 { 26236 goto offBase 26237 } // check that strings are the same 26238 { 26239 prg.baseFile.Get() 26240 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26241 } 26242 if x != memMin { 26243 goto offBase 26244 } 26245 { 26246 prg.baseFile.Get() 26247 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26248 } 26249 if x != 3000 { 26250 goto offBase 26251 } 26252 { 26253 prg.baseFile.Get() 26254 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26255 } 26256 if x != hashSize { 26257 goto offBase 26258 } 26259 { 26260 prg.baseFile.Get() 26261 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26262 } 26263 if x != hashPrime { 26264 goto offBase 26265 } 26266 { 26267 prg.baseFile.Get() 26268 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26269 } 26270 if x != maxInOpen { 26271 goto offBase 26272 } 26273 26274 // Undump the string pool 26275 { 26276 { 26277 prg.baseFile.Get() 26278 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26279 } 26280 if x < 0 { 26281 goto offBase 26282 } 26283 if x > poolSize { 26284 prg.termOut.Writeln("---! Must increase the ", "string pool size") /* \xref[Must increase the x] */ /* \xref[Must increase the x] */ 26285 goto offBase 26286 } else { 26287 prg.poolPtr = uint16(x) 26288 } 26289 } 26290 { 26291 { 26292 prg.baseFile.Get() 26293 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26294 } 26295 if x < 0 { 26296 goto offBase 26297 } 26298 if x > maxStrings { 26299 prg.termOut.Writeln("---! Must increase the ", "max strings") /* \xref[Must increase the x] */ /* \xref[Must increase the x] */ 26300 goto offBase 26301 } else { 26302 prg.strPtr = uint16(x) 26303 } 26304 } 26305 for ii := int32(0); ii <= int32(prg.strPtr); ii++ { 26306 k = ii 26307 _ = k 26308 { 26309 { 26310 prg.baseFile.Get() 26311 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26312 } 26313 if x < 0 || x > int32(prg.poolPtr) { 26314 goto offBase 26315 } else { 26316 prg.strStart[k] = uint16(x) 26317 } 26318 } 26319 prg.strRef[k] = byte(maxStrRef) 26320 } 26321 k = 0 26322 for k+4 < int32(prg.poolPtr) { 26323 { 26324 prg.baseFile.Get() 26325 w = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).qqqq() 26326 } 26327 prg.strPool[k] = byte(int32(w.b0) - minQuarterword) 26328 prg.strPool[k+1] = byte(int32(w.b1) - minQuarterword) 26329 prg.strPool[k+2] = byte(int32(w.b2) - minQuarterword) 26330 prg.strPool[k+3] = byte(int32(w.b3) - minQuarterword) 26331 k = k + 4 26332 } 26333 k = int32(prg.poolPtr) - 4 26334 { 26335 prg.baseFile.Get() 26336 w = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).qqqq() 26337 } 26338 prg.strPool[k] = byte(int32(w.b0) - minQuarterword) 26339 prg.strPool[k+1] = byte(int32(w.b1) - minQuarterword) 26340 prg.strPool[k+2] = byte(int32(w.b2) - minQuarterword) 26341 prg.strPool[k+3] = byte(int32(w.b3) - minQuarterword) 26342 prg.initStrPtr = prg.strPtr 26343 prg.initPoolPtr = prg.poolPtr 26344 prg.maxStrPtr = prg.strPtr 26345 prg.maxPoolPtr = prg.poolPtr 26346 26347 // Undump the dynamic memory 26348 { 26349 { 26350 prg.baseFile.Get() 26351 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26352 } 26353 if x < memMin+3+10+2+2+2+2+1+1000 || x > 3000-2-1 { 26354 goto offBase 26355 } else { 26356 prg.loMemMax = uint16(x) 26357 } 26358 } 26359 { 26360 { 26361 prg.baseFile.Get() 26362 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26363 } 26364 if x < memMin+3+10+2+2+2+2+1+1 || x > int32(prg.loMemMax) { 26365 goto offBase 26366 } else { 26367 prg.rover = uint16(x) 26368 } 26369 } 26370 p = uint16(memMin) 26371 q = prg.rover 26372 for { 26373 for ii := int32(p); ii <= int32(q)+1; ii++ { 26374 k = ii 26375 _ = k 26376 prg.baseFile.Get() 26377 prg.mem[k] = *(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P())) 26378 } 26379 p = uint16(int32(q) + int32(*(*prg.mem[q].hh()).lh())) 26380 if int32(p) > int32(prg.loMemMax) || int32(q) >= int32(*(*prg.mem[int32(q)+1].hh()).rh()) && int32(*(*prg.mem[int32(q)+1].hh()).rh()) != int32(prg.rover) { 26381 goto offBase 26382 } 26383 q = *(*prg.mem[int32(q)+1].hh()).rh() 26384 if int32(q) == int32(prg.rover) { 26385 break 26386 } 26387 } 26388 for ii := int32(p); ii <= int32(prg.loMemMax); ii++ { 26389 k = ii 26390 _ = k 26391 prg.baseFile.Get() 26392 prg.mem[k] = *(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P())) 26393 } 26394 { 26395 { 26396 prg.baseFile.Get() 26397 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26398 } 26399 if x < int32(prg.loMemMax)+1 || x > 3000-2 { 26400 goto offBase 26401 } else { 26402 prg.hiMemMin = uint16(x) 26403 } 26404 } 26405 { 26406 { 26407 prg.baseFile.Get() 26408 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26409 } 26410 if x < memMin || x > 3000 { 26411 goto offBase 26412 } else { 26413 prg.avail = uint16(x) 26414 } 26415 } 26416 prg.memEnd = 3000 26417 for ii := int32(prg.hiMemMin); ii <= int32(prg.memEnd); ii++ { 26418 k = ii 26419 _ = k 26420 prg.baseFile.Get() 26421 prg.mem[k] = *(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P())) 26422 } 26423 { 26424 prg.baseFile.Get() 26425 prg.varUsed = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26426 } 26427 { 26428 prg.baseFile.Get() 26429 prg.dynUsed = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26430 } 26431 26432 // Undump the table of equivalents and the hash table 26433 { 26434 { 26435 prg.baseFile.Get() 26436 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26437 } 26438 if x < 1 || x > hashBase+hashSize { 26439 goto offBase 26440 } else { 26441 prg.hashUsed = uint16(x) 26442 } 26443 } 26444 p = 0 26445 for { 26446 { 26447 { 26448 prg.baseFile.Get() 26449 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26450 } 26451 if x < int32(p)+1 || x > int32(prg.hashUsed) { 26452 goto offBase 26453 } else { 26454 p = uint16(x) 26455 } 26456 } 26457 { 26458 prg.baseFile.Get() 26459 prg.hash[p-1] = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).hh() 26460 } 26461 { 26462 prg.baseFile.Get() 26463 prg.eqtb[p-1] = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).hh() 26464 } 26465 if int32(p) == int32(prg.hashUsed) { 26466 break 26467 } 26468 } 26469 for ii := int32(prg.hashUsed) + 1; ii <= hashBase+hashSize+12; ii++ { 26470 p = halfword(ii) 26471 _ = p 26472 { 26473 prg.baseFile.Get() 26474 prg.hash[p-1] = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).hh() 26475 } 26476 { 26477 prg.baseFile.Get() 26478 prg.eqtb[p-1] = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).hh() 26479 } 26480 } 26481 { 26482 prg.baseFile.Get() 26483 prg.stCount = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26484 } 26485 26486 // Undump a few more things and the closing check word 26487 { 26488 { 26489 prg.baseFile.Get() 26490 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26491 } 26492 if x < maxGivenInternal || x > maxInternal { 26493 goto offBase 26494 } else { 26495 prg.intPtr = byte(x) 26496 } 26497 } 26498 for ii := int32(1); ii <= int32(prg.intPtr); ii++ { 26499 k = ii 26500 _ = k 26501 { 26502 prg.baseFile.Get() 26503 prg.internal[k-1] = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26504 } 26505 { 26506 { 26507 prg.baseFile.Get() 26508 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26509 } 26510 if x < 0 || x > int32(prg.strPtr) { 26511 goto offBase 26512 } else { 26513 prg.intName[k-1] = uint16(x) 26514 } 26515 } 26516 } 26517 { 26518 { 26519 prg.baseFile.Get() 26520 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26521 } 26522 if x < 0 || x > hashBase+hashSize { 26523 goto offBase 26524 } else { 26525 prg.startSym = uint16(x) 26526 } 26527 } 26528 { 26529 { 26530 prg.baseFile.Get() 26531 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26532 } 26533 if x < batchMode || x > errorStopMode { 26534 goto offBase 26535 } else { 26536 prg.interaction = byte(x) 26537 } 26538 } 26539 { 26540 { 26541 prg.baseFile.Get() 26542 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26543 } 26544 if x < 0 || x > int32(prg.strPtr) { 26545 goto offBase 26546 } else { 26547 prg.baseIdent = uint16(x) 26548 } 26549 } 26550 { 26551 { 26552 prg.baseFile.Get() 26553 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26554 } 26555 if x < 1 || x > hashBase+hashSize+12 { 26556 goto offBase 26557 } else { 26558 prg.bgLoc = uint16(x) 26559 } 26560 } 26561 { 26562 { 26563 prg.baseFile.Get() 26564 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26565 } 26566 if x < 1 || x > hashBase+hashSize+12 { 26567 goto offBase 26568 } else { 26569 prg.egLoc = uint16(x) 26570 } 26571 } 26572 { 26573 prg.baseFile.Get() 26574 prg.serialNo = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26575 } 26576 26577 { 26578 prg.baseFile.Get() 26579 x = *(*(*memoryWord)(unsafe.Pointer(prg.baseFile.Data4P()))).int() 26580 } 26581 if x != 69069 || prg.baseFile.EOF() { 26582 goto offBase 26583 } 26584 r = true 26585 goto exit // it worked! 26586 // it worked! 26587 offBase: 26588 ; 26589 prg.termOut.Writeln("(Fatal base file error; I'm stymied)") 26590 // \xref[Fatal base file error] 26591 r = false 26592 26593 exit: 26594 ; 26595 return r 26596 } 26597 26598 // 706. \[35] Expanding the next token 26599 26600 // tangle:pos ../../mf.web:14572:35: 26601 26602 // Only a few command codes |<min_command| can possibly be returned by 26603 // |get_next|; in increasing order, they are 26604 // |if_test|, |fi_or_else|, |input|, |iteration|, |repeat_loop|, 26605 // |exit_test|, |relax|, |scan_tokens|, |expand_after|, and |defined_macro|. 26606 // 26607 // \MF\ usually gets the next token of input by saying |get_x_next|. This is 26608 // like |get_next| except that it keeps getting more tokens until 26609 // finding |cur_cmd>=min_command|. In other words, |get_x_next| expands 26610 // macros and removes conditionals or iterations or input instructions that 26611 // might be present. 26612 // 26613 // It follows that |get_x_next| might invoke itself recursively. In fact, 26614 // there is massive recursion, since macro expansion can involve the 26615 // scanning of arbitrarily complex expressions, which in turn involve 26616 // macro expansion and conditionals, etc. 26617 // \xref[recursion] 26618 // 26619 // Therefore it's necessary to declare a whole bunch of |forward| 26620 // procedures at this point, and to insert some other procedures 26621 // that will be invoked by |get_x_next|. 26622 func (prg *prg) scanPrimary() { 26623 var ( 26624 p, q, r1 halfword // for list manipulation 26625 c quarterword // a primitive operation code 26626 myVarFlag/* 0..maxCommandCode */ byte // initial value of |var_flag| 26627 lDelim, rDelim halfword // hash addresses of a delimiter pair 26628 26629 // Other local variables for |scan_primary| 26630 groupLine int32 // where a group began 26631 26632 num, denom scaled // for primaries that are fractions, like `1/2' 26633 26634 preHead, postHead, tail halfword 26635 // prefix and suffix list variables 26636 tt smallNumber // approximation to the type of the variable-so-far 26637 t halfword // a token 26638 macroRef halfword // reference count for a suffixed macro 26639 ) 26640 myVarFlag = prg.varFlag 26641 prg.varFlag = 0 26642 26643 restart: 26644 { 26645 if prg.arithError { 26646 prg.clearArith() 26647 } 26648 } 26649 26650 // Supply diagnostic information, if requested 26651 // if panicking then check_mem(false); [ ] 26652 26653 if prg.interrupt != 0 { 26654 if prg.okToInterrupt { 26655 prg.backInput() 26656 { 26657 if prg.interrupt != 0 { 26658 prg.pauseForInstructions() 26659 } 26660 } 26661 prg.getXNext() 26662 } 26663 } 26664 switch prg.curCmd { 26665 case leftDelimiter: 26666 // Scan a delimited primary 26667 lDelim = prg.curSym 26668 rDelim = uint16(prg.curMod) 26669 prg.getXNext() 26670 prg.scanExpression() 26671 if int32(prg.curCmd) == comma && int32(prg.curType) >= known { 26672 p = prg.getNode(valueNodeSize) 26673 *(*prg.mem[p].hh()).b0() = byte(pairType) 26674 *(*prg.mem[p].hh()).b1() = byte(capsule) 26675 prg.initBigNode(p) 26676 q = uint16(*prg.mem[int32(p)+1].int()) 26677 prg.stashIn(q) 26678 26679 prg.getXNext() 26680 prg.scanExpression() 26681 if int32(prg.curType) < known { 26682 prg.dispErr(halfword(memMin), strNumber( /* "Nonnumeric ypart has been replaced by 0" */ 775)) 26683 // \xref[Nonnumeric...replaced by 0] 26684 { 26685 prg.helpPtr = 4 26686 prg.helpLine[3] = /* "I thought you were giving me a pair `(x,y)'; but" */ 776 26687 prg.helpLine[2] = /* "after finding a nice xpart `x' I found a ypart `y'" */ 777 26688 prg.helpLine[1] = /* "that isn't of numeric type. So I've changed y to zero." */ 778 26689 prg.helpLine[0] = /* "(The y that I didn't like appears above the error message.)" */ 779 26690 } 26691 prg.putGetFlushError(scaled(0)) 26692 } 26693 prg.stashIn(halfword(int32(q) + 2)) 26694 prg.checkDelimiter(lDelim, rDelim) 26695 prg.curType = byte(pairType) 26696 prg.curExp = int32(p) 26697 } else { 26698 prg.checkDelimiter(lDelim, rDelim) 26699 } 26700 26701 case beginGroup: 26702 // Scan a grouped primary 26703 groupLine = prg.line 26704 if prg.internal[tracingCommands-1] > 0 { 26705 prg.showCmdMod(int32(prg.curCmd), prg.curMod) 26706 } 26707 { 26708 p = prg.getAvail() 26709 *(*prg.mem[p].hh()).lh() = 0 26710 *(*prg.mem[p].hh()).rh() = prg.savePtr 26711 prg.savePtr = p 26712 } 26713 for { 26714 prg.doStatement() // ends with |cur_cmd>=semicolon| 26715 if int32(prg.curCmd) != semicolon { 26716 break 26717 } 26718 } 26719 if int32(prg.curCmd) != endGroup { 26720 { 26721 if int32(prg.interaction) == errorStopMode { 26722 } 26723 prg.printNl(strNumber( /* "! " */ 261)) 26724 prg.print( /* "A group begun on line " */ 780) /* \xref[!\relax] */ 26725 } 26726 // \xref[A group...never ended] 26727 prg.printInt(groupLine) 26728 prg.print( /* " never ended" */ 781) 26729 { 26730 prg.helpPtr = 2 26731 prg.helpLine[1] = /* "I saw a `begingroup' back there that hasn't been matched" */ 782 26732 prg.helpLine[0] = /* "by `endgroup'. So I've inserted `endgroup' now." */ 783 26733 } 26734 prg.backError() 26735 prg.curCmd = byte(endGroup) 26736 } 26737 prg.unsave() // this might change |cur_type|, if independent variables are recycled 26738 if prg.internal[tracingCommands-1] > 0 { 26739 prg.showCmdMod(int32(prg.curCmd), prg.curMod) 26740 } 26741 26742 case stringToken: 26743 // Scan a string constant 26744 prg.curType = byte(stringType) 26745 prg.curExp = prg.curMod 26746 26747 case numericToken: 26748 // Scan a primary that starts with a numeric token 26749 prg.curExp = prg.curMod 26750 prg.curType = byte(known) 26751 prg.getXNext() 26752 if int32(prg.curCmd) != slash { 26753 num = 0 26754 denom = 0 26755 } else { 26756 prg.getXNext() 26757 if int32(prg.curCmd) != numericToken { 26758 prg.backInput() 26759 prg.curCmd = byte(slash) 26760 prg.curMod = over 26761 prg.curSym = uint16(hashBase + hashSize + 4) 26762 26763 goto done 26764 } 26765 num = prg.curExp 26766 denom = prg.curMod 26767 if denom == 0 { 26768 { 26769 if int32(prg.interaction) == errorStopMode { 26770 } 26771 prg.printNl(strNumber( /* "! " */ 261)) 26772 prg.print( /* "Division by zero" */ 784) /* \xref[!\relax] */ 26773 } 26774 // \xref[Division by zero] 26775 { 26776 prg.helpPtr = 1 26777 prg.helpLine[0] = /* "I'll pretend that you meant to divide by 1." */ 785 26778 } 26779 prg.error1() 26780 } else { 26781 prg.curExp = prg.makeScaled(num, denom) 26782 } 26783 { 26784 if prg.arithError { 26785 prg.clearArith() 26786 } 26787 } 26788 prg.getXNext() 26789 } 26790 if int32(prg.curCmd) >= minPrimaryCommand { 26791 if int32(prg.curCmd) < numericToken { 26792 p = prg.stashCurExp() 26793 prg.scanPrimary() 26794 if abs(num) >= abs(denom) || int32(prg.curType) < pairType { 26795 prg.doBinary(p, quarterword(times)) 26796 } else { 26797 prg.fracMult(num, denom) 26798 prg.freeNode(p, halfword(valueNodeSize)) 26799 } 26800 } 26801 } 26802 26803 goto done 26804 26805 case nullary: 26806 // Scan a nullary operation 26807 prg.doNullary(quarterword(prg.curMod)) 26808 26809 case unary, typeName, cycle, plusOrMinus: 26810 // Scan a unary operation 26811 c = byte(prg.curMod) 26812 prg.getXNext() 26813 prg.scanPrimary() 26814 prg.doUnary(c) 26815 goto done 26816 26817 case primaryBinary: 26818 // Scan a binary operation with `\&[of]' between its operands 26819 c = byte(prg.curMod) 26820 prg.getXNext() 26821 prg.scanExpression() 26822 if int32(prg.curCmd) != ofToken { 26823 prg.missingErr(strNumber( /* "of" */ 479)) 26824 prg.print( /* " for " */ 715) 26825 prg.printCmdMod(primaryBinary, int32(c)) 26826 // \xref[Missing `of'] 26827 { 26828 prg.helpPtr = 1 26829 prg.helpLine[0] = /* "I've got the first argument; will look now for the other." */ 716 26830 } 26831 prg.backError() 26832 } 26833 p = prg.stashCurExp() 26834 prg.getXNext() 26835 prg.scanPrimary() 26836 prg.doBinary(p, c) 26837 goto done 26838 26839 case strOp: 26840 // Convert a suffix to a string 26841 prg.getXNext() 26842 prg.scanSuffix() 26843 prg.oldSetting = prg.selector 26844 prg.selector = byte(newString) 26845 prg.showTokenList(prg.curExp, memMin, 100000, 0) 26846 prg.flushTokenList(halfword(prg.curExp)) 26847 prg.curExp = int32(prg.makeString()) 26848 prg.selector = prg.oldSetting 26849 prg.curType = byte(stringType) 26850 26851 goto done 26852 26853 case internalQuantity: 26854 // Scan an internal numeric quantity 26855 q = uint16(prg.curMod) 26856 if int32(myVarFlag) == assignment { 26857 prg.getXNext() 26858 if int32(prg.curCmd) == assignment { 26859 prg.curExp = int32(prg.getAvail()) 26860 *(*prg.mem[prg.curExp].hh()).lh() = uint16(int32(q) + hashBase + hashSize + 12) 26861 prg.curType = byte(tokenList) 26862 goto done 26863 } 26864 prg.backInput() 26865 } 26866 prg.curType = byte(known) 26867 prg.curExp = prg.internal[q-1] 26868 26869 case capsuleToken: 26870 prg.makeExpCopy(halfword(prg.curMod)) 26871 case tagToken: 26872 // Scan a variable primary; |goto restart| if it turns out to be a macro 26873 { 26874 preHead = prg.avail 26875 if int32(preHead) == memMin { 26876 preHead = prg.getAvail() 26877 } else { 26878 prg.avail = *(*prg.mem[preHead].hh()).rh() 26879 *(*prg.mem[preHead].hh()).rh() = uint16(memMin) 26880 prg.dynUsed = prg.dynUsed + 1 26881 } 26882 } 26883 tail = preHead 26884 postHead = uint16(memMin) 26885 tt = byte(vacuous) 26886 for true { 26887 t = prg.curTok() 26888 *(*prg.mem[tail].hh()).rh() = t 26889 if int32(tt) != undefined { 26890 { 26891 p = *(*prg.mem[preHead].hh()).rh() 26892 q = *(*prg.mem[p].hh()).lh() 26893 tt = byte(undefined) 26894 if int32(*prg.eqtb[q-1].lh())%outerTag == tagToken { 26895 q = *prg.eqtb[q-1].rh() 26896 if int32(q) == memMin { 26897 goto done2 26898 } 26899 for true { 26900 p = *(*prg.mem[p].hh()).rh() 26901 if int32(p) == memMin { 26902 tt = *(*prg.mem[q].hh()).b0() 26903 goto done2 26904 } 26905 if int32(*(*prg.mem[q].hh()).b0()) != structured { 26906 goto done2 26907 } 26908 q = *(*prg.mem[*(*prg.mem[int32(q)+1].hh()).lh()].hh()).rh() // the |collective_subscript| attribute 26909 if int32(p) >= int32(prg.hiMemMin) { 26910 for { 26911 q = *(*prg.mem[q].hh()).rh() 26912 if int32(*(*prg.mem[int32(q)+2].hh()).lh()) >= int32(*(*prg.mem[p].hh()).lh()) { 26913 break 26914 } 26915 } 26916 if int32(*(*prg.mem[int32(q)+2].hh()).lh()) > int32(*(*prg.mem[p].hh()).lh()) { 26917 goto done2 26918 } 26919 } 26920 } 26921 } 26922 26923 done2: 26924 } 26925 if int32(tt) >= unsuffixedMacro { 26926 *(*prg.mem[tail].hh()).rh() = uint16(memMin) 26927 if int32(tt) > unsuffixedMacro { 26928 postHead = prg.getAvail() 26929 tail = postHead 26930 *(*prg.mem[tail].hh()).rh() = t 26931 26932 tt = byte(undefined) 26933 macroRef = uint16(*prg.mem[int32(q)+1].int()) 26934 *(*prg.mem[macroRef].hh()).lh() = uint16(int32(*(*prg.mem[macroRef].hh()).lh()) + 1) 26935 } else { 26936 // Set up unsuffixed macro call and |goto restart| 26937 p = prg.getAvail() 26938 *(*prg.mem[preHead].hh()).lh() = *(*prg.mem[preHead].hh()).rh() 26939 *(*prg.mem[preHead].hh()).rh() = p 26940 *(*prg.mem[p].hh()).lh() = t 26941 prg.macroCall(halfword(*prg.mem[int32(q)+1].int()), preHead, halfword(memMin)) 26942 prg.getXNext() 26943 goto restart 26944 } 26945 } 26946 } 26947 prg.getXNext() 26948 tail = t 26949 if int32(prg.curCmd) == leftBracket { 26950 prg.getXNext() 26951 prg.scanExpression() 26952 if int32(prg.curCmd) != rightBracket { 26953 prg.backInput() // that was the token following the current expression 26954 prg.backExpr() 26955 prg.curCmd = byte(leftBracket) 26956 prg.curMod = 0 26957 prg.curSym = uint16(hashBase + hashSize + 3) 26958 } else { 26959 if int32(prg.curType) != known { 26960 prg.badSubscript() 26961 } 26962 prg.curCmd = byte(numericToken) 26963 prg.curMod = prg.curExp 26964 prg.curSym = 0 26965 } 26966 } 26967 if int32(prg.curCmd) > maxSuffixToken { 26968 goto done1 26969 } 26970 if int32(prg.curCmd) < minSuffixToken { 26971 goto done1 26972 } 26973 } // now |cur_cmd| is |internal_quantity|, |tag_token|, or |numeric_token| 26974 // now |cur_cmd| is |internal_quantity|, |tag_token|, or |numeric_token| 26975 done1: 26976 if int32(postHead) != memMin { 26977 prg.backInput() 26978 p = prg.getAvail() 26979 q = *(*prg.mem[postHead].hh()).rh() 26980 *(*prg.mem[preHead].hh()).lh() = *(*prg.mem[preHead].hh()).rh() 26981 *(*prg.mem[preHead].hh()).rh() = postHead 26982 *(*prg.mem[postHead].hh()).lh() = q 26983 *(*prg.mem[postHead].hh()).rh() = p 26984 *(*prg.mem[p].hh()).lh() = *(*prg.mem[q].hh()).rh() 26985 *(*prg.mem[q].hh()).rh() = uint16(memMin) 26986 prg.macroCall(macroRef, preHead, halfword(memMin)) 26987 *(*prg.mem[macroRef].hh()).lh() = uint16(int32(*(*prg.mem[macroRef].hh()).lh()) - 1) 26988 prg.getXNext() 26989 goto restart 26990 } 26991 q = *(*prg.mem[preHead].hh()).rh() 26992 { 26993 *(*prg.mem[preHead].hh()).rh() = prg.avail 26994 prg.avail = preHead 26995 prg.dynUsed = prg.dynUsed - 1 26996 } 26997 if int32(prg.curCmd) == int32(myVarFlag) { 26998 prg.curType = byte(tokenList) 26999 prg.curExp = int32(q) 27000 goto done 27001 } 27002 p = prg.findVariable(q) 27003 if int32(p) != memMin { 27004 prg.makeExpCopy(p) 27005 } else { 27006 prg.obliterated(q) 27007 27008 prg.helpLine[2] = /* "While I was evaluating the suffix of this variable," */ 797 27009 prg.helpLine[1] = /* "something was redefined, and it's no longer a variable!" */ 798 27010 prg.helpLine[0] = /* "In order to get back on my feet, I've inserted `0' instead." */ 799 27011 prg.putGetFlushError(scaled(0)) 27012 } 27013 prg.flushNodeList(q) 27014 goto done 27015 27016 default: 27017 prg.badExp(strNumber( /* "A primary" */ 769)) 27018 goto restart 27019 // \xref[A primary expression...] 27020 27021 } 27022 27023 prg.getXNext() // the routines |goto done| if they don't want this 27024 // the routines |goto done| if they don't want this 27025 done: 27026 if int32(prg.curCmd) == leftBracket { 27027 if int32(prg.curType) >= known { 27028 p = prg.stashCurExp() 27029 prg.getXNext() 27030 prg.scanExpression() 27031 if int32(prg.curCmd) != comma { 27032 { 27033 prg.backInput() // that was the token following the current expression 27034 prg.backExpr() 27035 prg.curCmd = byte(leftBracket) 27036 prg.curMod = 0 27037 prg.curSym = uint16(hashBase + hashSize + 3) 27038 } 27039 prg.unstashCurExp(p) 27040 } else { 27041 q = prg.stashCurExp() 27042 prg.getXNext() 27043 prg.scanExpression() 27044 if int32(prg.curCmd) != rightBracket { 27045 prg.missingErr(strNumber(']')) 27046 27047 // \xref[Missing `]'] 27048 { 27049 prg.helpPtr = 3 27050 prg.helpLine[2] = /* "I've scanned an expression of the form `a[b,c'," */ 801 27051 prg.helpLine[1] = /* "so a right bracket should have come next." */ 802 27052 prg.helpLine[0] = /* "I shall pretend that one was there." */ 697 27053 } 27054 27055 prg.backError() 27056 } 27057 r1 = prg.stashCurExp() 27058 prg.makeExpCopy(q) 27059 27060 prg.doBinary(r1, quarterword(minus)) 27061 prg.doBinary(p, quarterword(times)) 27062 prg.doBinary(q, quarterword(plus)) 27063 prg.getXNext() 27064 } 27065 } 27066 } 27067 } // \2 27068 func (prg *prg) scanSuffix() { 27069 var ( 27070 h, t halfword // head and tail of the list being built 27071 p halfword // temporary register 27072 ) 27073 h = prg.getAvail() 27074 t = h 27075 for true { 27076 if int32(prg.curCmd) == leftBracket { 27077 prg.getXNext() 27078 prg.scanExpression() 27079 if int32(prg.curType) != known { 27080 prg.badSubscript() 27081 } 27082 if int32(prg.curCmd) != rightBracket { 27083 prg.missingErr(strNumber(']')) 27084 27085 // \xref[Missing `]'] 27086 { 27087 prg.helpPtr = 3 27088 prg.helpLine[2] = /* "I've seen a `[' and a subscript value, in a suffix," */ 803 27089 prg.helpLine[1] = /* "so a right bracket should have come next." */ 802 27090 prg.helpLine[0] = /* "I shall pretend that one was there." */ 697 27091 } 27092 27093 prg.backError() 27094 } 27095 prg.curCmd = byte(numericToken) 27096 prg.curMod = prg.curExp 27097 } 27098 if int32(prg.curCmd) == numericToken { 27099 p = prg.newNumTok(prg.curMod) 27100 } else if int32(prg.curCmd) == tagToken || int32(prg.curCmd) == internalQuantity { 27101 p = prg.getAvail() 27102 *(*prg.mem[p].hh()).lh() = prg.curSym 27103 } else { 27104 goto done 27105 } 27106 *(*prg.mem[t].hh()).rh() = p 27107 t = p 27108 prg.getXNext() 27109 } 27110 27111 done: 27112 prg.curExp = int32(*(*prg.mem[h].hh()).rh()) 27113 { 27114 *(*prg.mem[h].hh()).rh() = prg.avail 27115 prg.avail = h 27116 prg.dynUsed = prg.dynUsed - 1 27117 } 27118 prg.curType = byte(tokenList) 27119 } // \2 27120 func (prg *prg) scanSecondary() { 27121 var ( 27122 p halfword // for list manipulation 27123 c, d halfword // operation codes or modifiers 27124 macName halfword // token defined with \&[primarydef] 27125 ) 27126 restart: 27127 if int32(prg.curCmd) < minPrimaryCommand || int32(prg.curCmd) > maxPrimaryCommand { 27128 prg.badExp(strNumber( /* "A secondary" */ 804)) 27129 } 27130 // \xref[A secondary expression...] 27131 prg.scanPrimary() 27132 27133 continue1: 27134 if int32(prg.curCmd) <= maxSecondaryCommand { 27135 if int32(prg.curCmd) >= minSecondaryCommand { 27136 p = prg.stashCurExp() 27137 c = uint16(prg.curMod) 27138 d = uint16(prg.curCmd) 27139 if int32(d) == secondaryPrimaryMacro { 27140 macName = prg.curSym 27141 *(*prg.mem[c].hh()).lh() = uint16(int32(*(*prg.mem[c].hh()).lh()) + 1) 27142 } 27143 prg.getXNext() 27144 prg.scanPrimary() 27145 if int32(d) != secondaryPrimaryMacro { 27146 prg.doBinary(p, quarterword(c)) 27147 } else { 27148 prg.backInput() 27149 prg.binaryMac(p, c, macName) 27150 *(*prg.mem[c].hh()).lh() = uint16(int32(*(*prg.mem[c].hh()).lh()) - 1) 27151 prg.getXNext() 27152 goto restart 27153 } 27154 27155 goto continue1 27156 } 27157 } 27158 } // \2 27159 func (prg *prg) scanTertiary() { 27160 var ( 27161 p halfword // for list manipulation 27162 c, d halfword // operation codes or modifiers 27163 macName halfword // token defined with \&[secondarydef] 27164 ) 27165 restart: 27166 if int32(prg.curCmd) < minPrimaryCommand || int32(prg.curCmd) > maxPrimaryCommand { 27167 prg.badExp(strNumber( /* "A tertiary" */ 805)) 27168 } 27169 // \xref[A tertiary expression...] 27170 prg.scanSecondary() 27171 if int32(prg.curType) == futurePen { 27172 prg.materializePen() 27173 } 27174 27175 continue1: 27176 if int32(prg.curCmd) <= maxTertiaryCommand { 27177 if int32(prg.curCmd) >= minTertiaryCommand { 27178 p = prg.stashCurExp() 27179 c = uint16(prg.curMod) 27180 d = uint16(prg.curCmd) 27181 if int32(d) == tertiarySecondaryMacro { 27182 macName = prg.curSym 27183 *(*prg.mem[c].hh()).lh() = uint16(int32(*(*prg.mem[c].hh()).lh()) + 1) 27184 } 27185 prg.getXNext() 27186 prg.scanSecondary() 27187 if int32(d) != tertiarySecondaryMacro { 27188 prg.doBinary(p, quarterword(c)) 27189 } else { 27190 prg.backInput() 27191 prg.binaryMac(p, c, macName) 27192 *(*prg.mem[c].hh()).lh() = uint16(int32(*(*prg.mem[c].hh()).lh()) - 1) 27193 prg.getXNext() 27194 goto restart 27195 } 27196 27197 goto continue1 27198 } 27199 } 27200 } // \2 27201 func (prg *prg) scanExpression() { 27202 var ( 27203 p, q, r1, pp, qq halfword // for list manipulation 27204 c, d halfword // operation codes or modifiers 27205 myVarFlag/* 0..maxCommandCode */ byte // initial value of |var_flag| 27206 macName halfword // token defined with \&[tertiarydef] 27207 cycleHit bool // did a path expression just end with `\&[cycle]'? 27208 x, y scaled // explicit coordinates or tension at a path join 27209 t/* endpoint..open */ byte // knot type following a path join 27210 ) 27211 myVarFlag = prg.varFlag 27212 27213 restart: 27214 if int32(prg.curCmd) < minPrimaryCommand || int32(prg.curCmd) > maxPrimaryCommand { 27215 prg.badExp(strNumber( /* "An" */ 808)) 27216 } 27217 // \xref[An expression...] 27218 prg.scanTertiary() 27219 27220 continue1: 27221 if int32(prg.curCmd) <= maxExpressionCommand { 27222 if int32(prg.curCmd) >= minExpressionCommand { 27223 if int32(prg.curCmd) != equals || int32(myVarFlag) != assignment { 27224 p = prg.stashCurExp() 27225 c = uint16(prg.curMod) 27226 d = uint16(prg.curCmd) 27227 if int32(d) == expressionTertiaryMacro { 27228 macName = prg.curSym 27229 *(*prg.mem[c].hh()).lh() = uint16(int32(*(*prg.mem[c].hh()).lh()) + 1) 27230 } 27231 if int32(d) < ampersand || int32(d) == ampersand && (int32(*(*prg.mem[p].hh()).b0()) == pairType || int32(*(*prg.mem[p].hh()).b0()) == pathType) { 27232 cycleHit = false 27233 27234 // Convert the left operand, |p|, into a partial path ending at~|q|; but |return| if |p| doesn't have a suitable type 27235 { 27236 prg.unstashCurExp(p) 27237 if int32(prg.curType) == pairType { 27238 p = prg.newKnot() 27239 } else if int32(prg.curType) == pathType { 27240 p = uint16(prg.curExp) 27241 } else { 27242 goto exit 27243 } 27244 q = p 27245 for int32(*(*prg.mem[q].hh()).rh()) != int32(p) { 27246 q = *(*prg.mem[q].hh()).rh() 27247 } 27248 if int32(*(*prg.mem[p].hh()).b0()) != endpoint { 27249 r1 = prg.copyKnot(p) 27250 *(*prg.mem[q].hh()).rh() = r1 27251 q = r1 27252 } 27253 *(*prg.mem[p].hh()).b0() = byte(open) 27254 *(*prg.mem[q].hh()).b1() = byte(open) 27255 } 27256 27257 continuePath: 27258 if int32(prg.curCmd) == leftBrace { 27259 t = prg.scanDirection() 27260 if int32(t) != open { 27261 *(*prg.mem[q].hh()).b1() = t 27262 *prg.mem[int32(q)+5].int() = prg.curExp 27263 if int32(*(*prg.mem[q].hh()).b0()) == open { 27264 *(*prg.mem[q].hh()).b0() = t 27265 *prg.mem[int32(q)+3].int() = prg.curExp 27266 } // note that |left_given(q)=left_curl(q)| 27267 } 27268 } 27269 d = uint16(prg.curCmd) 27270 if int32(d) == pathJoin { 27271 prg.getXNext() 27272 if int32(prg.curCmd) == tension { 27273 prg.getXNext() 27274 y = int32(prg.curCmd) 27275 if int32(prg.curCmd) == atLeast { 27276 prg.getXNext() 27277 } 27278 prg.scanPrimary() 27279 27280 // Make sure that the current expression is a valid tension setting 27281 if int32(prg.curType) != known || prg.curExp < 0140000 { 27282 prg.dispErr(halfword(memMin), strNumber( /* "Improper tension has been set to 1" */ 826)) 27283 // \xref[Improper tension] 27284 { 27285 prg.helpPtr = 1 27286 prg.helpLine[0] = /* "The expression above should have been a number >=3/4." */ 827 27287 } 27288 prg.putGetFlushError(scaled(0200000)) 27289 } 27290 if y == atLeast { 27291 prg.curExp = -prg.curExp 27292 } 27293 *prg.mem[int32(q)+6].int() = prg.curExp 27294 if int32(prg.curCmd) == andCommand { 27295 prg.getXNext() 27296 y = int32(prg.curCmd) 27297 if int32(prg.curCmd) == atLeast { 27298 prg.getXNext() 27299 } 27300 prg.scanPrimary() 27301 27302 // Make sure that the current expression is a valid tension setting 27303 if int32(prg.curType) != known || prg.curExp < 0140000 { 27304 prg.dispErr(halfword(memMin), strNumber( /* "Improper tension has been set to 1" */ 826)) 27305 // \xref[Improper tension] 27306 { 27307 prg.helpPtr = 1 27308 prg.helpLine[0] = /* "The expression above should have been a number >=3/4." */ 827 27309 } 27310 prg.putGetFlushError(scaled(0200000)) 27311 } 27312 if y == atLeast { 27313 prg.curExp = -prg.curExp 27314 } 27315 } 27316 y = prg.curExp 27317 } else if int32(prg.curCmd) == controls { 27318 *(*prg.mem[q].hh()).b1() = byte(explicit) 27319 t = byte(explicit) 27320 prg.getXNext() 27321 prg.scanPrimary() 27322 27323 prg.knownPair() 27324 *prg.mem[int32(q)+5].int() = prg.curX 27325 *prg.mem[int32(q)+6].int() = prg.curY 27326 if int32(prg.curCmd) != andCommand { 27327 x = *prg.mem[int32(q)+5].int() 27328 y = *prg.mem[int32(q)+6].int() 27329 } else { 27330 prg.getXNext() 27331 prg.scanPrimary() 27332 27333 prg.knownPair() 27334 x = prg.curX 27335 y = prg.curY 27336 } 27337 } else { 27338 *prg.mem[int32(q)+6].int() = 0200000 27339 y = 0200000 27340 prg.backInput() // default tension 27341 // default tension 27342 goto done 27343 } 27344 if int32(prg.curCmd) != pathJoin { 27345 prg.missingErr(strNumber( /* ".." */ 409)) 27346 27347 // \xref[Missing `..'] 27348 { 27349 prg.helpPtr = 1 27350 prg.helpLine[0] = /* "A path join command should end with two dots." */ 825 27351 } 27352 prg.backError() 27353 } 27354 27355 done: 27356 } else if int32(d) != ampersand { 27357 goto finishPath 27358 } 27359 prg.getXNext() 27360 if int32(prg.curCmd) == leftBrace { 27361 t = prg.scanDirection() 27362 if int32(*(*prg.mem[q].hh()).b1()) != explicit { 27363 x = prg.curExp 27364 } else { 27365 t = byte(explicit) 27366 } // the direction information is superfluous 27367 } else if int32(*(*prg.mem[q].hh()).b1()) != explicit { 27368 t = byte(open) 27369 x = 0 27370 } 27371 if int32(prg.curCmd) == cycle { 27372 cycleHit = true 27373 prg.getXNext() 27374 pp = p 27375 qq = p 27376 if int32(d) == ampersand { 27377 if int32(p) == int32(q) { 27378 d = uint16(pathJoin) 27379 *prg.mem[int32(q)+6].int() = 0200000 27380 y = 0200000 27381 } 27382 } 27383 } else { 27384 prg.scanTertiary() 27385 27386 // Convert the right operand, |cur_exp|, into a partial path from |pp| to~|qq| 27387 { 27388 if int32(prg.curType) != pathType { 27389 pp = prg.newKnot() 27390 } else { 27391 pp = uint16(prg.curExp) 27392 } 27393 qq = pp 27394 for int32(*(*prg.mem[qq].hh()).rh()) != int32(pp) { 27395 qq = *(*prg.mem[qq].hh()).rh() 27396 } 27397 if int32(*(*prg.mem[pp].hh()).b0()) != endpoint { 27398 r1 = prg.copyKnot(pp) 27399 *(*prg.mem[qq].hh()).rh() = r1 27400 qq = r1 27401 } 27402 *(*prg.mem[pp].hh()).b0() = byte(open) 27403 *(*prg.mem[qq].hh()).b1() = byte(open) 27404 } 27405 } 27406 27407 // Join the partial paths and reset |p| and |q| to the head and tail of the result 27408 { 27409 if int32(d) == ampersand { 27410 if *prg.mem[int32(q)+1].int() != *prg.mem[int32(pp)+1].int() || *prg.mem[int32(q)+2].int() != *prg.mem[int32(pp)+2].int() { 27411 { 27412 if int32(prg.interaction) == errorStopMode { 27413 } 27414 prg.printNl(strNumber( /* "! " */ 261)) 27415 prg.print( /* "Paths don't touch; `&' will be changed to `..'" */ 828) /* \xref[!\relax] */ 27416 } 27417 // \xref[Paths don't touch] 27418 { 27419 prg.helpPtr = 3 27420 prg.helpLine[2] = /* "When you join paths `p&q', the ending point of p" */ 829 27421 prg.helpLine[1] = /* "must be exactly equal to the starting point of q." */ 830 27422 prg.helpLine[0] = /* "So I'm going to pretend that you said `p..q' instead." */ 831 27423 } 27424 prg.putGetError() 27425 d = uint16(pathJoin) 27426 *prg.mem[int32(q)+6].int() = 0200000 27427 y = 0200000 27428 } 27429 } 27430 27431 // Plug an opening in |right_type(pp)|, if possible 27432 if int32(*(*prg.mem[pp].hh()).b1()) == open { 27433 if int32(t) == curl || int32(t) == given { 27434 *(*prg.mem[pp].hh()).b1() = t 27435 *prg.mem[int32(pp)+5].int() = x 27436 } 27437 } 27438 if int32(d) == ampersand { 27439 if int32(*(*prg.mem[q].hh()).b0()) == open { 27440 if int32(*(*prg.mem[q].hh()).b1()) == open { 27441 *(*prg.mem[q].hh()).b0() = byte(curl) 27442 *prg.mem[int32(q)+3].int() = 0200000 27443 } 27444 } 27445 if int32(*(*prg.mem[pp].hh()).b1()) == open { 27446 if int32(t) == open { 27447 *(*prg.mem[pp].hh()).b1() = byte(curl) 27448 *prg.mem[int32(pp)+5].int() = 0200000 27449 } 27450 } 27451 *(*prg.mem[q].hh()).b1() = *(*prg.mem[pp].hh()).b1() 27452 *(*prg.mem[q].hh()).rh() = *(*prg.mem[pp].hh()).rh() 27453 27454 *prg.mem[int32(q)+5].int() = *prg.mem[int32(pp)+5].int() 27455 *prg.mem[int32(q)+6].int() = *prg.mem[int32(pp)+6].int() 27456 prg.freeNode(pp, halfword(knotNodeSize)) 27457 if int32(qq) == int32(pp) { 27458 qq = q 27459 } 27460 } else { 27461 if int32(*(*prg.mem[q].hh()).b1()) == open { 27462 if int32(*(*prg.mem[q].hh()).b0()) == curl || int32(*(*prg.mem[q].hh()).b0()) == given { 27463 *(*prg.mem[q].hh()).b1() = *(*prg.mem[q].hh()).b0() 27464 *prg.mem[int32(q)+5].int() = *prg.mem[int32(q)+3].int() 27465 } 27466 } 27467 *(*prg.mem[q].hh()).rh() = pp 27468 *prg.mem[int32(pp)+4].int() = y 27469 if int32(t) != open { 27470 *prg.mem[int32(pp)+3].int() = x 27471 *(*prg.mem[pp].hh()).b0() = t 27472 } 27473 } 27474 q = qq 27475 } 27476 if int32(prg.curCmd) >= minExpressionCommand { 27477 if int32(prg.curCmd) <= ampersand { 27478 if !cycleHit { 27479 goto continuePath 27480 } 27481 } 27482 } 27483 27484 finishPath: 27485 if cycleHit { 27486 if int32(d) == ampersand { 27487 p = q 27488 } 27489 } else { 27490 *(*prg.mem[p].hh()).b0() = byte(endpoint) 27491 if int32(*(*prg.mem[p].hh()).b1()) == open { 27492 *(*prg.mem[p].hh()).b1() = byte(curl) 27493 *prg.mem[int32(p)+5].int() = 0200000 27494 } 27495 *(*prg.mem[q].hh()).b1() = byte(endpoint) 27496 if int32(*(*prg.mem[q].hh()).b0()) == open { 27497 *(*prg.mem[q].hh()).b0() = byte(curl) 27498 *prg.mem[int32(q)+3].int() = 0200000 27499 } 27500 *(*prg.mem[q].hh()).rh() = p 27501 } 27502 prg.makeChoices(p) 27503 prg.curType = byte(pathType) 27504 prg.curExp = int32(p) 27505 } else { 27506 prg.getXNext() 27507 prg.scanTertiary() 27508 if int32(d) != expressionTertiaryMacro { 27509 prg.doBinary(p, quarterword(c)) 27510 } else { 27511 prg.backInput() 27512 prg.binaryMac(p, c, macName) 27513 *(*prg.mem[c].hh()).lh() = uint16(int32(*(*prg.mem[c].hh()).lh()) - 1) 27514 prg.getXNext() 27515 goto restart 27516 } 27517 } 27518 27519 goto continue1 27520 } 27521 } 27522 } 27523 27524 exit: 27525 } 27526 27527 func (prg *prg) getBoolean() { 27528 prg.getXNext() 27529 prg.scanExpression() 27530 if int32(prg.curType) != booleanType { 27531 prg.dispErr(halfword(memMin), strNumber( /* "Undefined condition will be treated as `false'" */ 832)) 27532 // \xref[Undefined condition...] 27533 { 27534 prg.helpPtr = 2 27535 prg.helpLine[1] = /* "The expression shown above should have had a definite" */ 833 27536 prg.helpLine[0] = /* "true-or-false value. I'm changing it to `false'." */ 834 27537 } 27538 27539 prg.putGetFlushError(falseCode) 27540 prg.curType = byte(booleanType) 27541 } 27542 } 27543 27544 // 153. \[9] Packed data 27545 27546 // tangle:pos ../../mf.web:3103:21: 27547 27548 // In order to make efficient use of storage space, \MF\ bases its major data 27549 // structures on a |memory_word|, which contains either a (signed) integer, 27550 // possibly scaled, or a small number of fields that are one half or one 27551 // quarter of the size used for storing integers. 27552 // 27553 // If |x| is a variable of type |memory_word|, it contains up to four 27554 // fields that can be referred to as follows: 27555 // $$\vbox[\halign[\hfil#&#\hfil&#\hfil\cr 27556 // |x|&.|int|&(an |integer|)\cr 27557 // |x|&.|sc|\qquad&(a |scaled| integer)\cr 27558 // |x.hh.lh|, |x.hh|&.|rh|&(two halfword fields)\cr 27559 // |x.hh.b0|, |x.hh.b1|, |x.hh|&.|rh|&(two quarterword fields, one halfword 27560 // field)\cr 27561 // |x.qqqq.b0|, |x.qqqq.b1|, |x.qqqq|&.|b2|, |x.qqqq.b3|\hskip-100pt 27562 // &\qquad\qquad\qquad(four quarterword fields)\cr]]$$ 27563 // This is somewhat cumbersome to write, and not very readable either, but 27564 // macros will be used to make the notation shorter and more transparent. 27565 // The \PASCAL\ code below gives a formal definition of |memory_word| and 27566 // its subsidiary types, using packed variant records. \MF\ makes no 27567 // assumptions about the relative positions of the fields within a word. 27568 // 27569 // Since we are assuming 32-bit integers, a halfword must contain at least 27570 // 16 bits, and a quarterword must contain at least 8 bits. 27571 // \xref[system dependencies] 27572 // But it doesn't hurt to have more bits; for example, with enough 36-bit 27573 // words you might be able to have |mem_max| as large as 262142. 27574 // 27575 // N.B.: Valuable memory space will be dreadfully wasted unless \MF\ is compiled 27576 // by a \PASCAL\ that packs all of the |memory_word| variants into 27577 // the space of a single integer. Some \PASCAL\ compilers will pack an 27578 // integer whose subrange is `|0..255|' into an eight-bit field, but others 27579 // insist on allocating space for an additional sign bit; on such systems you 27580 // can get 256 values into a quarterword only if the subrange is `|-128..127|'. 27581 // 27582 // The present implementation tries to accommodate as many variations as possible, 27583 // so it makes few assumptions. If integers having the subrange 27584 // `|min_quarterword..max_quarterword|' can be packed into a quarterword, 27585 // and if integers having the subrange `|min_halfword..max_halfword|' 27586 // can be packed into a halfword, everything should work satisfactorily. 27587 // 27588 // It is usually most efficient to have |min_quarterword=min_halfword=0|, 27589 // so one should try to achieve this unless it causes a severe problem. 27590 // The values defined here are recommended for most 32-bit computers. 27591 27592 // 155. 27593 27594 // tangle:pos ../../mf.web:3169:3: 27595 27596 // The operation of subtracting |min_halfword| occurs rather frequently in 27597 // \MF, so it is convenient to abbreviate this operation by using the macro 27598 // |ho| defined here. \MF\ will run faster with respect to compilers that 27599 // don't optimize the expression `|x-0|', if this macro is simplified in the 27600 // obvious way when |min_halfword=0|. Similarly, |qi| and |qo| are used for 27601 // input to and output from quarterwords. 27602 // \xref[system dependencies] 27603 27604 // 157. 27605 27606 // tangle:pos ../../mf.web:3212:3: 27607 27608 // When debugging, we may want to print a |memory_word| without knowing 27609 // what type it is; so we print it in all modes. 27610 // \xref[dirty \PASCAL]\xref[debugging] 27611 // procedure print_word( w:memory_word); 27612 // [prints |w| in all ways] 27613 // begin print_int(w.int); print_char([" "=]32); 27614 // 27615 // print_scaled(w.int ); print_char([" "=]32); print_scaled(w.int div [010000=]4096); print_ln; 27616 // 27617 // print_int(w.hh.lh); print_char(["="=]61); print_int(w.hh.b0); print_char([":"=]58); 27618 // print_int(w.hh.b1); print_char([";"=]59); print_int(w.hh.rh); print_char([" "=]32); 27619 // 27620 // print_int(w.qqqq.b0); print_char([":"=]58); print_int(w.qqqq.b1); print_char([":"=]58); 27621 // print_int(w.qqqq.b2); print_char([":"=]58); print_int(w.qqqq.b3); 27622 // end; 27623 // [ ] 27624 27625 // 158. \[10] Dynamic memory allocation 27626 27627 // tangle:pos ../../mf.web:3227:36: 27628 27629 // The \MF\ system does nearly all of its own memory allocation, so that it 27630 // can readily be transported into environments that do not have automatic 27631 // facilities for strings, garbage collection, etc., and so that it can be in 27632 // control of what error messages the user receives. The dynamic storage 27633 // requirements of \MF\ are handled by providing a large array |mem| in 27634 // which consecutive blocks of words are used as nodes by the \MF\ routines. 27635 // 27636 // Pointer variables are indices into this array, or into another array 27637 // called |eqtb| that will be explained later. A pointer variable might 27638 // also be a special flag that lies outside the bounds of |mem|, so we 27639 // allow pointers to assume any |halfword| value. The minimum memory 27640 // index represents a null pointer. 27641 27642 // 162. 27643 27644 // tangle:pos ../../mf.web:3297:3: 27645 27646 // If one-word memory is exhausted, it might mean that the user has forgotten 27647 // a token like `\&[enddef]' or `\&[endfor]'. We will define some procedures 27648 // later that try to help pinpoint the trouble. 27649 // \4 27650 // Declare the procedure called |show_token_list| 27651 func (prg *prg) printCapsule() { 27652 prg.printChar(asciiCode('(')) 27653 prg.printExp(prg.gPointer, smallNumber(0)) 27654 prg.printChar(asciiCode(')')) 27655 } 27656 27657 // 216. 27658 27659 // tangle:pos ../../mf.web:4772:3: 27660 27661 // A token list is a singly linked list of nodes in |mem|, where 27662 // each node contains a token and a link. Here's a subroutine that gets rid 27663 // of a token list when it is no longer needed. 27664 func (prg *prg) tokenRecycle() { 27665 prg.recycleValue(prg.gPointer) 27666 } // \2 27667 27668 func (prg *prg) closeFilesAndTerminate() { 27669 var ( 27670 k int32 // all-purpose index 27671 lh int32 // the length of the \.[TFM] header, in words 27672 lkOffset/* 0..256 */ uint16 // extra words inserted at beginning of |lig_kern| array 27673 p halfword // runs through a list of \.[TFM] dimensions 27674 x scaled // a |tfm_width| value being output to the \.[GF] file 27675 ) 27676 if prg.internal[tracingStats-1] > 0 { 27677 if prg.logOpened { 27678 prg.logFile.Writeln(" ") 27679 prg.logFile.Writeln("Here is how much of METAFONT's memory", " you used:") 27680 // \xref[Here is how much...] 27681 prg.logFile.Write(" ", int32(prg.maxStrPtr)-int32(prg.initStrPtr), knuth.WriteWidth(1), " string") 27682 if int32(prg.maxStrPtr) != int32(prg.initStrPtr)+1 { 27683 prg.logFile.Write("s") 27684 } 27685 prg.logFile.Writeln(" out of ", maxStrings-int32(prg.initStrPtr), knuth.WriteWidth(1)) 27686 27687 prg.logFile.Writeln(" ", int32(prg.maxPoolPtr)-int32(prg.initPoolPtr), knuth.WriteWidth(1), " string characters out of ", poolSize-int32(prg.initPoolPtr), knuth.WriteWidth(1)) 27688 27689 prg.logFile.Writeln(" ", int32(prg.loMemMax)-memMin+int32(prg.memEnd)-int32(prg.hiMemMin)+2, knuth.WriteWidth(1), 27690 " words of memory out of ", int32(prg.memEnd)+1-memMin, knuth.WriteWidth(1)) 27691 27692 prg.logFile.Writeln(" ", prg.stCount, knuth.WriteWidth(1), " symbolic tokens out of ", hashSize, knuth.WriteWidth(1)) 27693 27694 prg.logFile.Writeln(" ", prg.maxInStack, knuth.WriteWidth(1), "i,", prg.intPtr, knuth.WriteWidth(1), "n,", prg.maxRoundingPtr, knuth.WriteWidth(1), "r,", prg.maxParamStack, knuth.WriteWidth(1), "p,", int32(prg.maxBufStack)+1, knuth.WriteWidth(1), "b stack positions out of ", stackSize, knuth.WriteWidth(1), "i,", maxInternal, knuth.WriteWidth(1), "n,", maxWiggle, knuth.WriteWidth(1), "r,", paramSize, knuth.WriteWidth(1), "p,", bufSize, knuth.WriteWidth(1), "b") 27695 } 27696 } 27697 27698 // Finish the \.[TFM] and \.[GF] files 27699 if prg.gfPrevPtr > 0 || prg.internal[fontmaking-1] > 0 { 27700 prg.rover = uint16(memMin + 3 + 10 + 2 + 2 + 2 + 2 + 1 + 1) 27701 *(*prg.mem[prg.rover].hh()).rh() = 65535 27702 prg.loMemMax = uint16(int32(prg.hiMemMin) - 1) 27703 if int32(prg.loMemMax)-int32(prg.rover) > 65535 { 27704 prg.loMemMax = uint16(65535 + int32(prg.rover)) 27705 } 27706 *(*prg.mem[prg.rover].hh()).lh() = uint16(int32(prg.loMemMax) - int32(prg.rover)) 27707 *(*prg.mem[int32(prg.rover)+1].hh()).lh() = prg.rover 27708 *(*prg.mem[int32(prg.rover)+1].hh()).rh() = prg.rover 27709 *(*prg.mem[prg.loMemMax].hh()).rh() = uint16(memMin) 27710 *(*prg.mem[prg.loMemMax].hh()).lh() = uint16(memMin) 27711 27712 // Massage the \.[TFM] widths 27713 *(*prg.mem[3000-1].hh()).rh() = uint16(memMin + 3 + 10 + 2 + 2 + 2) 27714 for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ { 27715 k = ii 27716 _ = k 27717 if prg.charExists[k] { 27718 prg.tfmWidth[k] = int32(prg.sortIn(prg.tfmWidth[k])) 27719 } 27720 } 27721 prg.nw = uint16(prg.skimp(255) + 1) 27722 prg.dimenHead[1-1] = *(*prg.mem[3000-1].hh()).rh() 27723 if prg.perturbation >= 010000 { 27724 prg.tfmWarning(smallNumber(charWd)) 27725 } 27726 prg.fixDesignSize() 27727 prg.fixCheckSum() 27728 if prg.internal[fontmaking-1] > 0 { 27729 *(*prg.mem[3000-1].hh()).rh() = uint16(memMin + 3 + 10 + 2 + 2 + 2) 27730 for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ { 27731 k = ii 27732 _ = k 27733 if prg.charExists[k] { 27734 if prg.tfmHeight[k] == 0 { 27735 prg.tfmHeight[k] = memMin + 3 + 10 + 2 27736 } else { 27737 prg.tfmHeight[k] = int32(prg.sortIn(prg.tfmHeight[k])) 27738 } 27739 } 27740 } 27741 prg.nh = uint16(prg.skimp(15) + 1) 27742 prg.dimenHead[2-1] = *(*prg.mem[3000-1].hh()).rh() 27743 if prg.perturbation >= 010000 { 27744 prg.tfmWarning(smallNumber(charHt)) 27745 } 27746 *(*prg.mem[3000-1].hh()).rh() = uint16(memMin + 3 + 10 + 2 + 2 + 2) 27747 for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ { 27748 k = ii 27749 _ = k 27750 if prg.charExists[k] { 27751 if prg.tfmDepth[k] == 0 { 27752 prg.tfmDepth[k] = memMin + 3 + 10 + 2 27753 } else { 27754 prg.tfmDepth[k] = int32(prg.sortIn(prg.tfmDepth[k])) 27755 } 27756 } 27757 } 27758 prg.nd = uint16(prg.skimp(15) + 1) 27759 prg.dimenHead[3-1] = *(*prg.mem[3000-1].hh()).rh() 27760 if prg.perturbation >= 010000 { 27761 prg.tfmWarning(smallNumber(charDp)) 27762 } 27763 *(*prg.mem[3000-1].hh()).rh() = uint16(memMin + 3 + 10 + 2 + 2 + 2) 27764 for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ { 27765 k = ii 27766 _ = k 27767 if prg.charExists[k] { 27768 if prg.tfmItalCorr[k] == 0 { 27769 prg.tfmItalCorr[k] = memMin + 3 + 10 + 2 27770 } else { 27771 prg.tfmItalCorr[k] = int32(prg.sortIn(prg.tfmItalCorr[k])) 27772 } 27773 } 27774 } 27775 prg.ni = uint16(prg.skimp(63) + 1) 27776 prg.dimenHead[4-1] = *(*prg.mem[3000-1].hh()).rh() 27777 if prg.perturbation >= 010000 { 27778 prg.tfmWarning(smallNumber(charIc)) 27779 } 27780 prg.internal[fontmaking-1] = 0 // avoid loop in case of fatal error 27781 27782 // Finish the \.[TFM] file 27783 if int32(prg.jobName) == 0 { 27784 prg.openLogFile() 27785 } 27786 prg.packJobName(strNumber( /* ".tfm" */ 1045)) 27787 for !prg.bOpenOut(prg.tfmFile) { 27788 prg.promptFileName(strNumber( /* "file name for font metrics" */ 1046), strNumber( /* ".tfm" */ 1045)) 27789 } 27790 prg.metricFileName = prg.bMakeNameString(prg.tfmFile) 27791 27792 // Output the subfile sizes and header bytes 27793 k = headerSize 27794 for int32(prg.headerByte[k-1]) < 0 { 27795 k = k - 1 27796 } 27797 lh = (k + 3) / 4 // this is the number of header words 27798 if int32(prg.bc) > int32(prg.ec) { 27799 prg.bc = 1 27800 } // if there are no characters, |ec=0| and |bc=1| 27801 27802 // Compute the ligature/kern program offset and implant the left boundary label 27803 prg.bchar = prg.roundUnscaled(prg.internal[boundaryChar-1]) 27804 if prg.bchar < 0 || prg.bchar > 255 { 27805 prg.bchar = -1 27806 prg.lkStarted = false 27807 lkOffset = 0 27808 } else { 27809 prg.lkStarted = true 27810 lkOffset = 1 27811 } 27812 27813 // Find the minimum |lk_offset| and adjust all remainders 27814 k = int32(prg.labelPtr) // pointer to the largest unallocated label 27815 if int32(prg.labelLoc[k])+int32(lkOffset) > 255 { 27816 lkOffset = 0 27817 prg.lkStarted = false // location 0 can do double duty 27818 for { 27819 prg.charRemainder[prg.labelChar[k-1]] = lkOffset 27820 for int32(prg.labelLoc[k-1]) == int32(prg.labelLoc[k]) { 27821 k = k - 1 27822 prg.charRemainder[prg.labelChar[k-1]] = lkOffset 27823 } 27824 lkOffset = uint16(int32(lkOffset) + 1) 27825 k = k - 1 27826 if int32(lkOffset)+int32(prg.labelLoc[k]) < 256 { 27827 break 27828 } 27829 } 27830 // N.B.: |lk_offset=256| satisfies this when |k=0| 27831 } 27832 if int32(lkOffset) > 0 { 27833 for k > 0 { 27834 prg.charRemainder[prg.labelChar[k-1]] = uint16(int32(prg.charRemainder[prg.labelChar[k-1]]) + int32(lkOffset)) 27835 k = k - 1 27836 } 27837 } 27838 if int32(prg.bchLabel) < ligTableSize { 27839 prg.ligKern[prg.nl].b0 = byte(255 + minQuarterword) 27840 prg.ligKern[prg.nl].b1 = byte(0 + minQuarterword) 27841 prg.ligKern[prg.nl].b2 = byte((int32(prg.bchLabel)+int32(lkOffset))/256 + minQuarterword) 27842 prg.ligKern[prg.nl].b3 = byte((int32(prg.bchLabel)+int32(lkOffset))%256 + minQuarterword) 27843 prg.nl = uint16(int32(prg.nl) + 1) // possibly |nl=lig_table_size+1| 27844 } 27845 prg.tfmTwo(6 + lh + (int32(prg.ec) - int32(prg.bc) + 1) + int32(prg.nw) + int32(prg.nh) + int32(prg.nd) + int32(prg.ni) + int32(prg.nl) + int32(lkOffset) + int32(prg.nk) + int32(prg.ne) + int32(prg.np)) 27846 // this is the total number of file words that will be output 27847 prg.tfmTwo(lh) 27848 prg.tfmTwo(int32(prg.bc)) 27849 prg.tfmTwo(int32(prg.ec)) 27850 prg.tfmTwo(int32(prg.nw)) 27851 prg.tfmTwo(int32(prg.nh)) 27852 prg.tfmTwo(int32(prg.nd)) 27853 prg.tfmTwo(int32(prg.ni)) 27854 prg.tfmTwo(int32(prg.nl) + int32(lkOffset)) 27855 prg.tfmTwo(int32(prg.nk)) 27856 prg.tfmTwo(int32(prg.ne)) 27857 prg.tfmTwo(int32(prg.np)) 27858 for ii := int32(1); ii <= 4*lh; ii++ { 27859 k = ii 27860 _ = k 27861 if int32(prg.headerByte[k-1]) < 0 { 27862 prg.headerByte[k-1] = 0 27863 } 27864 prg.tfmFile.Write(prg.headerByte[k-1]) 27865 } 27866 27867 // Output the character information bytes, then output the dimensions themselves 27868 for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ { 27869 k = ii 27870 _ = k 27871 if !prg.charExists[k] { 27872 prg.tfmFour(0) 27873 } else { 27874 prg.tfmFile.Write(*(*prg.mem[prg.tfmWidth[k]].hh()).lh()) // the width index 27875 prg.tfmFile.Write(int32(*(*prg.mem[prg.tfmHeight[k]].hh()).lh())*16 + int32(*(*prg.mem[prg.tfmDepth[k]].hh()).lh())) 27876 prg.tfmFile.Write(int32(*(*prg.mem[prg.tfmItalCorr[k]].hh()).lh())*4 + int32(prg.charTag[k])) 27877 prg.tfmFile.Write(prg.charRemainder[k]) 27878 } 27879 } 27880 prg.tfmChanged = 0 27881 for ii := int32(1); ii <= 4; ii++ { 27882 k = ii 27883 _ = k 27884 prg.tfmFour(0) 27885 p = prg.dimenHead[k-1] 27886 for int32(p) != memMin+3+10+2+2+2 { 27887 prg.tfmFour(prg.dimenOut(*prg.mem[int32(p)+1].int())) 27888 p = *(*prg.mem[p].hh()).rh() 27889 } 27890 } 27891 27892 // Output the ligature/kern program 27893 for ii := int32(0); ii <= 255; ii++ { 27894 k = ii 27895 _ = k 27896 if int32(prg.skipTable[k]) < ligTableSize { 27897 prg.printNl(strNumber( /* "(local label " */ 1048)) 27898 prg.printInt(k) 27899 prg.print( /* ":: was missing)" */ 1049) 27900 // \xref[local label l:: was missing] 27901 prg.ll = prg.skipTable[k] 27902 for { 27903 prg.lll = uint16(int32(prg.ligKern[prg.ll].b0) - minQuarterword) 27904 prg.ligKern[prg.ll].b0 = byte(stopFlag) 27905 prg.ll = uint16(int32(prg.ll) - int32(prg.lll)) 27906 if int32(prg.lll) == 0 { 27907 break 27908 } 27909 } 27910 } 27911 } 27912 if prg.lkStarted { 27913 prg.tfmFile.Write(255) 27914 prg.tfmFile.Write(prg.bchar) 27915 prg.tfmTwo(0) 27916 } else { 27917 for ii := int32(1); ii <= int32(lkOffset); ii++ { 27918 k = ii 27919 _ = k // output the redirection specs 27920 prg.ll = uint16(prg.labelLoc[prg.labelPtr]) 27921 if prg.bchar < 0 { 27922 prg.tfmFile.Write(254) 27923 prg.tfmFile.Write(0) 27924 } else { 27925 prg.tfmFile.Write(255) 27926 prg.tfmFile.Write(prg.bchar) 27927 } 27928 prg.tfmTwo(int32(prg.ll) + int32(lkOffset)) 27929 for { 27930 prg.labelPtr = uint16(int32(prg.labelPtr) - 1) 27931 if int32(prg.labelLoc[prg.labelPtr]) < int32(prg.ll) { 27932 break 27933 } 27934 } 27935 } 27936 } 27937 for ii := int32(0); ii <= int32(prg.nl)-1; ii++ { 27938 k = ii 27939 _ = k 27940 prg.tfmQqqq(prg.ligKern[k]) 27941 } 27942 for ii := int32(0); ii <= int32(prg.nk)-1; ii++ { 27943 k = ii 27944 _ = k 27945 prg.tfmFour(prg.dimenOut(prg.kern[k])) 27946 } 27947 27948 // Output the extensible character recipes and the font metric parameters 27949 for ii := int32(0); ii <= int32(prg.ne)-1; ii++ { 27950 k = ii 27951 _ = k 27952 prg.tfmQqqq(prg.exten[k]) 27953 } 27954 for ii := int32(1); ii <= int32(prg.np); ii++ { 27955 k = ii 27956 _ = k 27957 if k == 1 { 27958 if abs(prg.param[1-1]) < 01000000000 { 27959 prg.tfmFour(prg.param[1-1] * 16) 27960 } else { 27961 prg.tfmChanged = prg.tfmChanged + 1 27962 if prg.param[1-1] > 0 { 27963 prg.tfmFour(017777777777) 27964 } else { 27965 prg.tfmFour(-017777777777) 27966 } 27967 } 27968 } else { 27969 prg.tfmFour(prg.dimenOut(prg.param[k-1])) 27970 } 27971 } 27972 if prg.tfmChanged > 0 { 27973 if prg.tfmChanged == 1 { 27974 prg.printNl(strNumber( /* "(a font metric dimension" */ 1050)) 27975 } else { 27976 prg.printNl(strNumber('(')) 27977 prg.printInt(prg.tfmChanged) 27978 // \xref[font metric dimensions...] 27979 prg.print( /* " font metric dimensions" */ 1051) 27980 } 27981 prg.print( /* " had to be decreased)" */ 1052) 27982 } 27983 if prg.internal[tracingStats-1] > 0 { 27984 prg.logFile.Writeln(" ") 27985 if int32(prg.bchLabel) < ligTableSize { 27986 prg.nl = uint16(int32(prg.nl) - 1) 27987 } 27988 prg.logFile.Writeln("(You used ", prg.nw, knuth.WriteWidth(1), "w,", prg.nh, knuth.WriteWidth(1), "h,", prg.nd, knuth.WriteWidth(1), "d,", prg.ni, knuth.WriteWidth(1), "i,", prg.nl, knuth.WriteWidth(1), "l,", prg.nk, knuth.WriteWidth(1), "k,", prg.ne, knuth.WriteWidth(1), "e,", prg.np, knuth.WriteWidth(1), "p metric file positions") 27989 prg.logFile.Writeln(" out of ", "256w,16h,16d,64i,", ligTableSize, knuth.WriteWidth(1), "l,", maxKerns, knuth.WriteWidth(1), "k,256e,", maxFontDimen, knuth.WriteWidth(1), "p)") 27990 } 27991 27992 prg.printNl(strNumber( /* "Font metrics written on " */ 1047)) 27993 prg.slowPrint(int32(prg.metricFileName)) 27994 prg.printChar(asciiCode('.')) 27995 // \xref[Font metrics written...] 27996 prg.bClose(prg.tfmFile) 27997 } 27998 if prg.gfPrevPtr > 0 { 27999 { 28000 prg.gfBuf[prg.gfPtr] = byte(post) 28001 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28002 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28003 prg.gfSwap() 28004 } 28005 } // beginning of the postamble 28006 prg.gfFour(prg.gfPrevPtr) 28007 prg.gfPrevPtr = prg.gfOffset + int32(prg.gfPtr) - 5 // |post| location 28008 prg.gfFour(prg.internal[designSize-1] * 16) 28009 for ii := int32(1); ii <= 4; ii++ { 28010 k = ii 28011 _ = k 28012 prg.gfBuf[prg.gfPtr] = byte(prg.headerByte[k-1]) 28013 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28014 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28015 prg.gfSwap() 28016 } 28017 } // the check sum 28018 prg.gfFour(prg.internal[hppp-1]) 28019 prg.gfFour(prg.internal[vppp-1]) 28020 28021 prg.gfFour(prg.gfMinM) 28022 prg.gfFour(prg.gfMaxM) 28023 prg.gfFour(prg.gfMinN) 28024 prg.gfFour(prg.gfMaxN) 28025 for ii := int32(0); ii <= 255; ii++ { 28026 k = ii 28027 _ = k 28028 if prg.charExists[k] { 28029 x = prg.gfDx[k] / 0200000 28030 if prg.gfDy[k] == 0 && x >= 0 && x < 256 && prg.gfDx[k] == x*0200000 { 28031 { 28032 prg.gfBuf[prg.gfPtr] = byte(charLoc + 1) 28033 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28034 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28035 prg.gfSwap() 28036 } 28037 } 28038 { 28039 prg.gfBuf[prg.gfPtr] = byte(k) 28040 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28041 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28042 prg.gfSwap() 28043 } 28044 } 28045 { 28046 prg.gfBuf[prg.gfPtr] = byte(x) 28047 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28048 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28049 prg.gfSwap() 28050 } 28051 } 28052 } else { 28053 { 28054 prg.gfBuf[prg.gfPtr] = byte(charLoc) 28055 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28056 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28057 prg.gfSwap() 28058 } 28059 } 28060 { 28061 prg.gfBuf[prg.gfPtr] = byte(k) 28062 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28063 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28064 prg.gfSwap() 28065 } 28066 } 28067 prg.gfFour(prg.gfDx[k]) 28068 prg.gfFour(prg.gfDy[k]) 28069 } 28070 x = *prg.mem[prg.tfmWidth[k]+1].int() 28071 if abs(x) > prg.maxTfmDimen { 28072 if x > 0 { 28073 x = 0100000000 - 1 28074 } else { 28075 x = 1 - 0100000000 28076 } 28077 } else { 28078 x = prg.makeScaled(x*16, prg.internal[designSize-1]) 28079 } 28080 prg.gfFour(x) 28081 prg.gfFour(prg.charPtr[k]) 28082 } 28083 } 28084 { 28085 prg.gfBuf[prg.gfPtr] = byte(postPost) 28086 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28087 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28088 prg.gfSwap() 28089 } 28090 } 28091 prg.gfFour(prg.gfPrevPtr) 28092 { 28093 prg.gfBuf[prg.gfPtr] = byte(gfIdByte) 28094 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28095 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28096 prg.gfSwap() 28097 } 28098 } 28099 28100 k = 4 + (gfBufSize-int32(prg.gfPtr))%4 // the number of 223's 28101 for k > 0 { 28102 { 28103 prg.gfBuf[prg.gfPtr] = 223 28104 prg.gfPtr = byte(int32(prg.gfPtr) + 1) 28105 if int32(prg.gfPtr) == int32(prg.gfLimit) { 28106 prg.gfSwap() 28107 } 28108 } 28109 k = k - 1 28110 } 28111 28112 // Empty the last bytes out of |gf_buf| 28113 if int32(prg.gfLimit) == int32(prg.halfBuf) { 28114 prg.writeGf(prg.halfBuf, gfIndex(gfBufSize-1)) 28115 } 28116 if int32(prg.gfPtr) > 0 { 28117 prg.writeGf(gfIndex(0), gfIndex(int32(prg.gfPtr)-1)) 28118 } 28119 prg.printNl(strNumber( /* "Output written on " */ 1063)) 28120 prg.slowPrint(int32(prg.outputFileName)) 28121 // \xref[Output written...] 28122 prg.print( /* " (" */ 558) 28123 prg.printInt(prg.totalChars) 28124 prg.print( /* " character" */ 1064) 28125 if prg.totalChars != 1 { 28126 prg.printChar(asciiCode('s')) 28127 } 28128 prg.print( /* ", " */ 1065) 28129 prg.printInt(prg.gfOffset + int32(prg.gfPtr)) 28130 prg.print( /* " bytes)." */ 1066) 28131 prg.bClose(prg.gfFile) 28132 } 28133 } 28134 if prg.logOpened { 28135 prg.logFile.Writeln() 28136 prg.aClose(prg.logFile) 28137 prg.selector = byte(int32(prg.selector) - 2) 28138 if int32(prg.selector) == termOnly { 28139 prg.printNl(strNumber( /* "Transcript written on " */ 1074)) 28140 // \xref[Transcript written...] 28141 prg.slowPrint(int32(prg.logName)) 28142 prg.printChar(asciiCode('.')) 28143 } 28144 } 28145 prg.termOut.Writeln() 28146 } 28147 28148 func (prg *prg) finalCleanup() { 28149 var ( 28150 c smallNumber // 0 for \&[end], 1 for \&[dump] 28151 ) 28152 c = byte(prg.curMod) 28153 if int32(prg.jobName) == 0 { 28154 prg.openLogFile() 28155 } 28156 for int32(prg.inputPtr) > 0 { 28157 if int32(prg.curInput.indexField) > maxInOpen { 28158 prg.endTokenList() 28159 } else { 28160 prg.endFileReading() 28161 } 28162 } 28163 for int32(prg.loopPtr) != memMin { 28164 prg.stopIteration() 28165 } 28166 for int32(prg.openParens) > 0 { 28167 prg.print( /* " )" */ 1075) 28168 prg.openParens = byte(int32(prg.openParens) - 1) 28169 } 28170 for int32(prg.condPtr) != memMin { 28171 prg.printNl(strNumber( /* "(end occurred when " */ 1076)) 28172 28173 // \xref[end occurred...] 28174 prg.printCmdMod(fiOrElse, int32(prg.curIf)) 28175 // `\.[if]' or `\.[elseif]' or `\.[else]' 28176 if prg.ifLine != 0 { 28177 prg.print( /* " on line " */ 1077) 28178 prg.printInt(prg.ifLine) 28179 } 28180 prg.print( /* " was incomplete)" */ 1078) 28181 prg.ifLine = *prg.mem[int32(prg.condPtr)+1].int() 28182 prg.curIf = *(*prg.mem[prg.condPtr].hh()).b1() 28183 prg.loopPtr = prg.condPtr 28184 prg.condPtr = *(*prg.mem[prg.condPtr].hh()).rh() 28185 prg.freeNode(prg.loopPtr, halfword(ifNodeSize)) 28186 } 28187 if int32(prg.history) != spotless { 28188 if int32(prg.history) == warningIssued || int32(prg.interaction) < errorStopMode { 28189 if int32(prg.selector) == termAndLog { 28190 prg.selector = byte(termOnly) 28191 prg.printNl(strNumber( /* "(see the transcript file for additional information)" */ 1079)) 28192 // \xref[see the transcript file...] 28193 prg.selector = byte(termAndLog) 28194 } 28195 } 28196 } 28197 if int32(c) == 1 { 28198 prg.storeBaseFile() 28199 goto exit 28200 28201 prg.printNl(strNumber( /* "(dump is performed only by INIMF)" */ 1080)) 28202 goto exit 28203 // \xref[dump...only by INIMF] 28204 } 28205 28206 exit: 28207 } 28208 28209 func (prg *prg) initPrim() { 28210 prg.primitive(strNumber( /* "tracingtitles" */ 410), halfword(internalQuantity), halfword(tracingTitles)) 28211 28212 // \xref[tracingtitles_][\&[tracingtitles] primitive] 28213 prg.primitive(strNumber( /* "tracingequations" */ 411), halfword(internalQuantity), halfword(tracingEquations)) 28214 28215 // \xref[tracing_equations_][\&[tracingequations] primitive] 28216 prg.primitive(strNumber( /* "tracingcapsules" */ 412), halfword(internalQuantity), halfword(tracingCapsules)) 28217 28218 // \xref[tracing_capsules_][\&[tracingcapsules] primitive] 28219 prg.primitive(strNumber( /* "tracingchoices" */ 413), halfword(internalQuantity), halfword(tracingChoices)) 28220 28221 // \xref[tracing_choices_][\&[tracingchoices] primitive] 28222 prg.primitive(strNumber( /* "tracingspecs" */ 414), halfword(internalQuantity), halfword(tracingSpecs)) 28223 28224 // \xref[tracing_specs_][\&[tracingspecs] primitive] 28225 prg.primitive(strNumber( /* "tracingpens" */ 415), halfword(internalQuantity), halfword(tracingPens)) 28226 28227 // \xref[tracing_pens_][\&[tracingpens] primitive] 28228 prg.primitive(strNumber( /* "tracingcommands" */ 416), halfword(internalQuantity), halfword(tracingCommands)) 28229 28230 // \xref[tracing_commands_][\&[tracingcommands] primitive] 28231 prg.primitive(strNumber( /* "tracingrestores" */ 417), halfword(internalQuantity), halfword(tracingRestores)) 28232 28233 // \xref[tracing_restores_][\&[tracingrestores] primitive] 28234 prg.primitive(strNumber( /* "tracingmacros" */ 418), halfword(internalQuantity), halfword(tracingMacros)) 28235 28236 // \xref[tracing_macros_][\&[tracingmacros] primitive] 28237 prg.primitive(strNumber( /* "tracingedges" */ 419), halfword(internalQuantity), halfword(tracingEdges)) 28238 28239 // \xref[tracing_edges_][\&[tracingedges] primitive] 28240 prg.primitive(strNumber( /* "tracingoutput" */ 420), halfword(internalQuantity), halfword(tracingOutput)) 28241 28242 // \xref[tracing_output_][\&[tracingoutput] primitive] 28243 prg.primitive(strNumber( /* "tracingstats" */ 421), halfword(internalQuantity), halfword(tracingStats)) 28244 28245 // \xref[tracing_stats_][\&[tracingstats] primitive] 28246 prg.primitive(strNumber( /* "tracingonline" */ 422), halfword(internalQuantity), halfword(tracingOnline)) 28247 28248 // \xref[tracing_online_][\&[tracingonline] primitive] 28249 prg.primitive(strNumber( /* "year" */ 423), halfword(internalQuantity), halfword(year)) 28250 28251 // \xref[year_][\&[year] primitive] 28252 prg.primitive(strNumber( /* "month" */ 424), halfword(internalQuantity), halfword(month)) 28253 28254 // \xref[month_][\&[month] primitive] 28255 prg.primitive(strNumber( /* "day" */ 425), halfword(internalQuantity), halfword(day)) 28256 28257 // \xref[day_][\&[day] primitive] 28258 prg.primitive(strNumber( /* "time" */ 426), halfword(internalQuantity), halfword(time)) 28259 28260 // \xref[time_][\&[time] primitive] 28261 prg.primitive(strNumber( /* "charcode" */ 427), halfword(internalQuantity), halfword(charCode)) 28262 28263 // \xref[char_code_][\&[charcode] primitive] 28264 prg.primitive(strNumber( /* "charext" */ 428), halfword(internalQuantity), halfword(charExt)) 28265 28266 // \xref[char_ext_][\&[charext] primitive] 28267 prg.primitive(strNumber( /* "charwd" */ 429), halfword(internalQuantity), halfword(charWd)) 28268 28269 // \xref[char_wd_][\&[charwd] primitive] 28270 prg.primitive(strNumber( /* "charht" */ 430), halfword(internalQuantity), halfword(charHt)) 28271 28272 // \xref[char_ht_][\&[charht] primitive] 28273 prg.primitive(strNumber( /* "chardp" */ 431), halfword(internalQuantity), halfword(charDp)) 28274 28275 // \xref[char_dp_][\&[chardp] primitive] 28276 prg.primitive(strNumber( /* "charic" */ 432), halfword(internalQuantity), halfword(charIc)) 28277 28278 // \xref[char_ic_][\&[charic] primitive] 28279 prg.primitive(strNumber( /* "chardx" */ 433), halfword(internalQuantity), halfword(charDx)) 28280 28281 // \xref[char_dx_][\&[chardx] primitive] 28282 prg.primitive(strNumber( /* "chardy" */ 434), halfword(internalQuantity), halfword(charDy)) 28283 28284 // \xref[char_dy_][\&[chardy] primitive] 28285 prg.primitive(strNumber( /* "designsize" */ 435), halfword(internalQuantity), halfword(designSize)) 28286 28287 // \xref[design_size_][\&[designsize] primitive] 28288 prg.primitive(strNumber( /* "hppp" */ 436), halfword(internalQuantity), halfword(hppp)) 28289 28290 // \xref[hppp_][\&[hppp] primitive] 28291 prg.primitive(strNumber( /* "vppp" */ 437), halfword(internalQuantity), halfword(vppp)) 28292 28293 // \xref[vppp_][\&[vppp] primitive] 28294 prg.primitive(strNumber( /* "xoffset" */ 438), halfword(internalQuantity), halfword(xOffset)) 28295 28296 // \xref[x_offset_][\&[xoffset] primitive] 28297 prg.primitive(strNumber( /* "yoffset" */ 439), halfword(internalQuantity), halfword(yOffset)) 28298 28299 // \xref[y_offset_][\&[yoffset] primitive] 28300 prg.primitive(strNumber( /* "pausing" */ 440), halfword(internalQuantity), halfword(pausing)) 28301 28302 // \xref[pausing_][\&[pausing] primitive] 28303 prg.primitive(strNumber( /* "showstopping" */ 441), halfword(internalQuantity), halfword(showstopping)) 28304 28305 // \xref[showstopping_][\&[showstopping] primitive] 28306 prg.primitive(strNumber( /* "fontmaking" */ 442), halfword(internalQuantity), halfword(fontmaking)) 28307 28308 // \xref[fontmaking_][\&[fontmaking] primitive] 28309 prg.primitive(strNumber( /* "proofing" */ 443), halfword(internalQuantity), halfword(proofing)) 28310 28311 // \xref[proofing_][\&[proofing] primitive] 28312 prg.primitive(strNumber( /* "smoothing" */ 444), halfword(internalQuantity), halfword(smoothing)) 28313 28314 // \xref[smoothing_][\&[smoothing] primitive] 28315 prg.primitive(strNumber( /* "autorounding" */ 445), halfword(internalQuantity), halfword(autorounding)) 28316 28317 // \xref[autorounding_][\&[autorounding] primitive] 28318 prg.primitive(strNumber( /* "granularity" */ 446), halfword(internalQuantity), halfword(granularity)) 28319 28320 // \xref[granularity_][\&[granularity] primitive] 28321 prg.primitive(strNumber( /* "fillin" */ 447), halfword(internalQuantity), halfword(fillin)) 28322 28323 // \xref[fillin_][\&[fillin] primitive] 28324 prg.primitive(strNumber( /* "turningcheck" */ 448), halfword(internalQuantity), halfword(turningCheck)) 28325 28326 // \xref[turning_check_][\&[turningcheck] primitive] 28327 prg.primitive(strNumber( /* "warningcheck" */ 449), halfword(internalQuantity), halfword(warningCheck)) 28328 28329 // \xref[warning_check_][\&[warningcheck] primitive] 28330 prg.primitive(strNumber( /* "boundarychar" */ 450), halfword(internalQuantity), halfword(boundaryChar)) 28331 28332 // \xref[boundary_char_][\&[boundarychar] primitive] 28333 28334 prg.primitive(strNumber( /* ".." */ 409), halfword(pathJoin), halfword(0)) 28335 28336 // \xref[.._][\.[..] primitive] 28337 prg.primitive(strNumber('['), halfword(leftBracket), halfword(0)) 28338 prg.eqtb[hashBase+hashSize+3-1] = prg.eqtb[prg.curSym-1] 28339 28340 // \xref[[ ][\.[[] primitive] 28341 prg.primitive(strNumber(']'), halfword(rightBracket), halfword(0)) 28342 28343 // \xref[] ][\.[]] primitive] 28344 prg.primitive(strNumber('}'), halfword(rightBrace), halfword(0)) 28345 28346 // \xref[]]][\.[\char`\]] primitive] 28347 prg.primitive(strNumber('{'), halfword(leftBrace), halfword(0)) 28348 28349 // \xref[][][\.[\char`\[] primitive] 28350 prg.primitive(strNumber(':'), halfword(colon), halfword(0)) 28351 prg.eqtb[hashBase+hashSize+5-1] = prg.eqtb[prg.curSym-1] 28352 28353 // \xref[: ][\.[:] primitive] 28354 prg.primitive(strNumber( /* "::" */ 459), halfword(doubleColon), halfword(0)) 28355 28356 // \xref[:: ][\.[::] primitive] 28357 prg.primitive(strNumber( /* "||:" */ 460), halfword(bcharLabel), halfword(0)) 28358 28359 // \xref[::: ][\.[\char'174\char'174:] primitive] 28360 prg.primitive(strNumber( /* ":=" */ 461), halfword(assignment), halfword(0)) 28361 28362 // \xref[:=_][\.[:=] primitive] 28363 prg.primitive(strNumber(','), halfword(comma), halfword(0)) 28364 28365 // \xref[, ][\., primitive] 28366 prg.primitive(strNumber(';'), halfword(semicolon), halfword(0)) 28367 prg.eqtb[hashBase+hashSize+6-1] = prg.eqtb[prg.curSym-1] 28368 28369 // \xref[; ][\.; primitive] 28370 prg.primitive(strNumber('\\'), halfword(relax), halfword(0)) 28371 28372 // \xref[]]\\][\.[\char`\\] primitive] 28373 28374 prg.primitive(strNumber( /* "addto" */ 462), halfword(addToCommand), halfword(0)) 28375 28376 // \xref[add_to_][\&[addto] primitive] 28377 prg.primitive(strNumber( /* "at" */ 463), halfword(atToken), halfword(0)) 28378 28379 // \xref[at_][\&[at] primitive] 28380 prg.primitive(strNumber( /* "atleast" */ 464), halfword(atLeast), halfword(0)) 28381 28382 // \xref[at_least_][\&[atleast] primitive] 28383 prg.primitive(strNumber( /* "begingroup" */ 465), halfword(beginGroup), halfword(0)) 28384 prg.bgLoc = prg.curSym 28385 28386 // \xref[begin_group_][\&[begingroup] primitive] 28387 prg.primitive(strNumber( /* "controls" */ 466), halfword(controls), halfword(0)) 28388 28389 // \xref[controls_][\&[controls] primitive] 28390 prg.primitive(strNumber( /* "cull" */ 467), halfword(cullCommand), halfword(0)) 28391 28392 // \xref[cull_][\&[cull] primitive] 28393 prg.primitive(strNumber( /* "curl" */ 468), halfword(curlCommand), halfword(0)) 28394 28395 // \xref[curl_][\&[curl] primitive] 28396 prg.primitive(strNumber( /* "delimiters" */ 469), halfword(delimiters), halfword(0)) 28397 28398 // \xref[delimiters_][\&[delimiters] primitive] 28399 prg.primitive(strNumber( /* "display" */ 470), halfword(displayCommand), halfword(0)) 28400 28401 // \xref[display_][\&[display] primitive] 28402 prg.primitive(strNumber( /* "endgroup" */ 453), halfword(endGroup), halfword(0)) 28403 prg.eqtb[hashBase+hashSize+10-1] = prg.eqtb[prg.curSym-1] 28404 prg.egLoc = prg.curSym 28405 28406 // \xref[endgroup_][\&[endgroup] primitive] 28407 prg.primitive(strNumber( /* "everyjob" */ 471), halfword(everyJobCommand), halfword(0)) 28408 28409 // \xref[every_job_][\&[everyjob] primitive] 28410 prg.primitive(strNumber( /* "exitif" */ 472), halfword(exitTest), halfword(0)) 28411 28412 // \xref[exit_if_][\&[exitif] primitive] 28413 prg.primitive(strNumber( /* "expandafter" */ 473), halfword(expandAfter), halfword(0)) 28414 28415 // \xref[expand_after_][\&[expandafter] primitive] 28416 prg.primitive(strNumber( /* "from" */ 474), halfword(fromToken), halfword(0)) 28417 28418 // \xref[from_][\&[from] primitive] 28419 prg.primitive(strNumber( /* "inwindow" */ 475), halfword(inWindow), halfword(0)) 28420 28421 // \xref[in_window_][\&[inwindow] primitive] 28422 prg.primitive(strNumber( /* "interim" */ 476), halfword(interimCommand), halfword(0)) 28423 28424 // \xref[interim_][\&[interim] primitive] 28425 prg.primitive(strNumber( /* "let" */ 477), halfword(letCommand), halfword(0)) 28426 28427 // \xref[let_][\&[let] primitive] 28428 prg.primitive(strNumber( /* "newinternal" */ 478), halfword(newInternal), halfword(0)) 28429 28430 // \xref[new_internal_][\&[newinternal] primitive] 28431 prg.primitive(strNumber( /* "of" */ 479), halfword(ofToken), halfword(0)) 28432 28433 // \xref[of_][\&[of] primitive] 28434 prg.primitive(strNumber( /* "openwindow" */ 480), halfword(openWindow), halfword(0)) 28435 28436 // \xref[open_window_][\&[openwindow] primitive] 28437 prg.primitive(strNumber( /* "randomseed" */ 481), halfword(randomSeed), halfword(0)) 28438 28439 // \xref[random_seed_][\&[randomseed] primitive] 28440 prg.primitive(strNumber( /* "save" */ 482), halfword(saveCommand), halfword(0)) 28441 28442 // \xref[save_][\&[save] primitive] 28443 prg.primitive(strNumber( /* "scantokens" */ 483), halfword(scanTokens), halfword(0)) 28444 28445 // \xref[scan_tokens_][\&[scantokens] primitive] 28446 prg.primitive(strNumber( /* "shipout" */ 484), halfword(shipOutCommand), halfword(0)) 28447 28448 // \xref[ship_out_][\&[shipout] primitive] 28449 prg.primitive(strNumber( /* "skipto" */ 485), halfword(skipTo), halfword(0)) 28450 28451 // \xref[skip_to_][\&[skipto] primitive] 28452 prg.primitive(strNumber( /* "step" */ 486), halfword(stepToken), halfword(0)) 28453 28454 // \xref[step_][\&[step] primitive] 28455 prg.primitive(strNumber( /* "str" */ 487), halfword(strOp), halfword(0)) 28456 28457 // \xref[str_][\&[str] primitive] 28458 prg.primitive(strNumber( /* "tension" */ 488), halfword(tension), halfword(0)) 28459 28460 // \xref[tension_][\&[tension] primitive] 28461 prg.primitive(strNumber( /* "to" */ 489), halfword(toToken), halfword(0)) 28462 28463 // \xref[to_][\&[to] primitive] 28464 prg.primitive(strNumber( /* "until" */ 490), halfword(untilToken), halfword(0)) 28465 28466 // \xref[until_][\&[until] primitive] 28467 28468 prg.primitive(strNumber( /* "def" */ 654), halfword(macroDef), halfword(startDef)) 28469 28470 // \xref[def_][\&[def] primitive] 28471 prg.primitive(strNumber( /* "vardef" */ 655), halfword(macroDef), halfword(varDef)) 28472 28473 // \xref[var_def_][\&[vardef] primitive] 28474 prg.primitive(strNumber( /* "primarydef" */ 656), halfword(macroDef), halfword(secondaryPrimaryMacro)) 28475 28476 // \xref[primary_def_][\&[primarydef] primitive] 28477 prg.primitive(strNumber( /* "secondarydef" */ 657), halfword(macroDef), halfword(tertiarySecondaryMacro)) 28478 28479 // \xref[secondary_def_][\&[secondarydef] primitive] 28480 prg.primitive(strNumber( /* "tertiarydef" */ 658), halfword(macroDef), halfword(expressionTertiaryMacro)) 28481 28482 // \xref[tertiary_def_][\&[tertiarydef] primitive] 28483 prg.primitive(strNumber( /* "enddef" */ 454), halfword(macroDef), halfword(endDef)) 28484 prg.eqtb[hashBase+hashSize+8-1] = prg.eqtb[prg.curSym-1] 28485 28486 // \xref[end_def_][\&[enddef] primitive] 28487 28488 prg.primitive(strNumber( /* "for" */ 659), halfword(iteration), halfword(hashBase+hashSize+12+1)) 28489 28490 // \xref[for_][\&[for] primitive] 28491 prg.primitive(strNumber( /* "forsuffixes" */ 660), halfword(iteration), halfword(hashBase+hashSize+12+1+paramSize)) 28492 28493 // \xref[for_suffixes_][\&[forsuffixes] primitive] 28494 prg.primitive(strNumber( /* "forever" */ 661), halfword(iteration), halfword(startForever)) 28495 28496 // \xref[forever_][\&[forever] primitive] 28497 prg.primitive(strNumber( /* "endfor" */ 455), halfword(iteration), halfword(endFor)) 28498 prg.eqtb[hashBase+hashSize+7-1] = prg.eqtb[prg.curSym-1] 28499 28500 // \xref[end_for_][\&[endfor] primitive] 28501 28502 prg.primitive(strNumber( /* "quote" */ 662), halfword(macroSpecial), halfword(quote)) 28503 28504 // \xref[quote_][\&[quote] primitive] 28505 prg.primitive(strNumber( /* "#@" */ 663), halfword(macroSpecial), halfword(macroPrefix)) 28506 28507 // \xref[]]]\#\AT!_][\.[\#\AT!] primitive] 28508 prg.primitive(strNumber('@'), halfword(macroSpecial), halfword(macroAt)) 28509 28510 // \xref[]]]\AT!_][\.[\AT!] primitive] 28511 prg.primitive(strNumber( /* "@#" */ 664), halfword(macroSpecial), halfword(macroSuffix)) 28512 28513 // \xref[]]]\AT!\#_][\.[\AT!\#] primitive] 28514 28515 prg.primitive(strNumber( /* "expr" */ 675), halfword(paramType), halfword(hashBase+hashSize+12+1)) 28516 28517 // \xref[expr_][\&[expr] primitive] 28518 prg.primitive(strNumber( /* "suffix" */ 676), halfword(paramType), halfword(hashBase+hashSize+12+1+paramSize)) 28519 28520 // \xref[suffix_][\&[suffix] primitive] 28521 prg.primitive(strNumber( /* "text" */ 677), halfword(paramType), halfword(hashBase+hashSize+12+1+paramSize+paramSize)) 28522 28523 // \xref[text_][\&[text] primitive] 28524 prg.primitive(strNumber( /* "primary" */ 678), halfword(paramType), halfword(primaryMacro)) 28525 28526 // \xref[primary_][\&[primary] primitive] 28527 prg.primitive(strNumber( /* "secondary" */ 679), halfword(paramType), halfword(secondaryMacro)) 28528 28529 // \xref[secondary_][\&[secondary] primitive] 28530 prg.primitive(strNumber( /* "tertiary" */ 680), halfword(paramType), halfword(tertiaryMacro)) 28531 28532 // \xref[tertiary_][\&[tertiary] primitive] 28533 28534 prg.primitive(strNumber( /* "input" */ 690), halfword(input), halfword(0)) 28535 28536 // \xref[input_][\&[input] primitive] 28537 prg.primitive(strNumber( /* "endinput" */ 616), halfword(input), halfword(1)) 28538 28539 // \xref[end_input_][\&[endinput] primitive] 28540 28541 prg.primitive(strNumber( /* "if" */ 717), halfword(ifTest), halfword(ifCode)) 28542 28543 // \xref[if_][\&[if] primitive] 28544 prg.primitive(strNumber( /* "fi" */ 452), halfword(fiOrElse), halfword(fiCode)) 28545 prg.eqtb[hashBase+hashSize+9-1] = prg.eqtb[prg.curSym-1] 28546 28547 // \xref[fi_][\&[fi] primitive] 28548 prg.primitive(strNumber( /* "else" */ 718), halfword(fiOrElse), halfword(elseCode)) 28549 28550 // \xref[else_][\&[else] primitive] 28551 prg.primitive(strNumber( /* "elseif" */ 719), halfword(fiOrElse), halfword(elseIfCode)) 28552 28553 // \xref[else_if_][\&[elseif] primitive] 28554 28555 prg.primitive(strNumber( /* "true" */ 348), halfword(nullary), halfword(trueCode)) 28556 28557 // \xref[true_][\&[true] primitive] 28558 prg.primitive(strNumber( /* "false" */ 349), halfword(nullary), halfword(falseCode)) 28559 28560 // \xref[false_][\&[false] primitive] 28561 prg.primitive(strNumber( /* "nullpicture" */ 350), halfword(nullary), halfword(nullPictureCode)) 28562 28563 // \xref[null_picture_][\&[nullpicture] primitive] 28564 prg.primitive(strNumber( /* "nullpen" */ 351), halfword(nullary), halfword(nullPenCode)) 28565 28566 // \xref[null_pen_][\&[nullpen] primitive] 28567 prg.primitive(strNumber( /* "jobname" */ 352), halfword(nullary), halfword(jobNameOp)) 28568 28569 // \xref[job_name_][\&[jobname] primitive] 28570 prg.primitive(strNumber( /* "readstring" */ 353), halfword(nullary), halfword(readStringOp)) 28571 28572 // \xref[read_string_][\&[readstring] primitive] 28573 prg.primitive(strNumber( /* "pencircle" */ 354), halfword(nullary), halfword(penCircle)) 28574 28575 // \xref[pen_circle_][\&[pencircle] primitive] 28576 prg.primitive(strNumber( /* "normaldeviate" */ 355), halfword(nullary), halfword(normalDeviate)) 28577 28578 // \xref[normal_deviate_][\&[normaldeviate] primitive] 28579 prg.primitive(strNumber( /* "odd" */ 356), halfword(unary), halfword(oddOp)) 28580 28581 // \xref[odd_][\&[odd] primitive] 28582 prg.primitive(strNumber( /* "known" */ 357), halfword(unary), halfword(knownOp)) 28583 28584 // \xref[known_][\&[known] primitive] 28585 prg.primitive(strNumber( /* "unknown" */ 358), halfword(unary), halfword(unknownOp)) 28586 28587 // \xref[unknown_][\&[unknown] primitive] 28588 prg.primitive(strNumber( /* "not" */ 359), halfword(unary), halfword(notOp)) 28589 28590 // \xref[not_][\&[not] primitive] 28591 prg.primitive(strNumber( /* "decimal" */ 360), halfword(unary), halfword(decimal)) 28592 28593 // \xref[decimal_][\&[decimal] primitive] 28594 prg.primitive(strNumber( /* "reverse" */ 361), halfword(unary), halfword(reverse)) 28595 28596 // \xref[reverse_][\&[reverse] primitive] 28597 prg.primitive(strNumber( /* "makepath" */ 362), halfword(unary), halfword(makePathOp)) 28598 28599 // \xref[make_path_][\&[makepath] primitive] 28600 prg.primitive(strNumber( /* "makepen" */ 363), halfword(unary), halfword(makePenOp)) 28601 28602 // \xref[make_pen_][\&[makepen] primitive] 28603 prg.primitive(strNumber( /* "totalweight" */ 364), halfword(unary), halfword(totalWeightOp)) 28604 28605 // \xref[total_weight_][\&[totalweight] primitive] 28606 prg.primitive(strNumber( /* "oct" */ 365), halfword(unary), halfword(octOp)) 28607 28608 // \xref[oct_][\&[oct] primitive] 28609 prg.primitive(strNumber( /* "hex" */ 366), halfword(unary), halfword(hexOp)) 28610 28611 // \xref[hex_][\&[hex] primitive] 28612 prg.primitive(strNumber( /* "ASCII" */ 367), halfword(unary), halfword(asciiOp)) 28613 28614 // \xref[ASCII_][\&[ASCII] primitive] 28615 prg.primitive(strNumber( /* "char" */ 368), halfword(unary), halfword(charOp)) 28616 28617 // \xref[char_][\&[char] primitive] 28618 prg.primitive(strNumber( /* "length" */ 369), halfword(unary), halfword(lengthOp)) 28619 28620 // \xref[length_][\&[length] primitive] 28621 prg.primitive(strNumber( /* "turningnumber" */ 370), halfword(unary), halfword(turningOp)) 28622 28623 // \xref[turning_number_][\&[turningnumber] primitive] 28624 prg.primitive(strNumber( /* "xpart" */ 371), halfword(unary), halfword(xPart)) 28625 28626 // \xref[x_part_][\&[xpart] primitive] 28627 prg.primitive(strNumber( /* "ypart" */ 372), halfword(unary), halfword(yPart)) 28628 28629 // \xref[y_part_][\&[ypart] primitive] 28630 prg.primitive(strNumber( /* "xxpart" */ 373), halfword(unary), halfword(xxPart)) 28631 28632 // \xref[xx_part_][\&[xxpart] primitive] 28633 prg.primitive(strNumber( /* "xypart" */ 374), halfword(unary), halfword(xyPart)) 28634 28635 // \xref[xy_part_][\&[xypart] primitive] 28636 prg.primitive(strNumber( /* "yxpart" */ 375), halfword(unary), halfword(yxPart)) 28637 28638 // \xref[yx_part_][\&[yxpart] primitive] 28639 prg.primitive(strNumber( /* "yypart" */ 376), halfword(unary), halfword(yyPart)) 28640 28641 // \xref[yy_part_][\&[yypart] primitive] 28642 prg.primitive(strNumber( /* "sqrt" */ 377), halfword(unary), halfword(sqrtOp)) 28643 28644 // \xref[sqrt_][\&[sqrt] primitive] 28645 prg.primitive(strNumber( /* "mexp" */ 378), halfword(unary), halfword(mExpOp)) 28646 28647 // \xref[m_exp_][\&[mexp] primitive] 28648 prg.primitive(strNumber( /* "mlog" */ 379), halfword(unary), halfword(mLogOp)) 28649 28650 // \xref[m_log_][\&[mlog] primitive] 28651 prg.primitive(strNumber( /* "sind" */ 380), halfword(unary), halfword(sinDOp)) 28652 28653 // \xref[sin_d_][\&[sind] primitive] 28654 prg.primitive(strNumber( /* "cosd" */ 381), halfword(unary), halfword(cosDOp)) 28655 28656 // \xref[cos_d_][\&[cosd] primitive] 28657 prg.primitive(strNumber( /* "floor" */ 382), halfword(unary), halfword(floorOp)) 28658 28659 // \xref[floor_][\&[floor] primitive] 28660 prg.primitive(strNumber( /* "uniformdeviate" */ 383), halfword(unary), halfword(uniformDeviate)) 28661 28662 // \xref[uniform_deviate_][\&[uniformdeviate] primitive] 28663 prg.primitive(strNumber( /* "charexists" */ 384), halfword(unary), halfword(charExistsOp)) 28664 28665 // \xref[char_exists_][\&[charexists] primitive] 28666 prg.primitive(strNumber( /* "angle" */ 385), halfword(unary), halfword(angleOp)) 28667 28668 // \xref[angle_][\&[angle] primitive] 28669 prg.primitive(strNumber( /* "cycle" */ 386), halfword(cycle), halfword(cycleOp)) 28670 28671 // \xref[cycle_][\&[cycle] primitive] 28672 prg.primitive(strNumber('+'), halfword(plusOrMinus), halfword(plus)) 28673 28674 // \xref[+ ][\.[+] primitive] 28675 prg.primitive(strNumber('-'), halfword(plusOrMinus), halfword(minus)) 28676 28677 // \xref[- ][\.[-] primitive] 28678 prg.primitive(strNumber('*'), halfword(secondaryBinary), halfword(times)) 28679 28680 // \xref[* ][\.[*] primitive] 28681 prg.primitive(strNumber('/'), halfword(slash), halfword(over)) 28682 prg.eqtb[hashBase+hashSize+4-1] = prg.eqtb[prg.curSym-1] 28683 28684 // \xref[/ ][\.[/] primitive] 28685 prg.primitive(strNumber( /* "++" */ 387), halfword(tertiaryBinary), halfword(pythagAdd)) 28686 28687 // \xref[++_][\.[++] primitive] 28688 prg.primitive(strNumber( /* "+-+" */ 311), halfword(tertiaryBinary), halfword(pythagSub)) 28689 28690 // \xref[+-+_][\.[+-+] primitive] 28691 prg.primitive(strNumber( /* "and" */ 389), halfword(andCommand), halfword(andOp)) 28692 28693 // \xref[and_][\&[and] primitive] 28694 prg.primitive(strNumber( /* "or" */ 388), halfword(tertiaryBinary), halfword(orOp)) 28695 28696 // \xref[or_][\&[or] primitive] 28697 prg.primitive(strNumber('<'), halfword(expressionBinary), halfword(lessThan)) 28698 28699 // \xref[< ][\.[<] primitive] 28700 prg.primitive(strNumber( /* "<=" */ 390), halfword(expressionBinary), halfword(lessOrEqual)) 28701 28702 // \xref[<=_][\.[<=] primitive] 28703 prg.primitive(strNumber('>'), halfword(expressionBinary), halfword(greaterThan)) 28704 28705 // \xref[> ][\.[>] primitive] 28706 prg.primitive(strNumber( /* ">=" */ 391), halfword(expressionBinary), halfword(greaterOrEqual)) 28707 28708 // \xref[>=_][\.[>=] primitive] 28709 prg.primitive(strNumber('='), halfword(equals), halfword(equalTo)) 28710 28711 // \xref[= ][\.[=] primitive] 28712 prg.primitive(strNumber( /* "<>" */ 392), halfword(expressionBinary), halfword(unequalTo)) 28713 28714 // \xref[<>_][\.[<>] primitive] 28715 prg.primitive(strNumber( /* "substring" */ 402), halfword(primaryBinary), halfword(substringOf)) 28716 28717 // \xref[substring_][\&[substring] primitive] 28718 prg.primitive(strNumber( /* "subpath" */ 403), halfword(primaryBinary), halfword(subpathOf)) 28719 28720 // \xref[subpath_][\&[subpath] primitive] 28721 prg.primitive(strNumber( /* "directiontime" */ 404), halfword(primaryBinary), halfword(directionTimeOf)) 28722 28723 // \xref[direction_time_][\&[directiontime] primitive] 28724 prg.primitive(strNumber( /* "point" */ 405), halfword(primaryBinary), halfword(pointOf)) 28725 28726 // \xref[point_][\&[point] primitive] 28727 prg.primitive(strNumber( /* "precontrol" */ 406), halfword(primaryBinary), halfword(precontrolOf)) 28728 28729 // \xref[precontrol_][\&[precontrol] primitive] 28730 prg.primitive(strNumber( /* "postcontrol" */ 407), halfword(primaryBinary), halfword(postcontrolOf)) 28731 28732 // \xref[postcontrol_][\&[postcontrol] primitive] 28733 prg.primitive(strNumber( /* "penoffset" */ 408), halfword(primaryBinary), halfword(penOffsetOf)) 28734 28735 // \xref[pen_offset_][\&[penoffset] primitive] 28736 prg.primitive(strNumber('&'), halfword(ampersand), halfword(concatenate)) 28737 28738 // \xref[!!!][\.[\&] primitive] 28739 prg.primitive(strNumber( /* "rotated" */ 393), halfword(secondaryBinary), halfword(rotatedBy)) 28740 28741 // \xref[rotated_][\&[rotated] primitive] 28742 prg.primitive(strNumber( /* "slanted" */ 394), halfword(secondaryBinary), halfword(slantedBy)) 28743 28744 // \xref[slanted_][\&[slanted] primitive] 28745 prg.primitive(strNumber( /* "scaled" */ 395), halfword(secondaryBinary), halfword(scaledBy)) 28746 28747 // \xref[scaled_][\&[scaled] primitive] 28748 prg.primitive(strNumber( /* "shifted" */ 396), halfword(secondaryBinary), halfword(shiftedBy)) 28749 28750 // \xref[shifted_][\&[shifted] primitive] 28751 prg.primitive(strNumber( /* "transformed" */ 397), halfword(secondaryBinary), halfword(transformedBy)) 28752 28753 // \xref[transformed_][\&[transformed] primitive] 28754 prg.primitive(strNumber( /* "xscaled" */ 398), halfword(secondaryBinary), halfword(xScaled)) 28755 28756 // \xref[x_scaled_][\&[xscaled] primitive] 28757 prg.primitive(strNumber( /* "yscaled" */ 399), halfword(secondaryBinary), halfword(yScaled)) 28758 28759 // \xref[y_scaled_][\&[yscaled] primitive] 28760 prg.primitive(strNumber( /* "zscaled" */ 400), halfword(secondaryBinary), halfword(zScaled)) 28761 28762 // \xref[z_scaled_][\&[zscaled] primitive] 28763 prg.primitive(strNumber( /* "intersectiontimes" */ 401), halfword(tertiaryBinary), halfword(intersect)) 28764 28765 // \xref[intersection_times_][\&[intersectiontimes] primitive] 28766 28767 prg.primitive(strNumber( /* "numeric" */ 341), halfword(typeName), halfword(numericType)) 28768 28769 // \xref[numeric_][\&[numeric] primitive] 28770 prg.primitive(strNumber( /* "string" */ 327), halfword(typeName), halfword(stringType)) 28771 28772 // \xref[string_][\&[string] primitive] 28773 prg.primitive(strNumber( /* "boolean" */ 325), halfword(typeName), halfword(booleanType)) 28774 28775 // \xref[boolean_][\&[boolean] primitive] 28776 prg.primitive(strNumber( /* "path" */ 332), halfword(typeName), halfword(pathType)) 28777 28778 // \xref[path_][\&[path] primitive] 28779 prg.primitive(strNumber( /* "pen" */ 329), halfword(typeName), halfword(penType)) 28780 28781 // \xref[pen_][\&[pen] primitive] 28782 prg.primitive(strNumber( /* "picture" */ 334), halfword(typeName), halfword(pictureType)) 28783 28784 // \xref[picture_][\&[picture] primitive] 28785 prg.primitive(strNumber( /* "transform" */ 336), halfword(typeName), halfword(transformType)) 28786 28787 // \xref[transform_][\&[transform] primitive] 28788 prg.primitive(strNumber( /* "pair" */ 337), halfword(typeName), halfword(pairType)) 28789 28790 // \xref[pair_][\&[pair] primitive] 28791 28792 prg.primitive(strNumber( /* "end" */ 912), halfword(stop), halfword(0)) 28793 28794 // \xref[end_][\&[end] primitive] 28795 prg.primitive(strNumber( /* "dump" */ 913), halfword(stop), halfword(1)) 28796 28797 // \xref[dump_][\&[dump] primitive] 28798 28799 prg.primitive(strNumber( /* "batchmode" */ 273), halfword(modeCommand), halfword(batchMode)) 28800 // \xref[batch_mode_][\&[batchmode] primitive] 28801 prg.primitive(strNumber( /* "nonstopmode" */ 274), halfword(modeCommand), halfword(nonstopMode)) 28802 // \xref[nonstop_mode_][\&[nonstopmode] primitive] 28803 prg.primitive(strNumber( /* "scrollmode" */ 275), halfword(modeCommand), halfword(scrollMode)) 28804 // \xref[scroll_mode_][\&[scrollmode] primitive] 28805 prg.primitive(strNumber( /* "errorstopmode" */ 919), halfword(modeCommand), halfword(errorStopMode)) 28806 // \xref[error_stop_mode_][\&[errorstopmode] primitive] 28807 28808 prg.primitive(strNumber( /* "inner" */ 920), halfword(protectionCommand), halfword(0)) 28809 28810 // \xref[inner_][\&[inner] primitive] 28811 prg.primitive(strNumber( /* "outer" */ 921), halfword(protectionCommand), halfword(1)) 28812 28813 // \xref[outer_][\&[outer] primitive] 28814 28815 prg.primitive(strNumber( /* "showtoken" */ 935), halfword(showCommand), halfword(showTokenCode)) 28816 28817 // \xref[show_token_][\&[showtoken] primitive] 28818 prg.primitive(strNumber( /* "showstats" */ 936), halfword(showCommand), halfword(showStatsCode)) 28819 28820 // \xref[show_stats_][\&[showstats] primitive] 28821 prg.primitive(strNumber( /* "show" */ 937), halfword(showCommand), halfword(showCode)) 28822 28823 // \xref[show_][\&[show] primitive] 28824 prg.primitive(strNumber( /* "showvariable" */ 938), halfword(showCommand), halfword(showVarCode)) 28825 28826 // \xref[show_var_][\&[showvariable] primitive] 28827 prg.primitive(strNumber( /* "showdependencies" */ 939), halfword(showCommand), halfword(showDependenciesCode)) 28828 28829 // \xref[show_dependencies_][\&[showdependencies] primitive] 28830 28831 prg.primitive(strNumber( /* "contour" */ 956), halfword(thingToAdd), halfword(contourCode)) 28832 28833 // \xref[contour_][\&[contour] primitive] 28834 prg.primitive(strNumber( /* "doublepath" */ 957), halfword(thingToAdd), halfword(doublePathCode)) 28835 28836 // \xref[double_path_][\&[doublepath] primitive] 28837 prg.primitive(strNumber( /* "also" */ 958), halfword(thingToAdd), halfword(alsoCode)) 28838 28839 // \xref[also_][\&[also] primitive] 28840 prg.primitive(strNumber( /* "withpen" */ 959), halfword(withOption), halfword(penType)) 28841 28842 // \xref[with_pen_][\&[withpen] primitive] 28843 prg.primitive(strNumber( /* "withweight" */ 960), halfword(withOption), halfword(known)) 28844 28845 // \xref[with_weight_][\&[withweight] primitive] 28846 prg.primitive(strNumber( /* "dropping" */ 961), halfword(cullOp), halfword(dropCode)) 28847 28848 // \xref[dropping_][\&[dropping] primitive] 28849 prg.primitive(strNumber( /* "keeping" */ 962), halfword(cullOp), halfword(keepCode)) 28850 28851 // \xref[keeping_][\&[keeping] primitive] 28852 28853 prg.primitive(strNumber( /* "message" */ 992), halfword(messageCommand), halfword(messageCode)) 28854 28855 // \xref[message_][\&[message] primitive] 28856 prg.primitive(strNumber( /* "errmessage" */ 993), halfword(messageCommand), halfword(errMessageCode)) 28857 28858 // \xref[err_message_][\&[errmessage] primitive] 28859 prg.primitive(strNumber( /* "errhelp" */ 994), halfword(messageCommand), halfword(errHelpCode)) 28860 28861 // \xref[err_help_][\&[errhelp] primitive] 28862 28863 prg.primitive(strNumber( /* "charlist" */ 1004), halfword(tfmCommand), halfword(charListCode)) 28864 28865 // \xref[char_list_][\&[charlist] primitive] 28866 prg.primitive(strNumber( /* "ligtable" */ 1005), halfword(tfmCommand), halfword(ligTableCode)) 28867 28868 // \xref[lig_table_][\&[ligtable] primitive] 28869 prg.primitive(strNumber( /* "extensible" */ 1006), halfword(tfmCommand), halfword(extensibleCode)) 28870 28871 // \xref[extensible_][\&[extensible] primitive] 28872 prg.primitive(strNumber( /* "headerbyte" */ 1007), halfword(tfmCommand), halfword(headerByteCode)) 28873 28874 // \xref[header_byte_][\&[headerbyte] primitive] 28875 prg.primitive(strNumber( /* "fontdimen" */ 1008), halfword(tfmCommand), halfword(fontDimenCode)) 28876 28877 // \xref[font_dimen_][\&[fontdimen] primitive] 28878 28879 prg.primitive(strNumber( /* "=:" */ 1026), halfword(ligKernToken), halfword(0)) 28880 // \xref[=:_][\.[=:] primitive] 28881 prg.primitive(strNumber( /* "=:|" */ 1027), halfword(ligKernToken), halfword(1)) 28882 // \xref[=:/_][\.[=:\char'174] primitive] 28883 prg.primitive(strNumber( /* "=:|>" */ 1028), halfword(ligKernToken), halfword(5)) 28884 // \xref[=:/>_][\.[=:\char'174>] primitive] 28885 prg.primitive(strNumber( /* "|=:" */ 1029), halfword(ligKernToken), halfword(2)) 28886 // \xref[=:/_][\.[\char'174=:] primitive] 28887 prg.primitive(strNumber( /* "|=:>" */ 1030), halfword(ligKernToken), halfword(6)) 28888 // \xref[=:/>_][\.[\char'174=:>] primitive] 28889 prg.primitive(strNumber( /* "|=:|" */ 1031), halfword(ligKernToken), halfword(3)) 28890 // \xref[=:/_][\.[\char'174=:\char'174] primitive] 28891 prg.primitive(strNumber( /* "|=:|>" */ 1032), halfword(ligKernToken), halfword(7)) 28892 // \xref[=:/>_][\.[\char'174=:\char'174>] primitive] 28893 prg.primitive(strNumber( /* "|=:|>>" */ 1033), halfword(ligKernToken), halfword(11)) 28894 // \xref[=:/>_][\.[\char'174=:\char'174>>] primitive] 28895 prg.primitive(strNumber( /* "kern" */ 1034), halfword(ligKernToken), halfword(128)) 28896 // \xref[kern_][\&[kern] primitive] 28897 28898 prg.primitive(strNumber( /* "special" */ 1058), halfword(specialCommand), halfword(stringType)) 28899 28900 // \xref[special_][\&[special] primitive] 28901 prg.primitive(strNumber( /* "numspecial" */ 1059), halfword(specialCommand), halfword(known)) 28902 28903 // \xref[num_special_][\&[numspecial] primitive] 28904 28905 } 28906 28907 func (prg *prg) initTab() { // initialize other tables 28908 var ( 28909 k int32 // all-purpose index 28910 ) 28911 prg.rover = uint16(memMin + 3 + 10 + 2 + 2 + 2 + 2 + 1 + 1) // initialize the dynamic memory 28912 *(*prg.mem[prg.rover].hh()).rh() = 65535 28913 *(*prg.mem[prg.rover].hh()).lh() = 1000 // which is a 1000-word available node 28914 *(*prg.mem[int32(prg.rover)+1].hh()).lh() = prg.rover 28915 *(*prg.mem[int32(prg.rover)+1].hh()).rh() = prg.rover 28916 28917 prg.loMemMax = uint16(int32(prg.rover) + 1000) 28918 *(*prg.mem[prg.loMemMax].hh()).rh() = uint16(memMin) 28919 *(*prg.mem[prg.loMemMax].hh()).lh() = uint16(memMin) 28920 28921 for ii := int32(3000 - 2); ii <= 3000; ii++ { 28922 k = ii 28923 _ = k 28924 prg.mem[k] = prg.mem[prg.loMemMax] 28925 } // clear list heads 28926 prg.avail = uint16(memMin) 28927 prg.memEnd = 3000 28928 prg.hiMemMin = uint16(3000 - 2) // initialize the one-word memory 28929 prg.varUsed = memMin + 3 + 10 + 2 + 2 + 2 + 2 + 1 + 1 - memMin 28930 prg.dynUsed = 3000 + 1 - int32(prg.hiMemMin) 28931 // initialize statistics 28932 28933 prg.intName[tracingTitles-1] = /* "tracingtitles" */ 410 28934 prg.intName[tracingEquations-1] = /* "tracingequations" */ 411 28935 prg.intName[tracingCapsules-1] = /* "tracingcapsules" */ 412 28936 prg.intName[tracingChoices-1] = /* "tracingchoices" */ 413 28937 prg.intName[tracingSpecs-1] = /* "tracingspecs" */ 414 28938 prg.intName[tracingPens-1] = /* "tracingpens" */ 415 28939 prg.intName[tracingCommands-1] = /* "tracingcommands" */ 416 28940 prg.intName[tracingRestores-1] = /* "tracingrestores" */ 417 28941 prg.intName[tracingMacros-1] = /* "tracingmacros" */ 418 28942 prg.intName[tracingEdges-1] = /* "tracingedges" */ 419 28943 prg.intName[tracingOutput-1] = /* "tracingoutput" */ 420 28944 prg.intName[tracingStats-1] = /* "tracingstats" */ 421 28945 prg.intName[tracingOnline-1] = /* "tracingonline" */ 422 28946 prg.intName[year-1] = /* "year" */ 423 28947 prg.intName[month-1] = /* "month" */ 424 28948 prg.intName[day-1] = /* "day" */ 425 28949 prg.intName[time-1] = /* "time" */ 426 28950 prg.intName[charCode-1] = /* "charcode" */ 427 28951 prg.intName[charExt-1] = /* "charext" */ 428 28952 prg.intName[charWd-1] = /* "charwd" */ 429 28953 prg.intName[charHt-1] = /* "charht" */ 430 28954 prg.intName[charDp-1] = /* "chardp" */ 431 28955 prg.intName[charIc-1] = /* "charic" */ 432 28956 prg.intName[charDx-1] = /* "chardx" */ 433 28957 prg.intName[charDy-1] = /* "chardy" */ 434 28958 prg.intName[designSize-1] = /* "designsize" */ 435 28959 prg.intName[hppp-1] = /* "hppp" */ 436 28960 prg.intName[vppp-1] = /* "vppp" */ 437 28961 prg.intName[xOffset-1] = /* "xoffset" */ 438 28962 prg.intName[yOffset-1] = /* "yoffset" */ 439 28963 prg.intName[pausing-1] = /* "pausing" */ 440 28964 prg.intName[showstopping-1] = /* "showstopping" */ 441 28965 prg.intName[fontmaking-1] = /* "fontmaking" */ 442 28966 prg.intName[proofing-1] = /* "proofing" */ 443 28967 prg.intName[smoothing-1] = /* "smoothing" */ 444 28968 prg.intName[autorounding-1] = /* "autorounding" */ 445 28969 prg.intName[granularity-1] = /* "granularity" */ 446 28970 prg.intName[fillin-1] = /* "fillin" */ 447 28971 prg.intName[turningCheck-1] = /* "turningcheck" */ 448 28972 prg.intName[warningCheck-1] = /* "warningcheck" */ 449 28973 prg.intName[boundaryChar-1] = /* "boundarychar" */ 450 28974 28975 prg.hashUsed = uint16(hashBase + hashSize) // nothing is used 28976 prg.stCount = 0 28977 28978 *prg.hash[hashBase+hashSize+11-1].rh() = 451 28979 *prg.hash[hashBase+hashSize+9-1].rh() = 452 28980 *prg.hash[hashBase+hashSize+10-1].rh() = 453 28981 *prg.hash[hashBase+hashSize+8-1].rh() = 454 28982 *prg.hash[hashBase+hashSize+7-1].rh() = 455 28983 28984 *prg.hash[hashBase+hashSize+6-1].rh() = ';' 28985 *prg.hash[hashBase+hashSize+5-1].rh() = ':' 28986 *prg.hash[hashBase+hashSize+4-1].rh() = '/' 28987 *prg.hash[hashBase+hashSize+3-1].rh() = '[' 28988 *prg.hash[hashBase+hashSize+2-1].rh() = ')' 28989 28990 *prg.hash[hashBase+hashSize-1].rh() = 456 28991 28992 *prg.eqtb[hashBase+hashSize+2-1].lh() = uint16(rightDelimiter) 28993 28994 *(*prg.mem[memMin+3+10+2+2+2].hh()).lh() = uint16(hashBase + hashSize + 12 + 1) 28995 *(*prg.mem[memMin+3+10+2+2+2].hh()).rh() = uint16(memMin) 28996 28997 *(*prg.mem[3000].hh()).lh() = 65535 // |link(sentinel)=null| 28998 28999 *(*prg.mem[memMin+3].hh()).lh() = uint16(memMin) 29000 *(*prg.mem[memMin+3].hh()).rh() = uint16(memMin) 29001 29002 *(*prg.mem[memMin+3+1].hh()).lh() = 1 29003 *(*prg.mem[memMin+3+1].hh()).rh() = uint16(memMin) 29004 for ii := int32(memMin + 3 + 2); ii <= memMin+3+8; ii++ { 29005 k = ii 29006 _ = k 29007 prg.mem[k] = prg.mem[memMin+3+1] 29008 } 29009 *prg.mem[memMin+3+9].int() = 0 29010 29011 *(*prg.mem[memMin].hh()).rh() = uint16(memMin) 29012 *(*prg.mem[memMin].hh()).lh() = uint16(memMin) 29013 29014 *prg.mem[memMin+1].int() = 0 29015 *prg.mem[memMin+2].int() = 0 29016 29017 prg.serialNo = 0 29018 *(*prg.mem[memMin+3+10].hh()).rh() = uint16(memMin + 3 + 10) 29019 *(*prg.mem[memMin+3+10+1].hh()).lh() = uint16(memMin + 3 + 10) 29020 *(*prg.mem[memMin+3+10].hh()).lh() = uint16(memMin) 29021 *(*prg.mem[memMin+3+10+1].hh()).rh() = uint16(memMin) 29022 29023 *(*prg.mem[memMin+3+10+2+2+2+2].hh()).b1() = byte(root) 29024 *(*prg.mem[memMin+3+10+2+2+2+2].hh()).rh() = uint16(hashBase + hashSize + 11) 29025 *prg.eqtb[hashBase+hashSize+11-1].rh() = uint16(memMin + 3 + 10 + 2 + 2 + 2 + 2) 29026 *prg.eqtb[hashBase+hashSize+11-1].lh() = uint16(tagToken) 29027 29028 *prg.eqtb[hashBase+hashSize+1-1].lh() = uint16(repeatLoop + outerTag) 29029 *prg.hash[hashBase+hashSize+1-1].rh() = 734 29030 29031 *(*prg.mem[memMin+3+10+2+2].hh()).b1() = byte(capsule) 29032 29033 *prg.mem[memMin+3+10+2+2+2+1].int() = 010000000000 29034 29035 *prg.mem[memMin+3+10+2+1].int() = 0 29036 *(*prg.mem[memMin+3+10+2].hh()).lh() = 0 29037 29038 prg.baseIdent = /* " (INIMF)" */ 1067 29039 29040 } 29041 29042 // procedure debug_help; [routine to display various things] 29043 // label breakpoint,exit; 29044 // var k, l, m, n:integer; 29045 // begin ; 29046 // while true do begin ; 29047 // print_nl(["debug # (-1 to exit):"=]1081); ; 29048 // [ \xref[debug \#] ] 29049 // read(term_in,m); 29050 // if m<0 then goto exit 29051 // else if m=0 then 29052 // begin goto breakpoint; 29053 // [go to every declared label at least once] 29054 // breakpoint: m:=0; ['BREAKPOINT'] 29055 // 29056 // end 29057 // else begin read(term_in,n); 29058 // case m of 29059 // [ \4 ] 29060 // [ Numbered cases for |debug_help| ] 29061 // 1: print_word(mem[n]); [display |mem[n]| in all forms] 29062 // 2: print_int( mem[ n].hh.lh ); 29063 // 3: print_int( mem[ n].hh.rh ); 29064 // 4: begin print_int( eqtb[ n].lh ); print_char([":"=]58); print_int( eqtb[ n].rh ); 29065 // end; 29066 // 5: print_variable_name(n); 29067 // 6: print_int(internal[n]); 29068 // 7: do_show_dependencies; 29069 // 9: show_token_list(n,mem_min ,100000,0); 29070 // 10: slow_print(n); 29071 // 11: check_mem(n>0); [check wellformedness; print new busy locations if |n>0|] 29072 // 12: search_mem(n); [look for pointers to |n|] 29073 // 13: begin read(term_in,l); print_cmd_mod(n,l); 29074 // end; 29075 // 14: for k:=0 to n do print(buffer[k]); 29076 // 15: panicking:=not panicking; 29077 // 29078 // 29079 // else print(["?"=]63) 29080 // end ; 29081 // end; 29082 // end; 29083 // exit:end; 29084 // [ ] 29085 29086 // 1204. 29087 29088 // tangle:pos ../../mf.web:22852:3: 29089 29090 // Now this is really it: \MF\ starts and ends here. 29091 // 29092 // The initial test involving |ready_already| should be deleted if the 29093 // \PASCAL\ runtime system is smart enough to detect such a ``mistake.'' 29094 // \xref[system dependencies] 29095 func (prg *prg) main() { 29096 defer func() { 29097 if prg.baseFile != nil { 29098 prg.baseFile.Close() 29099 } 29100 if prg.gfFile != nil { 29101 prg.gfFile.Close() 29102 } 29103 if prg.logFile != nil { 29104 prg.logFile.Close() 29105 } 29106 if prg.poolFile != nil { 29107 prg.poolFile.Close() 29108 } 29109 if prg.stderr != nil { 29110 prg.stderr.Close() 29111 } 29112 if prg.stdin != nil { 29113 prg.stdin.Close() 29114 } 29115 if prg.stdout != nil { 29116 prg.stdout.Close() 29117 } 29118 if prg.termIn != nil { 29119 prg.termIn.Close() 29120 } 29121 if prg.termOut != nil { 29122 prg.termOut.Close() 29123 } 29124 if prg.tfmFile != nil { 29125 prg.tfmFile.Close() 29126 } 29127 }() 29128 29129 prg.history = byte(fatalErrorStop) // in case we quit during initialization 29130 prg.termOut.Rewrite("TTY:", "/O") // open the terminal for output 29131 if prg.readyAlready == 314159 { 29132 goto startOfMf 29133 } 29134 29135 // Check the “constant” values... 29136 prg.bad = 0 29137 if halfErrorLine < 30 || halfErrorLine > errorLine-15 { 29138 prg.bad = 1 29139 } 29140 if maxPrintLine < 60 { 29141 prg.bad = 2 29142 } 29143 if gfBufSize%8 != 0 { 29144 prg.bad = 3 29145 } 29146 if memMin+1100 > 3000 { 29147 prg.bad = 4 29148 } 29149 if hashPrime > hashSize { 29150 prg.bad = 5 29151 } 29152 if headerSize%4 != 0 { 29153 prg.bad = 6 29154 } 29155 if ligTableSize < 255 || ligTableSize > 32510 { 29156 prg.bad = 7 29157 } 29158 29159 if memMax != 3000 { 29160 prg.bad = 10 29161 } 29162 29163 if memMax < 3000 { 29164 prg.bad = 10 29165 } 29166 if minQuarterword > 0 || maxQuarterword < 127 { 29167 prg.bad = 11 29168 } 29169 if 0 > 0 || 65535 < 32767 { 29170 prg.bad = 12 29171 } 29172 if minQuarterword < 0 || maxQuarterword > 65535 { 29173 prg.bad = 13 29174 } 29175 if memMin < 0 || memMax >= 65535 { 29176 prg.bad = 14 29177 } 29178 if maxStrings > 65535 { 29179 prg.bad = 15 29180 } 29181 if bufSize > 65535 { 29182 prg.bad = 16 29183 } 29184 if maxQuarterword-minQuarterword < 255 || 65535-0 < 65535 { 29185 prg.bad = 17 29186 } 29187 29188 if hashBase+hashSize+12+maxInternal > 65535 { 29189 prg.bad = 21 29190 } 29191 29192 if hashBase+hashSize+12+1+paramSize+paramSize+paramSize > 65535 { 29193 prg.bad = 22 29194 } 29195 29196 if 15*moveIncrement > bistackSize { 29197 prg.bad = 31 29198 } 29199 29200 if intPackets+17*intIncrement > bistackSize { 29201 prg.bad = 32 29202 } 29203 29204 if baseDefaultLength > fileNameSize { 29205 prg.bad = 41 29206 } 29207 29208 if prg.bad > 0 { 29209 prg.termOut.Writeln("Ouch---my internal constants have been clobbered!", 29210 "---case ", prg.bad, knuth.WriteWidth(1)) 29211 // \xref[Ouch...clobbered] 29212 29213 // \xref[Ouch...clobbered] 29214 goto finalEnd 29215 } 29216 prg.initialize() // set global variables to their starting values 29217 if !prg.getStringsStarted() { 29218 goto finalEnd 29219 } 29220 prg.initTab() // initialize the tables 29221 prg.initPrim() // call |primitive| for each primitive 29222 prg.initStrPtr = prg.strPtr 29223 prg.initPoolPtr = prg.poolPtr 29224 29225 prg.maxStrPtr = prg.strPtr 29226 prg.maxPoolPtr = prg.poolPtr 29227 prg.fixDateAndTime() 29228 29229 prg.readyAlready = 314159 29230 29231 startOfMf: 29232 prg.selector = byte(termOnly) 29233 prg.tally = 0 29234 prg.termOffset = 0 29235 prg.fileOffset = 0 29236 29237 prg.termOut.Write("This is METAFONT, Version 2.71828182 (TRAP)") 29238 if int32(prg.baseIdent) == 0 { 29239 prg.termOut.Writeln(" (no base preloaded)") 29240 } else { 29241 prg.slowPrint(int32(prg.baseIdent)) 29242 prg.printLn() 29243 } 29244 29245 prg.jobName = 0 29246 prg.logOpened = false 29247 29248 prg.outputFileName = 0 29249 29250 // Get the first line of input and prepare to start 29251 { 29252 { 29253 prg.inputPtr = 0 29254 prg.maxInStack = 0 29255 prg.inOpen = 0 29256 prg.openParens = 0 29257 prg.maxBufStack = 0 29258 prg.paramPtr = 0 29259 prg.maxParamStack = 0 29260 prg.first = 1 29261 prg.curInput.startField = 1 29262 prg.curInput.indexField = 0 29263 prg.line = 0 29264 prg.curInput.nameField = 0 29265 prg.forceEof = false 29266 if !prg.initTerminal() { 29267 goto finalEnd 29268 } 29269 prg.curInput.limitField = prg.last 29270 prg.first = uint16(int32(prg.last) + 1) // |init_terminal| has set |loc| and |last| 29271 } 29272 29273 prg.scannerStatus = byte(normal) 29274 29275 if int32(prg.baseIdent) == 0 || int32(prg.buffer[prg.curInput.locField]) == '&' { 29276 if int32(prg.baseIdent) != 0 { 29277 prg.initialize() 29278 } // erase preloaded base 29279 if !prg.openBaseFile() { 29280 goto finalEnd 29281 } 29282 if !prg.loadBaseFile() { 29283 prg.wClose(prg.baseFile) 29284 goto finalEnd 29285 } 29286 prg.wClose(prg.baseFile) 29287 for int32(prg.curInput.locField) < int32(prg.curInput.limitField) && int32(prg.buffer[prg.curInput.locField]) == ' ' { 29288 prg.curInput.locField = uint16(int32(prg.curInput.locField) + 1) 29289 } 29290 } 29291 prg.buffer[prg.curInput.limitField] = '%' 29292 29293 prg.fixDateAndTime() 29294 prg.initRandoms(prg.sysTime + prg.sysDay*0200000) 29295 29296 // Initialize the print |selector|... 29297 if int32(prg.interaction) == batchMode { 29298 prg.selector = byte(noPrint) 29299 } else { 29300 prg.selector = byte(termOnly) 29301 } 29302 if int32(prg.curInput.locField) < int32(prg.curInput.limitField) { 29303 if int32(prg.buffer[prg.curInput.locField]) != '\\' { 29304 prg.startInput() 29305 } 29306 } // \&[input] assumed 29307 } 29308 prg.history = byte(spotless) // ready to go! 29309 if int32(prg.startSym) > 0 { 29310 prg.curSym = prg.startSym 29311 prg.backInput() 29312 } 29313 prg.mainControl() // come to life 29314 prg.finalCleanup() // prepare for death 29315 prg.closeFilesAndTerminate() 29316 29317 finalEnd: 29318 prg.readyAlready = 0 29319 } 29320 29321 // 1214. \[51] System-dependent changes 29322 29323 // tangle:pos ../../mf.web:23125:35: 29324 29325 // This section should be replaced, if necessary, by any special 29326 // modifications of the program 29327 // that are necessary to make \MF\ work at a particular installation. 29328 // It is usually best to design your change file so that all changes to 29329 // previous sections preserve the section numbering; then everybody's version 29330 // will be consistent with the published program. More extensive changes, 29331 // which introduce new sections, can be inserted here; then only the index 29332 // itself will get a new section number. 29333 // \xref[system dependencies] 29334 29335 // 1215. \[52] Index 29336 29337 // tangle:pos ../../mf.web:23136:16: 29338 29339 // Here is where you can find all uses of each identifier in the program, 29340 // with underlined entries pointing to where the identifier was defined. 29341 // If the identifier is only one letter long, however, you get to see only 29342 // the underlined entries. [\sl All references are to section numbers instead of 29343 // page numbers.] 29344 // 29345 // This index also lists error messages and other aspects of the program 29346 // that you might want to look up some day. For example, the entry 29347 // for ``system dependencies'' lists all sections that should receive 29348 // special attention from people who are installing \MF\ in a new 29349 // operating environment. A list of various things that can't happen appears 29350 // under ``this can't happen''. 29351 // Approximately 25 sections are listed under ``inner loop''; these account 29352 // for more than 60\pct! of \MF's running time, exclusive of input and output.