home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / lang / c / 13354 < prev    next >
Encoding:
Internet Message Format  |  1992-09-08  |  60.4 KB

  1. Xref: sparky comp.lang.c:13354 comp.sources.d:1252 comp.unix.wizards:3852 alt.sources:2022 misc.misc:3277
  2. Path: sparky!uunet!cis.ohio-state.edu!ucbvax!hoptoad!chongo
  3. From: chongo@hoptoad.uucp (Landon C. Noll)
  4. Newsgroups: comp.lang.c,comp.sources.d,comp.unix.wizards,alt.sources,misc.misc
  5. Subject: 1992 International Obfuscated C Code Contest winners, 3 of 4
  6. Keywords: ioccc
  7. Message-ID: <34850@hoptoad.uucp>
  8. Date: 9 Sep 92 01:41:50 GMT
  9. Expires: 28 Nov 92 00:00:00 GMT
  10. Reply-To: chongo@hoptoad.UUCP (Landon C. Noll)
  11. Organization: Nebula Consultants in San Francisco
  12. Lines: 1737
  13.  
  14. Submitted-by: chongo@toad.com (Landon Curt Noll)
  15. #
  16. # Send comments, questions, bugs to: 
  17. #
  18. #    judges@toad.com   -or-   ...!{sun,uunet,utzoo,pyramid}!hoptoad!judges
  19. #
  20. # You are strongly encouraged to read the new contest rules before
  21. # sending any entries.  The rules, and sometimes the contest Email
  22. # address itself, change over time.  A valid entry one year may
  23. # be rejected in a later year due to changes in the rules.  The typical
  24. # start date for a contest is early March.  The typical end date for a
  25. # contest is early May.
  26. #
  27. # The contest rules are posted to comp.unix.wizards, comp.lang.c,
  28. # misc.misc, alt.sources and comp.sources.d.  If you do not have access 
  29. # to these groups, or if you missed the early March posting, you may 
  30. # request a copy from the judges, via Email, at the address above.
  31. #
  32. Archive-name: ioccc.1992/part03
  33.  
  34. ---- Cut Here and unpack ----
  35. #!/bin/sh
  36. # This is part 03 of ioccc.1992
  37. if touch 2>&1 | fgrep 'amc' > /dev/null
  38.  then TOUCH=touch
  39.  else TOUCH=true
  40. fi
  41. # ============= 1992/buzzard.2.design ==============
  42. echo "x - extracting 1992/buzzard.2.design (Text)"
  43. sed 's/^X//' << 'SHAR_EOF' > 1992/buzzard.2.design &&
  44. X            FIRST & THIRD
  45. X            almost FORTH
  46. X
  47. X    FORTH is a language mostly familiar to users of "small" machines.
  48. XFORTH programs are small because they are interpreted--a function
  49. Xcall in FORTH takes two bytes.  FORTH is an extendable language--
  50. Xbuilt-in primitives are indistinguishable from user-defined
  51. X_words_.  FORTH interpreters are small because much of the system
  52. Xcan be coded in FORTH--only a small number of primitives need to
  53. Xbe implemented.  Some FORTH interpreters can also compile defined
  54. Xwords into machine code, resulting in a fast system.
  55. X
  56. X    FIRST is an incredibly small language which is sufficient for
  57. Xdefining the language THIRD, which is mostly like FORTH.  There are
  58. Xsome differences, and THIRD is probably just enough like FORTH for
  59. Xthose differences to be disturbing to regular FORTH users.
  60. X
  61. X    The only existing FIRST interpreter is written in obfuscated C,
  62. Xand rings in at under 800 bytes of source code, although through
  63. Xdeletion of whitespace and unobfuscation it can be brought to about
  64. X650 bytes.
  65. X
  66. X    This document FIRST defines the FIRST environment and primitives,
  67. Xwith relevent design decision explanations.  It secondly documents
  68. Xthe general strategies we will use to implement THIRD.  The THIRD
  69. Xsection demonstrates how the complete THIRD system is built up
  70. Xusing FIRST.
  71. X
  72. X
  73. XSection 1:  FIRST
  74. X
  75. X
  76. XEnvironment
  77. X
  78. X    FIRST implements a virtual machine.  The machine has three chunks
  79. Xof memory: "main memory", "the stack", and "string storage".  When
  80. Xthe virtual machine wishes to do random memory accesses, they come
  81. Xout of main memory--it cannot access the stack or string storage.
  82. X
  83. X    The stack is simply a standard LIFO data structure that is used
  84. Ximplicitly by most of the FIRST primitives.  The stack is made up
  85. Xof ints, whatever size they are on the host machine.
  86. X
  87. X    String storage is used to store the names of built-in and defined
  88. Xprimitives.  Separate storage is used for these because it allows
  89. Xthe C code to use C string operations, reducing C source code size.
  90. X
  91. X    Main memory is a large array of ints.  When we speak of
  92. Xaddresses, we actually mean indices into main memory.  Main memory
  93. Xis used for two things, primarily: the return stack and the dictionary.
  94. X
  95. X    The return stack is a LIFO data structure, independent of
  96. Xthe abovementioned "the stack", which is used by FIRST to keep
  97. Xtrack of function call return addresses.
  98. X
  99. X    The dictionary is a list of words.  Each word contains a header
  100. Xand a data field.  In the header is the address of the previous word,
  101. Xan index into the string storage indicating where the name of this
  102. Xword is stored, and a "code pointer".  The code pointer is simply
  103. Xan integer which names which "machine-language-primitive" implements
  104. Xthis instruction.  For example, for defined words the code pointer
  105. Xnames the "run some code" primitive, which pushes the current program
  106. Xcounter onto the return stack and sets the counter to the address of
  107. Xthe data field for this word.
  108. X
  109. X    There are several important pointers into main memory.  There is
  110. Xa pointer to the most recently defined word, which is used to start
  111. Xsearches back through memory when compiling words.  There is a pointer
  112. Xto the top of the return stack.  There is a pointer to the current
  113. Xend of the dictionary, used while compiling.
  114. X
  115. X    For the last two pointers, namely the return stack pointer and
  116. Xthe dictionary pointer, there is an important distinction: the pointers
  117. Xthemselves are stored in main memory (in FIRST's main memory).  This
  118. Xis critical, because it means FIRST programs can get at them without
  119. Xany further primitives needing to be defined.
  120. X
  121. X
  122. XInstructions
  123. X
  124. X    There are two kinds of FIRST instructions, normal instructions and
  125. Ximmediate instructions.  Immediate instructions do something significant
  126. Xwhen they are used.  Normal instructions compile a pointer to their
  127. Xexecutable part onto the end of the dictionary.  As we will see, this
  128. Xmeans that by default FIRST simply compiles things.
  129. X
  130. X  Integer Operations
  131. XSymbol    Name        Function
  132. X  -    binary minus    pop top 2 elements of stack, subtract, push
  133. X  *    multiply    pop top 2 elements of stack, multiply, push
  134. X  /    divide        pop top 2 elements of stack, divide, push
  135. X  <0    less than 0    pop top element of stack, push 1 if < 0 else 0
  136. X
  137. XNote that we can synthesize addition and negation from binary minus,
  138. Xbut we cannot synthesize a time efficient divide or multiply from it.
  139. X<0 is synthesizable, but only nonportably.
  140. X
  141. X  Memory Operations
  142. XSymbol    Name        Function
  143. X  @    fetch        pop top of stack, treat as address to push contents of
  144. X  !    store        top of stack is address, 2nd is value; store to memory
  145. X                and pop both off the stack
  146. X
  147. X  Input/Output Operations
  148. XName            Function
  149. Xecho            output top of stack through C's putchar()
  150. Xkey            push C's getchar() onto top of stack
  151. X_read            read a space-delimited word, find it in the
  152. X                dictionary, and compile a pointer to
  153. X                that word's code pointer onto the
  154. X                current end of the dictionary
  155. X
  156. XAlthough _read could be synthesized from key, we need _read to be able
  157. Xto compile words to be able to start any syntheses.
  158. X
  159. X  Execution Operations
  160. XName            Function
  161. Xexit            leave the current function: pop the return stack
  162. X                into the program counter
  163. X
  164. X  Immediate (compilation) Operations
  165. XSymbol    Name        Function
  166. X  :    define        read in the next space-delimited word, add it to
  167. X                the end of our string storage, and generate
  168. X                a header for the new word so that when it
  169. X                is typed it compiles a pointer to itself
  170. X                so that it can be executed.
  171. Ximmediate immediate    when used immediately after a name following a ':',
  172. X                makes the word being defined run whenever
  173. X                it is typed.
  174. X
  175. X: cannot be synthesized, because we could not synthesize anything.
  176. Ximmediate has to be an immediate operation, so it could not be
  177. Xsynthesized unless by default operations were immediate; but that
  178. Xwould preclude our being able to do any useful compilation.
  179. X
  180. X  Stack Operations
  181. XName            Function
  182. Xpick            pop top of stack, use as index into stack and copy up
  183. X                that element
  184. X
  185. XIf the data stack were stored in main memory, we could synthesize pick;
  186. Xbut putting the stack and stack pointer in main memory would significantly
  187. Xincrease the C source code size.
  188. X
  189. X    There are three more primitives, but they are "internal only"--
  190. Xthey have no names and no dictionary entries.  The first is
  191. X"pushint".  It takes the next integer out of the instruction stream
  192. Xand pushes it on the stack.  This could be synthesized, but probably
  193. Xnot without using integer constants.  It is generated by _read when
  194. Xthe input is not a known word.  The second is "compile me".  When
  195. Xthis instruction is executed, a pointer to the word's data field is
  196. Xappended to the dictionary.  The third is "run me"--the word's data
  197. Xfield is taken to be a stream of pointers to words, and is executed.
  198. X
  199. X    One last note about the environment: FIRST builds a very small
  200. Xword internally that it executes as its main loop.  This word calls
  201. X_read and then calls itself.  Each time it calls itself, it uses
  202. Xup a word on the return stack, so it will eventually trash things.
  203. XThis is discussed some more in section 2.
  204. X
  205. X
  206. XHere's a handy summary of all the FIRST words:
  207. X
  208. X    - * /        binary integer operations on the stack
  209. X    <0        is top of stack less than 0?
  210. X    @ !        read from or write to memory
  211. X    echo key    output or input one character
  212. X    _read        read a word from input and compile a pointer to it
  213. X    exit        stop running the current function
  214. X    :        compile the header of a definition
  215. X    immediate    modify the header to create an immediate word
  216. X
  217. X    Here is a sample FIRST program.  I'm assuming you're using
  218. Xthe ASCII character set.  FIRST does not depend upon ASCII, but
  219. Xsince FIRST has no syntax for character constants, one normally has
  220. Xto use decimal values.  This can be gotten around using getchar, though.
  221. XOh.  One other odd thing.  FIRST initially builds its symbol table
  222. Xby calling : several times, so it needs to get the names of the base
  223. Xsymbols as its first 13 words of input.  You could even name them
  224. Xdifferently if you wanted.
  225. X    These FIRST programs have FORTH comments in them: they are contained
  226. Xinside parentheses.  FIRST programs cannot have FORTH comments; but I need
  227. Xsome device to indicate what's going on.  (THIRD programs are an entirely
  228. Xdifferent subject.)
  229. X
  230. X    ( Our first line gives the symbols for the built-ins )
  231. X: immediate _read @ ! - * / <0 exit echo key _pick
  232. X
  233. X    ( now we define a simple word that will print out a couple characters )
  234. X
  235. X: L            ( define a word named 'L' )
  236. X  108 echo        ( output an ascii 'l' )
  237. X  exit
  238. X
  239. X: hello            ( define a word named 'hello')
  240. X  72 echo        ( output an ascii 'H' )
  241. X  101 echo        ( output an ascii 'e' )
  242. X  111            ( push ascii 'o' onto the stack )
  243. X  L L            ( output two ascii 'l's )
  244. X  echo            ( output the 'o' we pushed on the stack before )
  245. X  10 echo        ( print a newline )
  246. X  exit            ( stop running this routine )
  247. X
  248. X: test immediate    ( define a word named 'test' that runs whenever typed )
  249. X  hello            ( call hello )
  250. X  exit
  251. X
  252. Xtest
  253. X
  254. X( The result of running this program should be: 
  255. XHello
  256. X)
  257. X
  258. X
  259. XSection 2: Motivating THIRD
  260. X
  261. X    What is missing from FIRST?  There are a large number of
  262. Ximportant primitives that aren't implemented, but which are
  263. Xeasy to implement.  drop , which throws away the top of the
  264. Xstack, can be implemented as { 0 * + } -- that is, multiply
  265. Xthe top of the stack by 0 (which turns the top of the stack
  266. Xinto a 0), and then add the top two elements of the stack.
  267. X
  268. X    dup , which copies the top of the stack, can be easily
  269. Ximplemented using temporary storage locations.  Conveniently,
  270. XFIRST leaves memory locations 3, 4, and 5 unused.  So we can
  271. Ximplement dup by writing the top of stack into 3, and then
  272. Xreading it out twice: { 3 ! 3 @ 3 @ }.
  273. X
  274. X    we will never use the FIRST primitive 'pick' in building THIRD,
  275. Xjust to show that it can be done; 'pick' is only provided because
  276. Xpick itself cannot be built out of the rest of FIRST's building
  277. Xblocks.
  278. X
  279. X    So, instead of worrying about stack primitives and the
  280. Xlike, what else is missing from FIRST?  We get recursion, but
  281. Xno control flow--no conditional operations.  We cannot at the
  282. Xmoment write a looping routine which terminates.
  283. X
  284. X    Another glaring dissimilarity between FIRST and FORTH is
  285. Xthat there is no "command mode"--you cannot be outside of a
  286. X: definition and issue some straight commands to be executed.
  287. XAlso, as we noted above, we cannot do comments.
  288. X
  289. X    FORTH also provides a system for defining new data types,
  290. Xusing the words [in one version of FORTH] <builds and does> .
  291. XWe would like to implement these words as well.
  292. X
  293. X    As the highest priority thing, we will build control flow
  294. Xstructures first.  Once we have control structures, we can
  295. Xwrite recursive routines that terminate, and we are ready to
  296. Xtackle tasks like parsing, and the building of a command mode.
  297. X
  298. X    By the way, location 0 holds the dictionary pointer, location
  299. X1 holds the return stack pointer, and location 2 should always
  300. Xbe 0--it's a fake dictionary entry that means "pushint".
  301. X
  302. X
  303. XSection 3: Building THIRD
  304. X
  305. X        In this section, I'm going to keep my conversation
  306. X        indented to this depth, rather than using fake comments--
  307. X        because we'll have real comments eventually.
  308. X
  309. X        The first thing we have to do is give the symbols for our
  310. X        built-ins.
  311. X
  312. X: immediate _read @ ! - * / < exit echo key _pick
  313. X
  314. X        Next we want to be mildly self commenting, so we define
  315. X        the word 'r' to push the *address of the return stack
  316. X        pointer* onto the stack--NOT the value of the return 
  317. X        stack pointer.  (In fact, when we run r, the value of
  318. X        the return stack pointer is temporarily changed.)
  319. X
  320. X: r 1 exit
  321. X
  322. X        Next, we're currently executing a short loop that contains
  323. X        _read and recursion, which is slowly blowing up the return
  324. X        stack.  So let's define a new word, from which you can
  325. X        never return.  What it does is drops the top value off
  326. X        the return stack, calls _read, then calls itself.  Because
  327. X        it kills the top of the return stack, it can recurse
  328. X        indefinitely.
  329. X
  330. X: ]
  331. X  r @            Get the value of the return stack pointer
  332. X  1 -            Subtract one
  333. X  r !            Store it back into the return stack pointer
  334. X  _read            Read and compile one word
  335. X  ]            Start over
  336. X
  337. X        Notice that we don't need to exit, since we never come
  338. X        back.  Also, it's possible that an immediate word may
  339. X        get run during _read, and that _read will never return!
  340. X
  341. X        Now let's get compile running.
  342. X
  343. X: main immediate ]
  344. Xmain
  345. X
  346. X        Next off, I'm going to do this the easy but non-portable
  347. X        way, and put some character constant definitions in.
  348. X        I wanted them at the top of the file, but that would have
  349. X        burned too much of the return stack.
  350. X
  351. X: '"'    34    exit
  352. X: ')'    41    exit
  353. X: '\n'    10    exit
  354. X: 'space' 32    exit
  355. X: '0'    48    exit
  356. X: '-'    45    exit
  357. X
  358. X: cr '\n' echo exit
  359. X
  360. X        Next, we want to define some temporary variables for
  361. X        locations 3, 4, and 5, since this'll make our code look
  362. X        clearer.
  363. X: _x 3 @ exit
  364. X: _x! 3 ! exit
  365. X: _y 4 @ exit
  366. X: _y! 4 ! exit
  367. X
  368. X        Ok.  Now, we want to make THIRD look vaguely like FORTH,
  369. X        so we're going to define ';'.  What ; ought to do is
  370. X        terminate a compilation, and turn control over to the
  371. X        command-mode handler.  We don't have one, so all we want
  372. X        ';' to do for now is compile 'exit' at the end of the
  373. X        current word.  To do this we'll need several other words.
  374. X        
  375. X        Swap by writing out the top two elements into temps, and
  376. X        then reading them back in the other order.
  377. X: swap _x! _y! _x _y exit
  378. X        Take another look and make sure you see why that works,
  379. X        since it LOOKS like I'm reading them back in the same
  380. X        order--in fact, it not only looks like it, but I AM!
  381. X
  382. X        Addition might be nice to have.  To add, we need to
  383. X        negate the top element of the stack, and then subtract.
  384. X        To negate, we subtract from 0.
  385. X: +
  386. X  0 swap -
  387. X  -
  388. X  exit
  389. X
  390. X        Create a copy of the top of stack
  391. X: dup _x! _x _x exit
  392. X
  393. X        Get a mnemonic name for our dictionary pointer--we need
  394. X        to compile stuff, so it goes through this.
  395. X: h 0 exit
  396. X
  397. X        We're going to need to advance that pointer, so let's
  398. X        make a generic pointer-advancing function.
  399. X        Given a pointer to a memory location, increment the value
  400. X        at that memory location.
  401. X: inc
  402. X  dup @            Get another copy of the address, and get the value
  403. X            so now we have value, address on top of stack.
  404. X  1 +            Add one to the value
  405. X  swap            Swap to put the address on top of the stack
  406. X  ! exit        Write it to memory
  407. X
  408. X        , is a standard FORTH word.  It should write the top of 
  409. X        stack into the dictionary, and advance the pointer
  410. X: ,
  411. X  h @            Get the value of the dictionary pointer
  412. X  !            Write the top of stack there
  413. X  h inc            And increment the dictionary pointer
  414. X  exit
  415. X
  416. X        ' is a standard FORTH word.  It should push the address
  417. X        of the word that follows it onto the stack.  We could
  418. X        do this by making ' immediate, but then it'd need to
  419. X        parse the next word.  Instead, we compile the next word
  420. X        as normal.  When ' is executed, the top of the return
  421. X        stack will point into the instruction stream immediately
  422. X        after the ' .  We push the word there, and advance the
  423. X        return stack pointer so that we don't execute it.
  424. X: '
  425. X  r @            Get the address of the top of return stack
  426. X            We currently have a pointer to the top of return stack
  427. X  @            Get the value from there
  428. X            We currently have a pointer to the instruction stream
  429. X  dup            Get another copy of it--the bottom copy will stick
  430. X                around until the end of this word
  431. X  1 +            Increment the pointer, pointing to the NEXT instruction
  432. X  r @ !            Write it back onto the top of the return stack
  433. X            We currently have our first copy of the old pointer
  434. X                to the instruction stream
  435. X  @            Get the value there--the address of the "next word"
  436. X  exit
  437. X
  438. X        Now we're set.  ; should be an immediate word that pushes
  439. X        the address of exit onto the stack, then writes it out.
  440. X: ; immediate
  441. X  ' exit         Get the address of exit
  442. X  ,            Compile it
  443. X  exit            And we should return
  444. X
  445. X        Now let's test out ; by defining a useful word:
  446. X: drop 0 * + ;
  447. X
  448. X        Since we have 'inc', we ought to make 'dec':
  449. X: dec dup @ 1 - swap ! ;
  450. X
  451. X        Our next goal, now that we have ;, is to implement
  452. X        if-then.  To do this, we'll need to play fast and
  453. X        loose with the return stack, so let's make some
  454. X        words to save us some effort.
  455. X
  456. X        First we want a word that pops off the top of the normal
  457. X        stack and pushes it on top of the return stack.  We'll
  458. X        call this 'tor', for TO-Return-stack.   It sounds easy,
  459. X        but when tor is running, there's an extra value on the
  460. X        return stack--tor's return address!  So we have to pop
  461. X        that off first...  We better just bite the bullet and
  462. X        code it out--but we can't really break it into smaller
  463. X        words, because that'll trash the return stack.
  464. X: tor
  465. X  r @ @            Get the value off the top of the return stack
  466. X  swap            Bring the value to be pushed to the top of stack
  467. X  r @ !            Write it over the current top of return stack
  468. X  r @ 1 + r !        Increment the return stack pointer--but can't use inc
  469. X  r @ !            Store our return address back on the return stack
  470. X;
  471. X
  472. X        Next we want the opposite routine, which pops the top
  473. X        of the return stack, and puts it on the normal stack.
  474. X: fromr
  475. X  r @ @            Save old value
  476. X  r @ 1 - r !        Decrement pointer
  477. X  r @ @            Get value that we want off
  478. X  swap            Bring return address to top
  479. X  r @ !            Store it and return
  480. X;
  481. X
  482. X        Now, if we have a routine that's recursing, and we
  483. X        want to be polite about the return stack, right before
  484. X        we recurse we can run { fromr drop } so the stack won't
  485. X        blow up.  This means, though, that the first time we
  486. X        enter this recursive routine, we blow our *real* return
  487. X        address--so when we're done, we'll return up two levels.
  488. X        To save a little, we make 'tail' mean { fromr drop };
  489. X        however, it's more complex since there's a new value on
  490. X        top of the return stack.
  491. X: tail fromr fromr drop tor ;
  492. X
  493. X        Now, we want to do 'if'.  To do this, we need to convert
  494. X        values to boolean values.  The next few words set this
  495. X        up.    
  496. X
  497. X        minus gives us unary negation.
  498. X: minus 0 swap - ;
  499. X
  500. X        If top of stack is boolean, bnot gives us inverse
  501. X: bnot 1 swap - ;
  502. X
  503. X        To compare two numbers, subtract and compare to 0.
  504. X: < - <0 ;
  505. X
  506. X        logical turns the top of stack into either 0 or 1.
  507. X: logical
  508. X  dup            Get two copies of it
  509. X  0 <            1 if < 0, 0 otherwise
  510. X  swap minus        Swap number back up, and take negative
  511. X  0 <            1 if original was > 0, 0 otherwise
  512. X  +            Add them up--has to be 0 or 1!
  513. X;
  514. X
  515. X        not returns 1 if top of stack is 0, and 0 otherwise
  516. X: not logical bnot ;
  517. X
  518. X        We can test equality by subtracting and comparing to 0.
  519. X: = - not ;
  520. X
  521. X        Just to show how you compute a branch:  Suppose you've
  522. X        compiled a call to branch, and immediately after it is
  523. X        an integer constant with the offset of how far to branch.
  524. X        To branch, we use the return stack to read the offset, and
  525. X        add that on to the top of the return stack, and return.
  526. X: branch
  527. X  r @            Address of top of return stack
  528. X  @            Our return address
  529. X  @            Value from there: the branch offset
  530. X  r @ @            Our return address again
  531. X  +            The address we want to execute at
  532. X  r @ !            Store it back onto the return stack
  533. X;
  534. X
  535. X        For conditional branches, we want to branch by a certain
  536. X        amount if true, otherwise we want to skip over the branch
  537. X        offset constant--that is, branch by one.  Assuming that
  538. X        the top of the stack is the branch offset, and the second
  539. X        on the stack is 1 if we should branch, and 0 if not, the
  540. X        following computes the correct branch offset.
  541. X: computebranch 1 - * 1 + ;
  542. X
  543. X        Branch if the value on top of the stack is 0.
  544. X: notbranch
  545. X  not
  546. X  r @ @ @        Get the branch offset
  547. X  computebranch        Adjust as necessary
  548. X  r @ @ +        Calculate the new address
  549. X  r @ !            Store it
  550. X;
  551. X
  552. X        here is a standard FORTH word which returns a pointer to
  553. X        the current dictionary address--that is, the value of
  554. X        the dictionary pointer.
  555. X: here h @ ;
  556. X
  557. X        We're ALL SET to compile if...else...then constructs!
  558. X        Here's what we do.  When we get 'if', we compile a call
  559. X        to notbranch, and then compile a dummy offset, because
  560. X        we don't know where the 'then' will be.  On the *stack*
  561. X        we leave the address where we compiled the dummy offset.
  562. X        'then' will calculate the offset and fill it in for us.
  563. X: if immediate
  564. X  ' notbranch ,        Compile notbranch
  565. X  here            Save the current dictionary address
  566. X  0 ,            Compile a dummy value
  567. X;
  568. X
  569. X        then expects the address to fixup to be on the stack.
  570. X: then immediate
  571. X  dup            Make another copy of the address
  572. X  here            Find the current location, where to branch to
  573. X  swap -        Calculate the difference between them
  574. X  swap !        Bring the address to the top, and store it.
  575. X;
  576. X
  577. X        Now that we can do if...then statements, we can do
  578. X        some parsing!  Let's introduce real FORTH comments.
  579. X        find-) will scan the input until it finds a ), and
  580. X        exit.
  581. X: find-)
  582. X  key            Read in a character
  583. X  ')' =            Compare it to close parentheses
  584. X  not if        If it's not equal
  585. X    tail find-)        repeat (popping R stack)
  586. X  then            Otherwise branch here and exit
  587. X;
  588. X
  589. X: ( immediate
  590. X  find-)
  591. X;
  592. X
  593. X( we should be able to do FORTH-style comments now )
  594. X
  595. X( now that we've got comments, we can comment the rest of the code
  596. X  in a legitimate [self parsing] fashion.  Note that you can't
  597. X  nest parentheses... )
  598. X
  599. X: else immediate
  600. X  ' branch ,        ( compile a definite branch )
  601. X  here            ( push the backpatching address )
  602. X  0 ,            ( compile a dummy offset for branch )
  603. X  swap            ( bring old backpatch address to top )
  604. X  dup here swap -    ( calculate the offset from old address )
  605. X  swap !        ( put the address on top and store it )
  606. X;
  607. X
  608. X: over _x! _y! _y _x _y ;
  609. X
  610. X: add
  611. X  _x!            ( save the pointer in a temp variable )
  612. X  _x @            ( get the value pointed to )
  613. X  +            ( add the incremement from on top of the stack )
  614. X  _x !            ( and save it )
  615. X;
  616. X
  617. X: allot    h add ;
  618. X
  619. X: maybebranch
  620. X  logical        ( force the TOS to be 0 or 1 )
  621. X  r @ @ @        ( load the branch offset )
  622. X  computebranch        ( calculate the condition offset [either TOS or 1])
  623. X  r @ @ +        ( add it to the return address )
  624. X  r @ !            ( store it to our return address and return )
  625. X;
  626. X
  627. X: mod _x! _y!        ( get x then y off of stack )
  628. X  _y _y _x / _x *    ( y - y / x * x )
  629. X  -
  630. X;
  631. X
  632. X: printnum
  633. X  dup
  634. X  10 mod '0' +
  635. X  swap 10 / dup
  636. X  if
  637. X    printnum
  638. X    echo
  639. X  else
  640. X    drop
  641. X    echo
  642. X  then
  643. X;
  644. X
  645. X: .
  646. X  dup 0 <
  647. X  if
  648. X    '-' echo minus
  649. X  then
  650. X  printnum
  651. X  'space' echo
  652. X;
  653. X
  654. X: debugprint dup . cr ;
  655. X
  656. X( the following routine takes a pointer to a string, and prints it,
  657. X  except for the trailing quote.  returns a pointer to the next word
  658. X  after the trailing quote )
  659. X
  660. X: _print
  661. X  dup 1 +
  662. X  swap @
  663. X  dup '"' =
  664. X  if
  665. X    drop exit
  666. X  then
  667. X  echo
  668. X  tail _print
  669. X;
  670. X
  671. X: print _print ;
  672. X
  673. X  ( print the next thing from the instruction stream )
  674. X: immprint
  675. X  r @ @
  676. X  print
  677. X  r @ !
  678. X;
  679. X
  680. X: find-"
  681. X  key dup ,
  682. X  '"' =
  683. X  if
  684. X    exit
  685. X  then
  686. X  tail find-"
  687. X;
  688. X
  689. X: " immediate
  690. X  key drop
  691. X  ' immprint ,
  692. X  find-"
  693. X;
  694. X
  695. X: do immediate
  696. X  ' swap ,        ( compile 'swap' to swap the limit and start )
  697. X  ' tor ,        ( compile to push the limit onto the return stack )
  698. X  ' tor ,        ( compile to push the start on the return stack )
  699. X  here            ( save this address so we can branch back to it )
  700. X;
  701. X
  702. X: i r @ 1 - @ ;
  703. X: j r @ 3 - @ ;
  704. X
  705. X: > swap < ;
  706. X: <= 1 + < ;
  707. X: >= swap <= ;
  708. X
  709. X: inci 
  710. X  r @ 1 -     ( get the pointer to i )
  711. X  inc        ( add one to it )
  712. X  r @ 1 - @     ( find the value again )
  713. X  r @ 2 - @    ( find the limit value )
  714. X  <=
  715. X  if
  716. X    r @ @ @ r @ @ + r @ ! exit        ( branch )
  717. X  then
  718. X  fromr 1 +
  719. X  fromr drop
  720. X  fromr drop
  721. X  tor
  722. X;
  723. X
  724. X: loop immediate ' inci @ here - , ;
  725. X
  726. X: loopexit
  727. X
  728. X  fromr drop        ( pop off our return address )
  729. X  fromr drop        ( pop off i )
  730. X  fromr drop        ( pop off the limit of i )
  731. X;            ( and return to the caller's caller routine )
  732. X
  733. X: execute
  734. X  8 !
  735. X  ' exit 9 !
  736. X  8 tor
  737. X;
  738. X
  739. X: :: ;          ( :: is going to be a word that does ':' at runtime )
  740. X
  741. X: fix-:: immediate 3 ' :: ! ;
  742. Xfix-::
  743. X
  744. X        ( Override old definition of ':' with a new one that invokes ] )
  745. X: : immediate :: ] ;
  746. X
  747. X: command
  748. X  here 5 !              ( store dict pointer in temp variable )
  749. X  _read                 ( compile a word )
  750. X                        ( if we get control back: )
  751. X  here 5 @
  752. X  = if
  753. X    tail command        ( we didn't compile anything )
  754. X  then
  755. X  here 1 - h !          ( decrement the dictionary pointer )
  756. X  here 5 @              ( get the original value )
  757. X  = if
  758. X    here @              ( get the word that was compiled )
  759. X    execute             ( and run it )
  760. X  else
  761. X    here @              ( else it was an integer constant, so push it )
  762. X    here 1 - h !        ( and decrement the dictionary pointer again )
  763. X  then
  764. X  tail command
  765. X;
  766. X
  767. X: make-immediate        ( make a word just compiled immediate )
  768. X  here 1 -              ( back up a word in the dictionary )
  769. X  dup dup               ( save the pointer to here )
  770. X  h !                   ( store as the current dictionary pointer )
  771. X  @                     ( get the run-time code pointer )
  772. X  swap                  ( get the dict pointer again )
  773. X  1 -                   ( point to the compile-time code pointer )
  774. X  !                     ( write run-time code pointer on compile-time pointer )
  775. X;
  776. X
  777. X: <build immediate
  778. X  make-immediate        ( make the word compiled so far immediate )
  779. X  ' :: ,                ( compile '::', so we read next word )
  780. X  2 ,                   ( compile 'pushint' )
  781. X  here 0 ,              ( write out a 0 but save address for does> )
  782. X  ' , ,                 ( compile a push that address onto dictionary )
  783. X;
  784. X
  785. X: does> immediate
  786. X  ' command ,           ( jump back into command mode at runtime )
  787. X  here swap !           ( backpatch the build> to point to here )
  788. X  2 ,                   ( compile run-code primitive so we look like a word )
  789. X  ' fromr ,             ( compile fromr, which leaves var address on stack )
  790. X;
  791. X
  792. X
  793. X: _dump                 ( dump out the definition of a word, sort of )
  794. X  dup " (" . " , "
  795. X  dup @                 ( save the pointer and get the contents )
  796. X  dup ' exit
  797. X  = if
  798. X        " ;)" cr exit
  799. X  then
  800. X  . " ), "
  801. X  1 +
  802. X  tail _dump
  803. X;
  804. X
  805. X: dump _dump ;
  806. X
  807. X: # . cr ;
  808. X  
  809. X: var <build , does> ;
  810. X: constant <build , does> @ ;
  811. X: array <build allot does> + ;
  812. X
  813. X: [ immediate command ;
  814. X: _welcome " Welcome to THIRD.
  815. XOk.
  816. X" ;
  817. X
  818. X: ; immediate ' exit , command exit
  819. X
  820. X[
  821. X
  822. X_welcome
  823. X
  824. SHAR_EOF
  825. $TOUCH -am 0908155392 1992/buzzard.2.design &&
  826. chmod 0444 1992/buzzard.2.design ||
  827. echo "restore of 1992/buzzard.2.design failed"
  828. set `wc -c 1992/buzzard.2.design`;Wc_c=$1
  829. if test "$Wc_c" != "25773"; then
  830.     echo original size 25773, current size $Wc_c
  831. fi
  832. # ============= 1992/buzzard.2.hint ==============
  833. echo "x - extracting 1992/buzzard.2.hint (Text)"
  834. sed 's/^X//' << 'SHAR_EOF' > 1992/buzzard.2.hint &&
  835. XBest Language Tool: <sean@stat.tamu.edu> Sean Barrett
  836. X
  837. X    Sean Barrett
  838. X    Software Construction Company
  839. X    430 Southwest Parkway, #1906
  840. X    College Station, TX 77840
  841. X    USA
  842. X
  843. X        Direct bounced email to <jon@stat.tamu.edu>.
  844. X
  845. XJudges' comments:
  846. X
  847. X    First:
  848. X    make first
  849. X    
  850. X    Second:
  851. X    echo help | cat third help.th - | first
  852. X    cat third demo5.th | first
  853. X    
  854. X    Third:
  855. X    cat third help.th - | first
  856. X
  857. X    Wait until Ok is printed and the type:
  858. X        2 3 + . cr        <-- yes you should really type the 2 letters: cr
  859. X
  860. X    Forth:
  861. X    Sorry, this is third!
  862. X
  863. X
  864. XSelected notes from the author:
  865. X
  866. X    What it does:
  867. X
  868. X        first implements a relatively primitive stack machine.  How
  869. X        primitive?  It supplies 13 visible primitives: 3 arithmetic,
  870. X        1 comparison, 2 memory-access, 2 character I/O, 3 primitives
  871. X        for defining new words, 1 tokenizing, and 1 special stack
  872. X        operation.  (There are also three internal operations for
  873. X        the stack machine: 'push this integer', 'call this code',
  874. X        and 'compile a call to this code'.)
  875. X
  876. X        It is very difficult to accomplish anything with this set
  877. X        of primitives, but they do have an interesting property.
  878. X
  879. X        This--what this interesting property is, or in other words
  880. X        what first is good for--is the major obfuscation; there are
  881. X        also minor source obfuscations, as well as some design tricks
  882. X        that are effectively obfuscations.  Details on the obfuscations
  883. X        are below, and the interesting property is discussed much
  884. X        further down.
  885. X
  886. X
  887. X    How to run it:
  888. X
  889. X        first expects you to first enter the names of the 13 primitives,
  890. X        separated by whitespace--it doesn't care what you name them, but
  891. X        if all the names aren't unique, you won't be able to use some of
  892. X        them.  After this you may type any sequence of valid first input.
  893. X        Valid first input is defined as any sequence of whitespace-delimited
  894. X        tokens which consist of primitives, new words you've defined, and
  895. X        integers (as parsed by "%d").  Invalid input behaves unpredictably,
  896. X        but gives no warning messages.  A sample program, demo1.1st, is
  897. X        included, but it only works on ASCII systems.
  898. X
  899. X        Do not expect to be able to do anything interesting with first.
  900. X
  901. X        To do something interesting, you need to feed first the file
  902. X        third first.  In unix, you can do
  903. X
  904. X                % cat third help.th - | first
  905. X
  906. X        to do this.  Hopefully most operating systems will provide a
  907. X        way to do this.  It may take some time for this to complete
  908. X    (I seem to remember it taking several minutes on an 8086 PC);
  909. X        THIRD will prompt you when it is finished.  The file third has
  910. X        not been obfuscated, due to sheer kindness on the author's part.
  911. X
  912. X        For more information on what you can do once you've piped
  913. X        THIRD into first, type 'help' and consult FORTH manuals for
  914. X        further reference.  Six sample THIRD programs are included
  915. X    in the files demo[1-6].th.  buzzard.2.README has more
  916. X    information.
  917. X
  918. X        Keep in mind that you are still running first, and
  919. X        are for the most part limited by first's tokenizer
  920. X        (notably, unknown words will attempt to be parsed as
  921. X        integers.)  It is possible to build a new parser that
  922. X        parses by hand, reading a single character at a time;
  923. X    however, such a parser cannot easily use the existing
  924. X    dictionary, and so would have to implement its own,
  925. X    thus requiring reimplementing all of first and third
  926. X    a second time--I did not care to tackle this project.
  927. X
  928. X
  929. X    Compiling:
  930. X
  931. X        first is reasonably portable.  You may need to adjust the
  932. X        size of the buffers on smaller machines; m[] needs to be
  933. X        at least 2000 long, though.
  934. X
  935. X        I say first is portable mainly because it uses native types.
  936. X        Unlike FORTH, which traditionally allows byte and multi-byte
  937. X        operations, all operations are performed on C 'int's.  That
  938. X        means first code is only as portable as the same code would
  939. X        be in C.  As in C, the result of dividing -1 by 2 is machine
  940. X        (or rather compiler) dependent.
  941. X
  942. X    How is first obfuscated?
  943. X
  944. X        first is obfuscated in several ways.  Some minor obfuscations
  945. X        like &w[&m[1]][s] for s+m[w+1] were in the original source
  946. X    but are no longer because, apparently, ANSI doesn't allow it
  947. X    (gcc -ansi -pedantic doesn't mind it, though.)
  948. X    Other related obfuscations are still present.  The top of the
  949. X    stack is cached in a variable, which increases performance
  950. X    massively if the compiler can figure out to keep it in a register;
  951. X    it also obfuscates the code.  (Unfortunately, the top of stack
  952. X    is a global variable and neither gcc nor most bundled compilers
  953. X    seem to register allocate it.)
  954. X    
  955. X        More significant are the design obfuscations.  m[0] is the
  956. X        "dictionary pointer", used when compiling words, and m[1] is
  957. X        the return stack index.  Both are used as integer offsets into
  958. X        m.  Both are kept in m, instead of as separate pointers,
  959. X        because they are then accessible to first programs, which is a
  960. X        crucial property of first.  Similarly the way words are stored
  961. X        in the dictionary is not obvious, so it can be difficult to
  962. X        follow exactly what the compiler words are doing.
  963. X
  964. X        Assuming you've waded through all that, you still have
  965. X        to penetrate the most significant obfuscation.  Traditionally,
  966. X        the question is whether a reader can answer the question "what
  967. X        will this do when I run it".  A reader who has deciphered first
  968. X        to this point may think they know the answer to this question,
  969. X        but they may not know the answer to the more important question,
  970. X        "what will this program do when given the right input?"  FORTH
  971. X        afficianados, and especially FORTH implementors, may recognize
  972. X        the similarity of the internal compiler format to many FORTH
  973. X        interal representations, and, being aware that FORTH interpreters
  974. X        can often by self-compiling, may be suspicious that this program
  975. X        can compile FORTH, or a significant subset of it, or at least be
  976. X        capable of doing so if fed the right input.  Of course, the name
  977. X        "THIRD" should be a dead giveaway, if the name "first" wasn't.
  978. X        (These numbers were largely chosed because they were five letters
  979. X        long, like "FORTH", and would not require truncation to five
  980. X        letters, which would be a dead giveaway.  Besides, THIRD represents
  981. X        a step backwards, in more ways than one.)
  982. X
  983. X
  984. X    What exactly is first, then?
  985. X
  986. X    first is a tiny interpreter which implements a sufficient
  987. X    pseudo-subset of FORTH to allow it to bootstrap a relatively
  988. X    complete version of FORTH (based loosely on forth79), which
  989. X    I call THIRD.  Complete relative to what, I'm not sure.
  990. X
  991. X    I believe first is close to the smallest amount of code possible
  992. X    to get this effect *using forth-style primitives*, and still have
  993. X    some efficiency (it is possible to get by without multiplication
  994. X    if you have addition, obviously).  In the design file, design,
  995. X    I give a justification for why each primitive in first was included.
  996. X
  997. X    THIRD is sorta slow, because first has so few primitives that
  998. X    many things that are primitives in FORTH (like swap) take a
  999. X    significant amount of time in THIRD.
  1000. X
  1001. X    When you get the 'Ok.' message from third, try out some sample
  1002. X    FORTH code (first has no way of knowing if keyboard input is
  1003. X    waiting, so it can't actually prompt you in a normal way.  It
  1004. X    only prints 'Ok.' after you define a word).
  1005. X
  1006. X        2 3 + . cr    ( add 2 and 3, and print it and a newline.)
  1007. X
  1008. X    and THIRD responds
  1009. X
  1010. X        5
  1011. X
  1012. X    Now try:
  1013. X
  1014. X        : test 11 1 do i . loop cr ;
  1015. X        test
  1016. X
  1017. X    and THIRD responds
  1018. X
  1019. X        1 2 3 4 5 6 7 8 9 10
  1020. X
  1021. X
  1022. X    When in THIRD, you can see how much space you're currently
  1023. X    using by typing
  1024. X
  1025. X        here .
  1026. X
  1027. X    The number THIRD replies is the number of machine words (ints)
  1028. X    that the dictionary (the first code) takes up, plus the
  1029. X    512 ints for the return stack.  If you compile the basic
  1030. X    THIRD system without the help word (strings take up one
  1031. X    int per character in the string!), you should find that
  1032. X    you're using around 1000 ints (plus the return stack).
  1033. X
  1034. X    Thus THIRD gives you a relatively complete FORTH system in
  1035. X    less than 700 chars of C source + about 1000 ints of
  1036. X    memory--and it's portable too (you could copy over the
  1037. X    THIRD memory dump to another machine, in theory).  If the
  1038. X    above numbers seem to you to be mixing apples and oranges
  1039. X    (C source and compiled THIRD code), note that you should
  1040. X    in theory be able to stick the compiled THIRD code into
  1041. X    the C source.
  1042. X
  1043. X
  1044. X    Software Construction Company gets credit for rekindling
  1045. X    my interest in FORTH and thus indirectly inspiring me
  1046. X    to write this program.
  1047. SHAR_EOF
  1048. $TOUCH -am 0908160292 1992/buzzard.2.hint &&
  1049. chmod 0444 1992/buzzard.2.hint ||
  1050. echo "restore of 1992/buzzard.2.hint failed"
  1051. set `wc -c 1992/buzzard.2.hint`;Wc_c=$1
  1052. if test "$Wc_c" != "8915"; then
  1053.     echo original size 8915, current size $Wc_c
  1054. fi
  1055. # ============= 1992/buzzard.2.orig.c ==============
  1056. echo "x - extracting 1992/buzzard.2.orig.c (Text)"
  1057. sed 's/^X//' << 'SHAR_EOF' > 1992/buzzard.2.orig.c &&
  1058. X#define c 0 [m] ++ [m] =
  1059. X#define z;break;case
  1060. X
  1061. Xchar s[5000];
  1062. Xint m[20000]={32},L=1,I,T[500],*S=T,t=64,w,f;
  1063. X
  1064. Xa(x)
  1065. X{
  1066. X   c L;
  1067. X   L= *m-1;
  1068. X   c t;
  1069. X   c x;
  1070. X   scanf("%s",s+t);
  1071. X   t+=strlen(s+t)+1;
  1072. X}
  1073. X
  1074. Xr(x)
  1075. X{
  1076. X   switch(x++[m]){
  1077. X    z 5:    for(w=scanf("%s",s)<1?exit(0):L;strcmp(s,&w[&m[1]][s]);w=m[w]);
  1078. X        w-1 ? r(w+2) : (c 2,c atoi(s))
  1079. X    z 12:    I=1[m]--[m]
  1080. X    z 15:    f=S[-f]
  1081. X    z 1:    c x 
  1082. X    z 9:    f *=* S--
  1083. X    z 7:    m[f]= *S--;
  1084. X        f= *S--
  1085. X    z 0:    *++S=f;
  1086. X        f=I++[m]
  1087. X    z 8:    f= *S --- f
  1088. X    z 2:    m[++1[m]]=I;
  1089. X        I=x
  1090. X    z 11:    f=0>f
  1091. X    z 4:    *m-=2;c 2
  1092. X    z 6:    f=f[m]
  1093. X    z 10:    f= *S--/f
  1094. X    z 3:    a(1);
  1095. X        c 2
  1096. X    z 13:    putchar(f);
  1097. X        f= *S--
  1098. X    z 14:    *++S=f;
  1099. X        f=getchar();
  1100. X   }
  1101. X}
  1102. X
  1103. Xmain()
  1104. X{
  1105. X   a(3);
  1106. X   a(4);
  1107. X   a(1);
  1108. X   w= *m;
  1109. X   c 5;
  1110. X   c 2;
  1111. X   I= *m;
  1112. X   c w;
  1113. X   c I-1;
  1114. X   for(w=6;w<16;)
  1115. X      a(1),c w++;
  1116. X   m[1]= *m;
  1117. X   for(*m+=512;;r(m[I++]));
  1118. X}
  1119. SHAR_EOF
  1120. $TOUCH -am 0817110092 1992/buzzard.2.orig.c &&
  1121. chmod 0444 1992/buzzard.2.orig.c ||
  1122. echo "restore of 1992/buzzard.2.orig.c failed"
  1123. set `wc -c 1992/buzzard.2.orig.c`;Wc_c=$1
  1124. if test "$Wc_c" != "794"; then
  1125.     echo original size 794, current size $Wc_c
  1126. fi
  1127. # ============= 1992/demo1.1st ==============
  1128. echo "x - extracting 1992/demo1.1st (Text)"
  1129. sed 's/^X//' << 'SHAR_EOF' > 1992/demo1.1st &&
  1130. X: immediate _read @ ! - * / <0 exit echo key _pick
  1131. X
  1132. X: show echo echo echo echo exit
  1133. X: all show show show show echo exit
  1134. X
  1135. X: doit immediate
  1136. X    10 33 100 108 114 111 87
  1137. X    32 111 108 108 101 72
  1138. X    all
  1139. Xexit
  1140. X
  1141. Xdoit
  1142. SHAR_EOF
  1143. $TOUCH -am 0817110092 1992/demo1.1st &&
  1144. chmod 0444 1992/demo1.1st ||
  1145. echo "restore of 1992/demo1.1st failed"
  1146. set `wc -c 1992/demo1.1st`;Wc_c=$1
  1147. if test "$Wc_c" != "212"; then
  1148.     echo original size 212, current size $Wc_c
  1149. fi
  1150. # ============= 1992/demo1.th ==============
  1151. echo "x - extracting 1992/demo1.th (Text)"
  1152. sed 's/^X//' << 'SHAR_EOF' > 1992/demo1.th &&
  1153. X: demo1 " Hello world!
  1154. X" ;
  1155. X
  1156. Xdemo1
  1157. SHAR_EOF
  1158. $TOUCH -am 0817110092 1992/demo1.th &&
  1159. chmod 0444 1992/demo1.th ||
  1160. echo "restore of 1992/demo1.th failed"
  1161. set `wc -c 1992/demo1.th`;Wc_c=$1
  1162. if test "$Wc_c" != "34"; then
  1163.     echo original size 34, current size $Wc_c
  1164. fi
  1165. # ============= 1992/demo2.th ==============
  1166. echo "x - extracting 1992/demo2.th (Text)"
  1167. sed 's/^X//' << 'SHAR_EOF' > 1992/demo2.th &&
  1168. X: demo2 
  1169. X
  1170. X    10 0        ( iterate from 0 stopping before 10 )
  1171. X    do
  1172. X        i .      ( print the loop counter )
  1173. X    loop
  1174. X    cr        ( add a newline )
  1175. X;
  1176. X
  1177. Xdemo2
  1178. SHAR_EOF
  1179. $TOUCH -am 0817110092 1992/demo2.th &&
  1180. chmod 0444 1992/demo2.th ||
  1181. echo "restore of 1992/demo2.th failed"
  1182. set `wc -c 1992/demo2.th`;Wc_c=$1
  1183. if test "$Wc_c" != "135"; then
  1184.     echo original size 135, current size $Wc_c
  1185. fi
  1186. # ============= 1992/demo3.th ==============
  1187. echo "x - extracting 1992/demo3.th (Text)"
  1188. sed 's/^X//' << 'SHAR_EOF' > 1992/demo3.th &&
  1189. X: printfour
  1190. X
  1191. X    dup        ( save the number on top of the stack )
  1192. X    4 =        ( compare it to four )
  1193. X    if
  1194. X      " forth "    ( output a string for it )
  1195. X      drop        ( and delete the saved value )
  1196. X        else
  1197. X      .
  1198. X    endif
  1199. X;
  1200. X
  1201. X: demo3 10 0 do i printfour loop cr ;
  1202. X
  1203. Xdemo3
  1204. SHAR_EOF
  1205. $TOUCH -am 0817110092 1992/demo3.th &&
  1206. chmod 0444 1992/demo3.th ||
  1207. echo "restore of 1992/demo3.th failed"
  1208. set `wc -c 1992/demo3.th`;Wc_c=$1
  1209. if test "$Wc_c" != "245"; then
  1210.     echo original size 245, current size $Wc_c
  1211. fi
  1212. # ============= 1992/demo4.th ==============
  1213. echo "x - extracting 1992/demo4.th (Text)"
  1214. sed 's/^X//' << 'SHAR_EOF' > 1992/demo4.th &&
  1215. X( compute factorial recursively )
  1216. X( take x as input, return x! and x as output )
  1217. X
  1218. X: fact-help
  1219. X
  1220. X  dup if
  1221. X    1 -            ( leave x-1 on top )
  1222. X    fact-help        ( leave x-1, [x-1]! )
  1223. X    1 +            ( leave x, [x-1]!, x )
  1224. X    swap over swap    ( leave [x-1]!, x, x )
  1225. X    *            ( into x!, x )
  1226. X    swap        ( into x, x! )
  1227. X  else
  1228. X    1 swap
  1229. X  then
  1230. X;
  1231. X
  1232. X: fact
  1233. X
  1234. X  fact-help
  1235. X  drop
  1236. X
  1237. X;
  1238. X
  1239. X: demo4
  1240. X  " 4 factorial is: " 4 fact . cr
  1241. X  " 6 factorial is: " 6 fact . cr
  1242. X;
  1243. X
  1244. Xdemo4
  1245. SHAR_EOF
  1246. $TOUCH -am 0817110092 1992/demo4.th &&
  1247. chmod 0444 1992/demo4.th ||
  1248. echo "restore of 1992/demo4.th failed"
  1249. set `wc -c 1992/demo4.th`;Wc_c=$1
  1250. if test "$Wc_c" != "439"; then
  1251.     echo original size 439, current size $Wc_c
  1252. fi
  1253. # ============= 1992/demo5.th ==============
  1254. echo "x - extracting 1992/demo5.th (Text)"
  1255. sed 's/^X//' << 'SHAR_EOF' > 1992/demo5.th &&
  1256. X( recursive factorial.  given x on top, followed by )
  1257. X( an "accumulator" containing the product except for x! )
  1258. X
  1259. X: fact-help2
  1260. X
  1261. X  dup if
  1262. X    swap over swap
  1263. X    *
  1264. X    swap 1 -
  1265. X    fact-help2
  1266. X  then
  1267. X;
  1268. X
  1269. X: fact
  1270. X
  1271. X  1 swap
  1272. X  fact-help2
  1273. X  drop
  1274. X;
  1275. X
  1276. X: demo5
  1277. X
  1278. X  " The factorial of 3 is: " 3 fact . cr
  1279. X  " The factorial of 5 is: " 5 fact . cr
  1280. X;
  1281. X
  1282. Xdemo5
  1283. SHAR_EOF
  1284. $TOUCH -am 0817110092 1992/demo5.th &&
  1285. chmod 0444 1992/demo5.th ||
  1286. echo "restore of 1992/demo5.th failed"
  1287. set `wc -c 1992/demo5.th`;Wc_c=$1
  1288. if test "$Wc_c" != "339"; then
  1289.     echo original size 339, current size $Wc_c
  1290. fi
  1291. # ============= 1992/demo6.th ==============
  1292. echo "x - extracting 1992/demo6.th (Text)"
  1293. sed 's/^X//' << 'SHAR_EOF' > 1992/demo6.th &&
  1294. X: foobar
  1295. X  2
  1296. X  [ 2 ,          ( '[' turns the compiler off, allowing us to execute code )
  1297. X    1 1 1 + + ,   ( and we compile in-line a 2 and a three )
  1298. X          ( the '2' means 'push the number following this' )
  1299. X  ]
  1300. X  + . cr
  1301. X;
  1302. X
  1303. Xfoobar
  1304. X
  1305. X: 'foobar ' foobar ;    ( ' can only be run inside the compiler )
  1306. X            ( ' leaves the address of the following word
  1307. X                on the stack )
  1308. X
  1309. X'foobar . cr
  1310. X
  1311. X'foobar dump
  1312. SHAR_EOF
  1313. $TOUCH -am 0817110092 1992/demo6.th &&
  1314. chmod 0444 1992/demo6.th ||
  1315. echo "restore of 1992/demo6.th failed"
  1316. set `wc -c 1992/demo6.th`;Wc_c=$1
  1317. if test "$Wc_c" != "388"; then
  1318.     echo original size 388, current size $Wc_c
  1319. fi
  1320. # ============= 1992/gson.c ==============
  1321. echo "x - extracting 1992/gson.c (Text)"
  1322. sed 's/^X//' << 'SHAR_EOF' > 1992/gson.c &&
  1323. X#include <stdio.h> 
  1324. X
  1325. Xlong a
  1326. X[4],b[
  1327. X4],c[4]
  1328. X,d[0400],e=1;
  1329. Xtypedef struct f{long g
  1330. X,h,i[4]       ,j;struct f*k;}f;f g,*
  1331. Xl[4096             ]; char h[256],*m,k=3;
  1332. X             long n    (o, p,q)long*o,*p,*q;{
  1333. X             long r          =4,s,i=0;for(;r--;s=i^
  1334. X             *o^*p,                i=i&*p|(i|*p)&~*o++,*q
  1335. X             ++=s,p                ++);return i;}t(i,p)long*p
  1336. X             ;{*c=d          [i],n(a,c,b),n(p,b,p);}u(j)f*j;{j->h
  1337. X             =(j->g    =j->i[0]|j->i[1]|j->i[2]|j->i[3])&4095;}v(
  1338. Xj,s)f*             j; {int i; for(j->k->k&&v(j->k, ' '),fseek(
  1339. Xstdin,       j->j, 0);i=getchar(),putchar(i-'\n'?i:s),i-
  1340. X'\n';);}w(o,r,j,x,p)f*o,*j;long p;{f q;int 
  1341. Xs,i=o->h;q.k=o;r>i?j=l[r=i]:r<i&&
  1342. X(s=r&~i)?(s|=s>>1, s|=s
  1343. X>>2,s|=s>>4,s
  1344. X|=s>>8
  1345. X,j=l[r
  1346. X=((r&i
  1347. X             |s)&~(s>>1))-1&i]):0;--x;for
  1348. X         (;x&&!(p&i);p>>=1);for(;!x&&j;n(o->i,j->i,q.
  1349. X        i),u(&q),q.g||(q.j=j->j,v(&q,'\n')),j=j->k);for(;x;j=x
  1350. X     ?j->k:0){for(;!j&&((r=(r&i)-1&i)-i&&(r&p)?2:(x=0));j=l[r]);!
  1351. X      x||(j->g&~o->g)||n                  (o->i,j->i,q.i)||(
  1352. X    u(&q), q.j=j                          ->j,q.g?w(&q
  1353. X   ,r,j->k,x                              ,p):v(&q,
  1354. X  '\n'));                                 }}y(){f
  1355. X j;char                                       *z,*p;
  1356. Xfor(;m                                    ? j.j=
  1357. Xftell(                                    stdin)
  1358. X,7,(m=                 gets(m                    ))||w(
  1359. X&g,315                 *13,l[                    4095]
  1360. X ,k,64*                 64)&0:                       0;n(g
  1361. X  .i,j.i,             b)||(u                    (&j),j.
  1362. X   k=l[j.h],l[j.h]= &j,y())){for(z=                p=h;*z&&(
  1363. X    d[*z++]||(p=0)););for(z=p?n(j.i              ,j.i,j.i)+h:"";
  1364. X  *z;t(*z++,j.i));}}main(o,p)char**         p; {for(;m = *++p;)for(;*m-
  1365. X'-'?*m:(k= -atoi(m))&0;d[*m]||(d[*m         ]=e,e<<=1),t(*m++,g.i)); u(&
  1366. X                 g),m=h
  1367. X                 ,y();}
  1368. SHAR_EOF
  1369. $TOUCH -am 0817110092 1992/gson.c &&
  1370. chmod 0444 1992/gson.c ||
  1371. echo "restore of 1992/gson.c failed"
  1372. set `wc -c 1992/gson.c`;Wc_c=$1
  1373. if test "$Wc_c" != "1513"; then
  1374.     echo original size 1513, current size $Wc_c
  1375. fi
  1376. # ============= 1992/gson.hint ==============
  1377. echo "x - extracting 1992/gson.hint (Text)"
  1378. sed 's/^X//' << 'SHAR_EOF' > 1992/gson.hint &&
  1379. XMost Humorous Output: <gson@niksula.hut.fi> Andreas Gustafsson
  1380. X
  1381. X    Andreas Gustafsson
  1382. X    Helsinki University of Technology
  1383. X    Arentikuja 1 D 305            (home address)
  1384. X    00410 Helsinki
  1385. X    FINLAND
  1386. X
  1387. X
  1388. XJudges' comments:
  1389. X
  1390. X    To make:
  1391. X    make ag
  1392. X    
  1393. X    Determine where your system dictionary is located.  You may find
  1394. X    it located in one of the following places:
  1395. X
  1396. X        /usr/dict/words
  1397. X        /usr/share/lib/spell/words
  1398. X        /usr/ucblib/dict/words
  1399. X        /dev/null            <-- for machines with nothing to say
  1400. X    
  1401. X    Then using the proper dictionary:
  1402. X
  1403. X        ag free software foundation    < /usr/dict/words
  1404. X        ag obfuscated c contest        < /usr/dict/words
  1405. X        ag unix international        < /usr/dict/words
  1406. X    ag george bush            < /usr/dict/words
  1407. X    ag bill clinton            < /usr/dict/words
  1408. X    ag ross perot            < /usr/dict/words
  1409. X    ag paul e tsongas        < /usr/dict/words
  1410. X
  1411. X    Recently some newspapers printed amusing anagrams of one of the
  1412. X    names listed above.  Run this program to find the anagrams they
  1413. X    weren't allowed to print!
  1414. X
  1415. X
  1416. XSelected notes from the author:
  1417. X
  1418. X    The name of the game:
  1419. X    
  1420. X    AG is short for either Anagram Generator or simply AnaGram.
  1421. X    It might also be construed to mean Alphabet Game, and by pure
  1422. X    coincidence it happens to be the author's initials.
  1423. X    
  1424. X    
  1425. X    What it does:
  1426. X    
  1427. X    AG takes one or more words as arguments, and tries to find
  1428. X    anagrams of those words, i.e. words or sentences containing
  1429. X    exactly the same letters.
  1430. X    
  1431. X    
  1432. X    How to use it:
  1433. X    
  1434. X    To run AG, you need a dictionary file consisting of distinct words
  1435. X    in the natural language of your choice, one word on each line.  If
  1436. X    your machine doesn't have one already, you can make your own
  1437. X    dictionary by concatenating a few hundred of your favourite Usenet
  1438. X    articles and piping them through the following obfuscated shell
  1439. X    script:
  1440. X    
  1441. X        #!/bin/sh
  1442. X        z=a-z];tr [A-Z\] \[$z|sed s/[\^$z[\^$z*/_/g|tr _ \\012|grep ..|sort -u
  1443. X    
  1444. X    Using articles from alt.folklore.computers is likely to make
  1445. X    a more professional-looking dictionary than rec.arts.erotica.
  1446. X    
  1447. X    AG must be run with the dictionary file as standard input.
  1448. X    
  1449. X    Because anagrams consisting of just a few words are generally more
  1450. X    meaningful than those consisting of dozens of very short words, the
  1451. X    number of words in the anagrams is limited to 3 by default.  This
  1452. X    limit can be changed using a numeric command line option, as in
  1453. X    "ag -4 international obfuscated c code contest </usr/dict/words".
  1454. X    
  1455. X    Bugs:
  1456. X    
  1457. X      - There is no error checking
  1458. X      - Standard input must be seekable, so you can't pipe the dictionary
  1459. X        into AG.
  1460. X      - The input sentence and each line in the dictionary may contain
  1461. X        at most 32 distinct letters, and each letter may occur at most 15
  1462. X        times.
  1463. X      - Words in the dictionary may be at most 255 bytes long
  1464. X      - AG cannot handle characters that sign-extend to negative values
  1465. X      - Although AG works on both 16-bit and 32-bit machines, 
  1466. X        the size of the problems it can solve is severely limited 
  1467. X        on machines that limit the stack size to 64k or less.
  1468. X    
  1469. X    
  1470. X    Obfuscatory notes:
  1471. X    
  1472. X    As you can see, AG takes advantage of the new '92 whitespace rules to
  1473. X    achieve a clear, readable, self-documenting layout.  The identifiers
  1474. X    have been chosen in a way appropriate for an alphabet game, and common
  1475. X    sources of bugs such as goto statements and malloc/free have been
  1476. X    eliminated.  As AG also refrains from abusing the preprocessor, it
  1477. X    doesn't really have much to offer in terms of "surface obfuscation".
  1478. X    Instead, it tries to achieve both its speed and its obscurity through a
  1479. X    careful choice of algorithms.  Some of the finer points of those
  1480. X    algorithms are outlined in the rot-13 encoded spoiler below.
  1481. X    
  1482. X    How it works:  (ROT13 to read)
  1483. X    
  1484. X    Urer sbyybjf n qrfpevcgvba bs fbzr bs gur qngn fgehpgherf naq
  1485. X    nytbevguzf hfrq ol NT.  Vg vf ol ab zrnaf pbzcyrgr, ohg vg znl uryc
  1486. X    lbh trg na vqrn nobhg gur trareny cevapvcyrf.
  1487. X    
  1488. X    --
  1489. X    
  1490. X    Vagreanyyl, NT ercerfragf jbeqf naq fragraprf nf neenlf bs 32
  1491. X    4-ovg vagrtre ryrzragf.  Rnpu ryrzrag ercerfragf gur ahzore bs
  1492. X    gvzrf n yrggre bpphef va gur jbeq/fragrapr.  Gurer ner 32 ryrzragf
  1493. X    orpnhfr 32 vf n pbairavrag cbjre bs gjb ynetre guna gur ahzore bs
  1494. X    yrggref va zbfg jrfgrea nycunorgf, naq gur ryrzragf ner 4 ovgf
  1495. X    rnpu orpnhfr gur fnzr yrggre vf hayvxryl gb bpphe zber guna 15
  1496. X    gvzrf va n cenpgvpny nantenz trarengvba ceboyrz.
  1497. X    
  1498. X    Gurfr 32*4-ovg neenlf ner npghnyyl fgberq va zrzbel va n
  1499. X    "ovg-genafcbfrq" sbezng, nf neenlf bs sbhe "ybat" inyhrf.  Vg vf
  1500. X    nffhzrq gung n "ybat" vf ng yrnfg 32 ovgf.  Gur svefg 4-ovg yrggre
  1501. X    pbhag vf sbezrq ol gur yrnfg fvtavsvpnag (2^0) ovg va rnpu bs gur
  1502. X    sbhe ybatf, gur arkg bar vf sbezrq ol gur 2^1 ovgf, rgp.
  1503. X    
  1504. X    Guvf fgbentr sbezng znxrf vg cbffvoyr gb nqq be fhogenpg gjb fhpu
  1505. X    irpgbef bs 32 4-ovg inyhrf va cnenyyry ol fvzhyngvat n frg bs 32
  1506. X    ovanel shyy nqqref va fbsgjner hfvat ovgjvfr ybtvpny bcrengvbaf.
  1507. X    R.t., nyy gur YFO:f bs gur erfhyg ner sbezrq va cnenyyry ol gnxvat
  1508. X    gur rkpyhfvir BE bs gur YFO:f va rnpu fhzznaq, naq 32 pneel ovgf
  1509. X    ner sbezrq va cnenyyry va n fvzvyne jnl hfvat n ybtvpny NAQ.
  1510. X    Guhf, 32 vaqrcraqrag 4-ovg nqqvgvbaf pna or cresbezrq ol whfg sbhe
  1511. X    vgrengvbaf bs n ybbc pbagnvavat fbzr 32-ovg ovgjvfr ybtvpny
  1512. X    bcrengvbaf, ohg ab nevguzrgvp bcrengvbaf bgure guna gubfr vzcyvrq
  1513. X    ol neenl vaqrkvat.
  1514. X    
  1515. X    Fhogenpgvba jbexf fvzvyneyl, naq va snpg NT bayl vzcyrzragf
  1516. X    fhogenpgvba qverpgyl, unaqyvat nqqvgvba ol zrnaf bs gur vqragvgl
  1517. X    n+o = n-(0-o).
  1518. X    
  1519. X    Va nqqvgvba gb guvf 32*4-ovg ercerfragngvba, NT nyfb sbezf n fb-pnyyrq
  1520. X    "fvtangher" gung vf gur ovgjvfr BE bs gur sbhe ybatf, juvpu vf
  1521. X    rdhvinyrag gb fnlvat gung gur fvtangher bs n jbeq pbagnvaf n ybtvpny 1
  1522. X    va gur ovg cbfvgvbaf pbeerfcbaqvat gb yrggref bppheevat ng yrnfg bapr
  1523. X    va gung jbeq.
  1524. X    
  1525. X    Gur svefg guvat NT qbrf vf gb pbafgehpg n ybbxhc gnoyr bs 256
  1526. X    ybatf, bar sbe rnpu 8-ovg punenpgre inyhr.  Gur ragel sbe n
  1527. X    punenpgre jvyy or mreb vs gung punenpgre qbrfa'g nccrne va gur
  1528. X    fragrapr tvira ba gur pbzznaq yvar, be vg jvyy unir n fvatyr ovg
  1529. X    frg vs gur punenpgre qbrf nccrne va gur fragrapr.  Ol nqqvat
  1530. X    gbtrgure gur ovg znfxf sbe nyy gur yrggref va gur vachg fragrapr
  1531. X    hfvat gur genafcbfr nqqvgvba zrgubq qrfpevorq nobir, NT sbezf gur
  1532. X    32*4 ovg neenl ercerfragngvba bs gur vachg fragrapr.
  1533. X    
  1534. X    Gur arkg npgvba cresbezrq vf ernqvat gur qvpgvbanel.  Gubfr jbeqf gung
  1535. X    pbagnva yrggref abg va gur vachg fragrapr ner vzzrqvngryl qvfpneqrq.
  1536. X    Jbeqf pbagnvavat gur evtug yrggref ohg va rkprffvir ahzoref ner
  1537. X    ryvzvangrq va n frcnengr purpx vaibyivat gur 32*4 ovg neenl.
  1538. X    
  1539. X    Gur erznvavat jbeqf, juvpu jvyy or ersreerq gb nf "pnaqvqngr jbeqf",
  1540. X    ner fgberq va 32*4-ovg ercerfragngvba, gbtrgure jvgu gurve fvtangherf 
  1541. X    naq bssfrgf vagb gur qvpgvbanel svyr fb gung gur cynva-grkg irefvba bs
  1542. X    n jbeq pna yngre or sbhaq sbe cevagvat.  Guvf vasbezngvba vf xrcg va n
  1543. X    ybpny "fgehpg" va gur qvpgvbanel-ernqvat shapgvba, naq zrzbel vf
  1544. X    nyybpngrq sbe rnpu pnaqvqngr jbeq fvzcyl ol znxvat nabgure erphefvir
  1545. X    pnyy gb gung shapgvba.
  1546. X    
  1547. X    Rnpu fgehpg fb nyybpngrq vf yvaxrq vagb n svkrq-fvmr unfu gnoyr bs
  1548. X    4096 ragevrf vaqrkrq ol gur 12 ybj ovgf bs gur jbeq'f fvtangher. 
  1549. X    Jura gur qvpgvbanel-ernqvat shapgvba rapbhagref raq-bs-svyr, nyy gur
  1550. X    pnaqvqngr jbeqf unir orra fgberq va arfgrq npgvingvba erpbeqf ba gur
  1551. X    fgnpx, npprffvoyr guebhtu gur unfu gnoyr.
  1552. X    
  1553. X    Trarengvat gur nantenzf vf gura qbar ol genirefvat gur unfu gnoyr naq
  1554. X    fhogenpgvat gur yrggref bs rnpu jbeq va gur unfu gnoyr sebz gur
  1555. X    "pheerag fragrapr", juvpu vavgvnyyl vf gur fragrapr tvira ba gur
  1556. X    pbzznaq yvar.
  1557. X    
  1558. X    Gur fhogenpgvba vf cresbezrq va cnenyyry ba gur 4-ovg yrggre pbhagf
  1559. X    nf qrfpevorq nobir, naq vs nyy 32 erfhygf ner mreb, na nantenz unf
  1560. X    orra sbhaq.  Vs gur erfhyg vf artngvir sbe bar be zber bs gur yrggref
  1561. X    (nf vaqvpngrq ol bar be zber "1" va n irpgbe bs 32 obeebj ovgf
  1562. X    erghearq ol gur fhogenpgvba ebhgvar), gur jbeq qvq abg zngpu gur
  1563. X    pheerag fragrapr naq vf vtaberq.  Svanyyl, vs gur erfhyg pbagnvarq
  1564. X    bayl abaartngvir yrggre pbhagf, jr unir sbhaq n cnegvny nantenz: 
  1565. X    n jbeq pbagnvavat fbzr, ohg abg nyy, bs gur yrggref va gur pheerag
  1566. X    fragrapr.  Va guvf pnfr jr erphefviryl gel gb svaq na nantenz bs gur
  1567. X    erznvavat yrggref.  Gur qrcgu bs gur erphefvba vf yvzvgrq gb gur
  1568. X    znkvzhz ahzore bs jbeqf va gur nantenz, nf fcrpvsvrq ol gur hfre.
  1569. X    
  1570. X    Jura gur qrrcrfg erphefvba yriry unf orra ernpurq, na bcgvzvmngvba pna
  1571. X    or nccyvrq: orpnhfr ab shegure erphefvba jvyy or qbar, gurer vf ab
  1572. X    arrq gb ybbx sbe cnegvny nantenzf, naq gurersber NT bayl arrqf gb
  1573. X    purpx sbe jbeqf gung pbagnva rknpgyl gur fnzr yrggref nf gur pheerag
  1574. X    fragrapr.  Gubfr jbeqf pna or sbhaq fvzcyl ol vaqrkvat gur unfu gnoyr
  1575. X    jvgu gur fvtangher bs gur pheerag fragrapr.
  1576. X    
  1577. X    Rira jura abg ba gur qrrcrfg erphefvba yriry, NT trarenyyl nibvqf
  1578. X    rknzvavat nyy gur ragevrf bs gur unfu gnoyr.  Gur vqrn vf gung jr ner
  1579. X    abg vagrerfgrq va unfu ohpxrgf jubfr jbeqf pbagnva nal yrggref abg
  1580. X    va gur pheerag fragrapr; gurfr ohpxrgf ner rknpgyl gubfr jubfr vaqrk
  1581. X    unf n ybtvpny bar va n ovg cbfvgvba jurer gur fvtangher bs gur pheerag
  1582. X    fragrapr unf n mreb.  Chg nabgure jnl, jr jnag gb ybbc guebhtu bayl
  1583. X    gubfr unfu ohpxrg vaqvprf "v" gung pbagnva mrebrf va nyy gur ovg
  1584. X    cbfvgvbaf jurer gur fvtangher "f" bs gur pheerag fragrapr pbagnvaf
  1585. X    n mreb; guvf pna or rkcerffrq va P nf (v & ~f == 0).
  1586. X    
  1587. X    Vg vf cbffvoyr gb ybbc guebhtu nyy fhpu ahzoref va na rssvpvrag jnl ol
  1588. X    gnxvat nqinagntr bs pregnva cebcregvrf bs ovanel nevguzrgvp: ol
  1589. X    sbepvat gur ovgf pbeerfcbaqvat gb mrebrf va "f" gb barf, jr pna znxr
  1590. X    gur pneevrf trarengrq va vaperzragvat "v" cebcntngr fgenvtug npebff
  1591. X    gubfr ovgf gung fubhyq erznva mreb.  Sbe rknzcyr, gur sbyybjvat
  1592. X    cebtenz cevagf nyy gubfr 16-ovg vagrtref gung pbagnva mrebrf va nyy
  1593. X    rira ovg cbfvgvbaf:
  1594. X    
  1595. X        znva(){vag v=0,f=0kNNNN;qb{cevags("%04k\g",v);}juvyr(v=((v|~f)+1)&f);}
  1596. X    
  1597. X    NT hfrf n fvzvyne zrgubq ohg jbexf va gur bccbfvgr qverpgvba, svaqvat
  1598. X    gur arkg ybjre inyhr jvgu mrebrf va tvira ovg cbfvgvbaf ol cebcntngvat
  1599. X    obeebjf npebff gubfr ovgf.  Fbzr nqqvgvbany nqwhfgzragf ner znqr
  1600. X    gb gur unfu gnoyr vaqrk jura vavgvngvat n erphefvir frnepu, hfvat
  1601. X    fvzvyne ovg-gjvqqyvat grpuavdhrf.
  1602. X    
  1603. X    Jurarire na nantenz unf orra sbhaq, vg vf cevagrq ol genirefvat n
  1604. X    yvaxrq yvfg sbezrq ol fgehpgf va gur npgvingvba erpbeqf bs gur
  1605. X    erphefvir vaibpngvbaf bs gur frnepu shapgvba, frrxvat gb gur ortvaavat
  1606. X    bs gur jbeq zngpurq ol gung vaibpngvba, naq pbclvat gur punenpgref bs
  1607. X    gur jbeq qverpgyl sebz fgnaqneq vachg gb fgnaqneq bhgchg.
  1608. SHAR_EOF
  1609. $TOUCH -am 0908160292 1992/gson.hint &&
  1610. chmod 0444 1992/gson.hint ||
  1611. echo "restore of 1992/gson.hint failed"
  1612. set `wc -c 1992/gson.hint`;Wc_c=$1
  1613. if test "$Wc_c" != "10891"; then
  1614.     echo original size 10891, current size $Wc_c
  1615. fi
  1616. # ============= 1992/help.th ==============
  1617. echo "x - extracting 1992/help.th (Text)"
  1618. sed 's/^X//' << 'SHAR_EOF' > 1992/help.th &&
  1619. X: help key  ( flush the carriage return form the input buffer )
  1620. X
  1621. X" The following are the standard known words; words marked with (*) are
  1622. Ximmediate words, which cannot be used from command mode, but only in
  1623. Xword definitions.  Words marked by (**) declare new words, so are always
  1624. Xfollowed by the new word.
  1625. X
  1626. X    ! @        fetch, store
  1627. X    + - * / mod    standard arithmetic operations
  1628. X    = < > <= >=    standard comparison operations
  1629. X
  1630. X    not        boolean not of top of stack
  1631. X    logical        turn top of stack into 0 or 1
  1632. X
  1633. X    dup over    duplicate the top of stack or second of stack
  1634. X    swap drop    reverse top two elements or drop topmost
  1635. X
  1636. X    inc dec        increment/decrement the value at address from stack
  1637. X    add        add a value from 2nd of stack into address from top
  1638. X
  1639. X    echo key    output character from, or input to, top of stack
  1640. X    . #        print out number on top of stack without/with cr
  1641. X    cr        print a carriage return
  1642. X
  1643. X[more]" key
  1644. X" (**)    var        declare variable with initial value taken from stack
  1645. X(**)    constant    declare constant with initial value taken from stack
  1646. X(**)    array        declare an array with size taken from stack
  1647. X
  1648. X(*)    if...else...then    FORTH branching construct
  1649. X(*)    do...loop        FORTH looping construct
  1650. X    i j            loop values (not variables)
  1651. X
  1652. X    print        print the string pointed to on screen
  1653. X
  1654. X(*)(**) :        declare a new THIRD word
  1655. X(*)    <build does>    declare a data types compile-time and run-time
  1656. X(*)    ;        terminate a word definition
  1657. X
  1658. X[more]" key
  1659. X" Advanced words:
  1660. X    here        current location in dictionary
  1661. X    h        pointer into dictionary
  1662. X    r        pointer to return stack
  1663. X    fromr tor    pop a value from or to the return stack
  1664. X
  1665. X    ,        write the top of stack to dictionary
  1666. X    '        store the address of the following word on the stack
  1667. X    allot        leave space on the dictionary
  1668. X
  1669. X    ::        compile a ':' header
  1670. X    [        switch into command mode
  1671. X    ]        continue doing : definitions
  1672. X" ;
  1673. SHAR_EOF
  1674. $TOUCH -am 0817110092 1992/help.th &&
  1675. chmod 0444 1992/help.th ||
  1676. echo "restore of 1992/help.th failed"
  1677. set `wc -c 1992/help.th`;Wc_c=$1
  1678. if test "$Wc_c" != "1774"; then
  1679.     echo original size 1774, current size $Wc_c
  1680. fi
  1681. # ============= 1992/imc.c ==============
  1682. echo "x - extracting 1992/imc.c (Text)"
  1683. sed 's/^X//' << 'SHAR_EOF' > 1992/imc.c &&
  1684. X#include             <stdio.h> 
  1685. X#include             <malloc.h> 
  1686. X#define              ext(a) (exit(a),0)
  1687. X#define I          " .:\';+<?F7RQ&%#*"
  1688. X#define a            "%s?\n"
  1689. X#define n            "0?\n"
  1690. X#define C            double    
  1691. X#define o             char
  1692. X#define l             long
  1693. X#define L            sscanf
  1694. X#define i            stderr
  1695. X#define e            stdout
  1696. X#define r               ext   (1)
  1697. X#define s(O,B)       L(++J,O,&B)!=1&&c>++q&&L(v[q],O,&B)!=1&&--q
  1698. X#define F(U,S,C,A) t=0,*++J&&(t=L(J,U,&C,&A)),(!t&&c>++q&&!(t=L(v[q],U,\
  1699. X           &C,&A)))?--q:(t<2&&c>++q&&!(t=L(v[q],S,&A))&&--q
  1700. X#define T(E)        (s("%d",E),E||(fputs(n,i),r))
  1701. X#define d(C,c)          (F("%lg,%lg","%lg",C,c)))
  1702. X#define O       (F("%d,%d","%d",N,U),(N&&U)||(fputs(n,i),r)))
  1703. X#define D              (s("%lg",f))
  1704. X#define E              putc
  1705. X                           C
  1706. X                        G=0,
  1707. X                        R
  1708. X                         =0,Q,H
  1709. X                        ,M,P,z,S
  1710. X                         =0,x=0
  1711. X                 ,        f=0;l b,j=0,          k
  1712. X                  =128,K=1,V,B=0,Y,m=128,p=0,N
  1713. X                 =768,U=768,h[]={0x59A66A95,256
  1714. X                 ,192,1,6912,1,0,0},t,A=0,W=0,Z=63,X=23
  1715. X                ;o*J,_;main(c,v)l c;o**v;{l q=1;for(;;q<
  1716. X          c       ?(((J=v[q])[0]&&J[0]<48&&J++,((_= *J)<99||
  1717. X        _/2==       '2'||(_-1)/3=='\"'||_==107||_/05*2==','||_
  1718. X          >0x074)?(   fprintf(i,a,v[q]),r):_>0152?(_/4>27?(_&1?(
  1719. X         O,Z=N,X=U):  (W++,N=Z,U=X)):_&1?T(K):T(k)):_>103?(d(G,
  1720. X    R    ),j=1):_&1? d(S,x):D,q++),q--,main(c-q,v+q)):A==0?(A=
  1721. X  1,f||(f=N/4.),b=(((N-1)&017)<8),q=(((N+7)>>3)+b)*U,(J=malloc(q)
  1722. X  )||(perror("malloc"),r),S-=(N/2)/f,x+=(U/2)/f):A==1?(B<U?(A=2,V
  1723. X    =    0,Q=x-B/f,j ||(R=Q),W&&E('\n',e),E(46,i)):(W&&E('\n',
  1724. X         e),E('\n',i  ),h[1]=N,h[2]=U,h[4]=q,W||(fwrite(h,1,32,
  1725. X          e),fwrite   (J,1,q,e)),free(J),ext(0))):A==2?(V<N?(j?
  1726. X        (H=V/f       +S,M=Q):(G=V/f+S,H=M=0),Y=0,A=03):((m&0x80
  1727. X           )       ||(m=0x80,p++),b&&(J[p++]=0),A=1,B++)):((Y
  1728. X                <k&&(P=H*H)+(z=M*M)<4.)?(M=2*H*M+R,H=P-z
  1729. X                 +G,Y++):(W&&E(I[0x0f*(Y&K)/K],e),Y&K?J
  1730. X                     [p]&=~m:(J[p]|=m),(m>>=1)||/*/
  1731. X                  (m=128,u--),A==6?ext(1):B<u
  1732. X                 .      e=3,l=2*c*/(       m
  1733. X                         =0x80,
  1734. X                        p++),V++
  1735. X                         ,A=0x2
  1736. X                        )
  1737. X                        ));
  1738. X                           }
  1739. SHAR_EOF
  1740. $TOUCH -am 0817110392 1992/imc.c &&
  1741. chmod 0444 1992/imc.c ||
  1742. echo "restore of 1992/imc.c failed"
  1743. set `wc -c 1992/imc.c`;Wc_c=$1
  1744. if test "$Wc_c" != "1965"; then
  1745.     echo original size 1965, current size $Wc_c
  1746. fi
  1747. echo "End of part 3, continue with part 4"
  1748. exit 0
  1749. -- 
  1750. For a good prime, call:  391581 * 2^216193 - 1
  1751.