modernc.org/knuth@v0.0.4/tangle/tangle.go (about) 1 // Code generated by '[/tmp/go-build2075925341/b001/exe/generate]', DO NOT EDIT. 2 3 // % This program by D. E. Knuth is not copyrighted and can be used freely. 4 // % Version 0 was released in December, 1981. 5 // % Version 1 was released in September, 1982, with version 0 of TeX. 6 // % Slight changes were made in October, 1982, for version 0.6 of TeX. 7 // % Version 1.2 introduced [:nnn] comments, added @= and @\ (December, 1982). 8 // % Version 1.4 added "history" (February, 1983). 9 // % Version 1.5 conformed to TeX version 0.96 and fixed @\ (March, 1983). 10 // % Version 1.7 introduced the new change file format (June, 1983). 11 // % Version 2.0 was released in July, 1983, with version 0.999 of TeX. 12 // % Version 2.5 was released in November, 1983, with version 1.0 of TeX. 13 // % Version 2.6 fixed a bug: force-line-break after a constant (August, 1984). 14 // % Version 2.7 fixed the definition of check_sum_prime (May, 1985). 15 // % Version 2.8 fixed a bug in change_buffer movement (August, 1985). 16 // % Version 2.9 allows nonnumeric macros before their def (December, 1988). 17 // % Version 3, for Sewell's book, fixed long-line bug in input_ln (March, 1989). 18 // % Version 4 was major change to allow 8-bit input (September, 1989). 19 // % Version 4.1 conforms to ANSI standard for-loop rules (September, 1990). 20 // % Version 4.2 fixes stat report if phase one dies (March, 1991). 21 // % Version 4.3 fixes @ bug in verbatim, catches extra ] (September, 1991). 22 // % Version 4.4 activates debug_help on errors as advertised (February, 1993). 23 // % Version 4.5 prevents modno-comments from being split across lines (Dec 2002). 24 // % Version 4.6 fixes archaic @z logic; is again big enough for TeX (Jan 2021). 25 // 26 // % Here is TeX material that gets inserted after \input webmac 27 // \def\hang[\hangindent 3em\indent\ignorespaces] 28 // \font\ninerm=cmr9 29 // \let\mc=\ninerm % medium caps for names like SAIL 30 // \def\PASCAL[Pascal] 31 // \def\pb[$\.|\ldots\.|$] % Pascal brackets (|...|) 32 // \def\v[\.[\char'174]] % vertical (|) in typewriter font 33 // \mathchardef\BA="3224 % double arrow 34 // \def\([] % kludge for alphabetizing certain module names 35 // 36 // \def\title[TANGLE] 37 // \def\contentspagenumber[125] % should be odd 38 // \def\topofcontents[\null\vfill 39 // \titlefalse % include headline on the contents page 40 // \def\rheader[\mainfont Appendix E\hfil \contentspagenumber] 41 // \centerline[\titlefont The [\ttitlefont TANGLE] processor] 42 // \vskip 15pt 43 // \centerline[(Version 4.6)] 44 // \vfill] 45 // \pageno=\contentspagenumber \advance\pageno by 1 46 // 47 // 48 49 // 1. Introduction 50 51 // tangle:pos tangle.web:45:17: 52 53 // This program converts a \.[WEB] file to a \PASCAL\ file. It was written 54 // by D. E. Knuth in September, 1981; a somewhat similar [\mc SAIL] program had 55 // been developed in March, 1979. Since this program describes itself, a 56 // bootstrapping process involving hand-translation had to be used to get started. 57 // 58 // For large \.[WEB] files one should have a large memory, since \.[TANGLE] keeps 59 // all the \PASCAL\ text in memory (in an abbreviated form). The program uses 60 // a few features of the local \PASCAL\ compiler that may need to be changed in 61 // other installations: 62 // 63 // \yskip\item[1)] Case statements have a default. 64 // \item[2)] Input-output routines may need to be adapted for use with a particular 65 // character set and/or for printing messages on the user's terminal. 66 // 67 // \yskip\noindent 68 // These features are also present in the \PASCAL\ version of \TeX, where they 69 // are used in a similar (but more complex) way. System-dependent portions 70 // of \.[TANGLE] can be identified by looking at the entries for `system 71 // dependencies' in the index below. 72 // \xref[system dependencies] 73 // 74 // The ``banner line'' defined here should be changed whenever \.[TANGLE] 75 // is modified. 76 77 // 2. 78 79 // tangle:pos tangle.web:72:3: 80 81 // The program begins with a fairly normal header, made up of pieces that 82 // \xref[system dependencies] 83 // will mostly be filled in later. The \.[WEB] input comes from files |web_file| 84 // and |change_file|, the \PASCAL\ output goes to file |Pascal_file|, 85 // and the string pool output goes to file |pool|. 86 // 87 // If it is necessary to abort the job because of a fatal error, the program 88 // calls the `|jump_out|' procedure, which goes to the label |end_of_TANGLE|. 89 // \4 90 // Compiler directives 91 // $C-,A+,D- 92 // no range check, catch arithmetic overflow, no debug overhead 93 // [$C+,D+] [ ] 94 // but turn everything on when debugging 95 96 package tangle 97 98 import ( 99 "math" 100 "unsafe" 101 102 "modernc.org/knuth" 103 ) 104 105 var ( 106 _ = math.MaxInt32 107 _ unsafe.Pointer 108 ) 109 110 type ( 111 char = byte 112 signal int 113 ) 114 115 func strcopy(dst []char, src string) { 116 for i := 0; i < len(dst) && i < len(src); i++ { 117 dst[i] = src[i] 118 } 119 } 120 121 func arraystr(a []char) string { 122 b := make([]byte, len(a)) 123 for i, c := range a { 124 b[i] = c 125 } 126 return string(b) 127 } 128 129 func abs(n int32) int32 { 130 if n >= 0 { 131 return n 132 } 133 134 return -n 135 } 136 137 func fabs(f float64) float64 { 138 if f >= 0 { 139 return f 140 } 141 142 return -f 143 } 144 145 func round(f float64) int32 { 146 if f >= 0 { 147 return int32(f + 0.5) 148 } 149 150 return int32(f - 0.5) 151 } 152 153 const ( 154 endOfTangle = 9999 /* go here to wrap it up */ 155 exit = 10 /* go here to leave a procedure */ 156 restart = 20 /* go here to start a procedure again */ 157 reswitch = 21 /* go here to start a case statement again */ 158 continue1 = 22 /* go here to resume a loop */ 159 done = 30 /* go here to exit a loop */ 160 found = 31 /* go here when you've found it */ 161 notFound = 32 /* go here when you've found something else */ 162 spotless = 0 /* |history| value for normal jobs */ 163 harmlessMessage = 1 /* |history| value when non-serious info was printed */ 164 errorMessage = 2 /* |history| value when an error was noted */ 165 fatalMessage = 3 /* |history| value when we had to stop prematurely */ 166 firstTextChar = 0 /* ordinal number of the smallest element of |text_char| */ 167 lastTextChar = 255 /* ordinal number of the largest element of |text_char| */ 168 andSign = 04 /* equivalent to `\.[and]' */ 169 notSign = 05 /* equivalent to `\.[not]' */ 170 setElementSign = 06 /* equivalent to `\.[in]' */ 171 tabMark = 011 /* ASCII code used as tab-skip */ 172 lineFeed = 012 /* ASCII code thrown away at end of line */ 173 formFeed = 014 /* ASCII code used at end of page */ 174 carriageReturn = 015 /* ASCII code used at end of line */ 175 leftArrow = 030 /* equivalent to `\.[:=]' */ 176 notEqual = 032 /* equivalent to `\.[<>]' */ 177 lessOrEqual = 034 /* equivalent to `\.[<=]' */ 178 greaterOrEqual = 035 /* equivalent to `\.[>=]' */ 179 equivalenceSign = 036 /* equivalent to `\.[==]' */ 180 orSign = 037 /* equivalent to `\.[or]' */ 181 ww = 2 /* we multiply the byte capacity by approximately this amount */ 182 zz = 3 /* we multiply the token capacity by approximately this amount */ 183 normal = 0 /* ordinary identifiers have |normal| ilk */ 184 numeric = 1 /* numeric macros and strings have |numeric| ilk */ 185 simple = 2 /* simple macros have |simple| ilk */ 186 parametric = 3 /* parametric macros have |parametric| ilk */ 187 less = 0 /* the first name is lexicographically less than the second */ 188 equal = 1 /* the first name is equal to the second */ 189 greater = 2 /* the first name is lexicographically greater than the second */ 190 prefix = 3 /* the first name is a proper prefix of the second */ 191 extension = 4 /* the first name is a proper extension of the second */ 192 param = 0 /* ASCII null code will not appear */ 193 verbatim = 02 /* extended ASCII alpha should not appear */ 194 forceLine = 03 /* extended ASCII beta should not appear */ 195 beginComment = 011 /* ASCII tab mark will not appear */ 196 endComment = 012 /* ASCII line feed will not appear */ 197 octal = 014 /* ASCII form feed will not appear */ 198 hex = 015 /* ASCII carriage return will not appear */ 199 doubleDot = 040 /* ASCII space will not appear except in strings */ 200 checkSum = 0175 /* will not be confused with right brace */ 201 join = 0177 /* ASCII delete will not appear */ 202 number = 0200 /* code returned by |get_output| when next output is numeric */ 203 moduleNumber = 0201 /* code returned by |get_output| for module numbers */ 204 identifier = 0202 /* code returned by |get_output| for identifiers */ 205 misc = 0 /* state associated with special characters */ 206 numOrId = 1 /* state associated with numbers and identifiers */ 207 sign = 2 /* state associated with pending \.+ or \.- */ 208 signVal = numOrId + 2 /* state associated with pending sign and value */ 209 signValSign = sign + 2 /* |sign_val| followed by another pending sign */ 210 signValVal = signVal + 2 /* |sign_val| followed by another pending value */ 211 unbreakable = signValVal + 1 /* state associated with \.[@\&] */ 212 str = 1 /* |send_out| code for a string */ 213 ident = 2 /* |send_out| code for an identifier */ 214 frac = 3 /* |send_out| code for a fraction */ 215 badCase = 666 /* this is a label used below */ 216 getFraction = 2 /* this label is used below */ 217 ignore = 0 /* control code of no interest to \.[TANGLE] */ 218 controlText = 0203 /* control code for `\.[@t]', `\.[@\^]', etc. */ 219 format = 0204 /* control code for `\.[@f]' */ 220 definition = 0205 /* control code for `\.[@d]' */ 221 beginPascal = 0206 /* control code for `\.[@p]' */ 222 moduleName = 0207 /* control code for `\.[@<]' */ 223 newModule = 0210 /* control code for `\.[@\ ]' and `\.[@*]' */ 224 breakpoint = 888 // place where a breakpoint is desirable 225 // \xref[system dependencies] 226 227 // Constants in the outer block 228 bufSize = 100 // maximum length of input line 229 maxBytes = 45000 // |1/ww| times the number of bytes in identifiers, 230 // strings, and module names; must be less than 65536 231 232 maxToks = 65000 // |1/zz| times the number of bytes in compressed \PASCAL\ code; 233 // must be less than 65536 234 235 maxNames = 4000 // number of identifiers, strings, module names; 236 // must be less than 10240 237 238 maxTexts = 2000 // number of replacement texts, must be less than 10240 239 hashSize = 353 // should be prime 240 longestName = 400 // module names shouldn't be longer than this 241 lineLength = 72 // lines of \PASCAL\ output have at most this many characters 242 outBufSize = 144 // length of output buffer, should be twice |line_length| 243 stackSize = 50 // number of simultaneous levels of macro expansion 244 maxIdLength = 32 // long identifiers are chopped to this length, which must 245 // not exceed |line_length| 246 247 unambigLength = 32 // identifiers must be unique if chopped to this length 248 ) 249 250 type ( 251 // Types in the outer block 252 asciiCode = /* 0..255 */ byte // eight-bit numbers, a subrange of the integers 253 254 textFile = knuth.File 255 256 eightBits = /* 0..255 */ byte // unsigned one-byte quantity 257 sixteenBits = /* 0..65535 */ uint16 // unsigned two-byte quantity 258 259 namePointer = /* 0..maxNames */ uint16 // identifies a name 260 261 textPointer = /* 0..maxTexts */ uint16 // identifies a replacement text 262 263 // \4 264 outputState = struct { 265 endField sixteenBits // ending location of replacement text 266 byteField sixteenBits // present location within replacement text 267 nameField namePointer // |byte_start| index for text being output 268 replField textPointer // |tok_start| index for text being output 269 modField uint16 // module number or zero if not a module 270 } 271 ) 272 273 type prg struct { 274 stdin, stdout, stderr knuth.File 275 /* Globals in the outer block */ history/* spotless..fatalMessage */ byte // how bad was this run? 276 277 xord [256]asciiCode 278 // specifies conversion of input characters 279 xchr [256]char 280 // specifies conversion of output characters 281 282 termOut textFile // the terminal as an output file 283 284 webFile textFile // primary input 285 changeFile textFile // updates 286 287 pascalFile textFile 288 pool textFile 289 290 buffer [101]asciiCode 291 292 phaseOne bool // |true| in Phase I, |false| in Phase II 293 294 byteMem [2][45001]asciiCode 295 // characters of names 296 tokMem [3][65001]eightBits // tokens 297 byteStart [4001]sixteenBits // directory into |byte_mem| 298 tokStart [2001]sixteenBits // directory into |tok_mem| 299 link [4001]sixteenBits // hash table or tree links 300 ilk [4001]sixteenBits // type codes or tree links 301 equiv [4001]sixteenBits // info corresponding to names 302 textLink [2001]sixteenBits // relates replacement texts 303 304 namePtr namePointer // first unused position in |byte_start| 305 stringPtr namePointer // next number to be given to a string of length |<>1| 306 bytePtr [2] /* 0..maxBytes */ uint16 307 // first unused position in |byte_mem| 308 poolCheckSum int32 // sort of a hash for the whole string pool 309 310 // \hskip1em 311 textPtr textPointer // first unused position in |tok_start| 312 // \hskip1em 313 tokPtr [3] /* 0..maxToks */ uint16 314 // first unused position in a given segment of |tok_mem| 315 // \hskip1em 316 z/* 0..zz-1 */ byte // current segment of |tok_mem| 317 // max_tok_ptr:array[0..zz-1] of 0..max_toks; 318 // [largest values assumed by |tok_ptr|] 319 // [ ] 320 321 idFirst/* 0..bufSize */ byte // where the current identifier begins in the buffer 322 idLoc/* 0..bufSize */ byte // just after the current identifier in the buffer 323 doubleChars/* 0..bufSize */ byte // correction to length in case of strings 324 325 hash, chopHash [354]sixteenBits // heads of hash lists 326 choppedId [33]asciiCode // chopped identifier 327 328 modText [401]asciiCode // name being sought for 329 330 lastUnnamed textPointer // most recent replacement text of unnamed module 331 332 curState outputState // |cur_end|, |cur_byte|, |cur_name|, 333 // |cur_repl|, |cur_mod| 334 335 stack [50]outputState // info for non-current levels 336 stackPtr/* 0..stackSize */ byte // first unused location in the output state stack 337 338 zo/* 0..zz-1 */ byte // the segment of |tok_mem| from which output is coming 339 340 braceLevel eightBits // current depth of $\.[@\[]\ldots\.[@\]]$ nesting 341 342 curVal int32 // additional information corresponding to output token 343 344 outBuf [145]asciiCode // assembled characters 345 outPtr/* 0..outBufSize */ byte // first available place in |out_buf| 346 breakPtr/* 0..outBufSize */ byte // last breaking place in |out_buf| 347 semiPtr/* 0..outBufSize */ byte // last semicolon breaking place in |out_buf| 348 349 outState eightBits // current status of partial output 350 outVal, outApp int32 // pending values 351 outSign asciiCode // sign to use if appending |out_val>=0| 352 lastSign/* -1.. +1 */ int8 // sign to use if appending a zero 353 354 outContrib [72]asciiCode // a contribution to |out_buf| 355 356 ii1 int32 // general purpose |for| loop variable in the outer block 357 line int32 // the number of the current line in the current file 358 otherLine int32 // the number of the current line in the input file that 359 // is not currently being read 360 361 tempLine int32 // used when interchanging |line| with |other_line| 362 limit/* 0..bufSize */ byte // the last character position occupied in the buffer 363 loc/* 0..bufSize */ byte // the next character position to be read from the buffer 364 inputHasEnded bool // if |true|, there is no more input 365 changing bool // if |true|, the current line is from |change_file| 366 367 changeBuffer [101]asciiCode 368 changeLimit/* 0..bufSize */ byte // the last position occupied in |change_buffer| 369 370 curModule namePointer // name of module just scanned 371 scanningHex bool // are we scanning a hexadecimal constant? 372 373 nextControl eightBits // control code waiting to be acted upon 374 375 curReplText textPointer // replacement text formed by |scan_repl| 376 377 moduleCount/* 0..027777 */ uint16 // the current module number 378 379 // trouble_shooting:boolean; [is |debug_help| wanted?] 380 // ddt:integer; [operation code for the |debug_help| routine] 381 // dd:integer; [operand in procedures performed by |debug_help|] 382 // debug_cycle:integer; [threshold for |debug_help| stopping] 383 // debug_skipped:integer; [we have skipped this many |debug_help| calls] 384 // term_in:text_file; [the user's terminal as an input file] 385 // [ ] 386 387 // wo:0..ww-1; [segment of memory for which statistics are being printed] 388 // [ ] 389 390 // Error handling procedures 391 // 392 // procedure debug_help; forward; [ ] 393 } 394 395 func (prg *prg) error1() { // prints '\..' and location of error message 396 var ( 397 j/* 0..outBufSize */ byte // index into |out_buf| 398 k, l/* 0..bufSize */ byte // indices into |buffer| 399 ) 400 if prg.phaseOne { 401 if prg.changing { 402 prg.stdout.Write(". (change file ") 403 } else { 404 prg.stdout.Write(". (") 405 } 406 prg.stdout.Writeln("l.", prg.line, knuth.WriteWidth(1), ")") 407 if int32(prg.loc) >= int32(prg.limit) { 408 l = prg.limit 409 } else { 410 l = prg.loc 411 } 412 for ii := int32(1); ii <= int32(l); ii++ { 413 k = byte(ii) 414 _ = k 415 if int32(prg.buffer[int32(k)-1]) == tabMark { 416 prg.stdout.Write(" ") 417 } else { 418 prg.stdout.Write(string(rune(prg.xchr[prg.buffer[int32(k)-1]]))) 419 } 420 } // print the characters already read 421 prg.stdout.Writeln() 422 for ii := int32(1); ii <= int32(l); ii++ { 423 k = byte(ii) 424 _ = k 425 prg.stdout.Write(" ") 426 } // space out the next line 427 for ii := int32(l) + 1; ii <= int32(prg.limit); ii++ { 428 k = byte(ii) 429 _ = k 430 prg.stdout.Write(string(rune(prg.xchr[prg.buffer[int32(k)-1]]))) 431 } // print the part not yet read 432 prg.stdout.Write(" ") // this space separates the message from future asterisks 433 } else { 434 // Print error location based on output buffer 435 prg.stdout.Writeln(". (l.", prg.line, knuth.WriteWidth(1), ")") 436 for ii := int32(1); ii <= int32(prg.outPtr); ii++ { 437 j = byte(ii) 438 _ = j 439 prg.stdout.Write(string(rune(prg.xchr[prg.outBuf[int32(j)-1]]))) 440 } // print current partial line 441 prg.stdout.Write("... ") // indicate that this information is partial 442 } 443 prg.history = byte(errorMessage) 444 // debug_skipped:=debug_cycle; debug_help; [ ] 445 } 446 447 func (prg *prg) jumpOut() { 448 panic(signal(endOfTangle)) 449 } 450 451 func (prg *prg) initialize() { 452 var ( 453 // Local variables for initialization 454 i/* 0..255 */ byte 455 456 wi/* 0..ww-1 */ byte // to initialize the |byte_mem| indices 457 458 zi/* 0..zz-1 */ byte // to initialize the |tok_mem| indices 459 460 h/* 0..hashSize */ uint16 // index into hash-head arrays 461 ) 462 prg.history = byte(spotless) 463 464 prg.xchr[040] = ' ' 465 prg.xchr[041] = '!' 466 prg.xchr[042] = '"' 467 prg.xchr[043] = '#' 468 prg.xchr[044] = '$' 469 prg.xchr[045] = '%' 470 prg.xchr[046] = '&' 471 prg.xchr[047] = '\'' 472 473 prg.xchr[050] = '(' 474 prg.xchr[051] = ')' 475 prg.xchr[052] = '*' 476 prg.xchr[053] = '+' 477 prg.xchr[054] = ',' 478 prg.xchr[055] = '-' 479 prg.xchr[056] = '.' 480 prg.xchr[057] = '/' 481 482 prg.xchr[060] = '0' 483 prg.xchr[061] = '1' 484 prg.xchr[062] = '2' 485 prg.xchr[063] = '3' 486 prg.xchr[064] = '4' 487 prg.xchr[065] = '5' 488 prg.xchr[066] = '6' 489 prg.xchr[067] = '7' 490 491 prg.xchr[070] = '8' 492 prg.xchr[071] = '9' 493 prg.xchr[072] = ':' 494 prg.xchr[073] = ';' 495 prg.xchr[074] = '<' 496 prg.xchr[075] = '=' 497 prg.xchr[076] = '>' 498 prg.xchr[077] = '?' 499 500 prg.xchr[0100] = '@' 501 prg.xchr[0101] = 'A' 502 prg.xchr[0102] = 'B' 503 prg.xchr[0103] = 'C' 504 prg.xchr[0104] = 'D' 505 prg.xchr[0105] = 'E' 506 prg.xchr[0106] = 'F' 507 prg.xchr[0107] = 'G' 508 509 prg.xchr[0110] = 'H' 510 prg.xchr[0111] = 'I' 511 prg.xchr[0112] = 'J' 512 prg.xchr[0113] = 'K' 513 prg.xchr[0114] = 'L' 514 prg.xchr[0115] = 'M' 515 prg.xchr[0116] = 'N' 516 prg.xchr[0117] = 'O' 517 518 prg.xchr[0120] = 'P' 519 prg.xchr[0121] = 'Q' 520 prg.xchr[0122] = 'R' 521 prg.xchr[0123] = 'S' 522 prg.xchr[0124] = 'T' 523 prg.xchr[0125] = 'U' 524 prg.xchr[0126] = 'V' 525 prg.xchr[0127] = 'W' 526 527 prg.xchr[0130] = 'X' 528 prg.xchr[0131] = 'Y' 529 prg.xchr[0132] = 'Z' 530 prg.xchr[0133] = '[' 531 prg.xchr[0134] = '\\' 532 prg.xchr[0135] = ']' 533 prg.xchr[0136] = '^' 534 prg.xchr[0137] = '_' 535 536 prg.xchr[0140] = '`' 537 prg.xchr[0141] = 'a' 538 prg.xchr[0142] = 'b' 539 prg.xchr[0143] = 'c' 540 prg.xchr[0144] = 'd' 541 prg.xchr[0145] = 'e' 542 prg.xchr[0146] = 'f' 543 prg.xchr[0147] = 'g' 544 545 prg.xchr[0150] = 'h' 546 prg.xchr[0151] = 'i' 547 prg.xchr[0152] = 'j' 548 prg.xchr[0153] = 'k' 549 prg.xchr[0154] = 'l' 550 prg.xchr[0155] = 'm' 551 prg.xchr[0156] = 'n' 552 prg.xchr[0157] = 'o' 553 554 prg.xchr[0160] = 'p' 555 prg.xchr[0161] = 'q' 556 prg.xchr[0162] = 'r' 557 prg.xchr[0163] = 's' 558 prg.xchr[0164] = 't' 559 prg.xchr[0165] = 'u' 560 prg.xchr[0166] = 'v' 561 prg.xchr[0167] = 'w' 562 563 prg.xchr[0170] = 'x' 564 prg.xchr[0171] = 'y' 565 prg.xchr[0172] = 'z' 566 prg.xchr[0173] = '{' 567 prg.xchr[0174] = '|' 568 prg.xchr[0175] = '}' 569 prg.xchr[0176] = '~' 570 571 prg.xchr[0] = ' ' 572 prg.xchr[0177] = ' ' // these ASCII codes are not used 573 574 for ii := int32(1); ii <= 037; ii++ { 575 i = byte(ii) 576 _ = i 577 prg.xchr[i] = ' ' 578 } 579 for ii := int32(0200); ii <= 0377; ii++ { 580 i = byte(ii) 581 _ = i 582 prg.xchr[i] = ' ' 583 } 584 585 for ii := int32(firstTextChar); ii <= lastTextChar; ii++ { 586 i = byte(ii) 587 _ = i 588 prg.xord[i] = ' ' 589 } 590 for ii := int32(1); ii <= 0377; ii++ { 591 i = byte(ii) 592 _ = i 593 prg.xord[prg.xchr[i]] = i 594 } 595 prg.xord[' '] = ' ' 596 597 prg.pascalFile.Rewrite() 598 prg.pool.Rewrite() 599 600 for ii := int32(0); ii <= ww-1; ii++ { 601 wi = byte(ii) 602 _ = wi 603 prg.byteStart[wi] = 0 604 prg.bytePtr[wi] = 0 605 } 606 prg.byteStart[ww] = 0 // this makes name 0 of length zero 607 prg.namePtr = 1 608 prg.stringPtr = 256 609 prg.poolCheckSum = 271828 610 611 for ii := int32(0); ii <= zz-1; ii++ { 612 zi = byte(ii) 613 _ = zi 614 prg.tokStart[zi] = 0 615 prg.tokPtr[zi] = 0 616 } 617 prg.tokStart[zz] = 0 // this makes replacement text 0 of length zero 618 prg.textPtr = 1 619 prg.z = byte(1 % zz) 620 621 prg.ilk[0] = 0 // the binary search tree starts out with nothing in it 622 prg.equiv[0] = 0 // the undefined module has no replacement text 623 624 for ii := int32(0); ii <= hashSize-1; ii++ { 625 h = uint16(ii) 626 _ = h 627 prg.hash[h] = 0 628 prg.chopHash[h] = 0 629 } 630 631 prg.lastUnnamed = 0 632 prg.textLink[0] = 0 633 634 prg.scanningHex = false 635 636 prg.modText[0] = ' ' 637 638 // trouble_shooting:=true; debug_cycle:=1; debug_skipped:=0; 639 // 640 // trouble_shooting:=false; debug_cycle:=99999; [use these when it almost works] 641 // reset(term_in,'TTY:','/I'); [open |term_in| as the terminal, don't do a |get|] 642 // [ ] 643 644 } 645 646 // 3. 647 648 // tangle:pos tangle.web:95:3: 649 650 // Some of this code is optional for use when debugging only; 651 // such material is enclosed between the delimiters |debug| and $|gubed|$. 652 // Other parts, delimited by |stat| and $|tats|$, are optionally included if 653 // statistics about \.[TANGLE]'s memory usage are desired. 654 655 // 5. 656 657 // tangle:pos tangle.web:124:3: 658 659 // Labels are given symbolic names by the following definitions. We insert 660 // the label `|exit|:' just before the `\ignorespaces|end|\unskip' of a 661 // procedure in which we have used the `|return|' statement defined below; 662 // the label `|restart|' is occasionally used at the very beginning of a 663 // procedure; and the label `|reswitch|' is occasionally used just prior to 664 // a \&[case] statement in which some cases change the conditions and we wish to 665 // branch to the newly applicable case. 666 // Loops that are set up with the \&[loop] construction defined below are 667 // commonly exited by going to `|done|' or to `|found|' or to `|not_found|', 668 // and they are sometimes repeated by going to `|continue|'. 669 670 // 6. 671 672 // tangle:pos tangle.web:143:3: 673 674 // Here are some macros for common programming idioms. 675 676 // 7. 677 678 // tangle:pos tangle.web:153:3: 679 680 // We assume that |case| statements may include a default case that applies 681 // if no matching label is found. Thus, we shall use constructions like 682 // \xref[system dependencies] 683 // $$\vbox[\halign[#\hfil\cr 684 // |case x of|\cr 685 // 1: $\langle\,$code for $x=1\,\rangle$;\cr 686 // 3: $\langle\,$code for $x=3\,\rangle$;\cr 687 // |othercases| $\langle\,$code for |x<>1| and |x<>3|$\,\rangle$\cr 688 // |endcases|\cr]]$$ 689 // since most \PASCAL\ compilers have plugged this hole in the language by 690 // incorporating some sort of default mechanism. For example, the compiler 691 // used to develop \.[WEB] and \TeX\ allows `|others|:' as a default label, 692 // and other \PASCAL s allow syntaxes like `\ignorespaces|else|\unskip' or 693 // `\&[otherwise]' or `\\[otherwise]:', etc. The definitions of |othercases| 694 // and |endcases| should be changed to agree with local conventions. (Of 695 // course, if no default mechanism is available, the |case| statements of 696 // this program must be extended by listing all remaining cases. The author 697 // would have taken the trouble to modify \.[TANGLE] so that such extensions 698 // were done automatically, if he had not wanted to encourage \PASCAL\ 699 // compiler writers to make this important change in \PASCAL, where it belongs.) 700 701 // 15. 702 703 // tangle:pos tangle.web:432:3: 704 705 // Some of the ASCII codes below @'40 have been given symbolic names in 706 // \.[WEAVE] and \.[TANGLE] because they are used with a special meaning. 707 708 // 19. Input and output 709 710 // tangle:pos tangle.web:494:21: 711 712 // The input conventions of this program are intended to be very much like those 713 // of \TeX\ (except, of course, that they are much simpler, because much less 714 // needs to be done). Furthermore they are identical to those of \.[WEAVE]. 715 // Therefore people who need to make modifications to all three systems 716 // should be able to do so without too many headaches. 717 // 718 // We use the standard \PASCAL\ input/output procedures in several places that 719 // \TeX\ cannot, since \.[TANGLE] does not have to deal with files that are named 720 // dynamically by the user, and since there is no input from the terminal. 721 722 // 22. 723 724 // tangle:pos tangle.ch:77:3: 725 726 // The |update_terminal| procedure is called when we want 727 // to make sure that everything we have output to the terminal so far has 728 // actually left the computer's internal buffers and been sent. 729 // \xref[system dependencies] 730 731 // 24. 732 733 // tangle:pos tangle.web:541:3: 734 735 // The following code opens the input files. Since these files were listed 736 // in the program header, we assume that the \PASCAL\ runtime system has 737 // already checked that suitable file names have been given; therefore no 738 // additional error checking needs to be done. 739 // \xref[system dependencies] 740 func (prg *prg) openInput() { 741 prg.webFile.Reset() 742 prg.changeFile.Reset() 743 } 744 745 // 28. 746 747 // tangle:pos tangle.web:571:3: 748 749 // The |input_ln| procedure brings the next line of input from the specified 750 // file into the |buffer| array and returns the value |true|, unless the file has 751 // already been entirely read, in which case it returns |false|. The conventions 752 // of \TeX\ are followed; i.e., |ASCII_code| numbers representing the next line 753 // of the file are input into |buffer[0]|, |buffer[1]|, \dots, 754 // |buffer[limit-1]|; trailing blanks are ignored; 755 // and the global variable |limit| is set to the length of the 756 // \xref[system dependencies] 757 // line. The value of |limit| must be strictly less than |buf_size|. 758 // 759 // We assume that none of the |ASCII_code| values 760 // of |buffer[j]| for |0<=j<limit| is equal to 0, @'177, |line_feed|, |form_feed|, 761 // or |carriage_return|. 762 func (prg *prg) inputLn(f textFile) (r bool) { 763 // inputs a line or returns |false| 764 var ( 765 finalLimit /* 0..bufSize */ byte // |limit| without trailing blanks 766 ) 767 prg.limit = 0 768 finalLimit = 0 769 if f.EOF() { 770 r = false 771 } else { 772 for !f.EOLN() { 773 prg.buffer[prg.limit] = prg.xord[*f.ByteP()] 774 f.Get() 775 prg.limit = byte(int32(prg.limit) + 1) 776 if int32(prg.buffer[int32(prg.limit)-1]) != ' ' { 777 finalLimit = prg.limit 778 } 779 if int32(prg.limit) == bufSize { 780 for !f.EOLN() { 781 f.Get() 782 } 783 prg.limit = byte(int32(prg.limit) - 1) // keep |buffer[buf_size]| empty 784 if int32(finalLimit) > int32(prg.limit) { 785 finalLimit = prg.limit 786 } 787 { 788 prg.stdout.Writeln() 789 prg.stdout.Write("! Input line too long") 790 } 791 prg.loc = 0 792 prg.error1() 793 // \xref[Input line too long] 794 } 795 } 796 f.Readln() 797 prg.limit = finalLimit 798 r = true 799 } 800 return r 801 } 802 803 // 35. 804 805 // tangle:pos tangle.web:699:3: 806 807 // Sometimes the program's behavior is far different from what it should be, 808 // and \.[TANGLE] prints an error message that is really for the \.[TANGLE] 809 // maintenance person, not the user. In such cases the program says 810 // |confusion('indication of where we are')|. 811 812 // 36. 813 814 // tangle:pos tangle.web:707:3: 815 816 // An overflow stop occurs if \.[TANGLE]'s tables aren't large enough. 817 818 // 47. 819 820 // tangle:pos tangle.web:851:3: 821 822 // Four types of identifiers are distinguished by their |ilk|: 823 // 824 // \yskip\hang |normal| identifiers will appear in the \PASCAL\ program as 825 // ordinary identifiers since they have not been defined to be macros; the 826 // corresponding value in the |equiv| array 827 // for such identifiers is a link in a secondary hash table that 828 // is used to check whether any two of them agree in their first |unambig_length| 829 // characters after underline symbols are removed and lowercase letters are 830 // changed to uppercase. 831 // 832 // \yskip\hang |numeric| identifiers have been defined to be numeric macros; 833 // their |equiv| value contains the corresponding numeric value plus $2^[15]$. 834 // Strings are treated as numeric macros. 835 // 836 // \yskip\hang |simple| identifiers have been defined to be simple macros; 837 // their |equiv| value points to the corresponding replacement text. 838 // 839 // \yskip\hang |parametric| identifiers have been defined to be parametric macros; 840 // like simple identifiers, their |equiv| value points to the replacement text. 841 842 // 49. 843 844 // tangle:pos tangle.web:893:3: 845 846 // Here is a little procedure that prints the text of a given name. 847 func (prg *prg) printId(p namePointer) { // print identifier or module name 848 var ( 849 k/* 0..maxBytes */ uint16 // index into |byte_mem| 850 w/* 0..ww-1 */ byte // segment of |byte_mem| 851 ) 852 if int32(p) >= int32(prg.namePtr) { 853 prg.stdout.Write("IMPOSSIBLE") 854 } else { 855 w = byte(int32(p) % ww) 856 for ii := int32(prg.byteStart[p]); ii <= int32(prg.byteStart[int32(p)+ww])-1; ii++ { 857 k = uint16(ii) 858 _ = k 859 prg.stdout.Write(string(rune(prg.xchr[prg.byteMem[w][k]]))) 860 } 861 } 862 } 863 864 // 53. 865 866 // tangle:pos tangle.web:957:3: 867 868 // Here now is the main procedure for finding identifiers (and strings). 869 // The parameter |t| is set to |normal| except when the identifier is 870 // a macro name that is just being defined; in the latter case, |t| will be 871 // |numeric|, |simple|, or |parametric|. 872 func (prg *prg) idLookup(t eightBits) (r namePointer) { 873 var ( 874 c eightBits // byte being chopped 875 i/* 0..bufSize */ byte // index into |buffer| 876 h/* 0..hashSize */ uint16 // hash code 877 k/* 0..maxBytes */ uint16 // index into |byte_mem| 878 w/* 0..ww-1 */ byte // segment of |byte_mem| 879 l/* 0..bufSize */ byte // length of the given identifier 880 p, q namePointer // where the identifier is being sought 881 s/* 0..unambigLength */ byte // index into |chopped_id| 882 ) 883 l = byte(int32(prg.idLoc) - int32(prg.idFirst)) // compute the length 884 885 // Compute the hash code |h| 886 h = uint16(prg.buffer[prg.idFirst]) 887 i = byte(int32(prg.idFirst) + 1) 888 for int32(i) < int32(prg.idLoc) { 889 h = uint16((int32(h) + int32(h) + int32(prg.buffer[i])) % hashSize) 890 i = byte(int32(i) + 1) 891 } 892 893 // Compute the name location |p| 894 p = prg.hash[h] 895 for int32(p) != 0 { 896 if int32(prg.byteStart[int32(p)+ww])-int32(prg.byteStart[p]) == int32(l) { 897 i = prg.idFirst 898 k = prg.byteStart[p] 899 w = byte(int32(p) % ww) 900 for int32(i) < int32(prg.idLoc) && int32(prg.buffer[i]) == int32(prg.byteMem[w][k]) { 901 i = byte(int32(i) + 1) 902 k = uint16(int32(k) + 1) 903 } 904 if int32(i) == int32(prg.idLoc) { 905 goto found 906 } // all characters agree 907 } 908 p = prg.link[p] 909 } 910 p = prg.namePtr // the current identifier is new 911 prg.link[p] = prg.hash[h] 912 prg.hash[h] = p // insert |p| at beginning of hash list 913 // insert |p| at beginning of hash list 914 found: 915 ; 916 if int32(p) == int32(prg.namePtr) || int32(t) != normal { 917 if int32(p) != int32(prg.namePtr) && int32(t) != normal && int32(prg.ilk[p]) == normal || int32(p) == int32(prg.namePtr) && int32(t) == normal && int32(prg.buffer[prg.idFirst]) != '"' { 918 i = prg.idFirst 919 s = 0 920 h = 0 921 for int32(i) < int32(prg.idLoc) && int32(s) < unambigLength { 922 if int32(prg.buffer[i]) != '_' { 923 if int32(prg.buffer[i]) >= 'a' { 924 prg.choppedId[s] = byte(int32(prg.buffer[i]) - 040) 925 } else { 926 prg.choppedId[s] = prg.buffer[i] 927 } 928 h = uint16((int32(h) + int32(h) + int32(prg.choppedId[s])) % hashSize) 929 s = byte(int32(s) + 1) 930 } 931 i = byte(int32(i) + 1) 932 } 933 prg.choppedId[s] = 0 934 } 935 if int32(p) != int32(prg.namePtr) { 936 if int32(prg.ilk[p]) == normal { 937 if int32(t) == numeric { 938 prg.stdout.Writeln() 939 prg.stdout.Write("! This identifier has already appeared") 940 prg.error1() 941 } 942 // \xref[This identifier has already...] 943 944 // Remove |p| from secondary hash table 945 q = prg.chopHash[h] 946 if int32(q) == int32(p) { 947 prg.chopHash[h] = prg.equiv[p] 948 } else { 949 for int32(prg.equiv[q]) != int32(p) { 950 q = prg.equiv[q] 951 } 952 prg.equiv[q] = prg.equiv[p] 953 } 954 } else { 955 prg.stdout.Writeln() 956 prg.stdout.Write("! This identifier was defined before") 957 prg.error1() 958 } 959 // \xref[This identifier was defined...] 960 prg.ilk[p] = uint16(t) 961 } else { 962 // Enter a new identifier into the table at position |p| 963 if int32(t) == normal && int32(prg.buffer[prg.idFirst]) != '"' { 964 q = prg.chopHash[h] 965 for int32(q) != 0 { 966 { 967 k = prg.byteStart[q] 968 s = 0 969 w = byte(int32(q) % ww) 970 for int32(k) < int32(prg.byteStart[int32(q)+ww]) && int32(s) < unambigLength { 971 c = prg.byteMem[w][k] 972 if int32(c) != '_' { 973 if int32(c) >= 'a' { 974 c = byte(int32(c) - 040) 975 } // merge lowercase with uppercase 976 if int32(prg.choppedId[s]) != int32(c) { 977 goto notFound 978 } 979 s = byte(int32(s) + 1) 980 } 981 k = uint16(int32(k) + 1) 982 } 983 if int32(k) == int32(prg.byteStart[int32(q)+ww]) && int32(prg.choppedId[s]) != 0 { 984 goto notFound 985 } 986 { 987 prg.stdout.Writeln() 988 prg.stdout.Write("! Identifier conflict with ") 989 } 990 // \xref[Identifier conflict...] 991 for ii := int32(prg.byteStart[q]); ii <= int32(prg.byteStart[int32(q)+ww])-1; ii++ { 992 k = uint16(ii) 993 _ = k 994 prg.stdout.Write(string(rune(prg.xchr[prg.byteMem[w][k]]))) 995 } 996 prg.error1() 997 q = 0 // only one conflict will be printed, since |equiv[0]=0| 998 // only one conflict will be printed, since |equiv[0]=0| 999 notFound: 1000 } 1001 q = prg.equiv[q] 1002 } 1003 prg.equiv[p] = prg.chopHash[h] 1004 prg.chopHash[h] = p // put |p| at front of secondary list 1005 } 1006 w = byte(int32(prg.namePtr) % ww) 1007 k = prg.bytePtr[w] 1008 if int32(k)+int32(l) > maxBytes { 1009 prg.stderr.Writeln("! Sorry, ", "byte memory", " capacity exceeded") 1010 prg.error1() 1011 prg.history = byte(fatalMessage) 1012 prg.jumpOut() 1013 } 1014 if int32(prg.namePtr) > maxNames-ww { 1015 prg.stderr.Writeln("! Sorry, ", "name", " capacity exceeded") 1016 prg.error1() 1017 prg.history = byte(fatalMessage) 1018 prg.jumpOut() 1019 } 1020 i = prg.idFirst // get ready to move the identifier into |byte_mem| 1021 for int32(i) < int32(prg.idLoc) { 1022 prg.byteMem[w][k] = prg.buffer[i] 1023 k = uint16(int32(k) + 1) 1024 i = byte(int32(i) + 1) 1025 } 1026 prg.bytePtr[w] = k 1027 prg.byteStart[int32(prg.namePtr)+ww] = k 1028 prg.namePtr = uint16(int32(prg.namePtr) + 1) 1029 if int32(prg.buffer[prg.idFirst]) != '"' { 1030 prg.ilk[p] = uint16(t) 1031 } else { 1032 // Define and output a new string of the pool 1033 prg.ilk[p] = uint16(numeric) // strings are like numeric macros 1034 if int32(l)-int32(prg.doubleChars) == 2 { 1035 prg.equiv[p] = uint16(int32(prg.buffer[int32(prg.idFirst)+1]) + 0100000) 1036 } else { 1037 prg.equiv[p] = uint16(int32(prg.stringPtr) + 0100000) 1038 l = byte(int32(l) - int32(prg.doubleChars) - 1) 1039 if int32(l) > 99 { 1040 prg.stdout.Writeln() 1041 prg.stdout.Write("! Preprocessed string is too long") 1042 prg.error1() 1043 } 1044 // \xref[Preprocessed string is too long] 1045 prg.stringPtr = uint16(int32(prg.stringPtr) + 1) 1046 prg.pool.Write(string(rune(prg.xchr['0'+int32(l)/10])), string(rune(prg.xchr['0'+int32(l)%10]))) // output the length 1047 prg.poolCheckSum = prg.poolCheckSum + prg.poolCheckSum + int32(l) 1048 for prg.poolCheckSum > 03777777667 { 1049 prg.poolCheckSum = prg.poolCheckSum - 03777777667 1050 } 1051 i = byte(int32(prg.idFirst) + 1) 1052 for int32(i) < int32(prg.idLoc) { 1053 prg.pool.Write(string(rune(prg.xchr[prg.buffer[i]]))) // output characters of string 1054 prg.poolCheckSum = prg.poolCheckSum + prg.poolCheckSum + int32(prg.buffer[i]) 1055 for prg.poolCheckSum > 03777777667 { 1056 prg.poolCheckSum = prg.poolCheckSum - 03777777667 1057 } 1058 if int32(prg.buffer[i]) == '"' || int32(prg.buffer[i]) == '@' { 1059 i = byte(int32(i) + 2) 1060 } else { 1061 i = byte(int32(i) + 1) 1062 } 1063 } 1064 prg.pool.Writeln() 1065 } 1066 } 1067 } 1068 } 1069 r = p 1070 return r 1071 } 1072 1073 // 66. 1074 1075 // tangle:pos tangle.web:1158:3: 1076 1077 // According to the rules of \.[WEB], no module name 1078 // should be a proper prefix of another, so a ``clean'' comparison should 1079 // occur between any two names. The result of |mod_lookup| is 0 if this 1080 // prefix condition is violated. An error message is printed when such violations 1081 // are detected during phase two of \.[WEAVE]. 1082 func (prg *prg) modLookup(l sixteenBits) (r namePointer) { 1083 var ( 1084 c/* less..extension */ byte // comparison between two names 1085 j/* 0..longestName */ uint16 // index into |mod_text| 1086 k/* 0..maxBytes */ uint16 // index into |byte_mem| 1087 w/* 0..ww-1 */ byte // segment of |byte_mem| 1088 p namePointer // current node of the search tree 1089 q namePointer // father of node |p| 1090 ) 1091 c = byte(greater) 1092 q = 0 1093 p = prg.ilk[0] // |rlink[0]| is the root of the tree 1094 for int32(p) != 0 { 1095 { 1096 k = prg.byteStart[p] 1097 w = byte(int32(p) % ww) 1098 c = byte(equal) 1099 j = 1 1100 for int32(k) < int32(prg.byteStart[int32(p)+ww]) && int32(j) <= int32(l) && int32(prg.modText[j]) == int32(prg.byteMem[w][k]) { 1101 k = uint16(int32(k) + 1) 1102 j = uint16(int32(j) + 1) 1103 } 1104 if int32(k) == int32(prg.byteStart[int32(p)+ww]) { 1105 if int32(j) > int32(l) { 1106 c = byte(equal) 1107 } else { 1108 c = byte(extension) 1109 } 1110 } else if int32(j) > int32(l) { 1111 c = byte(prefix) 1112 } else if int32(prg.modText[j]) < int32(prg.byteMem[w][k]) { 1113 c = byte(less) 1114 } else { 1115 c = byte(greater) 1116 } 1117 } 1118 q = p 1119 if int32(c) == less { 1120 p = prg.link[q] 1121 } else if int32(c) == greater { 1122 p = prg.ilk[q] 1123 } else { 1124 goto found 1125 } 1126 } 1127 1128 // Enter a new module name into the tree 1129 w = byte(int32(prg.namePtr) % ww) 1130 k = prg.bytePtr[w] 1131 if int32(k)+int32(l) > maxBytes { 1132 prg.stderr.Writeln("! Sorry, ", "byte memory", " capacity exceeded") 1133 prg.error1() 1134 prg.history = byte(fatalMessage) 1135 prg.jumpOut() 1136 } 1137 if int32(prg.namePtr) > maxNames-ww { 1138 prg.stderr.Writeln("! Sorry, ", "name", " capacity exceeded") 1139 prg.error1() 1140 prg.history = byte(fatalMessage) 1141 prg.jumpOut() 1142 } 1143 p = prg.namePtr 1144 if int32(c) == less { 1145 prg.link[q] = p 1146 } else { 1147 prg.ilk[q] = p 1148 } 1149 prg.link[p] = 0 1150 prg.ilk[p] = 0 1151 c = byte(equal) 1152 prg.equiv[p] = 0 1153 for ii := int32(1); ii <= int32(l); ii++ { 1154 j = uint16(ii) 1155 _ = j 1156 prg.byteMem[w][int32(k)+int32(j)-1] = prg.modText[j] 1157 } 1158 prg.bytePtr[w] = uint16(int32(k) + int32(l)) 1159 prg.byteStart[int32(prg.namePtr)+ww] = uint16(int32(k) + int32(l)) 1160 prg.namePtr = uint16(int32(prg.namePtr) + 1) 1161 1162 found: 1163 if int32(c) != equal { 1164 { 1165 prg.stdout.Writeln() 1166 prg.stdout.Write("! Incompatible section names") 1167 prg.error1() 1168 } 1169 p = 0 1170 // \xref[Incompatible module names] 1171 } 1172 r = p 1173 return r 1174 } 1175 1176 // 69. 1177 1178 // tangle:pos tangle.web:1218:3: 1179 1180 // The |prefix_lookup| procedure is supposed to find exactly one module 1181 // name that has |mod_text[1..l]| as a prefix. Actually the algorithm silently 1182 // accepts also the situation that some module name is a prefix of 1183 // |mod_text[1..l]|, because the user who painstakingly typed in more than 1184 // necessary probably doesn't want to be told about the wasted effort. 1185 func (prg *prg) prefixLookup(l sixteenBits) (r namePointer) { // finds name extension 1186 var ( 1187 c/* less..extension */ byte // comparison between two names 1188 count/* 0..maxNames */ uint16 // the number of hits 1189 j/* 0..longestName */ uint16 // index into |mod_text| 1190 k/* 0..maxBytes */ uint16 // index into |byte_mem| 1191 w/* 0..ww-1 */ byte // segment of |byte_mem| 1192 p namePointer // current node of the search tree 1193 q namePointer // another place to resume the search after one branch is done 1194 r1 namePointer // extension found 1195 ) 1196 q = 0 1197 p = prg.ilk[0] 1198 count = 0 1199 r1 = 0 // begin search at root of tree 1200 for int32(p) != 0 { 1201 { 1202 k = prg.byteStart[p] 1203 w = byte(int32(p) % ww) 1204 c = byte(equal) 1205 j = 1 1206 for int32(k) < int32(prg.byteStart[int32(p)+ww]) && int32(j) <= int32(l) && int32(prg.modText[j]) == int32(prg.byteMem[w][k]) { 1207 k = uint16(int32(k) + 1) 1208 j = uint16(int32(j) + 1) 1209 } 1210 if int32(k) == int32(prg.byteStart[int32(p)+ww]) { 1211 if int32(j) > int32(l) { 1212 c = byte(equal) 1213 } else { 1214 c = byte(extension) 1215 } 1216 } else if int32(j) > int32(l) { 1217 c = byte(prefix) 1218 } else if int32(prg.modText[j]) < int32(prg.byteMem[w][k]) { 1219 c = byte(less) 1220 } else { 1221 c = byte(greater) 1222 } 1223 } 1224 if int32(c) == less { 1225 p = prg.link[p] 1226 } else if int32(c) == greater { 1227 p = prg.ilk[p] 1228 } else { 1229 r1 = p 1230 count = uint16(int32(count) + 1) 1231 q = prg.ilk[p] 1232 p = prg.link[p] 1233 } 1234 if int32(p) == 0 { 1235 p = q 1236 q = 0 1237 } 1238 } 1239 if int32(count) != 1 { 1240 if int32(count) == 0 { 1241 prg.stdout.Writeln() 1242 prg.stdout.Write("! Name does not match") 1243 prg.error1() 1244 } else { 1245 prg.stdout.Writeln() 1246 prg.stdout.Write("! Ambiguous prefix") 1247 prg.error1() 1248 } 1249 } 1250 // \xref[Ambiguous prefix] 1251 r = r1 // the result will be 0 if there was no match 1252 return r 1253 } 1254 1255 // 72. 1256 1257 // tangle:pos tangle.web:1277:3: 1258 1259 // If the first byte of a token is less than @'200, the token occupies a 1260 // single byte. Otherwise we make a sixteen-bit token by combining two consecutive 1261 // bytes |a| and |b|. If |@'200<=a<@'250|, then $(a-@'200)\times2^8+b$ points 1262 // to an identifier; if |@'250<=a<@'320|, then 1263 // $(a-@'250)\times2^8+b$ points to a module name; otherwise, i.e., if 1264 // |@'320<=a<@'400|, then $(a-@'320)\times2^8+b$ is the number of the module 1265 // in which the current replacement text appears. 1266 // 1267 // Codes less than @'200 are 7-bit ASCII codes that represent themselves. 1268 // In particular, a single-character identifier like `|x|' will be a one-byte 1269 // token, while all longer identifiers will occupy two bytes. 1270 // 1271 // Some of the 7-bit ASCII codes will not be present, however, so we can 1272 // use them for special purposes. The following symbolic names are used: 1273 // 1274 // \yskip\hang |param| denotes insertion of a parameter. This occurs only in 1275 // the replacement texts of parametric macros, outside of single-quoted strings 1276 // in those texts. 1277 // 1278 // \hang |begin_comment| denotes \.[@\[], which will become either 1279 // \.[\[] or \.[[]. 1280 // 1281 // \hang |end_comment| denotes \.[@\]], which will become either 1282 // \.[\]] or \.[]]. 1283 // 1284 // \hang |octal| denotes the \.[@\'] that precedes an octal constant. 1285 // 1286 // \hang |hex| denotes the \.[@"] that precedes a hexadecimal constant. 1287 // 1288 // \hang |check_sum| denotes the \.[@\char'44] that denotes the string pool 1289 // check sum. 1290 // 1291 // \hang |join| denotes the concatenation of adjacent items with no 1292 // space or line breaks allowed between them (the \.[@\&] operation of \.[WEB]). 1293 // 1294 // \hang |double_dot| denotes `\.[..]' in \PASCAL. 1295 // 1296 // \hang |verbatim| denotes the \.[@=] that begins a verbatim \PASCAL\ string. 1297 // The \.[@>] at the end of such a string is also denoted by |verbatim|. 1298 // 1299 // \hang |force_line| denotes the \.[@\\] that forces a new line in the 1300 // \PASCAL\ output. 1301 // \xref[ASCII code] 1302 1303 // 73. 1304 1305 // tangle:pos tangle.web:1332:3: 1306 1307 // The following procedure is used to enter a two-byte value into 1308 // |tok_mem| when a replacement text is being generated. 1309 func (prg *prg) storeTwoBytes(x sixteenBits) { 1310 if int32(prg.tokPtr[prg.z])+2 > maxToks { 1311 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 1312 prg.error1() 1313 prg.history = byte(fatalMessage) 1314 prg.jumpOut() 1315 } 1316 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = byte(int32(x) / 0400) // this could be done by a shift command 1317 prg.tokMem[prg.z][int32(prg.tokPtr[prg.z])+1] = byte(int32(x) % 0400) // this could be done by a logical and 1318 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 2) 1319 } 1320 1321 // 74. 1322 1323 // tangle:pos tangle.web:1343:3: 1324 1325 // When \.[TANGLE] is being operated in debug mode, it has a procedure to display 1326 // a replacement text in symbolic form. This procedure has not been spruced up to 1327 // generate a real great format, but at least the results are not as bad as 1328 // a memory dump. 1329 // procedure print_repl( p:text_pointer); 1330 // var k:0..max_toks; [index into |tok_mem|] 1331 // a: sixteen_bits; [current byte(s)] 1332 // zp: 0..zz-1; [segment of |tok_mem| being accessed] 1333 // begin if p>=text_ptr then write('BAD') 1334 // else begin k:=tok_start[p]; zp:=p mod zz; 1335 // while k<tok_start[p+zz] do 1336 // begin a:=tok_mem[zp,k]; 1337 // if a>=[0200=]128 then 1338 // [ Display two-byte token starting with |a| ] 1339 // begin k:= k+1 ; 1340 // if a<[0250=]168 then [identifier or string] 1341 // begin a:=(a-[0200=]128)*[0400=]256+tok_mem[zp,k]; print_id(a); 1342 // if byte_mem[a mod ww,byte_start[a]]=[""""=]34 then write('"') 1343 // else write(' ') ; 1344 // end 1345 // else if a<[0320=]208 then [module name] 1346 // begin write('@<') ; print_id((a-[0250=]168)*[0400=]256+tok_mem[zp,k]); 1347 // write('@>') ; 1348 // end 1349 // else begin a:=(a-[0320=]208)*[0400=]256+tok_mem[zp,k]; [module number] 1350 // write('@', xchr[["["=] 123], a: 1,'@', xchr[["]"=] 125]) ; [can't use right brace 1351 // between \&[debug] and \&[gubed]] 1352 // end; 1353 // end 1354 // 1355 // else 1356 // [ Display one-byte token |a| ] 1357 // case a of 1358 // begin_comment: write('@', xchr[["["=] 123]) ; 1359 // end_comment: write('@', xchr[["]"=] 125]) ; [can't use right brace 1360 // between \&[debug] and \&[gubed]] 1361 // octal: write('@''') ; 1362 // hex: write('@"') ; 1363 // check_sum: write(' 271828 ') ; 1364 // param: write('#') ; 1365 // ["@"=]64: write('@@') ; 1366 // verbatim: write('@=') ; 1367 // force_line: write('@\') ; 1368 // else write( xchr[ a]) 1369 // end 1370 // 1371 // ; 1372 // k:= k+1 ; 1373 // end; 1374 // end; 1375 // end; 1376 // [ ] 1377 1378 // 77. Stacks for output 1379 1380 // tangle:pos tangle.web:1396:22: 1381 1382 // Let's make sure that our data structures contain enough information to 1383 // produce the entire \PASCAL\ program as desired, by working next on the 1384 // algorithms that actually do produce that program. 1385 1386 // 81. 1387 1388 // tangle:pos tangle.web:1453:3: 1389 1390 // Parameters must also be stacked. They are placed in 1391 // |tok_mem| just above the other replacement texts, and dummy parameter 1392 // `names' are placed in |byte_start| just after the other names. 1393 // The variables |text_ptr| and |tok_ptr[z]| essentially serve as parameter 1394 // stack pointers during the output phase, so there is no need for a separate 1395 // data structure to handle this problem. 1396 1397 // 84. 1398 1399 // tangle:pos tangle.web:1479:3: 1400 1401 // When the replacement text for name |p| is to be inserted into the output, 1402 // the following subroutine is called to save the old level of output and get 1403 // the new one going. 1404 func (prg *prg) pushLevel(p namePointer) { 1405 if int32(prg.stackPtr) == stackSize { 1406 prg.stderr.Writeln("! Sorry, ", "stack", " capacity exceeded") 1407 prg.error1() 1408 prg.history = byte(fatalMessage) 1409 prg.jumpOut() 1410 } else { 1411 prg.stack[prg.stackPtr-1] = prg.curState // save |cur_end|, |cur_byte|, etc. 1412 prg.stackPtr = byte(int32(prg.stackPtr) + 1) 1413 prg.curState.nameField = p 1414 prg.curState.replField = prg.equiv[p] 1415 prg.zo = byte(int32(prg.curState.replField) % zz) 1416 prg.curState.byteField = prg.tokStart[prg.curState.replField] 1417 prg.curState.endField = prg.tokStart[int32(prg.curState.replField)+zz] 1418 prg.curState.modField = 0 1419 } 1420 } 1421 1422 // 85. 1423 1424 // tangle:pos tangle.web:1493:3: 1425 1426 // When we come to the end of a replacement text, the |pop_level| subroutine 1427 // does the right thing: It either moves to the continuation of this replacement 1428 // text or returns the state to the most recently stacked level. Part of this 1429 // subroutine, which updates the parameter stack, will be given later when we 1430 // study the parameter stack in more detail. 1431 func (prg *prg) popLevel() { 1432 if int32(prg.textLink[prg.curState.replField]) == 0 { 1433 if int32(prg.ilk[prg.curState.nameField]) == parametric { 1434 prg.namePtr = uint16(int32(prg.namePtr) - 1) 1435 prg.textPtr = uint16(int32(prg.textPtr) - 1) 1436 prg.z = byte(int32(prg.textPtr) % zz) 1437 // if tok_ptr[z]>max_tok_ptr[z] then max_tok_ptr[z]:=tok_ptr[z]; 1438 // 1439 // [ ] 1440 // the maximum value of |tok_ptr| occurs just before parameter popping 1441 prg.tokPtr[prg.z] = prg.tokStart[prg.textPtr] 1442 // byte_ptr[ name_ptr mod ww]:= byte_ptr[ name_ptr mod ww]-1 ; [ ] 1443 } 1444 } else if int32(prg.textLink[prg.curState.replField]) < maxTexts { 1445 prg.curState.replField = prg.textLink[prg.curState.replField] // we will stay on the same level 1446 prg.zo = byte(int32(prg.curState.replField) % zz) 1447 prg.curState.byteField = prg.tokStart[prg.curState.replField] 1448 prg.curState.endField = prg.tokStart[int32(prg.curState.replField)+zz] 1449 1450 goto exit 1451 } 1452 prg.stackPtr = byte(int32(prg.stackPtr) - 1) // we will go down to the previous level 1453 if int32(prg.stackPtr) > 0 { 1454 prg.curState = prg.stack[prg.stackPtr-1] 1455 prg.zo = byte(int32(prg.curState.replField) % zz) 1456 } 1457 1458 exit: 1459 } 1460 1461 // 87. 1462 1463 // tangle:pos tangle.web:1536:3: 1464 1465 // If |get_output| finds that no more output remains, it returns the value zero. 1466 func (prg *prg) getOutput() (r sixteenBits) { 1467 var ( 1468 a sixteenBits // value of current byte 1469 b eightBits // byte being copied 1470 bal sixteenBits // excess of \.( versus \.) while copying a parameter 1471 k/* 0..maxBytes */ uint16 // index into |byte_mem| 1472 w/* 0..ww-1 */ byte // segment of |byte_mem| 1473 ) 1474 restart: 1475 if int32(prg.stackPtr) == 0 { 1476 a = 0 1477 goto found 1478 } 1479 if int32(prg.curState.byteField) == int32(prg.curState.endField) { 1480 prg.curVal = -int32(prg.curState.modField) 1481 prg.popLevel() 1482 if prg.curVal == 0 { 1483 goto restart 1484 } 1485 a = uint16(moduleNumber) 1486 goto found 1487 } 1488 a = uint16(prg.tokMem[prg.zo][prg.curState.byteField]) 1489 prg.curState.byteField = uint16(int32(prg.curState.byteField) + 1) 1490 if int32(a) < 0200 { 1491 if int32(a) == param { 1492 prg.pushLevel(namePointer(int32(prg.namePtr) - 1)) 1493 goto restart 1494 } else { 1495 goto found 1496 } 1497 } 1498 a = uint16((int32(a)-0200)*0400 + int32(prg.tokMem[prg.zo][prg.curState.byteField])) 1499 prg.curState.byteField = uint16(int32(prg.curState.byteField) + 1) 1500 if int32(a) < 024000 { 1501 switch prg.ilk[a] { 1502 case normal: 1503 prg.curVal = int32(a) 1504 a = uint16(identifier) 1505 1506 case numeric: 1507 prg.curVal = int32(prg.equiv[a]) - 0100000 1508 a = uint16(number) 1509 1510 case simple: 1511 prg.pushLevel(a) 1512 goto restart 1513 1514 case parametric: 1515 for int32(prg.curState.byteField) == int32(prg.curState.endField) && int32(prg.stackPtr) > 0 { 1516 prg.popLevel() 1517 } 1518 if int32(prg.stackPtr) == 0 || int32(prg.tokMem[prg.zo][prg.curState.byteField]) != '(' { 1519 { 1520 prg.stdout.Writeln() 1521 prg.stdout.Write("! No parameter given for ") 1522 } 1523 prg.printId(a) 1524 prg.error1() 1525 // \xref[No parameter given for macro] 1526 1527 // \xref[No parameter given for macro] 1528 goto restart 1529 } 1530 1531 // Copy the parameter into |tok_mem| 1532 bal = 1 1533 prg.curState.byteField = uint16(int32(prg.curState.byteField) + 1) // skip the opening `\.(' 1534 for true { 1535 b = prg.tokMem[prg.zo][prg.curState.byteField] 1536 prg.curState.byteField = uint16(int32(prg.curState.byteField) + 1) 1537 if int32(b) == param { 1538 prg.storeTwoBytes(sixteenBits(int32(prg.namePtr) + 077777)) 1539 } else { 1540 if int32(b) >= 0200 { 1541 { 1542 if int32(prg.tokPtr[prg.z]) == maxToks { 1543 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 1544 prg.error1() 1545 prg.history = byte(fatalMessage) 1546 prg.jumpOut() 1547 } 1548 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = b 1549 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 1550 } 1551 b = prg.tokMem[prg.zo][prg.curState.byteField] 1552 prg.curState.byteField = uint16(int32(prg.curState.byteField) + 1) 1553 } else { 1554 switch b { 1555 case '(': 1556 bal = uint16(int32(bal) + 1) 1557 // ")"= 1558 case ')': 1559 bal = uint16(int32(bal) - 1) 1560 if int32(bal) == 0 { 1561 goto done 1562 } 1563 1564 // "'"= 1565 case '\'': 1566 for { 1567 { 1568 if int32(prg.tokPtr[prg.z]) == maxToks { 1569 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 1570 prg.error1() 1571 prg.history = byte(fatalMessage) 1572 prg.jumpOut() 1573 } 1574 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = b 1575 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 1576 } 1577 b = prg.tokMem[prg.zo][prg.curState.byteField] 1578 prg.curState.byteField = uint16(int32(prg.curState.byteField) + 1) 1579 if int32(b) == '\'' { 1580 break 1581 } 1582 } 1583 // copy string, don't change |bal| 1584 default: 1585 } 1586 } 1587 { 1588 if int32(prg.tokPtr[prg.z]) == maxToks { 1589 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 1590 prg.error1() 1591 prg.history = byte(fatalMessage) 1592 prg.jumpOut() 1593 } 1594 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = b 1595 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 1596 } 1597 } 1598 } 1599 1600 done: 1601 ; 1602 prg.equiv[prg.namePtr] = prg.textPtr 1603 prg.ilk[prg.namePtr] = uint16(simple) 1604 w = byte(int32(prg.namePtr) % ww) 1605 k = prg.bytePtr[w] 1606 // if k=max_bytes then begin writeln( stderr,'! Sorry, ','byte memory',' capacity exceeded') ; error; history:=fatal_message ; jump_out; end [ \xref[Sorry, x capacity exceeded] ] ; 1607 // 1608 // byte_mem[w,k]:=["#"=]35; k:= k+1 ; byte_ptr[w]:=k; 1609 // [ ] 1610 // this code has set the parameter identifier for debugging printouts 1611 if int32(prg.namePtr) > maxNames-ww { 1612 prg.stderr.Writeln("! Sorry, ", "name", " capacity exceeded") 1613 prg.error1() 1614 prg.history = byte(fatalMessage) 1615 prg.jumpOut() 1616 } 1617 prg.byteStart[int32(prg.namePtr)+ww] = k 1618 prg.namePtr = uint16(int32(prg.namePtr) + 1) 1619 if int32(prg.textPtr) > maxTexts-zz { 1620 prg.stderr.Writeln("! Sorry, ", "text", " capacity exceeded") 1621 prg.error1() 1622 prg.history = byte(fatalMessage) 1623 prg.jumpOut() 1624 } 1625 prg.textLink[prg.textPtr] = 0 1626 prg.tokStart[int32(prg.textPtr)+zz] = prg.tokPtr[prg.z] 1627 prg.textPtr = uint16(int32(prg.textPtr) + 1) 1628 prg.z = byte(int32(prg.textPtr) % zz) 1629 prg.pushLevel(a) 1630 goto restart 1631 1632 default: 1633 prg.stderr.Writeln("! This can't happen (", "output", ")") 1634 prg.error1() 1635 prg.history = byte(fatalMessage) 1636 prg.jumpOut() // \xref[This can't happen] 1637 } 1638 1639 goto found 1640 } 1641 if int32(a) < 050000 { 1642 a = uint16(int32(a) - 024000) 1643 if int32(prg.equiv[a]) != 0 { 1644 prg.pushLevel(a) 1645 } else if int32(a) != 0 { 1646 { 1647 prg.stdout.Writeln() 1648 prg.stdout.Write("! Not present: <") 1649 } 1650 prg.printId(a) 1651 prg.stdout.Write(">") 1652 prg.error1() 1653 // \xref[Not present: <section name>] 1654 } 1655 1656 goto restart 1657 } 1658 prg.curVal = int32(a) - 050000 1659 a = uint16(moduleNumber) 1660 prg.curState.modField = uint16(prg.curVal) 1661 1662 found: 1663 r = a 1664 return r 1665 } 1666 1667 // 97. 1668 1669 // tangle:pos tangle.web:1800:3: 1670 1671 // Here is a routine that is invoked when |out_ptr>line_length| 1672 // or when it is time to flush out the final line. The |flush_buffer| procedure 1673 // often writes out the line up to the current |break_ptr| position, then moves the 1674 // remaining information to the front of |out_buf|. However, it prefers to 1675 // write only up to |semi_ptr|, if the residual line won't be too long. 1676 func (prg *prg) flushBuffer() { // writes one line to output file 1677 var ( 1678 k/* 0..outBufSize */ byte // index into |out_buf| 1679 b/* 0..outBufSize */ byte // value of |break_ptr| upon entry 1680 ) 1681 b = prg.breakPtr 1682 if int32(prg.semiPtr) != 0 && int32(prg.outPtr)-int32(prg.semiPtr) <= lineLength { 1683 prg.breakPtr = prg.semiPtr 1684 } 1685 for ii := int32(1); ii <= int32(prg.breakPtr); ii++ { 1686 k = byte(ii) 1687 _ = k 1688 prg.pascalFile.Write(string(rune(prg.xchr[prg.outBuf[int32(k)-1]]))) 1689 } 1690 prg.pascalFile.Writeln() 1691 prg.line = prg.line + 1 1692 if prg.line%100 == 0 { 1693 prg.stdout.Write(".") 1694 if prg.line%500 == 0 { 1695 prg.stdout.Write(prg.line, knuth.WriteWidth(1)) 1696 } 1697 // progress report 1698 } 1699 if int32(prg.breakPtr) < int32(prg.outPtr) { 1700 if int32(prg.outBuf[prg.breakPtr]) == ' ' { 1701 prg.breakPtr = byte(int32(prg.breakPtr) + 1) // drop space at break 1702 if int32(prg.breakPtr) > int32(b) { 1703 b = prg.breakPtr 1704 } 1705 } 1706 for ii := int32(prg.breakPtr); ii <= int32(prg.outPtr)-1; ii++ { 1707 k = byte(ii) 1708 _ = k 1709 prg.outBuf[int32(k)-int32(prg.breakPtr)] = prg.outBuf[k] 1710 } 1711 } 1712 prg.outPtr = byte(int32(prg.outPtr) - int32(prg.breakPtr)) 1713 prg.breakPtr = byte(int32(b) - int32(prg.breakPtr)) 1714 prg.semiPtr = 0 1715 if int32(prg.outPtr) > lineLength { 1716 { 1717 prg.stdout.Writeln() 1718 prg.stdout.Write("! Long line must be truncated") 1719 prg.error1() 1720 } 1721 prg.outPtr = byte(lineLength) 1722 // \xref[Long line must be truncated] 1723 } 1724 } 1725 1726 // 99. 1727 1728 // tangle:pos tangle.web:1840:3: 1729 1730 // Another simple and useful routine appends the decimal equivalent of 1731 // a nonnegative integer to the output buffer. 1732 func (prg *prg) appVal(v int32) { // puts |v| into buffer, assumes |v>=0| 1733 var ( 1734 k /* 0..outBufSize */ byte // index into |out_buf| 1735 ) 1736 k = byte(outBufSize) // first we put the digits at the very end of |out_buf| 1737 for { 1738 prg.outBuf[k] = byte(v % 10) 1739 v = v / 10 1740 k = byte(int32(k) - 1) 1741 if v == 0 { 1742 break 1743 } 1744 } 1745 for { 1746 k = byte(int32(k) + 1) 1747 { 1748 prg.outBuf[prg.outPtr] = byte(int32(prg.outBuf[k]) + '0') 1749 prg.outPtr = byte(int32(prg.outPtr) + 1) 1750 } 1751 if int32(k) == outBufSize { 1752 break 1753 } 1754 } // then we append them, most significant first 1755 } 1756 1757 // 101. 1758 1759 // tangle:pos tangle.web:1878:3: 1760 1761 // A slightly subtle point in the following code is that the user may ask 1762 // for a |join| operation (i.e., \.[@\&]) following whatever is being sent 1763 // out. We will see later that |join| is implemented in part by calling 1764 // |send_out(frac,0)|. 1765 func (prg *prg) sendOut(t eightBits, v sixteenBits) { 1766 var ( 1767 k /* 0..lineLength */ byte // index into |out_contrib| 1768 ) 1769 // Get the buffer ready for appending the new information 1770 restart: 1771 switch prg.outState { 1772 case numOrId: 1773 if int32(t) != frac { 1774 prg.breakPtr = prg.outPtr 1775 if int32(t) == ident { 1776 prg.outBuf[prg.outPtr] = ' ' 1777 prg.outPtr = byte(int32(prg.outPtr) + 1) 1778 } 1779 } 1780 case sign: 1781 { 1782 prg.outBuf[prg.outPtr] = byte(',' - prg.outApp) 1783 prg.outPtr = byte(int32(prg.outPtr) + 1) 1784 } 1785 if int32(prg.outPtr) > lineLength { 1786 prg.flushBuffer() 1787 } 1788 prg.breakPtr = prg.outPtr 1789 1790 case signVal, signValSign: 1791 if prg.outVal < 0 || prg.outVal == 0 && int32(prg.lastSign) < 0 { 1792 prg.outBuf[prg.outPtr] = '-' 1793 prg.outPtr = byte(int32(prg.outPtr) + 1) 1794 } else if int32(prg.outSign) > 0 { 1795 prg.outBuf[prg.outPtr] = prg.outSign 1796 prg.outPtr = byte(int32(prg.outPtr) + 1) 1797 } 1798 prg.appVal(abs(prg.outVal)) 1799 if int32(prg.outPtr) > lineLength { 1800 prg.flushBuffer() 1801 } 1802 1803 prg.outState = byte(int32(prg.outState) - 2) 1804 goto restart 1805 1806 case signValVal: 1807 // Reduce |sign_val_val| to |sign_val| and |goto restart| 1808 if int32(t) == frac || (int32(t) == ident && int32(v) == 3 && (int32(prg.outContrib[1-1]) == 'D' && int32(prg.outContrib[2-1]) == 'I' && int32(prg.outContrib[3-1]) == 'V' || int32(prg.outContrib[1-1]) == 'M' && int32(prg.outContrib[2-1]) == 'O' && int32(prg.outContrib[3-1]) == 'D') || int32(t) == misc && (int32(v) == '*' || int32(v) == '/')) { 1809 if prg.outVal < 0 || prg.outVal == 0 && int32(prg.lastSign) < 0 { 1810 prg.outBuf[prg.outPtr] = '-' 1811 prg.outPtr = byte(int32(prg.outPtr) + 1) 1812 } else if int32(prg.outSign) > 0 { 1813 prg.outBuf[prg.outPtr] = prg.outSign 1814 prg.outPtr = byte(int32(prg.outPtr) + 1) 1815 } 1816 prg.appVal(abs(prg.outVal)) 1817 if int32(prg.outPtr) > lineLength { 1818 prg.flushBuffer() 1819 } 1820 1821 prg.outSign = '+' 1822 prg.outVal = prg.outApp 1823 } else { 1824 prg.outVal = prg.outVal + prg.outApp 1825 } 1826 prg.outState = byte(signVal) 1827 goto restart 1828 1829 case misc: 1830 if int32(t) != frac { 1831 prg.breakPtr = prg.outPtr 1832 } 1833 1834 default: // this is for |unbreakable| state 1835 } 1836 if int32(t) != misc { 1837 for ii := int32(1); ii <= int32(v); ii++ { 1838 k = byte(ii) 1839 _ = k 1840 prg.outBuf[prg.outPtr] = prg.outContrib[k-1] 1841 prg.outPtr = byte(int32(prg.outPtr) + 1) 1842 } 1843 } else { 1844 prg.outBuf[prg.outPtr] = byte(v) 1845 prg.outPtr = byte(int32(prg.outPtr) + 1) 1846 } 1847 if int32(prg.outPtr) > lineLength { 1848 prg.flushBuffer() 1849 } 1850 if int32(t) == misc && (int32(v) == ';' || int32(v) == '}') { 1851 prg.semiPtr = prg.outPtr 1852 prg.breakPtr = prg.outPtr 1853 } 1854 if int32(t) >= ident { 1855 prg.outState = byte(numOrId) 1856 } else { 1857 prg.outState = byte(misc) 1858 } 1859 } 1860 1861 // 106. 1862 1863 // tangle:pos tangle.web:1942:3: 1864 1865 // The following routine is called with $v=\pm1$ when a plus or minus sign is 1866 // appended to the output. It extends \PASCAL\ to allow repeated signs 1867 // (e.g., `\.[--]' is equivalent to `\.+'), rather than to give an error message. 1868 // The signs following `\.E' in real constants are treated as part of a fraction, 1869 // so they are not seen by this routine. 1870 func (prg *prg) sendSign(v int32) { 1871 switch prg.outState { 1872 case sign, signValSign: 1873 prg.outApp = prg.outApp * v 1874 case signVal: 1875 prg.outApp = v 1876 prg.outState = byte(signValSign) 1877 1878 case signValVal: 1879 prg.outVal = prg.outVal + prg.outApp 1880 prg.outApp = v 1881 prg.outState = byte(signValSign) 1882 1883 default: 1884 prg.breakPtr = prg.outPtr 1885 prg.outApp = v 1886 prg.outState = byte(sign) 1887 1888 } 1889 1890 prg.lastSign = int8(prg.outApp) 1891 } 1892 1893 // 107. 1894 1895 // tangle:pos tangle.web:1962:3: 1896 1897 // When a (signed) integer value is to be output, we call |send_val|. 1898 func (prg *prg) sendVal(v int32) { 1899 switch prg.outState { 1900 case numOrId: 1901 if int32(prg.outPtr) == int32(prg.breakPtr)+3 || int32(prg.outPtr) == int32(prg.breakPtr)+4 && int32(prg.outBuf[prg.breakPtr]) == ' ' { 1902 if int32(prg.outBuf[int32(prg.outPtr)-3]) == 'D' && int32(prg.outBuf[int32(prg.outPtr)-2]) == 'I' && int32(prg.outBuf[int32(prg.outPtr)-1]) == 'V' || int32(prg.outBuf[int32(prg.outPtr)-3]) == 'M' && int32(prg.outBuf[int32(prg.outPtr)-2]) == 'O' && int32(prg.outBuf[int32(prg.outPtr)-1]) == 'D' { 1903 goto badCase 1904 } 1905 } 1906 prg.outSign = ' ' 1907 prg.outState = byte(signVal) 1908 prg.outVal = v 1909 prg.breakPtr = prg.outPtr 1910 prg.lastSign = int8(+1) 1911 1912 case misc: 1913 if int32(prg.outPtr) == int32(prg.breakPtr)+1 && (int32(prg.outBuf[prg.breakPtr]) == '*' || int32(prg.outBuf[prg.breakPtr]) == '/') { 1914 goto badCase 1915 } 1916 prg.outSign = 0 1917 prg.outState = byte(signVal) 1918 prg.outVal = v 1919 prg.breakPtr = prg.outPtr 1920 prg.lastSign = int8(+1) 1921 1922 // \4 1923 // Handle cases of |send_val| when |out_state| contains a sign 1924 case sign: 1925 prg.outSign = '+' 1926 prg.outState = byte(signVal) 1927 prg.outVal = prg.outApp * v 1928 1929 case signVal: 1930 prg.outState = byte(signValVal) 1931 prg.outApp = v 1932 { 1933 prg.stdout.Writeln() 1934 prg.stdout.Write("! Two numbers occurred without a sign between them") 1935 prg.error1() 1936 } 1937 1938 case signValSign: 1939 prg.outState = byte(signValVal) 1940 prg.outApp = prg.outApp * v 1941 1942 case signValVal: 1943 prg.outVal = prg.outVal + prg.outApp 1944 prg.outApp = v 1945 { 1946 prg.stdout.Writeln() 1947 prg.stdout.Write("! Two numbers occurred without a sign between them") 1948 prg.error1() 1949 } 1950 // \xref[Two numbers occurred...] 1951 1952 default: 1953 goto badCase 1954 } 1955 1956 goto exit 1957 1958 badCase: 1959 if v >= 0 { 1960 if int32(prg.outState) == numOrId { 1961 prg.breakPtr = prg.outPtr 1962 { 1963 prg.outBuf[prg.outPtr] = ' ' 1964 prg.outPtr = byte(int32(prg.outPtr) + 1) 1965 } 1966 } 1967 prg.appVal(v) 1968 if int32(prg.outPtr) > lineLength { 1969 prg.flushBuffer() 1970 } 1971 prg.outState = byte(numOrId) 1972 } else { 1973 { 1974 prg.outBuf[prg.outPtr] = '(' 1975 prg.outPtr = byte(int32(prg.outPtr) + 1) 1976 } 1977 { 1978 prg.outBuf[prg.outPtr] = '-' 1979 prg.outPtr = byte(int32(prg.outPtr) + 1) 1980 } 1981 prg.appVal(-v) 1982 { 1983 prg.outBuf[prg.outPtr] = ')' 1984 prg.outPtr = byte(int32(prg.outPtr) + 1) 1985 } 1986 if int32(prg.outPtr) > lineLength { 1987 prg.flushBuffer() 1988 } 1989 prg.outState = byte(misc) 1990 } 1991 1992 exit: 1993 } 1994 1995 // 113. 1996 1997 // tangle:pos tangle.web:2040:3: 1998 1999 // A many-way switch is used to send the output: 2000 func (prg *prg) sendTheOutput() { 2001 var ( 2002 curChar eightBits // the latest character received 2003 k/* 0..lineLength */ byte // index into |out_contrib| 2004 j/* 0..maxBytes */ uint16 // index into |byte_mem| 2005 w/* 0..ww-1 */ byte // segment of |byte_mem| 2006 n int32 // number being scanned 2007 ) 2008 for int32(prg.stackPtr) > 0 { 2009 curChar = byte(prg.getOutput()) 2010 2011 reswitch: 2012 switch curChar { 2013 case 0: // this case might arise if output ends unexpectedly 2014 // \4 2015 // Cases related to identifiers 2016 // "A"= 2017 case 'A', 'Z' - 24, 'Z' - 23, 'Z' - 22, 2018 'Z' - 21, 'Z' - 20, 'Z' - 19, 'Z' - 18, 2019 'Z' - 17, 'Z' - 16, 'Z' - 15, 'Z' - 14, 2020 'Z' - 13, 'Z' - 12, 'Z' - 11, 'Z' - 10, 2021 'Z' - 9, 'Z' - 8, 'Z' - 7, 'Z' - 6, 2022 'Z' - 5, 'Z' - 4, 'Z' - 3, 'Z' - 2, 2023 'Z' - 1, 'Z': 2024 prg.outContrib[1-1] = curChar 2025 prg.sendOut(eightBits(ident), sixteenBits(1)) 2026 2027 // "a"= 2028 case 'a', 'z' - 24, 'z' - 23, 'z' - 22, 2029 'z' - 21, 'z' - 20, 'z' - 19, 'z' - 18, 2030 'z' - 17, 'z' - 16, 'z' - 15, 'z' - 14, 2031 'z' - 13, 'z' - 12, 'z' - 11, 'z' - 10, 2032 'z' - 9, 'z' - 8, 'z' - 7, 'z' - 6, 2033 'z' - 5, 'z' - 4, 'z' - 3, 'z' - 2, 2034 'z' - 1, 'z': 2035 prg.outContrib[1-1] = byte(int32(curChar) - 040) 2036 prg.sendOut(eightBits(ident), sixteenBits(1)) 2037 2038 case identifier: 2039 k = 0 2040 j = prg.byteStart[prg.curVal] 2041 w = byte(prg.curVal % ww) 2042 for int32(k) < maxIdLength && int32(j) < int32(prg.byteStart[prg.curVal+ww]) { 2043 k = byte(int32(k) + 1) 2044 prg.outContrib[k-1] = prg.byteMem[w][j] 2045 j = uint16(int32(j) + 1) 2046 if int32(prg.outContrib[k-1]) >= 'a' { 2047 prg.outContrib[k-1] = byte(int32(prg.outContrib[k-1]) - 040) 2048 } else if int32(prg.outContrib[k-1]) == '_' { 2049 k = byte(int32(k) - 1) 2050 } 2051 } 2052 prg.sendOut(eightBits(ident), sixteenBits(k)) 2053 2054 // \4 2055 // Cases related to constants, possibly leading to |get_fraction| or |reswitch| 2056 // "0"= 2057 case '0', '1', '2', '3', 2058 '4', '5', '6', '7', 2059 '8', '9': 2060 n = 0 2061 for { 2062 curChar = byte(int32(curChar) - '0') 2063 if n >= 01463146314 { 2064 prg.stdout.Writeln() 2065 prg.stdout.Write("! Constant too big") 2066 prg.error1() 2067 } else { 2068 n = 10*n + int32(curChar) 2069 } 2070 curChar = byte(prg.getOutput()) 2071 if int32(curChar) > '9' || int32(curChar) < '0' { 2072 break 2073 } 2074 } 2075 prg.sendVal(n) 2076 k = 0 2077 if int32(curChar) == 'e' { 2078 curChar = 'E' 2079 } 2080 // \xref[uppercase] 2081 if int32(curChar) == 'E' { 2082 goto getFraction 2083 } else { 2084 goto reswitch 2085 } 2086 2087 case checkSum: 2088 prg.sendVal(prg.poolCheckSum) 2089 case octal: 2090 n = 0 2091 curChar = '0' 2092 for { 2093 curChar = byte(int32(curChar) - '0') 2094 if n >= 02000000000 { 2095 prg.stdout.Writeln() 2096 prg.stdout.Write("! Constant too big") 2097 prg.error1() 2098 } else { 2099 n = 8*n + int32(curChar) 2100 } 2101 curChar = byte(prg.getOutput()) 2102 if int32(curChar) > '7' || int32(curChar) < '0' { 2103 break 2104 } 2105 } 2106 prg.sendVal(n) 2107 goto reswitch 2108 2109 case hex: 2110 n = 0 2111 curChar = '0' 2112 for { 2113 if int32(curChar) >= 'A' { 2114 curChar = byte(int32(curChar) + 10 - 'A') 2115 } else { 2116 curChar = byte(int32(curChar) - '0') 2117 } 2118 if n >= 01000000000 { 2119 prg.stdout.Writeln() 2120 prg.stdout.Write("! Constant too big") 2121 prg.error1() 2122 } else { 2123 n = 16*n + int32(curChar) 2124 } 2125 curChar = byte(prg.getOutput()) 2126 if int32(curChar) > 'F' || int32(curChar) < '0' || int32(curChar) > '9' && int32(curChar) < 'A' { 2127 break 2128 } 2129 } 2130 prg.sendVal(n) 2131 goto reswitch 2132 2133 case number: 2134 prg.sendVal(prg.curVal) 2135 // "."= 2136 case '.': 2137 k = 1 2138 prg.outContrib[1-1] = '.' 2139 curChar = byte(prg.getOutput()) 2140 if int32(curChar) == '.' { 2141 prg.outContrib[2-1] = '.' 2142 prg.sendOut(eightBits(str), sixteenBits(2)) 2143 } else if int32(curChar) >= '0' && int32(curChar) <= '9' { 2144 goto getFraction 2145 } else { 2146 prg.sendOut(eightBits(misc), sixteenBits('.')) 2147 goto reswitch 2148 } 2149 2150 // "+"= 2151 case '+', '-': 2152 prg.sendSign(',' - int32(curChar)) 2153 // \4 2154 // Cases like \.[<>] and \.[:=] 2155 case andSign: 2156 prg.outContrib[1-1] = 'A' 2157 prg.outContrib[2-1] = 'N' 2158 prg.outContrib[3-1] = 'D' 2159 // \xref[uppercase] 2160 prg.sendOut(eightBits(ident), sixteenBits(3)) 2161 2162 case notSign: 2163 prg.outContrib[1-1] = 'N' 2164 prg.outContrib[2-1] = 'O' 2165 prg.outContrib[3-1] = 'T' 2166 prg.sendOut(eightBits(ident), sixteenBits(3)) 2167 2168 case setElementSign: 2169 prg.outContrib[1-1] = 'I' 2170 prg.outContrib[2-1] = 'N' 2171 prg.sendOut(eightBits(ident), sixteenBits(2)) 2172 2173 case orSign: 2174 prg.outContrib[1-1] = 'O' 2175 prg.outContrib[2-1] = 'R' 2176 prg.sendOut(eightBits(ident), sixteenBits(2)) 2177 2178 case leftArrow: 2179 prg.outContrib[1-1] = ':' 2180 prg.outContrib[2-1] = '=' 2181 prg.sendOut(eightBits(str), sixteenBits(2)) 2182 2183 case notEqual: 2184 prg.outContrib[1-1] = '<' 2185 prg.outContrib[2-1] = '>' 2186 prg.sendOut(eightBits(str), sixteenBits(2)) 2187 2188 case lessOrEqual: 2189 prg.outContrib[1-1] = '<' 2190 prg.outContrib[2-1] = '=' 2191 prg.sendOut(eightBits(str), sixteenBits(2)) 2192 2193 case greaterOrEqual: 2194 prg.outContrib[1-1] = '>' 2195 prg.outContrib[2-1] = '=' 2196 prg.sendOut(eightBits(str), sixteenBits(2)) 2197 2198 case equivalenceSign: 2199 prg.outContrib[1-1] = '=' 2200 prg.outContrib[2-1] = '=' 2201 prg.sendOut(eightBits(str), sixteenBits(2)) 2202 2203 case doubleDot: 2204 prg.outContrib[1-1] = '.' 2205 prg.outContrib[2-1] = '.' 2206 prg.sendOut(eightBits(str), sixteenBits(2)) 2207 2208 // "'"= 2209 case '\'': 2210 // Send a string, |goto reswitch| 2211 k = 1 2212 prg.outContrib[1-1] = '\'' 2213 for { 2214 if int32(k) < lineLength { 2215 k = byte(int32(k) + 1) 2216 } 2217 prg.outContrib[k-1] = byte(prg.getOutput()) 2218 if int32(prg.outContrib[k-1]) == '\'' || int32(prg.stackPtr) == 0 { 2219 break 2220 } 2221 } 2222 if int32(k) == lineLength { 2223 prg.stdout.Writeln() 2224 prg.stdout.Write("! String too long") 2225 prg.error1() 2226 } 2227 // \xref[String too long] 2228 prg.sendOut(eightBits(str), sixteenBits(k)) 2229 curChar = byte(prg.getOutput()) 2230 if int32(curChar) == '\'' { 2231 prg.outState = byte(unbreakable) 2232 } 2233 2234 goto reswitch 2235 2236 // Other printable characters 2237 // "!"= 2238 case '!', '"', '#', '$', 2239 '%', '&', '(', ')', 2240 '*', ',', '/', ':', 2241 ';', '<', '=', '>', 2242 '?', '@', '[', '\\', 2243 ']', '^', '_', '`', 2244 '{', '|': 2245 prg.sendOut(eightBits(misc), sixteenBits(curChar)) 2246 // \4 2247 // Cases involving \.[@\[] and \.[@\]] 2248 case beginComment: 2249 if int32(prg.braceLevel) == 0 { 2250 prg.sendOut(eightBits(misc), sixteenBits('{')) 2251 } else { 2252 prg.sendOut(eightBits(misc), sixteenBits('[')) 2253 } 2254 prg.braceLevel = byte(int32(prg.braceLevel) + 1) 2255 2256 case endComment: 2257 if int32(prg.braceLevel) > 0 { 2258 prg.braceLevel = byte(int32(prg.braceLevel) - 1) 2259 if int32(prg.braceLevel) == 0 { 2260 prg.sendOut(eightBits(misc), sixteenBits('}')) 2261 } else { 2262 prg.sendOut(eightBits(misc), sixteenBits(']')) 2263 } 2264 } else { 2265 prg.stdout.Writeln() 2266 prg.stdout.Write("! Extra @}") 2267 prg.error1() 2268 } 2269 // \xref[Extra \AT!\]] 2270 case moduleNumber: 2271 k = 2 2272 if int32(prg.braceLevel) == 0 { 2273 prg.outContrib[1-1] = '{' 2274 } else { 2275 prg.outContrib[1-1] = '[' 2276 } 2277 if prg.curVal < 0 { 2278 prg.outContrib[k-1] = ':' 2279 prg.curVal = -prg.curVal 2280 k = byte(int32(k) + 1) 2281 } 2282 n = 10 2283 for prg.curVal >= n { 2284 n = 10 * n 2285 } 2286 for { 2287 n = n / 10 2288 prg.outContrib[k-1] = byte('0' + prg.curVal/n) 2289 prg.curVal = prg.curVal % n 2290 k = byte(int32(k) + 1) 2291 if n == 1 { 2292 break 2293 } 2294 } 2295 if int32(prg.outContrib[2-1]) != ':' { 2296 prg.outContrib[k-1] = ':' 2297 k = byte(int32(k) + 1) 2298 } 2299 if int32(prg.braceLevel) == 0 { 2300 prg.outContrib[k-1] = '}' 2301 } else { 2302 prg.outContrib[k-1] = ']' 2303 } 2304 prg.sendOut(eightBits(str), sixteenBits(k)) 2305 2306 case join: 2307 prg.sendOut(eightBits(frac), sixteenBits(0)) 2308 prg.outState = byte(unbreakable) 2309 2310 case verbatim: 2311 // Send verbatim string 2312 k = 0 2313 for { 2314 if int32(k) < lineLength { 2315 k = byte(int32(k) + 1) 2316 } 2317 prg.outContrib[k-1] = byte(prg.getOutput()) 2318 if int32(prg.outContrib[k-1]) == verbatim || int32(prg.stackPtr) == 0 { 2319 break 2320 } 2321 } 2322 if int32(k) == lineLength { 2323 prg.stdout.Writeln() 2324 prg.stdout.Write("! Verbatim string too long") 2325 prg.error1() 2326 } 2327 // \xref[Verbatim string too long] 2328 prg.sendOut(eightBits(str), sixteenBits(int32(k)-1)) 2329 2330 case forceLine: 2331 // Force a line break 2332 prg.sendOut(eightBits(str), sixteenBits(0)) // normalize the buffer 2333 for int32(prg.outPtr) > 0 { 2334 if int32(prg.outPtr) <= lineLength { 2335 prg.breakPtr = prg.outPtr 2336 } 2337 prg.flushBuffer() 2338 } 2339 prg.outState = byte(misc) 2340 2341 default: 2342 prg.stdout.Writeln() 2343 prg.stdout.Write("! Can't output ASCII code ", curChar, knuth.WriteWidth(1)) 2344 prg.error1() 2345 // \xref[Can't output ASCII code n] 2346 } 2347 2348 goto continue1 2349 2350 getFraction: 2351 for { 2352 if int32(k) < lineLength { 2353 k = byte(int32(k) + 1) 2354 } 2355 prg.outContrib[k-1] = curChar 2356 curChar = byte(prg.getOutput()) 2357 if int32(prg.outContrib[k-1]) == 'E' && (int32(curChar) == '+' || int32(curChar) == '-') { 2358 if int32(k) < lineLength { 2359 k = byte(int32(k) + 1) 2360 } 2361 prg.outContrib[k-1] = curChar 2362 curChar = byte(prg.getOutput()) 2363 } else if int32(curChar) == 'e' { 2364 curChar = 'E' 2365 } 2366 if int32(curChar) != 'E' && (int32(curChar) < '0' || int32(curChar) > '9') { 2367 break 2368 } 2369 } 2370 if int32(k) == lineLength { 2371 prg.stdout.Writeln() 2372 prg.stdout.Write("! Fraction too long") 2373 prg.error1() 2374 } 2375 // \xref[Fraction too long] 2376 prg.sendOut(eightBits(frac), sixteenBits(k)) 2377 goto reswitch 2378 2379 continue1: 2380 } 2381 } 2382 2383 // 123. Introduction to the input phase 2384 2385 // tangle:pos tangle.web:2291:36: 2386 2387 // We have now seen that \.[TANGLE] will be able to output the full 2388 // \PASCAL\ program, if we can only get that program into the byte memory in 2389 // the proper format. The input process is something like the output process 2390 // in reverse, since we compress the text as we read it in and we expand it 2391 // as we write it out. 2392 // 2393 // There are three main input routines. The most interesting is the one that gets 2394 // the next token of a \PASCAL\ text; the other two are used to scan rapidly past 2395 // \TeX\ text in the \.[WEB] source code. One of the latter routines will jump to 2396 // the next token that starts with `\.[@]', and the other skips to the end 2397 // of a \PASCAL\ comment. 2398 2399 // 125. 2400 2401 // tangle:pos tangle.web:2319:3: 2402 2403 // As we change |changing| from |true| to |false| and back again, we must 2404 // remember to swap the values of |line| and |other_line| so that the |err_print| 2405 // routine will be sure to report the correct line number. 2406 2407 // 127. 2408 2409 // tangle:pos tangle.web:2337:3: 2410 2411 // Here's a simple function that checks if the two buffers are different. 2412 func (prg *prg) linesDontMatch() (r bool) { 2413 var ( 2414 k /* 0..bufSize */ byte // index into the buffers 2415 ) 2416 r = true 2417 if int32(prg.changeLimit) != int32(prg.limit) { 2418 goto exit 2419 } 2420 if int32(prg.limit) > 0 { 2421 for ii := int32(0); ii <= int32(prg.limit)-1; ii++ { 2422 k = byte(ii) 2423 _ = k 2424 if int32(prg.changeBuffer[k]) != int32(prg.buffer[k]) { 2425 goto exit 2426 } 2427 } 2428 } 2429 r = false 2430 2431 exit: 2432 ; 2433 return r 2434 } 2435 2436 // 128. 2437 2438 // tangle:pos tangle.web:2349:3: 2439 2440 // Procedure |prime_the_change_buffer| sets |change_buffer| in preparation 2441 // for the next matching operation. Since blank lines in the change file are 2442 // not used for matching, we have |(change_limit=0)and not changing| if and 2443 // only if the change file is exhausted. This procedure is called only 2444 // when |changing| is true; hence error messages will be reported correctly. 2445 func (prg *prg) primeTheChangeBuffer() { 2446 var ( 2447 k /* 0..bufSize */ byte // index into the buffers 2448 ) 2449 prg.changeLimit = 0 // this value will be used if the change file ends 2450 2451 // Skip over comment lines in the change file; |return| if end of file 2452 for true { 2453 prg.line = prg.line + 1 2454 if !prg.inputLn(prg.changeFile) { 2455 goto exit 2456 } 2457 if int32(prg.limit) < 2 { 2458 goto continue1 2459 } 2460 if int32(prg.buffer[0]) != '@' { 2461 goto continue1 2462 } 2463 if int32(prg.buffer[1]) >= 'X' && int32(prg.buffer[1]) <= 'Z' { 2464 prg.buffer[1] = byte(int32(prg.buffer[1]) + 'z' - 'Z') 2465 } // lowercasify 2466 if int32(prg.buffer[1]) == 'x' { 2467 goto done 2468 } 2469 if int32(prg.buffer[1]) == 'y' || int32(prg.buffer[1]) == 'z' { 2470 prg.loc = 2 2471 { 2472 prg.stdout.Writeln() 2473 prg.stdout.Write("! Where is the matching @x?") 2474 prg.error1() 2475 } 2476 // \xref[Where is the match...] 2477 } 2478 2479 continue1: 2480 } 2481 2482 done: 2483 ; 2484 2485 // Skip to the next nonblank line; |return| if end of file 2486 for { 2487 prg.line = prg.line + 1 2488 if !prg.inputLn(prg.changeFile) { 2489 { 2490 prg.stdout.Writeln() 2491 prg.stdout.Write("! Change file ended after @x") 2492 prg.error1() 2493 } 2494 // \xref[Change file ended...] 2495 2496 // \xref[Change file ended...] 2497 goto exit 2498 } 2499 if int32(prg.limit) > 0 { 2500 break 2501 } 2502 } 2503 2504 // Move |buffer| and |limit| to |change_buffer| and |change_limit| 2505 { 2506 prg.changeLimit = prg.limit 2507 if int32(prg.limit) > 0 { 2508 for ii := int32(0); ii <= int32(prg.limit)-1; ii++ { 2509 k = byte(ii) 2510 _ = k 2511 prg.changeBuffer[k] = prg.buffer[k] 2512 } 2513 } 2514 } 2515 2516 exit: 2517 } 2518 2519 // 132. 2520 2521 // tangle:pos tangle.web:2400:3: 2522 2523 // The following procedure is used to see if the next change entry should 2524 // go into effect; it is called only when |changing| is false. 2525 // The idea is to test whether or not the current 2526 // contents of |buffer| matches the current contents of |change_buffer|. 2527 // If not, there's nothing more to do; but if so, a change is called for: 2528 // All of the text down to the \.[@y] is supposed to match. An error 2529 // message is issued if any discrepancy is found. Then the procedure 2530 // prepares to read the next line from |change_file|. 2531 func (prg *prg) checkChange() { 2532 var ( 2533 n int32 // the number of discrepancies found 2534 k/* 0..bufSize */ byte // index into the buffers 2535 ) 2536 if prg.linesDontMatch() { 2537 goto exit 2538 } 2539 n = 0 2540 for true { 2541 prg.changing = !prg.changing 2542 prg.tempLine = prg.otherLine 2543 prg.otherLine = prg.line 2544 prg.line = prg.tempLine // now it's |true| 2545 prg.line = prg.line + 1 2546 if !prg.inputLn(prg.changeFile) { 2547 { 2548 prg.stdout.Writeln() 2549 prg.stdout.Write("! Change file ended before @y") 2550 prg.error1() 2551 } 2552 // \xref[Change file ended...] 2553 prg.changeLimit = 0 2554 prg.changing = !prg.changing 2555 prg.tempLine = prg.otherLine 2556 prg.otherLine = prg.line 2557 prg.line = prg.tempLine // |false| again 2558 // |false| again 2559 goto exit 2560 } 2561 2562 // If the current line starts with \.[@y], report any discrepancies and |return| 2563 if int32(prg.limit) > 1 { 2564 if int32(prg.buffer[0]) == '@' { 2565 if int32(prg.buffer[1]) >= 'X' && int32(prg.buffer[1]) <= 'Z' { 2566 prg.buffer[1] = byte(int32(prg.buffer[1]) + 'z' - 'Z') 2567 } // lowercasify 2568 if int32(prg.buffer[1]) == 'x' || int32(prg.buffer[1]) == 'z' { 2569 prg.loc = 2 2570 { 2571 prg.stdout.Writeln() 2572 prg.stdout.Write("! Where is the matching @y?") 2573 prg.error1() 2574 } 2575 // \xref[Where is the match...] 2576 } else if int32(prg.buffer[1]) == 'y' { 2577 if n > 0 { 2578 prg.loc = 2 2579 { 2580 prg.stdout.Writeln() 2581 prg.stdout.Write("! Hmm... ", n, knuth.WriteWidth(1), 2582 " of the preceding lines failed to match") 2583 prg.error1() 2584 } 2585 // \xref[Hmm... n of the preceding...] 2586 } 2587 2588 goto exit 2589 } 2590 } 2591 } 2592 2593 // Move |buffer| and |limit|... 2594 { 2595 prg.changeLimit = prg.limit 2596 if int32(prg.limit) > 0 { 2597 for ii := int32(0); ii <= int32(prg.limit)-1; ii++ { 2598 k = byte(ii) 2599 _ = k 2600 prg.changeBuffer[k] = prg.buffer[k] 2601 } 2602 } 2603 } 2604 prg.changing = !prg.changing 2605 prg.tempLine = prg.otherLine 2606 prg.otherLine = prg.line 2607 prg.line = prg.tempLine // now it's |false| 2608 prg.line = prg.line + 1 2609 if !prg.inputLn(prg.webFile) { 2610 { 2611 prg.stdout.Writeln() 2612 prg.stdout.Write("! WEB file ended during a change") 2613 prg.error1() 2614 } 2615 // \xref[WEB file ended...] 2616 prg.inputHasEnded = true 2617 goto exit 2618 } 2619 if prg.linesDontMatch() { 2620 n = n + 1 2621 } 2622 } 2623 2624 exit: 2625 } 2626 2627 // 135. 2628 2629 // tangle:pos tangle.web:2460:3: 2630 2631 // The |get_line| procedure is called when |loc>limit|; it puts the next 2632 // line of merged input into the buffer and updates the other variables 2633 // appropriately. A space is placed at the right end of the line. 2634 func (prg *prg) getLine() { 2635 restart: 2636 if prg.changing { 2637 prg.line = prg.line + 1 2638 if !prg.inputLn(prg.changeFile) { 2639 { 2640 prg.stdout.Writeln() 2641 prg.stdout.Write("! Change file ended without @z") 2642 prg.error1() 2643 } 2644 // \xref[Change file ended...] 2645 prg.buffer[0] = '@' 2646 prg.buffer[1] = 'z' 2647 prg.limit = 2 2648 } 2649 if int32(prg.limit) > 1 { 2650 if int32(prg.buffer[0]) == '@' { 2651 if int32(prg.buffer[1]) >= 'X' && int32(prg.buffer[1]) <= 'Z' { 2652 prg.buffer[1] = byte(int32(prg.buffer[1]) + 'z' - 'Z') 2653 } // lowercasify 2654 if int32(prg.buffer[1]) == 'x' || int32(prg.buffer[1]) == 'y' { 2655 prg.loc = 2 2656 { 2657 prg.stdout.Writeln() 2658 prg.stdout.Write("! Where is the matching @z?") 2659 prg.error1() 2660 } 2661 // \xref[Where is the match...] 2662 } else if int32(prg.buffer[1]) == 'z' { 2663 prg.primeTheChangeBuffer() 2664 prg.changing = !prg.changing 2665 prg.tempLine = prg.otherLine 2666 prg.otherLine = prg.line 2667 prg.line = prg.tempLine 2668 } 2669 } 2670 } 2671 } 2672 if !prg.changing { 2673 { 2674 prg.line = prg.line + 1 2675 if !prg.inputLn(prg.webFile) { 2676 prg.inputHasEnded = true 2677 } else if int32(prg.changeLimit) > 0 { 2678 prg.checkChange() 2679 } 2680 } 2681 if prg.changing { 2682 goto restart 2683 } 2684 } 2685 prg.loc = 0 2686 prg.buffer[prg.limit] = ' ' 2687 } 2688 2689 // 139. 2690 2691 // tangle:pos tangle.web:2513:3: 2692 2693 // Important milestones are reached during the input phase when certain 2694 // control codes are sensed. 2695 // 2696 // Control codes in \.[WEB] begin with `\.[@]', and the next character 2697 // identifies the code. Some of these are of interest only to \.[WEAVE], 2698 // so \.[TANGLE] ignores them; the others are converted by \.[TANGLE] into 2699 // internal code numbers by the |control_code| function below. The ordering 2700 // of these internal code numbers has been chosen to simplify the program logic; 2701 // larger numbers are given to the control codes that denote more significant 2702 // milestones. 2703 func (prg *prg) controlCode(c asciiCode) (r eightBits) { 2704 switch c { 2705 case '@': 2706 r = '@' // `quoted' at sign 2707 // "'"= 2708 case '\'': 2709 r = byte(octal) // precedes octal constant 2710 // """"= 2711 case '"': 2712 r = byte(hex) // precedes hexadecimal constant 2713 // "$"= 2714 case '$': 2715 r = byte(checkSum) // string pool check sum 2716 // " "= 2717 case ' ', tabMark: 2718 r = byte(newModule) // beginning of a new module 2719 // "*"= 2720 case '*': 2721 prg.stdout.Write("*", int32(prg.moduleCount)+1, knuth.WriteWidth(1)) 2722 // print a progress report 2723 r = byte(newModule) // beginning of a new module 2724 2725 // "D"= 2726 case 'D', 'd': 2727 r = byte(definition) // macro definition 2728 // "F"= 2729 case 'F', 'f': 2730 r = byte(format) // format definition 2731 // "["= 2732 case '{': 2733 r = byte(beginComment) // begin-comment delimiter 2734 // "]"= 2735 case '}': 2736 r = byte(endComment) // end-comment delimiter 2737 // "P"= 2738 case 'P', 'p': 2739 r = byte(beginPascal) // \PASCAL\ text in unnamed module 2740 // "T"= 2741 case 'T', 't', '^', '.', 2742 ':': 2743 r = byte(controlText) // control text to be ignored 2744 // "&"= 2745 case '&': 2746 r = byte(join) // concatenate two tokens 2747 // "<"= 2748 case '<': 2749 r = byte(moduleName) // beginning of a module name 2750 // "="= 2751 case '=': 2752 r = byte(verbatim) // beginning of \PASCAL\ verbatim mode 2753 // "\"= 2754 case '\\': 2755 r = byte(forceLine) 2756 // force a new line in \PASCAL\ output 2757 default: 2758 r = byte(ignore) // ignore all other cases 2759 } 2760 return r 2761 } 2762 2763 // 140. 2764 2765 // tangle:pos tangle.web:2557:3: 2766 2767 // The |skip_ahead| procedure reads through the input at fairly high speed 2768 // until finding the next non-ignorable control code, which it returns. 2769 func (prg *prg) skipAhead() (r eightBits) { 2770 var ( 2771 c eightBits // control code found 2772 ) 2773 for true { 2774 if int32(prg.loc) > int32(prg.limit) { 2775 prg.getLine() 2776 if prg.inputHasEnded { 2777 c = byte(newModule) 2778 goto done 2779 } 2780 } 2781 prg.buffer[int32(prg.limit)+1] = '@' 2782 for int32(prg.buffer[prg.loc]) != '@' { 2783 prg.loc = byte(int32(prg.loc) + 1) 2784 } 2785 if int32(prg.loc) <= int32(prg.limit) { 2786 prg.loc = byte(int32(prg.loc) + 2) 2787 c = prg.controlCode(prg.buffer[int32(prg.loc)-1]) 2788 if int32(c) != ignore || int32(prg.buffer[int32(prg.loc)-1]) == '>' { 2789 goto done 2790 } 2791 } 2792 } 2793 2794 done: 2795 r = c 2796 return r 2797 } 2798 2799 // 141. 2800 2801 // tangle:pos tangle.web:2579:3: 2802 2803 // The |skip_comment| procedure reads through the input at somewhat high speed 2804 // until finding the first unmatched right brace or until coming to the end 2805 // of the file. It ignores characters following `\.\\' characters, since all 2806 // braces that aren't nested are supposed to be hidden in that way. For 2807 // example, consider the process of skipping the first comment below, 2808 // where the string containing the right brace has been typed as \.[\`\\.\\\]\'] 2809 // in the \.[WEB] file. 2810 func (prg *prg) skipComment() { 2811 var ( 2812 bal eightBits // excess of left braces 2813 c asciiCode // current character 2814 ) 2815 bal = 0 2816 for true { 2817 if int32(prg.loc) > int32(prg.limit) { 2818 prg.getLine() 2819 if prg.inputHasEnded { 2820 { 2821 prg.stdout.Writeln() 2822 prg.stdout.Write("! Input ended in mid-comment") 2823 prg.error1() 2824 } 2825 // \xref[Input ended in mid-comment] 2826 2827 // \xref[Input ended in mid-comment] 2828 goto exit 2829 } 2830 } 2831 c = prg.buffer[prg.loc] 2832 prg.loc = byte(int32(prg.loc) + 1) 2833 2834 // Do special things when |c="@", "\", "[", "]"|; |return| at end 2835 if int32(c) == '@' { 2836 c = prg.buffer[prg.loc] 2837 if int32(c) != ' ' && int32(c) != tabMark && int32(c) != '*' { 2838 prg.loc = byte(int32(prg.loc) + 1) 2839 } else { 2840 { 2841 prg.stdout.Writeln() 2842 prg.stdout.Write("! Section ended in mid-comment") 2843 prg.error1() 2844 } 2845 // \xref[Section ended in mid-comment] 2846 prg.loc = byte(int32(prg.loc) - 1) 2847 goto exit 2848 } 2849 } else if int32(c) == '\\' && int32(prg.buffer[prg.loc]) != '@' { 2850 prg.loc = byte(int32(prg.loc) + 1) 2851 } else if int32(c) == '{' { 2852 bal = byte(int32(bal) + 1) 2853 } else if int32(c) == '}' { 2854 if int32(bal) == 0 { 2855 goto exit 2856 } 2857 bal = byte(int32(bal) - 1) 2858 } 2859 } 2860 2861 exit: 2862 } 2863 2864 // 145. 2865 2866 // tangle:pos tangle.web:2648:3: 2867 2868 // At the top level, |get_next| is a multi-way switch based on the next 2869 // character in the input buffer. A |new_module| code is inserted at the 2870 // very end of the input file. 2871 func (prg *prg) getNext() (r eightBits) { 2872 var ( 2873 c eightBits // the current character 2874 d eightBits // the next character 2875 j, k/* 0..longestName */ uint16 // indices into |mod_text| 2876 ) 2877 restart: 2878 if int32(prg.loc) > int32(prg.limit) { 2879 prg.getLine() 2880 if prg.inputHasEnded { 2881 c = byte(newModule) 2882 goto found 2883 } 2884 } 2885 c = prg.buffer[prg.loc] 2886 prg.loc = byte(int32(prg.loc) + 1) 2887 if prg.scanningHex { 2888 if int32(c) >= '0' && int32(c) <= '9' || int32(c) >= 'A' && int32(c) <= 'F' { 2889 goto found 2890 } else { 2891 prg.scanningHex = false 2892 } 2893 } 2894 switch c { 2895 case 'A', 'Z' - 24, 'Z' - 23, 'Z' - 22, 2896 'Z' - 21, 'Z' - 20, 'Z' - 19, 'Z' - 18, 2897 'Z' - 17, 'Z' - 16, 'Z' - 15, 'Z' - 14, 2898 'Z' - 13, 'Z' - 12, 'Z' - 11, 'Z' - 10, 2899 'Z' - 9, 'Z' - 8, 'Z' - 7, 'Z' - 6, 2900 'Z' - 5, 'Z' - 4, 'Z' - 3, 'Z' - 2, 2901 'Z' - 1, 'Z', 'a', 'z' - 24, 2902 'z' - 23, 'z' - 22, 'z' - 21, 'z' - 20, 2903 'z' - 19, 'z' - 18, 'z' - 17, 'z' - 16, 2904 'z' - 15, 'z' - 14, 'z' - 13, 'z' - 12, 2905 'z' - 11, 'z' - 10, 'z' - 9, 'z' - 8, 2906 'z' - 7, 'z' - 6, 'z' - 5, 'z' - 4, 2907 'z' - 3, 'z' - 2, 'z' - 1, 'z': 2908 // Get an identifier 2909 if (int32(c) == 'e' || int32(c) == 'E') && int32(prg.loc) > 1 { 2910 if int32(prg.buffer[int32(prg.loc)-2]) <= '9' && int32(prg.buffer[int32(prg.loc)-2]) >= '0' { 2911 c = 0 2912 } 2913 } 2914 if int32(c) != 0 { 2915 prg.loc = byte(int32(prg.loc) - 1) 2916 prg.idFirst = prg.loc 2917 for { 2918 prg.loc = byte(int32(prg.loc) + 1) 2919 d = prg.buffer[prg.loc] 2920 if (int32(d) < '0' || int32(d) > '9' && int32(d) < 'A' || int32(d) > 'Z' && int32(d) < 'a' || int32(d) > 'z') && int32(d) != '_' { 2921 break 2922 } 2923 } 2924 if int32(prg.loc) > int32(prg.idFirst)+1 { 2925 c = byte(identifier) 2926 prg.idLoc = prg.loc 2927 } 2928 } else { 2929 c = 'E' 2930 } // exponent of a real constant 2931 2932 // """"= 2933 case '"': 2934 // Get a preprocessed string 2935 prg.doubleChars = 0 2936 prg.idFirst = byte(int32(prg.loc) - 1) 2937 for { 2938 d = prg.buffer[prg.loc] 2939 prg.loc = byte(int32(prg.loc) + 1) 2940 if int32(d) == '"' || int32(d) == '@' { 2941 if int32(prg.buffer[prg.loc]) == int32(d) { 2942 prg.loc = byte(int32(prg.loc) + 1) 2943 d = 0 2944 prg.doubleChars = byte(int32(prg.doubleChars) + 1) 2945 } else { 2946 if int32(d) == '@' { 2947 prg.stdout.Writeln() 2948 prg.stdout.Write("! Double @ sign missing") 2949 prg.error1() 2950 } 2951 } 2952 } else if int32(prg.loc) > int32(prg.limit) { 2953 { 2954 prg.stdout.Writeln() 2955 prg.stdout.Write("! String constant didn't end") 2956 prg.error1() 2957 } 2958 d = '"' 2959 // \xref[String constant didn't end] 2960 } 2961 if int32(d) == '"' { 2962 break 2963 } 2964 } 2965 prg.idLoc = byte(int32(prg.loc) - 1) 2966 c = byte(identifier) 2967 2968 // "@"= 2969 case '@': 2970 // Get control code and possible module name 2971 c = prg.controlCode(prg.buffer[prg.loc]) 2972 prg.loc = byte(int32(prg.loc) + 1) 2973 if int32(c) == ignore { 2974 goto restart 2975 } else if int32(c) == hex { 2976 prg.scanningHex = true 2977 } else if int32(c) == moduleName { 2978 k = 0 2979 for true { 2980 if int32(prg.loc) > int32(prg.limit) { 2981 prg.getLine() 2982 if prg.inputHasEnded { 2983 { 2984 prg.stdout.Writeln() 2985 prg.stdout.Write("! Input ended in section name") 2986 prg.error1() 2987 } 2988 // \xref[Input ended in section name] 2989 2990 // \xref[Input ended in section name] 2991 goto done 2992 } 2993 } 2994 d = prg.buffer[prg.loc] 2995 2996 // If end of name, |goto done| 2997 if int32(d) == '@' { 2998 d = prg.buffer[int32(prg.loc)+1] 2999 if int32(d) == '>' { 3000 prg.loc = byte(int32(prg.loc) + 2) 3001 goto done 3002 } 3003 if int32(d) == ' ' || int32(d) == tabMark || int32(d) == '*' { 3004 { 3005 prg.stdout.Writeln() 3006 prg.stdout.Write("! Section name didn't end") 3007 prg.error1() 3008 } 3009 goto done 3010 // \xref[Section name didn't end] 3011 } 3012 k = uint16(int32(k) + 1) 3013 prg.modText[k] = '@' 3014 prg.loc = byte(int32(prg.loc) + 1) // now |d=buffer[loc]| again 3015 } 3016 prg.loc = byte(int32(prg.loc) + 1) 3017 if int32(k) < longestName-1 { 3018 k = uint16(int32(k) + 1) 3019 } 3020 if int32(d) == ' ' || int32(d) == tabMark { 3021 d = ' ' 3022 if int32(prg.modText[int32(k)-1]) == ' ' { 3023 k = uint16(int32(k) - 1) 3024 } 3025 } 3026 prg.modText[k] = d 3027 } 3028 3029 done: 3030 if int32(k) >= longestName-2 { 3031 { 3032 prg.stdout.Writeln() 3033 prg.stdout.Write("! Section name too long: ") 3034 } 3035 // \xref[Section name too long] 3036 for ii := int32(1); ii <= 25; ii++ { 3037 j = uint16(ii) 3038 _ = j 3039 prg.stdout.Write(string(rune(prg.xchr[prg.modText[j]]))) 3040 } 3041 prg.stdout.Write("...") /* */ 3042 if int32(prg.history) == spotless { 3043 prg.history = byte(harmlessMessage) 3044 } 3045 } 3046 if int32(prg.modText[k]) == ' ' && int32(k) > 0 { 3047 k = uint16(int32(k) - 1) 3048 } 3049 3050 if int32(k) > 3 { 3051 if int32(prg.modText[k]) == '.' && int32(prg.modText[int32(k)-1]) == '.' && int32(prg.modText[int32(k)-2]) == '.' { 3052 prg.curModule = prg.prefixLookup(sixteenBits(int32(k) - 3)) 3053 } else { 3054 prg.curModule = prg.modLookup(k) 3055 } 3056 } else { 3057 prg.curModule = prg.modLookup(k) 3058 } 3059 } else if int32(c) == controlText { 3060 for { 3061 c = prg.skipAhead() 3062 if int32(c) != '@' { 3063 break 3064 } 3065 } 3066 if int32(prg.buffer[int32(prg.loc)-1]) != '>' { 3067 prg.stdout.Writeln() 3068 prg.stdout.Write("! Improper @ within control text") 3069 prg.error1() 3070 } 3071 // \xref[Improper \AT! within control text] 3072 3073 // \xref[Improper \AT! within control text] 3074 goto restart 3075 } 3076 3077 // \4 3078 // Compress two-symbol combinations like `\.[:=]' 3079 // "."= 3080 case '.': 3081 if int32(prg.buffer[prg.loc]) == '.' { 3082 if int32(prg.loc) <= int32(prg.limit) { 3083 c = byte(doubleDot) 3084 prg.loc = byte(int32(prg.loc) + 1) 3085 } 3086 } else if int32(prg.buffer[prg.loc]) == ')' { 3087 if int32(prg.loc) <= int32(prg.limit) { 3088 c = ']' 3089 prg.loc = byte(int32(prg.loc) + 1) 3090 } 3091 } 3092 // ":"= 3093 case ':': 3094 if int32(prg.buffer[prg.loc]) == '=' { 3095 if int32(prg.loc) <= int32(prg.limit) { 3096 c = byte(leftArrow) 3097 prg.loc = byte(int32(prg.loc) + 1) 3098 } 3099 } 3100 // "="= 3101 case '=': 3102 if int32(prg.buffer[prg.loc]) == '=' { 3103 if int32(prg.loc) <= int32(prg.limit) { 3104 c = byte(equivalenceSign) 3105 prg.loc = byte(int32(prg.loc) + 1) 3106 } 3107 } 3108 // ">"= 3109 case '>': 3110 if int32(prg.buffer[prg.loc]) == '=' { 3111 if int32(prg.loc) <= int32(prg.limit) { 3112 c = byte(greaterOrEqual) 3113 prg.loc = byte(int32(prg.loc) + 1) 3114 } 3115 } 3116 // "<"= 3117 case '<': 3118 if int32(prg.buffer[prg.loc]) == '=' { 3119 if int32(prg.loc) <= int32(prg.limit) { 3120 c = byte(lessOrEqual) 3121 prg.loc = byte(int32(prg.loc) + 1) 3122 } 3123 } else if int32(prg.buffer[prg.loc]) == '>' { 3124 if int32(prg.loc) <= int32(prg.limit) { 3125 c = byte(notEqual) 3126 prg.loc = byte(int32(prg.loc) + 1) 3127 } 3128 } 3129 // "("= 3130 case '(': 3131 if int32(prg.buffer[prg.loc]) == '*' { 3132 if int32(prg.loc) <= int32(prg.limit) { 3133 c = byte(beginComment) 3134 prg.loc = byte(int32(prg.loc) + 1) 3135 } 3136 } else if int32(prg.buffer[prg.loc]) == '.' { 3137 if int32(prg.loc) <= int32(prg.limit) { 3138 c = '[' 3139 prg.loc = byte(int32(prg.loc) + 1) 3140 } 3141 } 3142 // "*"= 3143 case '*': 3144 if int32(prg.buffer[prg.loc]) == ')' { 3145 if int32(prg.loc) <= int32(prg.limit) { 3146 c = byte(endComment) 3147 prg.loc = byte(int32(prg.loc) + 1) 3148 } 3149 } 3150 3151 // " "= 3152 case ' ', tabMark: 3153 goto restart // ignore spaces and tabs 3154 // "["= 3155 case '{': 3156 prg.skipComment() 3157 goto restart 3158 3159 // "]"= 3160 case '}': 3161 { 3162 prg.stdout.Writeln() 3163 prg.stdout.Write("! Extra }") 3164 prg.error1() 3165 } 3166 goto restart 3167 // \xref[Extra \]] 3168 3169 default: 3170 if int32(c) >= 128 { 3171 goto restart 3172 } else { 3173 } 3174 } 3175 3176 found: 3177 r = c 3178 return r 3179 } 3180 3181 // 157. 3182 3183 // tangle:pos tangle.web:2846:3: 3184 3185 // The evaluation of a numeric expression makes use of two variables called the 3186 // |accumulator| and the |next_sign|. At the beginning, |accumulator| is zero and 3187 // |next_sign| is $+1$. When a \.+ or \.- is scanned, |next_sign| is multiplied 3188 // by the value of that sign. When a numeric value is scanned, it is multiplied by 3189 // |next_sign| and added to the |accumulator|, then |next_sign| is reset to $+1$. 3190 func (prg *prg) scanNumeric(p namePointer) { 3191 var ( 3192 accumulator int32 // accumulates sums 3193 nextSign/* -1.. +1 */ int8 // sign to attach to next value 3194 q namePointer // points to identifiers being evaluated 3195 val int32 // constants being evaluated 3196 ) 3197 accumulator = 0 3198 nextSign = int8(+1) 3199 for true { 3200 prg.nextControl = prg.getNext() 3201 3202 reswitch: 3203 switch prg.nextControl { 3204 case '0', '1', '2', '3', 3205 '4', '5', '6', '7', 3206 '8', '9': 3207 val = 0 3208 for { 3209 val = 10*val + int32(prg.nextControl) - '0' 3210 prg.nextControl = prg.getNext() 3211 if int32(prg.nextControl) > '9' || int32(prg.nextControl) < '0' { 3212 break 3213 } 3214 } 3215 { 3216 accumulator = accumulator + int32(nextSign)*val 3217 nextSign = int8(+1) 3218 } 3219 goto reswitch 3220 3221 case octal: 3222 val = 0 3223 prg.nextControl = '0' 3224 for { 3225 val = 8*val + int32(prg.nextControl) - '0' 3226 prg.nextControl = prg.getNext() 3227 if int32(prg.nextControl) > '7' || int32(prg.nextControl) < '0' { 3228 break 3229 } 3230 } 3231 { 3232 accumulator = accumulator + int32(nextSign)*val 3233 nextSign = int8(+1) 3234 } 3235 goto reswitch 3236 3237 case hex: 3238 val = 0 3239 prg.nextControl = '0' 3240 for { 3241 if int32(prg.nextControl) >= 'A' { 3242 prg.nextControl = byte(int32(prg.nextControl) + '0' + 10 - 'A') 3243 } 3244 val = 16*val + int32(prg.nextControl) - '0' 3245 prg.nextControl = prg.getNext() 3246 if int32(prg.nextControl) > 'F' || int32(prg.nextControl) < '0' || int32(prg.nextControl) > '9' && int32(prg.nextControl) < 'A' { 3247 break 3248 } 3249 } 3250 { 3251 accumulator = accumulator + int32(nextSign)*val 3252 nextSign = int8(+1) 3253 } 3254 goto reswitch 3255 3256 case identifier: 3257 q = prg.idLookup(eightBits(normal)) 3258 if int32(prg.ilk[q]) != numeric { 3259 prg.nextControl = '*' 3260 goto reswitch // leads to error 3261 } 3262 { 3263 accumulator = accumulator + int32(nextSign)*(int32(prg.equiv[q])-0100000) 3264 nextSign = int8(+1) 3265 } 3266 3267 // "+"= 3268 case '+': 3269 // "-"= 3270 case '-': 3271 nextSign = -nextSign 3272 case format, definition, moduleName, beginPascal, 3273 newModule: 3274 goto done 3275 // ";"= 3276 case ';': 3277 prg.stdout.Writeln() 3278 prg.stdout.Write("! Omit semicolon in numeric definition") 3279 prg.error1() 3280 3281 // \xref[Omit semicolon in numeric def...] 3282 default: 3283 { 3284 prg.stdout.Writeln() 3285 prg.stdout.Write("! Improper numeric definition will be flushed") 3286 prg.error1() 3287 } 3288 // \xref[Improper numeric definition...] 3289 for { 3290 prg.nextControl = prg.skipAhead() 3291 if int32(prg.nextControl) >= format { 3292 break 3293 } 3294 } 3295 if int32(prg.nextControl) == moduleName { 3296 prg.loc = byte(int32(prg.loc) - 2) 3297 prg.nextControl = prg.getNext() 3298 } 3299 accumulator = 0 3300 goto done 3301 3302 } 3303 } 3304 3305 done: 3306 ; 3307 if abs(accumulator) >= 0100000 { 3308 { 3309 prg.stdout.Writeln() 3310 prg.stdout.Write("! Value too big: ", accumulator, knuth.WriteWidth(1)) 3311 prg.error1() 3312 } 3313 accumulator = 0 3314 // \xref[Value too big] 3315 } 3316 prg.equiv[p] = uint16(accumulator + 0100000) // name |p| now is defined to equal |accumulator| 3317 } 3318 3319 // 163. Scanning a macro definition 3320 3321 // tangle:pos tangle.web:2930:32: 3322 3323 // The rules for generating the replacement texts corresponding to simple 3324 // macros, parametric macros, and \PASCAL\ texts of a module are almost 3325 // identical, so a single procedure is used for all three cases. The 3326 // differences are that 3327 // 3328 // \yskip\item[a)] The sign |#| denotes a parameter only when it appears 3329 // outside of strings in a parametric macro; otherwise it stands for the 3330 // ASCII character |#|. (This is not used in standard \PASCAL, but some 3331 // \PASCAL s allow, for example, `\.[/\#]' after a certain kind of file name.) 3332 // 3333 // \item[b)]Module names are not allowed in simple macros or parametric macros; 3334 // in fact, the appearance of a module name terminates such macros and denotes 3335 // the name of the current module. 3336 // 3337 // \item[c)]The symbols \.[@d] and \.[@f] and \.[@p] are not allowed after 3338 // module names, while they terminate macro definitions. 3339 3340 // 165. 3341 func (prg *prg) scanRepl(t eightBits) { 3342 var ( 3343 a sixteenBits // the current token 3344 b asciiCode // a character from the buffer 3345 bal eightBits // left parentheses minus right parentheses 3346 ) 3347 bal = 0 3348 for true { 3349 continue1: 3350 a = uint16(prg.getNext()) 3351 switch a { 3352 case '(': 3353 bal = byte(int32(bal) + 1) 3354 // ")"= 3355 case ')': 3356 if int32(bal) == 0 { 3357 prg.stdout.Writeln() 3358 prg.stdout.Write("! Extra )") 3359 prg.error1() 3360 } else { 3361 bal = byte(int32(bal) - 1) 3362 } 3363 // "'"= 3364 case '\'': 3365 // Copy a string from the buffer to |tok_mem| 3366 b = '\'' 3367 for true { 3368 { 3369 if int32(prg.tokPtr[prg.z]) == maxToks { 3370 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3371 prg.error1() 3372 prg.history = byte(fatalMessage) 3373 prg.jumpOut() 3374 } 3375 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = b 3376 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3377 } 3378 if int32(b) == '@' { 3379 if int32(prg.buffer[prg.loc]) == '@' { 3380 prg.loc = byte(int32(prg.loc) + 1) 3381 } else { 3382 prg.stdout.Writeln() 3383 prg.stdout.Write("! You should double @ signs in strings") 3384 prg.error1() 3385 } 3386 } 3387 // \xref[You should double \AT! signs] 3388 if int32(prg.loc) == int32(prg.limit) { 3389 { 3390 prg.stdout.Writeln() 3391 prg.stdout.Write("! String didn't end") 3392 prg.error1() 3393 } 3394 // \xref[String didn't end] 3395 prg.buffer[prg.loc] = '\'' 3396 prg.buffer[int32(prg.loc)+1] = 0 3397 } 3398 b = prg.buffer[prg.loc] 3399 prg.loc = byte(int32(prg.loc) + 1) 3400 if int32(b) == '\'' { 3401 if int32(prg.buffer[prg.loc]) != '\'' { 3402 goto found 3403 } else { 3404 prg.loc = byte(int32(prg.loc) + 1) 3405 { 3406 if int32(prg.tokPtr[prg.z]) == maxToks { 3407 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3408 prg.error1() 3409 prg.history = byte(fatalMessage) 3410 prg.jumpOut() 3411 } 3412 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = '\'' 3413 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3414 } 3415 } 3416 } 3417 } 3418 3419 found: 3420 ; // now |a| holds the final |"'"| that will be stored 3421 3422 // "#"= 3423 case '#': 3424 if int32(t) == parametric { 3425 a = uint16(param) 3426 } 3427 // \4 3428 // In cases that |a| is a non-ASCII token (|identifier|, |module_name|, etc.), either process it and change |a| to a byte that should be stored, or |goto continue| if |a| should be ignored, or |goto done| if |a| signals the end of this replacement text 3429 case identifier: 3430 a = prg.idLookup(eightBits(normal)) 3431 { 3432 if int32(prg.tokPtr[prg.z]) == maxToks { 3433 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3434 prg.error1() 3435 prg.history = byte(fatalMessage) 3436 prg.jumpOut() 3437 } 3438 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = byte(int32(a)/0400 + 0200) 3439 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3440 } 3441 a = uint16(int32(a) % 0400) 3442 3443 case moduleName: 3444 if int32(t) != moduleName { 3445 goto done 3446 } else { 3447 { 3448 if int32(prg.tokPtr[prg.z]) == maxToks { 3449 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3450 prg.error1() 3451 prg.history = byte(fatalMessage) 3452 prg.jumpOut() 3453 } 3454 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = byte(int32(prg.curModule)/0400 + 0250) 3455 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3456 } 3457 a = uint16(int32(prg.curModule) % 0400) 3458 } 3459 case verbatim: 3460 // Copy verbatim string from the buffer to |tok_mem| 3461 { 3462 if int32(prg.tokPtr[prg.z]) == maxToks { 3463 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3464 prg.error1() 3465 prg.history = byte(fatalMessage) 3466 prg.jumpOut() 3467 } 3468 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = byte(verbatim) 3469 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3470 } 3471 prg.buffer[int32(prg.limit)+1] = '@' 3472 3473 reswitch: 3474 if int32(prg.buffer[prg.loc]) == '@' { 3475 if int32(prg.loc) < int32(prg.limit) { 3476 if int32(prg.buffer[int32(prg.loc)+1]) == '@' { 3477 { 3478 if int32(prg.tokPtr[prg.z]) == maxToks { 3479 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3480 prg.error1() 3481 prg.history = byte(fatalMessage) 3482 prg.jumpOut() 3483 } 3484 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = '@' 3485 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3486 } 3487 prg.loc = byte(int32(prg.loc) + 2) 3488 3489 goto reswitch 3490 } 3491 } 3492 } else { 3493 { 3494 if int32(prg.tokPtr[prg.z]) == maxToks { 3495 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3496 prg.error1() 3497 prg.history = byte(fatalMessage) 3498 prg.jumpOut() 3499 } 3500 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = prg.buffer[prg.loc] 3501 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3502 } 3503 prg.loc = byte(int32(prg.loc) + 1) 3504 3505 goto reswitch 3506 } 3507 if int32(prg.loc) >= int32(prg.limit) { 3508 prg.stdout.Writeln() 3509 prg.stdout.Write("! Verbatim string didn't end") 3510 prg.error1() 3511 } else if int32(prg.buffer[int32(prg.loc)+1]) != '>' { 3512 prg.stdout.Writeln() 3513 prg.stdout.Write("! You should double @ signs in verbatim strings") 3514 prg.error1() 3515 } 3516 // \xref[You should double \AT! signs] 3517 prg.loc = byte(int32(prg.loc) + 2) 3518 // another |verbatim| byte will be stored, since |a=verbatim| 3519 3520 case definition, format, beginPascal: 3521 if int32(t) != moduleName { 3522 goto done 3523 } else { 3524 { 3525 prg.stdout.Writeln() 3526 prg.stdout.Write("! @", string(rune(prg.xchr[prg.buffer[int32(prg.loc)-1]])), 3527 // \xref[\AT!p is ignored in Pascal text] 3528 // \xref[\AT!d is ignored in Pascal text] 3529 // \xref[\AT!f is ignored in Pascal text] 3530 " is ignored in Pascal text") 3531 prg.error1() 3532 } 3533 goto continue1 3534 } 3535 case newModule: 3536 goto done 3537 3538 default: 3539 } 3540 3541 { 3542 if int32(prg.tokPtr[prg.z]) == maxToks { 3543 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3544 prg.error1() 3545 prg.history = byte(fatalMessage) 3546 prg.jumpOut() 3547 } 3548 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = byte(a) 3549 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3550 } // store |a| in |tok_mem| 3551 } 3552 3553 done: 3554 prg.nextControl = byte(a) 3555 3556 // Make sure the parentheses balance 3557 if int32(bal) > 0 { 3558 if int32(bal) == 1 { 3559 prg.stdout.Writeln() 3560 prg.stdout.Write("! Missing )") 3561 prg.error1() 3562 } else { 3563 prg.stdout.Writeln() 3564 prg.stdout.Write("! Missing ", bal, knuth.WriteWidth(1), " )'s") 3565 prg.error1() 3566 } 3567 // \xref[Missing n )] 3568 for int32(bal) > 0 { 3569 { 3570 if int32(prg.tokPtr[prg.z]) == maxToks { 3571 prg.stderr.Writeln("! Sorry, ", "token", " capacity exceeded") 3572 prg.error1() 3573 prg.history = byte(fatalMessage) 3574 prg.jumpOut() 3575 } 3576 prg.tokMem[prg.z][prg.tokPtr[prg.z]] = ')' 3577 prg.tokPtr[prg.z] = uint16(int32(prg.tokPtr[prg.z]) + 1) 3578 } 3579 bal = byte(int32(bal) - 1) 3580 } 3581 } 3582 if int32(prg.textPtr) > maxTexts-zz { 3583 prg.stderr.Writeln("! Sorry, ", "text", " capacity exceeded") 3584 prg.error1() 3585 prg.history = byte(fatalMessage) 3586 prg.jumpOut() 3587 } 3588 prg.curReplText = prg.textPtr 3589 prg.tokStart[int32(prg.textPtr)+zz] = prg.tokPtr[prg.z] 3590 prg.textPtr = uint16(int32(prg.textPtr) + 1) 3591 if int32(prg.z) == zz-1 { 3592 prg.z = 0 3593 } else { 3594 prg.z = byte(int32(prg.z) + 1) 3595 } 3596 } 3597 3598 // 170. 3599 3600 // tangle:pos tangle.web:3057:3: 3601 3602 // The following procedure is used to define a simple or parametric macro, 3603 // just after the `\.[==]' of its definition has been scanned. 3604 func (prg *prg) defineMacro(t eightBits) { 3605 var ( 3606 p namePointer // the identifier being defined 3607 ) 3608 p = prg.idLookup(t) 3609 prg.scanRepl(t) 3610 3611 prg.equiv[p] = prg.curReplText 3612 prg.textLink[prg.curReplText] = 0 3613 } 3614 3615 // 172. 3616 3617 // tangle:pos tangle.web:3075:3: 3618 3619 // The top level of |scan_module| is trivial. 3620 func (prg *prg) scanModule() { 3621 var ( 3622 p namePointer // module name for the current module 3623 ) 3624 prg.moduleCount = uint16(int32(prg.moduleCount) + 1) 3625 3626 // Scan the \(definition part of the current module 3627 prg.nextControl = 0 3628 for true { 3629 continue1: 3630 for int32(prg.nextControl) <= format { 3631 prg.nextControl = prg.skipAhead() 3632 if int32(prg.nextControl) == moduleName { 3633 prg.loc = byte(int32(prg.loc) - 2) 3634 prg.nextControl = prg.getNext() 3635 } 3636 } 3637 if int32(prg.nextControl) != definition { 3638 goto done 3639 } 3640 prg.nextControl = prg.getNext() // get identifier name 3641 if int32(prg.nextControl) != identifier { 3642 { 3643 prg.stdout.Writeln() 3644 prg.stdout.Write("! Definition flushed, must start with ", 3645 // \xref[Definition flushed...] 3646 "identifier of length > 1") 3647 prg.error1() 3648 } 3649 goto continue1 3650 } 3651 prg.nextControl = prg.getNext() // get token after the identifier 3652 if int32(prg.nextControl) == '=' { 3653 prg.scanNumeric(prg.idLookup(eightBits(numeric))) 3654 goto continue1 3655 } else if int32(prg.nextControl) == equivalenceSign { 3656 prg.defineMacro(eightBits(simple)) 3657 goto continue1 3658 } else if int32(prg.nextControl) == '(' { 3659 prg.nextControl = prg.getNext() 3660 if int32(prg.nextControl) == '#' { 3661 prg.nextControl = prg.getNext() 3662 if int32(prg.nextControl) == ')' { 3663 prg.nextControl = prg.getNext() 3664 if int32(prg.nextControl) == '=' { 3665 { 3666 prg.stdout.Writeln() 3667 prg.stdout.Write("! Use == for macros") 3668 prg.error1() 3669 } 3670 // \xref[Use == for macros] 3671 prg.nextControl = byte(equivalenceSign) 3672 } 3673 if int32(prg.nextControl) == equivalenceSign { 3674 prg.defineMacro(eightBits(parametric)) 3675 goto continue1 3676 } 3677 } 3678 } 3679 } 3680 3681 { 3682 prg.stdout.Writeln() 3683 prg.stdout.Write("! Definition flushed since it starts badly") 3684 prg.error1() 3685 } 3686 // \xref[Definition flushed...] 3687 } 3688 3689 done: 3690 ; 3691 3692 // Scan the \PASCAL\ part of the current module 3693 switch prg.nextControl { 3694 case beginPascal: 3695 p = 0 3696 case moduleName: 3697 p = prg.curModule 3698 3699 // Check that |=| or |==| follows this module name, otherwise |return| 3700 for { 3701 prg.nextControl = prg.getNext() 3702 if int32(prg.nextControl) != '+' { 3703 break 3704 } 3705 } // allow optional `\.[+=]' 3706 if int32(prg.nextControl) != '=' && int32(prg.nextControl) != equivalenceSign { 3707 { 3708 prg.stdout.Writeln() 3709 prg.stdout.Write("! Pascal text flushed, = sign is missing") 3710 prg.error1() 3711 } 3712 // \xref[Pascal text flushed...] 3713 for { 3714 prg.nextControl = prg.skipAhead() 3715 if int32(prg.nextControl) == newModule { 3716 break 3717 } 3718 } 3719 3720 goto exit 3721 } 3722 3723 default: 3724 goto exit 3725 } 3726 3727 // Insert the module number into |tok_mem| 3728 prg.storeTwoBytes(sixteenBits(0150000 + int32(prg.moduleCount))) // |@'150000=@'320*@'400| 3729 3730 prg.scanRepl(eightBits(moduleName)) // now |cur_repl_text| points to the replacement text 3731 3732 // Update the data structure so that the replacement text is accessible 3733 if int32(p) == 0 { 3734 prg.textLink[prg.lastUnnamed] = prg.curReplText 3735 prg.lastUnnamed = prg.curReplText 3736 } else if int32(prg.equiv[p]) == 0 { 3737 prg.equiv[p] = prg.curReplText 3738 } else { 3739 p = prg.equiv[p] 3740 for int32(prg.textLink[p]) < maxTexts { 3741 p = prg.textLink[p] 3742 } // find end of list 3743 prg.textLink[p] = prg.curReplText 3744 } 3745 prg.textLink[prg.curReplText] = uint16(maxTexts) 3746 // mark this replacement text as a nonmacro 3747 3748 exit: 3749 } 3750 3751 // 181. 3752 // procedure debug_help; [routine to display various things] 3753 // label breakpoint,exit; 3754 // var k:integer; [index into various arrays] 3755 // begin debug_skipped:= debug_skipped+1 ; 3756 // if debug_skipped<debug_cycle then goto exit ; 3757 // debug_skipped:=0; 3758 // while true do begin begin writeln() ; write('#') ; end ; ; [prompt] 3759 // read(term_in,ddt); [read a debug-command code] 3760 // if ddt<0 then goto exit 3761 // else if ddt=0 then 3762 // begin goto breakpoint; 3763 // [go to every label at least once] 3764 // breakpoint: ddt:=0; 3765 // 3766 // end 3767 // else begin read(term_in,dd); 3768 // case ddt of 3769 // 1: print_id(dd); 3770 // 2: print_repl(dd); 3771 // 3: for k:=1 to dd do write( xchr[ buffer[ k]]) ; 3772 // 4: for k:=1 to dd do write( xchr[ mod_text[ k]]) ; 3773 // 5: for k:=1 to out_ptr do write( xchr[ out_buf[ k]]) ; 3774 // 6: for k:=1 to dd do write( xchr[ out_contrib[ k]]) ; 3775 // else write('?') 3776 // end ; 3777 // end; 3778 // end; 3779 // exit:end; 3780 // [ ] 3781 3782 // 182. The main program 3783 3784 // tangle:pos tangle.web:3240:21: 3785 3786 // We have defined plenty of procedures, and it is time to put the last 3787 // pieces of the puzzle in place. Here is where \.[TANGLE] starts, and where 3788 // it ends. 3789 // \xref[system dependencies] 3790 func (prg *prg) main() { 3791 defer func() { 3792 if prg.changeFile != nil { 3793 prg.changeFile.Close() 3794 } 3795 if prg.pascalFile != nil { 3796 prg.pascalFile.Close() 3797 } 3798 if prg.pool != nil { 3799 prg.pool.Close() 3800 } 3801 if prg.stderr != nil { 3802 prg.stderr.Close() 3803 } 3804 if prg.stdin != nil { 3805 prg.stdin.Close() 3806 } 3807 if prg.stdout != nil { 3808 prg.stdout.Close() 3809 } 3810 if prg.termOut != nil { 3811 prg.termOut.Close() 3812 } 3813 if prg.webFile != nil { 3814 prg.webFile.Close() 3815 } 3816 }() 3817 3818 prg.initialize() 3819 3820 // Initialize the input system 3821 prg.openInput() 3822 prg.line = 0 3823 prg.otherLine = 0 3824 3825 prg.changing = true 3826 prg.primeTheChangeBuffer() 3827 prg.changing = !prg.changing 3828 prg.tempLine = prg.otherLine 3829 prg.otherLine = prg.line 3830 prg.line = prg.tempLine 3831 3832 prg.limit = 0 3833 prg.loc = 1 3834 prg.buffer[0] = ' ' 3835 prg.inputHasEnded = false 3836 3837 prg.stdout.Writeln("This is TANGLE, Version 4.6 (gotangle v0.0-prereleaase)") // print a ``banner line'' 3838 3839 // Phase I: Read all the user's text and compress it into |tok_mem| 3840 prg.phaseOne = true 3841 prg.moduleCount = 0 3842 for { 3843 prg.nextControl = prg.skipAhead() 3844 if int32(prg.nextControl) == newModule { 3845 break 3846 } 3847 } 3848 for !prg.inputHasEnded { 3849 prg.scanModule() 3850 } 3851 3852 // Check that all changes have been read 3853 if int32(prg.changeLimit) != 0 { 3854 for ii := int32(0); ii <= int32(prg.changeLimit)-1; ii++ { 3855 prg.ii1 = ii 3856 _ = prg.ii1 3857 prg.buffer[prg.ii1] = prg.changeBuffer[prg.ii1] 3858 } 3859 prg.limit = prg.changeLimit 3860 prg.changing = true 3861 prg.line = prg.otherLine 3862 prg.loc = prg.changeLimit 3863 { 3864 prg.stdout.Writeln() 3865 prg.stdout.Write("! Change file entry did not match") 3866 prg.error1() 3867 } 3868 // \xref[Change file entry did not match] 3869 } 3870 prg.phaseOne = false 3871 3872 // for ii:=0 to zz-1 do max_tok_ptr[ii]:=tok_ptr[ii]; [ ] 3873 3874 // Phase II:... 3875 if int32(prg.textLink[0]) == 0 { 3876 { 3877 prg.stdout.Writeln() 3878 prg.stdout.Write("! No output was specified.") 3879 } /* */ 3880 if int32(prg.history) == spotless { 3881 prg.history = byte(harmlessMessage) 3882 } 3883 // \xref[No output was specified] 3884 } else { 3885 { 3886 prg.stdout.Writeln() 3887 prg.stdout.Write("Writing the output file") 3888 } 3889 3890 // Initialize the output stacks 3891 prg.stackPtr = 1 3892 prg.braceLevel = 0 3893 prg.curState.nameField = 0 3894 prg.curState.replField = prg.textLink[0] 3895 prg.zo = byte(int32(prg.curState.replField) % zz) 3896 prg.curState.byteField = prg.tokStart[prg.curState.replField] 3897 prg.curState.endField = prg.tokStart[int32(prg.curState.replField)+zz] 3898 prg.curState.modField = 0 3899 3900 // Initialize the output buffer 3901 prg.outState = byte(misc) 3902 prg.outPtr = 0 3903 prg.breakPtr = 0 3904 prg.semiPtr = 0 3905 prg.outBuf[0] = 0 3906 prg.line = 1 3907 3908 prg.sendTheOutput() 3909 3910 // Empty the last line... 3911 prg.breakPtr = prg.outPtr 3912 prg.semiPtr = 0 3913 prg.flushBuffer() 3914 if int32(prg.braceLevel) != 0 { 3915 prg.stdout.Writeln() 3916 prg.stdout.Write("! Program ended at brace level ", prg.braceLevel, knuth.WriteWidth(1)) 3917 prg.error1() 3918 } 3919 // \xref[Program ended at brace level n] 3920 3921 { 3922 prg.stdout.Writeln() 3923 prg.stdout.Write("Done.") 3924 } 3925 } 3926 if int32(prg.stringPtr) > 256 { 3927 { 3928 prg.stdout.Writeln() 3929 prg.stdout.Write(int32(prg.stringPtr)-256, knuth.WriteWidth(1), " strings written to string pool file.") 3930 } 3931 prg.pool.Write("*") 3932 for ii := int32(1); ii <= 9; ii++ { 3933 prg.ii1 = ii 3934 _ = prg.ii1 3935 prg.outBuf[prg.ii1] = byte(prg.poolCheckSum % 10) 3936 prg.poolCheckSum = prg.poolCheckSum / 10 3937 } 3938 for ii := int32(9); ii >= 1; ii-- { 3939 prg.ii1 = ii 3940 _ = prg.ii1 3941 prg.pool.Write(string(rune(prg.xchr['0'+int32(prg.outBuf[prg.ii1])]))) 3942 } 3943 prg.pool.Writeln() 3944 } 3945 // 3946 // [ Print statistics about memory usage ] 3947 // begin writeln() ; write('Memory usage statistics:') ; end ; 3948 // begin writeln() ; write( name_ptr: 1, ' names, ', text_ptr: 1, ' replacement texts;') ; end ; 3949 // begin writeln() ; write( byte_ptr[ 0]: 1) ; end ; 3950 // for wo:=1 to ww-1 do write('+', byte_ptr[ wo]: 1) ; 3951 // if phase_one then 3952 // for ii:=0 to zz-1 do max_tok_ptr[ii]:=tok_ptr[ii]; 3953 // write(' bytes, ', max_tok_ptr[ 0]: 1) ; 3954 // for ii:=1 to zz-1 do write('+', max_tok_ptr[ ii]: 1) ; 3955 // write(' tokens.') ; 3956 // 3957 // ; [ ] 3958 3959 // \4\4 3960 // here files should be closed if the operating system requires it 3961 3962 // Print the job |history| 3963 switch prg.history { 3964 case spotless: 3965 prg.stdout.Writeln() 3966 prg.stdout.Write("(No errors were found.)") 3967 case harmlessMessage: 3968 prg.stdout.Writeln() 3969 prg.stdout.Write("(Did you see the warning message above?)") 3970 case errorMessage: 3971 prg.stdout.Writeln() 3972 prg.stdout.Write("(Pardon me, but I think I spotted something wrong.)") 3973 case fatalMessage: 3974 prg.stdout.Writeln() 3975 prg.stdout.Write("(That was a fatal error, my friend.)") 3976 } 3977 prg.stdout.Writeln() 3978 } 3979 3980 // 188. System-dependent changes 3981 3982 // tangle:pos tangle.web:3307:29: 3983 3984 // This module should be replaced, if necessary, by changes to the program 3985 // that are necessary to make \.[TANGLE] work at a particular installation. 3986 // It is usually best to design your change file so that all changes to 3987 // previous modules preserve the module numbering; then everybody's version 3988 // will be consistent with the printed program. More extensive changes, 3989 // which introduce new modules, can be inserted here; then only the index 3990 // itself will get a new module number. 3991 // \xref[system dependencies] 3992 3993 // 189. Index 3994 3995 // tangle:pos tangle.web:3317:10: 3996 3997 // Here is a cross-reference table for the \.[TANGLE] processor. 3998 // All modules in which an identifier is 3999 // used are listed with that identifier, except that reserved words are 4000 // indexed only when they appear in format definitions, and the appearances 4001 // of identifiers in module names are not indexed. Underlined entries 4002 // correspond to where the identifier was declared. Error messages and 4003 // a few other things like ``ASCII code'' are indexed here too.