home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / EFFO / pd6.lzh / SRC / kernel.c < prev    next >
Text File  |  1990-05-08  |  62KB  |  3,179 lines

  1. /*
  2.   C BASED FORTH-83 MULTI-TASKING KERNEL
  3.  
  4.   Copyright (c) 1989 by Mikael R.K. Patel
  5.  
  6.   Computer Aided Design Laboratory (CADLAB)
  7.   Department of Computer and Information Science
  8.   Linkoping University
  9.   S-581 83 LINKOPING
  10.   SWEDEN
  11.  
  12.   Email: mip@ida.liu.se
  13.  
  14.   Started on: 30 June 1988
  15.  
  16.   Last updated on: 11 December 1989
  17.  
  18.   Dependencies:
  19.        (cc) kernel.h, error.h, memory.h and io.c
  20.  
  21.   Description:
  22.        Virtual Forth machine and kernel code supporting multi-tasking of
  23.        light weight processes. A pure 32-bit Forth-83 Standard implementation.
  24.  
  25.        Extended with argument binding and local variables, exception
  26.        handling, queue data management, multi-tasking, symbol hiding and
  27.        casting, forwarding, null terminated string and memory allocation,
  28.        file search paths, and source library module loading.
  29.   
  30.        The kernel does not implement the block word set. All code is
  31.        stored as text files.
  32.  
  33.   Copying:
  34.        This program is free software; you can redistribute it and/or modify
  35.        it under the terms of the GNU General Public License as published by
  36.        the Free Software Foundation; either version 1, or (at your option)
  37.        any later version.
  38.  
  39.        This program is distributed in the hope that it will be useful,
  40.        but WITHOUT ANY WARRANTY; without even the implied warranty of
  41.        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  42.        GNU General Public License for more details.
  43.  
  44.        You should have received a copy of the GNU General Public License
  45.        along with this program; see the file COPYING.  If not, write to
  46.        the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  47.  
  48. */
  49.  
  50. #include "kernel.h"
  51. #include "memory.h"
  52. #include "error.h"
  53. #include "io.h"
  54.  
  55.  
  56. /* EXTERNAL DECLARATIONS */
  57.  
  58. extern void io_dispatch();
  59.  
  60.  
  61. /* INTERNAL FORWARD DECLARATIONS */
  62.  
  63. extern ENTRY terminate;
  64. extern ENTRY toexception;
  65. extern ENTRY kernel_abort;
  66. extern ENTRY span;
  67. extern ENTRY state;
  68. extern ENTRY vocabulary;
  69. extern char  thepad[];
  70. extern char  thetib[];
  71.  
  72.  
  73. /* VOCABULARY LISTING PARAMETERS */
  74.  
  75. #define COLUMNWIDTH 15
  76. #define LINEWIDTH 75
  77.  
  78.  
  79. /* CONTROL STRUCTURE MARKERS */
  80.  
  81. #define ELSE 1
  82. #define THEN 2
  83. #define AGAIN 4
  84. #define UNTIL 8
  85. #define WHILE 16
  86. #define REPEAT 32
  87. #define LOOP 64
  88. #define PLUSLOOP 128
  89. #define OF 256
  90. #define ENDOF 512
  91. #define ENDCASE 1024
  92. #define SEMICOLON 2048
  93.  
  94.  
  95. /* MULTI-TASKING MACHINE REGISTERS */
  96.  
  97. long verbose;                  /* Application or programming mode */
  98. long quited;                   /* Interpreter toploop state */
  99. long running;                  /* Task switch flag */
  100. long tasking;                  /* Multi-tasking flag */
  101.  
  102. TASK *tp;                      /* Task pointer */
  103. TASK *foreground;              /* Foreground task pointer */
  104.  
  105.  
  106. /* FORTH MACHINE REGISTERS */
  107.  
  108. long tos;                      /* Top of stack register */
  109. long *sp;                      /* Parameter stack pointer */
  110. long *s0;                      /* Bottom of parameter stack pointer */
  111.  
  112. long *ip;                      /* Instruction pointer */
  113. long *rp;                      /* Return stack pointer */
  114. long *r0;                      /* Bottom of return stack pointer */
  115.  
  116. long *fp;                      /* Argument frame pointer */
  117. long *ep;                      /* Exception frame pointer */
  118.  
  119.  
  120. /* VOCABULARY SEARCH LISTS */
  121.  
  122. #define CONTEXTSIZE 32
  123.  
  124. static ENTRY *current = &forth;
  125. static ENTRY *context[CONTEXTSIZE] = {&forth};
  126.  
  127.  
  128. /* ENTRY LOOKUP CACHE, SIZE AND HASH FUNCTION */
  129.  
  130. #define CACHESIZE 256
  131. #define hash(s) ((s[0] + (s[1] << 4)) & (CACHESIZE - 1))
  132.  
  133. static ENTRY *cache[CACHESIZE];
  134.  
  135.  
  136. /* DICTIONARY AREA FOR THREADED CODE AND DATA */
  137.  
  138. long *dictionary;
  139. long *dp;
  140.  
  141.  
  142. /* INTERNAL STRUCTURE SIZES */
  143.  
  144. #define PADSIZE 84
  145. #define TIBSIZE 256
  146.     
  147.  
  148. /* INNER MULTI-TASKING FORTH VIRTUAL MACHINE */
  149.  
  150. void doinner()
  151. {
  152.     long e;
  153.  
  154.     /* Exception marking and handler */
  155.     if (e = setjmp(restart)) {
  156.        spush(e);
  157.        doraise();
  158.     }
  159.     
  160.     /* Run virtual machine until task switch */
  161.     running = TRUE;
  162.     while (running) {
  163.  
  164.        /* Fetch next thread to execute */
  165.        ENTRY *p = (ENTRY *) *ip++;
  166.  
  167.        /* Select on type of entry */
  168.        switch (p -> code) {
  169.          case CODE:
  170.            ((void (*)()) (p -> parameter))(); 
  171.            break;
  172.          case COLON:
  173.            rpush(ip);
  174.            jump(p -> parameter);
  175.            break;
  176.          case VARIABLE:
  177.            spush(&(p -> parameter));
  178.            break;
  179.          case CONSTANT:
  180.            spush(p -> parameter);
  181.            break;
  182.          case VOCABULARY:
  183.            doappend(p);
  184.            break;
  185.          case CREATE:
  186.            spush(p -> parameter);
  187.            break;
  188.          case USER:
  189.            spush(tp + p -> parameter);
  190.            break;
  191.          case LOCAL:
  192.            spush(*((long *) (long) fp - p -> parameter));
  193.            break;
  194.          case FORWARD:
  195.            if (p -> parameter)
  196.                docall((ENTRY *) p -> parameter);
  197.            else {
  198.                (void) printf("%s: unresolved forward entry\n", p -> name);
  199.                doabort();
  200.            }
  201.            break;
  202.          case EXCEPTION:
  203.            spush(p);
  204.            break;
  205.          case FIELD:
  206.            tos = p -> parameter + tos;
  207.            break;
  208.          default: /* DOES: FORTH LEVEL INTERPRETATION */
  209.            rpush(ip);
  210.            spush(p -> parameter);
  211.            jump(p -> code);
  212.            break;
  213.        }
  214.     }
  215. }
  216.  
  217. void docommand()
  218. {
  219.     long e;
  220.  
  221.     /* Exception marking and handler */
  222.     if (e = setjmp(restart)) {
  223.        spush(e);
  224.        doraise();
  225.        return;
  226.     }
  227.  
  228.     /* Execute command on top of stack */
  229.     doexecute();
  230.  
  231.     /* Check if this affects the virtual machine */
  232.     if (rp != r0) {
  233.        tasking = TRUE;
  234.  
  235.        /* Run the virtual machine and allow user extension */
  236.        while (tasking) {
  237.            doinner();
  238.            io_dispatch();
  239.        }
  240.     }
  241. }
  242.  
  243. void docall(p)
  244.     ENTRY *p;
  245. {
  246.     /* Select on type of entry */
  247.     switch (p -> code) {
  248.       case CODE:
  249.        ((void (*)()) (p -> parameter))(); 
  250.        return; 
  251.       case COLON:
  252.        rpush(ip);
  253.        jump(p -> parameter);
  254.        return;
  255.       case VARIABLE:
  256.        spush(&(p -> parameter));
  257.        return;
  258.       case CONSTANT:
  259.        spush(p -> parameter);
  260.        return;
  261.       case VOCABULARY:
  262.        doappend(p);
  263.        return;
  264.       case CREATE:
  265.        spush(p -> parameter);
  266.        return;
  267.       case USER:
  268.        spush(tp + p -> parameter);
  269.        return;
  270.       case LOCAL:
  271.        spush(*((long *) (long) fp - p -> parameter));
  272.        return;
  273.       case FORWARD:
  274.        if (p -> parameter)
  275.            docall((ENTRY *) p -> parameter);
  276.        else {
  277.            (void) printf("%s: unresolved forward entry\n", p -> name);
  278.            doabort();
  279.        }
  280.        return;
  281.       case EXCEPTION:
  282.        spush(p);
  283.        return;
  284.       case FIELD:
  285.        tos = p -> parameter + tos;
  286.        return;
  287.       default: /* DOES: FORTH LEVEL INTERPRETATION */
  288.        rpush(ip);
  289.        spush(p -> parameter);
  290.        jump(p -> code);
  291.        return;
  292.     }
  293. }
  294.  
  295. void doappend(p)
  296.     ENTRY *p;
  297. {
  298.     long v;
  299.     
  300.     /* Flush the entry cache */
  301.     spush(FALSE);
  302.     dorestore();
  303.  
  304.     /* Check if the vocabulary is a member of the current search set */
  305.     for (v = 0; v < CONTEXTSIZE; v++)
  306.  
  307.        /* If a member then rotate the vocabulary first */
  308.        if (p == context[v]) {
  309.            for (; v; v--) context[v] = context[v - 1];
  310.            context[0] = p;
  311.            return;
  312.        }
  313.  
  314.     /* If not a member, then insert first into the search set */
  315.     for (v = CONTEXTSIZE - 1; v > 0; v--) context[v] = context[v - 1];
  316.     context[0] = p;
  317. }    
  318.  
  319.  
  320. /* VOCABULARY ROOT */
  321.  
  322. ENTRY forth = {(ENTRY *) NIL, "forth", NORMAL, VOCABULARY, (long) &vocabulary};
  323.  
  324.  
  325. /* CONTROL: EXTENSION LEVEL DEFINITIONS */
  326.  
  327. void doparenbranch()
  328. {
  329.     branch(*ip);
  330. }
  331.  
  332. COMPILATION_CODE(parenbranch, forth, "(branch)", doparenbranch);
  333.  
  334. void doparenqbranch()
  335. {
  336.     long flag = spop;
  337.     
  338.     /* Check flag on top of stack and branch if false */
  339.     if (flag)
  340.        skip;
  341.     else
  342.        branch(*ip);
  343. }
  344.  
  345. COMPILATION_CODE(parenqbranch, parenbranch, "(?branch)", doparenqbranch);
  346.  
  347. void doparendo()
  348. {
  349.     /* Build a loop frame on return stack */
  350.     rpush(ip++);
  351.     rpush(spop);
  352.     rpush(spop);
  353. }
  354.  
  355. COMPILATION_CODE(parendo, parenqbranch, "(do)", doparendo);
  356.  
  357. void doparenqdo()
  358. {
  359.     /* Check if the start and stop value are equal */
  360.     if (tos == snth(0)) {
  361.  
  362.        /* If equal then branch over the loop block */
  363.        sdrop(1);
  364.        branch(*ip);
  365.     }
  366.     else {
  367.  
  368.        /* else build a loop frame on the return stack */
  369.        rpush(ip++);
  370.        rpush(spop);
  371.        rpush(spop);
  372.     }
  373. }
  374.  
  375. COMPILATION_CODE(parenqdo, parendo, "(?do)", doparenqdo);
  376.  
  377. void doparenloop()
  378. {
  379.     /* Increment the index by one and check if within loop range */
  380.     rnth(1) += 1;
  381.     if (rnth(0) > rnth(1)) {
  382.  
  383.        /* Branch if still within range */
  384.        branch(*ip);
  385.        return;
  386.     }
  387.  
  388.     /* Else remove the loop frame from the return stack and skip */
  389.     rdrop(3);
  390.     skip;
  391.  
  392. }
  393.  
  394. COMPILATION_CODE(parenloop, parenqdo, "(loop)", doparenloop);
  395.  
  396. void doparenplusloop()
  397. {
  398.     long d = spop;
  399.  
  400.     /* Increment the index with the top of stack value */
  401.     rnth(1) += d;
  402.  
  403.     /* Check direction and if the index is still within the loop range */
  404.     if (d > 0) {
  405.        if (rnth(0) > rnth(1)) {
  406.            branch(*ip);
  407.            return;
  408.        }
  409.     }
  410.     else {
  411.        if (rnth(0) < rnth(1)) {
  412.            branch(*ip);
  413.            return;
  414.        }
  415.     }
  416.  
  417.     /* Else remove the loop frame from the return stack and skip */
  418.     rdrop(3);
  419.     skip;
  420. }
  421.  
  422. COMPILATION_CODE(parenplusloop, parenloop, "(+loop)", doparenplusloop);
  423.  
  424.  
  425. /* COMPILATION LITERALS */
  426.  
  427. void doparenliteral()
  428.     spush(*ip++);
  429. }
  430.  
  431. COMPILATION_CODE(parenliteral, parenplusloop, "(literal)", doparenliteral);
  432.  
  433. void doparendotquote()
  434. {
  435.     (void) printf("%s", *ip++);
  436. }
  437.  
  438. COMPILATION_CODE(parendotquote, parenliteral, "(.\")", doparendotquote);
  439.  
  440. void doparenabortquote()
  441. {
  442.     long flag = spop;
  443.     
  444.     /* Check flag on top of stack. If true then abort and give inline message */
  445.     if (flag) {
  446.        doparendotquote();
  447.        doabort();
  448.     }
  449.     else skip;
  450. }
  451.  
  452. COMPILATION_CODE(parenabortquote, parendotquote, "(abort\")", doparenabortquote);
  453.  
  454. void doparensemicolon()
  455. {
  456.     jump(rpop);
  457. }
  458.  
  459. COMPILATION_CODE(parensemicolon, parendotquote, "(;)", doparensemicolon);
  460.  
  461. void doparendoes()
  462. {
  463.     ((ENTRY *) (current -> parameter)) -> code = (long) ip;
  464.     jump(rpop);
  465. }
  466.  
  467. COMPILATION_CODE(parendoes, parensemicolon, "(does>)", doparendoes);
  468.  
  469.  
  470. /* THREADING PRIMITIVES */
  471.  
  472. void dothread()
  473. {
  474.     *dp++ = spop;
  475. }
  476.  
  477. NORMAL_CODE(thread, parendoes, "thread", dothread);
  478.  
  479. void dounthread()
  480. {
  481.     unary(*(long *));
  482. }
  483.  
  484. NORMAL_CODE(unthread, thread, "unthread", dounthread);
  485.  
  486.  
  487. /* COMPILATION: STANDARD EXTENSION LEVEL DEFINITIONS */
  488.  
  489. void doforwardmark()
  490. {
  491.     dohere();
  492.     spush(0);
  493.     docomma();
  494. }
  495.  
  496. COMPILATION_CODE(forwardmark, unthread, ">mark", doforwardmark);
  497.  
  498. void dobackwardmark()
  499. {
  500.     dohere();
  501. }
  502.  
  503. COMPILATION_CODE(backwardmark, forwardmark, "<mark", dobackwardmark);
  504.  
  505. void doforwardresolve()
  506. {
  507.     dohere();
  508.     doover();
  509.     dominus();
  510.     doswap();
  511.     dostore();
  512. }
  513.  
  514. COMPILATION_CODE(forwardresolve, backwardmark, ">resolve", doforwardresolve);
  515.  
  516. void dobackwardresolve()
  517. {
  518.     dohere();
  519.     dominus();
  520.     docomma();
  521. }
  522.  
  523. COMPILATION_CODE(backwardresolve, forwardresolve, "<resolve", dobackwardresolve);
  524.  
  525. NORMAL_VOCABULARY(compiler, forth, "compiler", backwardresolve);
  526.  
  527.  
  528. /* LOCAL VARIABLES AND ARGUMENT BINDING */
  529.  
  530. static ENTRY *theframed = (ENTRY *) NIL;
  531.  
  532. void doremovelocals()
  533. {
  534.     /* Check if the last definition used an argument definition */
  535.     if (theframed) {
  536.        
  537.        /* Restore the vocabulary structure */
  538.        spush(theframed);
  539.        dorestore();
  540.        theframed = (ENTRY *) NIL;
  541.     }
  542. }
  543.  
  544. void doparenlink()  
  545. {
  546.     /* Build an argument and local variable frame */
  547.     spush(tos);
  548.     rpush(fp);
  549.  
  550.     /* Using the two inline values: arguments and local variables */
  551.     fp = sp + *ip++;
  552.     sp = sp - *ip++;
  553.  
  554.     /* Save entry stack pointer to allow result movement on exit */
  555.     rpush(sp);
  556. }
  557.  
  558. COMPILATION_CODE(parenlink, forth, "(link)", doparenlink);
  559.  
  560. void doparenunlink()  
  561. {    
  562.     long *t;
  563.  
  564.     /* Remove the argument and local variable frame */
  565.     t = (long *) rpop;
  566.     spush(tos);
  567.  
  568.     /* And move results to new top of stack */
  569.     for (--t; t > sp; *--fp = *--t);
  570.     sp = fp;
  571.     spop;
  572.  
  573.     /* Restore old frame pointer */
  574.     fp = (long *) rpop;
  575. }
  576.  
  577. COMPILATION_CODE(parenunlink, parenlink, "(unlink)", doparenunlink);
  578.  
  579. void doparenunlinksemicolon() 
  580. {
  581.     long *t;
  582.  
  583.     /* Remove the argument and local variable frame */
  584.     t = (long *) rpop;
  585.     spush(tos);
  586.  
  587.     /* And move results to new top of stack */
  588.     for (--t; t > sp; *--fp = *--t);
  589.     sp = fp;
  590.     spop;
  591.  
  592.     /* Restore old frame pointer */
  593.     fp = (long *) rpop;
  594.  
  595.     /* Return from this colon definition */
  596.     jump(rpop);
  597. }
  598.  
  599. COMPILATION_CODE(parenunlinksemicolon, parenunlink, "(unlink;)", doparenunlinksemicolon);
  600.  
  601. void doparenunlinkdoes()
  602. {
  603.     long *t;
  604.  
  605.     /* Remove the argument and local variable frame */
  606.     t = (long *) rpop;
  607.     spush(tos);
  608.  
  609.     /* And move results to new top of stack */
  610.     for (--t; t > sp; *--fp = *--t);
  611.     sp = fp;
  612.     spop;
  613.  
  614.     /* Restore old frame pointer */
  615.     fp = (long *) rpop;
  616.  
  617.     /* Make the last definition of the following does code */
  618.     ((ENTRY *) ((ENTRY *) current -> parameter)) -> code = (long) ip;
  619.  
  620.     /* Return from this colon definition */
  621.     jump(rpop);
  622. }
  623.  
  624. COMPILATION_CODE(parenunlinkdoes, parenunlinksemicolon, "(unlinkdoes>)", doparenunlinkdoes);
  625.  
  626. void doparenlocal()
  627. {
  628.     spush(((long *) (long) fp - *ip++));
  629. }
  630.  
  631. COMPILATION_CODE(parenlocal, parenunlinkdoes, "(local)", doparenlocal);
  632.  
  633. void doparenlocalstore()
  634. {
  635.     *((long *) (long) fp - *ip++) = spop;
  636. }
  637.  
  638. COMPILATION_CODE(parenlocalstore, parenlocal, "(local!)", doparenlocalstore);
  639.  
  640. void doparenlocalfetch()
  641. {
  642.     spush(*((long *) (long) fp - *ip++));
  643. }
  644.  
  645. COMPILATION_CODE(parenlocalfetch, parenlocalstore, "(local@)", doparenlocalfetch);
  646.  
  647. void doassignlocal()
  648. {
  649.     *((long *) (long) fp - ((ENTRY *) *ip++) -> parameter) = spop;
  650. }
  651.  
  652. COMPILATION_CODE(assignlocal, parenlocalfetch, "->", doassignlocal);
  653.  
  654. COMPILATION_CODE(localexit, assignlocal, "exit", doparenunlinksemicolon);
  655.  
  656. void docurlebracket()
  657. {
  658.     long frameflag = 1;
  659.     long argflag   = 1;
  660.     long arguments = 0;
  661.     long locals    = 0;
  662.  
  663.     /* Check only one active lexical levels allowed */
  664.     if (theframed) {
  665.        (void) printf("%s: illegal argument binding\n", theframed -> name);
  666.        doremovelocals();
  667.        doabort();
  668.        return;
  669.     }
  670.  
  671.     /* Save pointer to latest defintion to allow removal of local names */
  672.     theframed = (ENTRY *) current -> parameter;
  673.  
  674.     /* While the end of the frame description is not found */
  675.     while (frameflag) {
  676.  
  677.        /* Scan the next symbol */
  678.        spush(' ');
  679.        doword();
  680.        if (io_eof()) {
  681.            (void) printf("locals: end of file during scan of parameter list\n");
  682.            doabort();
  683.            return;
  684.        }
  685.  
  686.        /* Check if it marks the end of the argument section */
  687.        if (STREQ(tos, "|")) {
  688.            argflag = 0;
  689.        }
  690.        else {
  691.            /* else check if its the end of the frame description */
  692.             if (STREQ(tos, "}")) {
  693.                frameflag = 0;
  694.            }
  695.            else {
  696.                /* Or the beginning of the return description */
  697.                if (STREQ(tos, "--")) {
  698.                    spop;
  699.                    spush('}');
  700.                    doword();
  701.                    frameflag = 0;
  702.                }
  703.                else {
  704.                    /* If not then make the symbol a local variable */
  705.                    if (argflag)
  706.                        arguments++;
  707.                    else
  708.                        locals++;
  709.                    (void) makeentry((char *) tos,
  710.                                     (long) LOCAL,
  711.                                     (long) COMPILATION,
  712.                                     arguments + locals);
  713.                }
  714.            }
  715.        }
  716.        spop;
  717.     }
  718.  
  719.     /* Compile the parameter binding linkage */
  720.     spush(&parenlink);
  721.     dothread();
  722.  
  723.     /* And the appropriate frame size */
  724.     spush(arguments);
  725.     docomma();
  726.     spush(locals);
  727.     docomma();
  728. }
  729.  
  730. COMPILATION_IMMEDIATE_CODE(curlebracket, localexit, "{", docurlebracket);
  731.  
  732. NORMAL_VOCABULARY(locals, compiler, "locals", curlebracket);
  733.  
  734.  
  735. /* NULL TERMINATED STRINGS */
  736.  
  737. void doparenquote()
  738. {
  739.     spush(*ip++);
  740. }
  741.  
  742. COMPILATION_CODE(parenquote, forth, "(\")", doparenquote);
  743.  
  744. void doquote()
  745. {
  746.     /* Scan for the string if not end of input */
  747.     (void) io_scan(thetib, '"');
  748.  
  749.     /* Make a copy of it */
  750.     spush(thetib);
  751.     dostringcopy();
  752.  
  753.     /* If compilation mode then thread a string literal */
  754.     if (state.parameter) {
  755.        spush(&parenquote);
  756.        dothread();
  757.        docomma();
  758.     }
  759. }
  760.  
  761. IMMEDIATE_CODE(quote, parenquote, "\"", doquote);
  762.  
  763. void dostringlength()
  764. {
  765.     tos = (long) strlen((char *) tos);
  766. }
  767.  
  768. NORMAL_CODE(stringlength, quote, "length", dostringlength);
  769.  
  770. void dostringcopy()
  771. {
  772.     tos = (long) strcpy(malloc((unsigned) strlen((char *) tos) + 1), (char *) tos);
  773. }
  774.  
  775. NORMAL_CODE(stringcopy, stringlength, "copy", dostringcopy);
  776.  
  777. void dostringequal()
  778. {
  779.     char *s = (char *) spop;
  780.     
  781.     tos = ((STREQ(tos, s) ? TRUE : FALSE));
  782. }
  783.  
  784. NORMAL_CODE(stringequal, stringcopy, "=", dostringequal);
  785.  
  786. void dostringcat()
  787. {
  788.     char *s = (char *) spop;
  789.     
  790.     tos = (long) strcat((char *) tos, s);
  791. }
  792.  
  793. NORMAL_CODE(stringcat, stringequal, "+", dostringcat);
  794.  
  795. void dostringprint()
  796. {
  797.     char *s = (char *) spop;
  798.     
  799.     (void) printf("%s", s);
  800. }
  801.  
  802. NORMAL_CODE(stringprint, stringcat, "print", dostringprint);
  803.  
  804. NORMAL_VOCABULARY(string, locals, "string", stringprint); 
  805.  
  806.  
  807. /* MEMORY ALLOCATION */
  808.  
  809. void domalloc()
  810. {
  811.     tos = (long) malloc((unsigned) tos);
  812. }
  813.  
  814. NORMAL_CODE(kernel_malloc, forth, "malloc", domalloc);
  815.  
  816. void dorealloc()
  817. {
  818.     char *m = (char *) spop;
  819.     
  820.     tos = (long) realloc(m, (unsigned) tos);
  821. }
  822.  
  823. NORMAL_CODE(kernel_realloc, kernel_malloc, "realloc", dorealloc);
  824.  
  825. void dofree()
  826. {
  827.     char *m = (char *) spop;
  828.     
  829.     free(m);
  830. }
  831.  
  832. NORMAL_CODE(kernel_free, kernel_realloc, "free", dofree);
  833.  
  834. NORMAL_VOCABULARY(memory, string, "memory", kernel_free); 
  835.  
  836.  
  837. /* DOUBLE LINKED LIST */
  838.  
  839. void doqemptyqueue()
  840. {
  841.     compare(== (long) (((QUEUE *) tos) -> succ));
  842. }
  843.  
  844. NORMAL_CODE(qemptyqueue, forth, "?empty", doqemptyqueue);
  845.  
  846. void dointoqueue()
  847. {
  848.     QUEUE *t, *q;
  849.  
  850.     q = (QUEUE *) spop;
  851.     t = (QUEUE *) spop;
  852.  
  853.     t -> pred = q -> pred;
  854.     t -> succ = q;
  855.  
  856.     q -> pred -> succ = t;
  857.     q -> pred = t;
  858. }
  859.  
  860. NORMAL_CODE(intoqueue, qemptyqueue, "into", dointoqueue);
  861.  
  862. void dooutqueue()
  863. {
  864.     QUEUE *t = (QUEUE *) spop;
  865.  
  866.     t -> succ -> pred = t -> pred;
  867.     t -> pred -> succ = t -> succ;
  868.  
  869.     t -> succ = t -> pred = t;
  870. }
  871.  
  872. NORMAL_CODE(outqueue, intoqueue, "out", dooutqueue);
  873.  
  874. NORMAL_VOCABULARY(queues, memory, "queues", outqueue);
  875.  
  876.  
  877. /* MULTI-TASKING */
  878.  
  879. static long toterminate = (long) &terminate;
  880.  
  881. NORMAL_CONSTANT(kernel_foreground, forth, "foreground", (long) &foreground);
  882.  
  883. NORMAL_CONSTANT(kernel_running, kernel_foreground, "running", (long) &tp);
  884.  
  885. void douser()
  886. {
  887.     spush(NORMAL);
  888.     spush(USER);
  889.     spush(' ');
  890.     doword();
  891.     doentry();
  892. }
  893.  
  894. NORMAL_CODE(user, kernel_running, "user", douser);
  895.  
  896. TASK *maketask(users, params, returns, action)
  897.     long users, params, returns, action;
  898. {
  899.     long size = sizeof(TASK_HEADER) + users + params + returns;
  900.     TASK *t = (TASK *) malloc((unsigned) size);
  901.  
  902.     /* Initiate queues structure, status and environment */
  903.     t -> queue.succ = t -> queue.pred = (QUEUE *) t;
  904.     t -> status = READY;
  905.  
  906.     t -> s0 = t -> sp = (long *) ((char *) t + size - returns);
  907.     t -> r0 = t -> rp = (long *) ((char *) t + size);
  908.     t -> ip = (action ? (long *) action : (long *) &toterminate);
  909.     t -> fp = NIL;
  910.     t -> ep = NIL;
  911.  
  912.     /* Return task pointer */
  913.     return t;
  914. }
  915.  
  916. void dotask()
  917. {
  918.     long users, params, returns, action;
  919.  
  920.     action  = spop;
  921.     returns = spop;
  922.     params  = spop;
  923.     users   = spop;
  924.     spush(maketask(users, params, returns, action));
  925. }
  926.  
  927. NORMAL_CODE(task, user, "task", dotask);
  928.  
  929. void doresume()
  930. {
  931.     TASK *t = (TASK *) tos;
  932.  
  933.     /* Check if the task to resume is the current task and active */
  934.     if (t -> status && t != tp) {
  935.  
  936.        /* Store the state of the current task */
  937.        tp -> sp = sp;
  938.        tp -> s0 = s0;
  939.        tp -> ip = ip;
  940.        tp -> rp = rp;
  941.        tp -> r0 = r0;
  942.        tp -> fp = fp;
  943.        tp -> ep = ep;
  944.  
  945.        /* Indicate task switch to the virtual machine */
  946.        running = FALSE;
  947.     
  948.        /* Restore the parameter task */
  949.        sp = t -> sp;
  950.        s0 = t -> s0;
  951.        ip = t -> ip;
  952.        rp = t -> rp;
  953.        r0 = t -> r0;
  954.        fp = t -> fp;
  955.        ep = t -> ep;
  956.        tp = t;
  957.     }
  958.  
  959.     /* Load top of stack again */
  960.     spop;
  961. }
  962.  
  963. NORMAL_CODE(resume, task, "resume", doresume);
  964.  
  965. void doschedule()
  966. {
  967.     /* Put the task after the current task */
  968.     spush(tp -> queue.succ);
  969.     dointoqueue();
  970.  
  971.     /* Resume the task now */
  972.     dodetach();
  973.  
  974.     /* Restore parameter and return stack */
  975.     spush(tp);
  976.     rpush(&toterminate);
  977.  
  978.     /* Mark the task as running */
  979.     tp -> status = RUNNING;
  980. }
  981.  
  982. NORMAL_CODE(schedule, resume, "schedule", doschedule);
  983.  
  984. void dodetach()
  985. {
  986.     /* Resume the next task in the system task queue */
  987.     spush(tp -> queue.succ);
  988.     doresume();
  989. }
  990.  
  991. NORMAL_CODE(detach, schedule , "detach", dodetach);
  992.  
  993. void doterminate()
  994. {
  995.     TASK *t = tp;
  996.  
  997.     /* Check if the task is the foreground task */
  998.     if (tp == foreground) {
  999.  
  1000.        /* Empty the return stack and signal end of execution to inner loop */
  1001.        rinit;
  1002.        running = FALSE;
  1003.        tasking = FALSE;
  1004.  
  1005.        /* Foreground should always terminate on last exit */
  1006.        ip = (long *) &toterminate;
  1007.     }
  1008.     else {
  1009.  
  1010.        /* else remove the current task from the system task queue */
  1011.        dodetach();
  1012.        t -> status = TERMINATED;
  1013.        spush(t);
  1014.        dooutqueue();
  1015.     }
  1016. }
  1017.  
  1018. NORMAL_CODE(terminate, detach, "terminate", doterminate);
  1019.  
  1020. NORMAL_VOCABULARY(multitasking, queues, "multi-tasking", terminate);
  1021.  
  1022.  
  1023. /* EXCEPTION MANAGEMENT */
  1024.  
  1025. void donewexception()
  1026. {
  1027.     spush(NIL);
  1028.     spush(NORMAL);
  1029.     spush(EXCEPTION);
  1030.     spush(' ');
  1031.     doword();
  1032.     doentry();
  1033. }
  1034.  
  1035. NORMAL_CODE(newexception, forth, "exception", donewexception);
  1036.  
  1037. void doparenexceptionsemicolon()
  1038. {  
  1039.     /* Restore the old exception frame pointer */
  1040.     ep = (long *) rpop;
  1041.  
  1042.     /* Remove the exception frame */
  1043.     rdrop(4);
  1044.     
  1045.     /* Return from the current definition */
  1046.     jump(rpop);
  1047. }
  1048.  
  1049. COMPILATION_CODE(parenexceptionsemicolon, newexception, "(exception;)", doparenexceptionsemicolon);
  1050.  
  1051. void doparenexceptionunlinksemicolon()
  1052. {  
  1053.     long *t;
  1054.  
  1055.     /* Remove the argument and local variable frame */
  1056.     t = (long *) rpop;
  1057.     spush(tos);
  1058.  
  1059.     /* And move results to new top of stack */
  1060.     for (--t; t > sp; *--fp = *--t);
  1061.     sp = fp;
  1062.     spop;
  1063.  
  1064.     /* Restore old frame pointer */
  1065.     fp = (long *) rpop;
  1066.  
  1067.     /* Restore the old exception frame pointer */
  1068.     ep = (long *) rpop;
  1069.  
  1070.     /* Remove the exception frame */
  1071.     rdrop(4);
  1072.     
  1073.     /* Return from the current definition */
  1074.     jump(rpop);
  1075. }
  1076.  
  1077. COMPILATION_CODE(parenexceptionunlinksemicolon, parenexceptionsemicolon, "(exceptionunlink;)", doparenexceptionunlinksemicolon);
  1078.  
  1079. void doparenexception()
  1080. {   
  1081.     long body;
  1082.  
  1083.     /* Capture pointer to body */
  1084.     body = spop;
  1085.    
  1086.     /* Build an exception frame */
  1087.     rpush(tos);
  1088.     rpush(sp);
  1089.     rpush(ip);
  1090.     rpush(fp);
  1091.     rpush(ep);
  1092.     ep = rp;
  1093.     
  1094.     /* Jump to the body of the definition */
  1095.     jump(body);
  1096. }
  1097.  
  1098. COMPILATION_CODE(parenexception, parenexceptionunlinksemicolon, "(exception>)", doparenexception);
  1099.  
  1100. void doexception()
  1101. {  
  1102.     ENTRY *t;
  1103.  
  1104.     /* Set up pointer to last definition */
  1105.     dolast();
  1106.     t = (ENTRY *) spop;
  1107.     
  1108.     /* Compile an exit of the current definition */
  1109.     spush((theframed ? &parenexceptionunlinksemicolon : &parenexceptionsemicolon));
  1110.     dothread();
  1111.     doremovelocals();
  1112.     
  1113.     /* Redefine the code type of the last definition */
  1114.     t -> code = (long) dp;
  1115.     
  1116.     /* Compile the run time exception management definition */
  1117.     spush(&parenexception);
  1118.     dothread();
  1119. }
  1120.  
  1121. COMPILATION_IMMEDIATE_CODE(exception, parenexception, "exception>", doexception);
  1122.  
  1123. void doraise()
  1124. {  
  1125.     long s = spop;
  1126.     
  1127.     /* Check if there is an exception block available */
  1128.     if (ep) {
  1129.  
  1130.        /* Restore the call environment */
  1131.        rp = ep;
  1132.        ep = (long *) rpop;
  1133.        fp = (long *) rpop;
  1134.        ip = (long *) rpop;
  1135.        sp = (long *) rpop;
  1136.        tos = rpop;
  1137.  
  1138.        /* Pass on the signal or exception to the exception block */
  1139.        spush(s);
  1140.     }
  1141.     else {
  1142.        
  1143.        /* Call low level management of signal */
  1144.        (void) error_signal(s);
  1145.     }
  1146. }
  1147.  
  1148. NORMAL_CODE(raise, exception, "raise", doraise);
  1149.  
  1150. NORMAL_VOCABULARY(exceptions, multitasking, "exceptions", raise);
  1151.  
  1152.  
  1153. /* LOGIC: FORTH-83 VOCABULARY */
  1154.  
  1155. NORMAL_CONSTANT(false, exceptions, "false", FALSE);
  1156.  
  1157. NORMAL_CONSTANT(true, false, "true", TRUE);
  1158.  
  1159. void doboolean()
  1160. {
  1161.     compare(!= 0);
  1162. }
  1163.  
  1164. NORMAL_CODE(boolean, true, "boolean", doboolean);
  1165.  
  1166. void donot()
  1167. {
  1168.     unary(~);
  1169. }
  1170.  
  1171. NORMAL_CODE(not, boolean, "not", donot);
  1172.  
  1173. void doand()
  1174. {
  1175.     binary(&);
  1176. }
  1177.  
  1178. NORMAL_CODE(and, not, "and", doand);
  1179.  
  1180. void door()
  1181. {
  1182.     binary(|);
  1183. }
  1184.  
  1185. NORMAL_CODE(or, and, "or", door);
  1186.  
  1187. void doxor()
  1188. {
  1189.     binary(^);
  1190. }
  1191.  
  1192. NORMAL_CODE(xor, or, "xor", doxor);
  1193.  
  1194. void doqwithin()
  1195. {
  1196.     long value;
  1197.     long upper;
  1198.     long lower;
  1199.     
  1200.     upper = spop;
  1201.     lower = spop;
  1202.     value = spop;
  1203.     
  1204.     spush((value > upper) || (value < lower) ? FALSE : TRUE);
  1205. }
  1206.     
  1207. NORMAL_CODE(qwithin, xor, "?within", doqwithin);
  1208.  
  1209.  
  1210. /* STACK MANIPULATION */
  1211.  
  1212. void dodup()
  1213. {
  1214.     spush(tos);
  1215. }
  1216.  
  1217. NORMAL_CODE(kernel_dup, qwithin, "dup", dodup);
  1218.  
  1219. void dodrop()
  1220. {
  1221.     spop;
  1222. }
  1223.  
  1224. NORMAL_CODE(drop, kernel_dup, "drop", dodrop);
  1225.  
  1226. void doswap()
  1227. {
  1228.     long t = tos;
  1229.  
  1230.     tos = snth(0);
  1231.     snth(0) = t;
  1232. }
  1233.  
  1234. NORMAL_CODE(swap, drop, "swap", doswap);
  1235.  
  1236. void doover()
  1237. {
  1238.     spush(snth(1));
  1239. }
  1240.  
  1241. NORMAL_CODE(over, swap, "over", doover);
  1242.  
  1243. void dorot()
  1244. {
  1245.     long t = tos;
  1246.  
  1247.     tos = snth(1);
  1248.     snth(1) = snth(0);
  1249.     snth(0) = t;
  1250. }
  1251.  
  1252. NORMAL_CODE(rot, over, "rot", dorot);
  1253.  
  1254. void dopick()
  1255. {
  1256.     tos = snth(tos);
  1257. }
  1258.  
  1259. NORMAL_CODE(pick, rot, "pick", dopick);
  1260.  
  1261. void doroll()
  1262. {
  1263.     long e;
  1264.     long *s;
  1265.  
  1266.     /* Fetch roll parameters: number and element */
  1267.     e = snth(tos);
  1268.  
  1269.     /* Roll the stack */
  1270.     for (s = sp + tos; s > sp; s--) *s = *(s - 1);
  1271.     sp++;
  1272.     
  1273.     /* And assign the new top of stack */
  1274.     tos = e;
  1275. }
  1276.  
  1277. NORMAL_CODE(roll, pick, "roll", doroll);
  1278.  
  1279. void doqdup()
  1280. {
  1281.     if (tos) spush(tos);
  1282. }
  1283.  
  1284. NORMAL_CODE(qdup, roll, "?dup", doqdup);
  1285.  
  1286. void dotor()
  1287. {
  1288.     rpush(spop);
  1289. }
  1290.  
  1291. COMPILATION_CODE(tor, qdup, ">r", dotor);
  1292.  
  1293. void dofromr()
  1294. {
  1295.     spush(rpop);
  1296. }
  1297.  
  1298. COMPILATION_CODE(fromr, tor, "r>", dofromr);
  1299.  
  1300. void docopyr()
  1301. {
  1302.     spush(*rp);
  1303. }
  1304.  
  1305. COMPILATION_CODE(copyr, fromr, "r@", docopyr);
  1306.  
  1307. void dodepth()
  1308. {
  1309.     long *t = sp;
  1310.  
  1311.     spush((s0 - t));
  1312. }
  1313.  
  1314. NORMAL_CODE(depth, copyr, "depth", dodepth);
  1315.  
  1316. void dodots()
  1317. {
  1318.     /* Print the stack depth */
  1319.     (void) printf("[%d] ", s0 - sp);
  1320.  
  1321.     /* Check if there are any elements on the stack */
  1322.     if (s0 - sp > 0) {
  1323.        long *s;
  1324.  
  1325.        /* Print them and don't forget top of stack */
  1326.        for (s = s0 - 2; s >= sp; s--) {
  1327.            (void) printf("\\");
  1328.            spush(*s);
  1329.            if (tos < 0) {
  1330.                (void) putchar('-');
  1331.                tos = -tos;
  1332.            }
  1333.            dolesssharp();
  1334.            dosharps();
  1335.            dosharpgreater();
  1336.            dotype();
  1337.        }
  1338.        (void) printf("\\");
  1339.        dodup();
  1340.        dodot();
  1341.     }
  1342. }
  1343.  
  1344. NORMAL_CODE(dots, depth, ".s", dodots);
  1345.  
  1346.  
  1347. /* COMPARISON */
  1348.  
  1349. void dolessthan()
  1350. {
  1351.     relation(<);
  1352. }
  1353.  
  1354. NORMAL_CODE(lessthan, dots, "<", dolessthan);
  1355.  
  1356. void doequals()
  1357. {
  1358.     relation(==);
  1359. }
  1360.  
  1361. NORMAL_CODE(equals, lessthan, "=", doequals);
  1362.  
  1363. void dogreaterthan()
  1364. {
  1365.     relation(>);
  1366. }
  1367.  
  1368. NORMAL_CODE(greaterthan, equals, ">", dogreaterthan);
  1369.  
  1370. void dozeroless()
  1371. {
  1372.     compare(< 0);
  1373. }
  1374.  
  1375. NORMAL_CODE(zeroless, greaterthan, "0<", dozeroless);
  1376.  
  1377. void dozeroequals()
  1378. {
  1379.     compare(== 0);
  1380. }
  1381.  
  1382. NORMAL_CODE(zeroequals, zeroless, "0=", dozeroequals);
  1383.  
  1384. void dozerogreater()
  1385. {
  1386.     compare(> 0);
  1387. }
  1388.  
  1389. NORMAL_CODE(zerogreater, zeroequals, "0>", dozerogreater);
  1390.  
  1391. void doulessthan()
  1392. {
  1393.     urelation(<);
  1394. }
  1395.  
  1396. NORMAL_CODE(ulessthan, zerogreater, "u<", doulessthan);
  1397.  
  1398.  
  1399. /* CONSTANTS */
  1400.  
  1401. NORMAL_CONSTANT(nil, ulessthan, "nil", NIL);
  1402.  
  1403. NORMAL_CONSTANT(minustwo, nil, "-2", -2);
  1404.  
  1405. NORMAL_CONSTANT(minusone, minustwo, "-1", -1);
  1406.  
  1407. NORMAL_CONSTANT(zero, minusone, "0", 0);
  1408.  
  1409. NORMAL_CONSTANT(one, zero, "1", 1);
  1410.  
  1411. NORMAL_CONSTANT(two, one, "2", 2);
  1412.  
  1413.  
  1414. /* ARITHMETRIC */
  1415.  
  1416. void doplus()
  1417. {
  1418.     binary(+);
  1419. }
  1420.  
  1421. NORMAL_CODE(plus, two, "+", doplus);
  1422.  
  1423. void dominus()
  1424. {
  1425.     binary(-);
  1426. }
  1427.  
  1428. NORMAL_CODE(minus, plus, "-", dominus);
  1429.  
  1430. void dooneplus()
  1431. {
  1432.     unary(++);
  1433. }
  1434.  
  1435. NORMAL_CODE(oneplus, minus, "1+", dooneplus);
  1436.  
  1437. void dooneminus()
  1438. {
  1439.     unary(--);
  1440. }
  1441.  
  1442. NORMAL_CODE(oneminus, oneplus, "1-", dooneminus);
  1443.  
  1444. void dotwoplus()
  1445. {
  1446.     unary(2 +);
  1447. }
  1448.  
  1449. NORMAL_CODE(twoplus, oneminus, "2+", dotwoplus);
  1450.  
  1451. void dotwominus()
  1452. {
  1453.     unary(-2 +);
  1454. }
  1455.  
  1456. NORMAL_CODE(twominus, twoplus, "2-", dotwominus);
  1457.  
  1458. void dotwotimes()
  1459. {
  1460.     tos <<= 1;
  1461. }
  1462.  
  1463. NORMAL_CODE(twotimes, twominus, "2*", dotwotimes);
  1464.  
  1465. void doleftshift()
  1466. {
  1467.     binary(<<);
  1468. }
  1469.  
  1470. NORMAL_CODE(leftshift, twotimes, "<<", doleftshift);
  1471.  
  1472. void dotimes()
  1473. {
  1474.     binary(*);
  1475. }
  1476.  
  1477. NORMAL_CODE(kernel_times, leftshift, "*", dotimes);
  1478.  
  1479. void doumtimes()
  1480. {
  1481.     ubinary(*);
  1482. }
  1483.  
  1484. NORMAL_CODE(kernel_utimes, kernel_times, "um*", doumtimes);
  1485.  
  1486. void doumdividemod()
  1487. {
  1488.     long t = snth(0);
  1489.  
  1490.     snth(0) = (unsigned long) t % (unsigned long) tos;
  1491.     tos = (unsigned long) t / (unsigned long) tos;
  1492. }
  1493.  
  1494. NORMAL_CODE(umdividemod, kernel_utimes, "um/mod", doumdividemod);
  1495.  
  1496. void dotwodivide()
  1497. {
  1498.     tos >>= 1;
  1499. }
  1500.  
  1501. NORMAL_CODE(twodivide, umdividemod, "2/", dotwodivide);
  1502.  
  1503. void dorightshift()
  1504. {
  1505.     binary(>>);
  1506. }
  1507.  
  1508. NORMAL_CODE(rightshift, twodivide, ">>", dorightshift);
  1509.  
  1510. void dodivide()
  1511. {
  1512.     binary(/);
  1513. }
  1514.  
  1515. NORMAL_CODE(divide, rightshift, "/", dodivide);
  1516.  
  1517. void domod()
  1518. {
  1519.     binary(%);
  1520. }
  1521.  
  1522. NORMAL_CODE(mod, divide, "mod", domod);
  1523.  
  1524. void dodividemod()
  1525. {
  1526.     long t = snth(0);
  1527.  
  1528.     snth(0) = t % tos;
  1529.     tos = t / tos;
  1530. }
  1531.  
  1532. NORMAL_CODE(dividemod, mod, "/mod", dodividemod);
  1533.  
  1534. void dotimesdividemod()
  1535. {
  1536.     long t = spop;
  1537.  
  1538.     tos = tos * snth(0);
  1539.     snth(0) = tos % t;
  1540.     tos = tos / t;
  1541. }
  1542.  
  1543. NORMAL_CODE(timesdividemod, dividemod, "*/mod", dotimesdividemod);
  1544.  
  1545. void dotimesdivide()
  1546. {
  1547.     long t = spop;
  1548.  
  1549.     binary(*);
  1550.     spush(t);
  1551.     binary(/);
  1552. }
  1553.  
  1554. NORMAL_CODE(timesdivide, timesdividemod, "*/", dotimesdivide);
  1555.  
  1556. void domin()
  1557. {
  1558.     long t = spop;
  1559.     
  1560.     tos = (t < tos ? t : tos);
  1561. }
  1562.  
  1563. NORMAL_CODE(min, timesdivide, "min", domin);
  1564.  
  1565. void domax()
  1566. {
  1567.     long t = spop;
  1568.     
  1569.     tos = (t > tos ? t : tos);
  1570. }
  1571.  
  1572. NORMAL_CODE(max, min, "max", domax);
  1573.  
  1574. void doabs()
  1575. {
  1576.     tos = (tos < 0 ? -tos : tos);
  1577. }
  1578.  
  1579. NORMAL_CODE(kernel_abs, max, "abs", doabs);
  1580.  
  1581. void donegate()
  1582. {
  1583.     unary(-);
  1584. }
  1585.  
  1586. NORMAL_CODE(negate, kernel_abs, "negate", donegate);
  1587.  
  1588.  
  1589. /* MEMORY */
  1590.  
  1591. void dofetch()
  1592. {
  1593.     unary(*(long *));
  1594. }
  1595.  
  1596. NORMAL_CODE(fetch, negate, "@", dofetch);
  1597.  
  1598. void dostore()
  1599. {
  1600.     *((long *) tos) = snth(0);
  1601.     sdrop(1);
  1602. }
  1603.  
  1604. NORMAL_CODE(store, fetch, "!", dostore);
  1605.  
  1606. void dowfetch()
  1607. {
  1608.     unary(*(word *));
  1609. }
  1610.  
  1611. NORMAL_CODE(wfetch, store, "w@", dowfetch);
  1612.  
  1613. void dowstore()
  1614. {
  1615.     *((word *) tos) = snth(0);
  1616.     sdrop(1);
  1617. }
  1618.  
  1619. NORMAL_CODE(wstore, wfetch, "w!", dowstore);
  1620.  
  1621. void docfetch()
  1622. {
  1623.     unary(*(char *));
  1624. }
  1625.  
  1626. NORMAL_CODE(cfetch, wstore, "c@", docfetch);
  1627.  
  1628. void docstore()
  1629. {
  1630.     *((char *) tos) = snth(0);
  1631.     sdrop(1);
  1632. }
  1633.  
  1634. NORMAL_CODE(cstore, cfetch, "c!", docstore);
  1635.  
  1636. void doffetch()
  1637. {
  1638.     long pos;
  1639.     long width;
  1640.  
  1641.     width = spop;
  1642.     pos = spop;
  1643.     tos = (tos >> pos) & ~(-1 << width);
  1644. }
  1645.  
  1646. NORMAL_CODE(ffetch, cstore, "f@", doffetch);
  1647.  
  1648. void dofstore()
  1649. {
  1650.     long pos;
  1651.     long width;
  1652.     long value;
  1653.  
  1654.     width = spop;
  1655.     pos = spop;
  1656.     value = spop;
  1657.     tos = ((tos & ~(-1 << width)) << pos) | (value & ~((~(-1 << width)) << pos));
  1658. }
  1659.  
  1660. NORMAL_CODE(fstore, ffetch, "f!", dofstore);
  1661.  
  1662. void dobfetch()
  1663. {
  1664.     long bit = spop;
  1665.  
  1666.     tos = (((tos >> bit) & 1) ? TRUE : FALSE);
  1667. }
  1668.  
  1669. NORMAL_CODE(bfetch, fstore, "b@", dobfetch);
  1670.  
  1671. void dobstore()
  1672. {
  1673.     long bit;
  1674.     long value;
  1675.  
  1676.     bit = spop;
  1677.     value = spop;
  1678.  
  1679.     tos = (tos ? (value | (1 << bit)) : (value & ~(1 << bit)));
  1680. }
  1681.  
  1682. NORMAL_CODE(bstore, bfetch, "b!", dobstore);
  1683.  
  1684. void doplusstore()
  1685. {
  1686.     *((long *) tos) += snth(0);
  1687.     sdrop(1);
  1688. }
  1689.  
  1690. NORMAL_CODE(plusstore, bstore, "+!", doplusstore);
  1691.  
  1692.  
  1693. /* STRINGS */
  1694.  
  1695. void docmove()
  1696. {
  1697.     register long n;
  1698.     register char *to;
  1699.     register char *from;
  1700.  
  1701.     n = spop;
  1702.     to = (char *) spop;
  1703.     from = (char *) spop;
  1704.  
  1705.     while (--n != -1) *to++ = *from++;
  1706. }
  1707.  
  1708. NORMAL_CODE(cmove, plusstore, "cmove", docmove);
  1709.  
  1710. void docmoveup()
  1711. {
  1712.     register long n;
  1713.     register char *to;
  1714.     register char *from;
  1715.  
  1716.     n = spop;
  1717.     to = (char *) spop;
  1718.     from = (char *) spop;
  1719.  
  1720.     to += n;
  1721.     from += n;
  1722.     while (--n != -1) *--to = *--from;
  1723. }
  1724.  
  1725. NORMAL_CODE(cmoveup, cmove, "cmove>", docmoveup);
  1726.  
  1727. void dofill()
  1728. {
  1729.     register char with;
  1730.     register long n;
  1731.     register char *from;
  1732.  
  1733.     with = (char) spop;
  1734.     n = spop;
  1735.     from = (char *) spop;
  1736.  
  1737.     while (--n != -1) *from++ = with;
  1738. }
  1739.  
  1740. NORMAL_CODE(fill, cmoveup, "fill", dofill);
  1741.  
  1742. void docount()
  1743. {
  1744.     spush(*((char *) tos));
  1745.     snth(0)++;
  1746. }
  1747.  
  1748. NORMAL_CODE(count, fill, "count", docount);
  1749.  
  1750. void dodashtrailing()
  1751. {
  1752.     char *p = (char *) (snth(0) + tos);
  1753.     
  1754.     tos += 1;
  1755.     while (--tos && (*--p == ' '));
  1756. }
  1757.  
  1758. NORMAL_CODE(dashtrailing, count, "-trailing", dodashtrailing);
  1759.  
  1760.  
  1761. /* NUMERICAL CONVERSION */
  1762.  
  1763. NORMAL_VARIABLE(base, dashtrailing, "base", 10);
  1764.  
  1765. void dobinary()
  1766. {
  1767.     base.parameter = 2;
  1768. }
  1769.  
  1770. NORMAL_CODE(kernel_binary, base, "binary", dobinary);
  1771.  
  1772. void dooctal()
  1773. {
  1774.     base.parameter = 8;
  1775. }
  1776.  
  1777. NORMAL_CODE(octal, kernel_binary, "octal", dooctal);
  1778.  
  1779. void dodecimal()
  1780. {
  1781.     base.parameter = 10;
  1782. }
  1783.  
  1784. NORMAL_CODE(decimal, octal, "decimal", dodecimal);
  1785.  
  1786. void dohex()
  1787. {
  1788.     base.parameter = 16;
  1789. }
  1790.  
  1791. NORMAL_CODE(hex, decimal, "hex", dohex);
  1792.  
  1793. void doconvert()
  1794. {
  1795.     register char c;
  1796.     register long b;
  1797.     register long n;
  1798.     
  1799.     b = base.parameter;
  1800.     n = snth(0);                       
  1801.  
  1802.     for (;;) {
  1803.        c = *(char *) tos;
  1804.        if (c < '0' || c > 'z' || (c > '9' && c < 'a')) {
  1805.            snth(0) = n;
  1806.            return;
  1807.        }
  1808.        else {
  1809.            if (c > '9') c = c - 'a' + ':';
  1810.            c = c - '0';
  1811.            if (c < 0 || c >= b) {
  1812.                snth(0) = n;
  1813.                return;
  1814.            }
  1815.            n = (n * b) + c;
  1816.            tos += 1;
  1817.        }
  1818.     }
  1819. }
  1820.  
  1821. NORMAL_CODE(convert, hex, "convert", doconvert);
  1822.  
  1823. static long hld;
  1824.  
  1825. void dolesssharp()
  1826. {
  1827.     hld = (long) thepad + PADSIZE;
  1828. }
  1829.  
  1830. NORMAL_CODE(lesssharp, convert, "<#", dolesssharp);
  1831.  
  1832. void dosharp()
  1833. {
  1834.     long n = tos;
  1835.     
  1836.     tos = (unsigned long) n / (unsigned long) base.parameter;
  1837.     n = (unsigned long) n % (unsigned long) base.parameter;
  1838.     *(char *) --hld = n + ((n > 9) ? 'a' - 10 : '0');
  1839. }
  1840.  
  1841. NORMAL_CODE(sharp, lesssharp, "#", dosharp);
  1842.  
  1843. void dosharps()
  1844. {
  1845.     do { dosharp(); } while (tos);
  1846. }
  1847.  
  1848. NORMAL_CODE(sharps, sharp, "#s", dosharps);
  1849.  
  1850. void dohold()
  1851. {
  1852.     *(char *) --hld = spop;
  1853. }
  1854.  
  1855. NORMAL_CODE(hold, sharps, "hold", dohold);
  1856.  
  1857. void dosign()
  1858. {
  1859.     long flag = spop;
  1860.     
  1861.     if (flag < 0) *(char *) --hld = '-';
  1862. }
  1863.  
  1864. NORMAL_CODE(sign, hold, "sign", dosign);
  1865.  
  1866. void dosharpgreater()
  1867. {
  1868.     tos = hld;
  1869.     spush(thepad + PADSIZE - hld);
  1870. }
  1871.  
  1872. NORMAL_CODE(sharpgreater, sign, "#>", dosharpgreater);
  1873.  
  1874. void doqnumber()
  1875. {
  1876.     char *s0;
  1877.     char *s1;
  1878.     
  1879.     s0 = (char *) spop;
  1880.     spush(0);
  1881.     if (*s0 == '-') {
  1882.        spush(s0 + 1);
  1883.     }
  1884.     else {
  1885.        spush(s0);
  1886.     }
  1887.     doconvert();
  1888.     s1 = (char *) spop;
  1889.     if (*s1 == '\0') {
  1890.        if (*s0 == '-') unary(-);
  1891.        spush(TRUE);
  1892.     }
  1893.     else {
  1894.        tos = (long) s0;
  1895.        spush(FALSE);
  1896.     }
  1897. }
  1898.  
  1899. NORMAL_CODE(qnumber, sharpgreater, "?number", doqnumber);
  1900.  
  1901.  
  1902. /* CONTROL STRUCTURES */
  1903.  
  1904. long docheck(this)
  1905.     int this;
  1906. {
  1907.     ENTRY *last;
  1908.     long follow = spop;
  1909.  
  1910.     /* Check if the symbol is in the follow set */
  1911.     if (this & follow) {
  1912.  
  1913.        /* Return true is so */
  1914.        return TRUE;
  1915.     }
  1916.     else {
  1917.  
  1918.        /* Else report a control structure error */
  1919.        dolast();
  1920.        last = (ENTRY *) spop;
  1921.        (void) printf("%s: illegal control structure\n", last -> name);
  1922.        doabort();
  1923.  
  1924.        return FALSE;
  1925.     }
  1926. }
  1927.  
  1928. void dodo()
  1929. {
  1930.     spush(&parendo);
  1931.     dothread();
  1932.     doforwardmark();
  1933.     dobackwardmark();
  1934.     spush(LOOP+PLUSLOOP);
  1935. }
  1936.  
  1937. COMPILATION_IMMEDIATE_CODE(kernel_do, qnumber, "do", dodo);
  1938.  
  1939. void doqdo()
  1940. {
  1941.     spush(&parenqdo);
  1942.     dothread();
  1943.     doforwardmark();
  1944.     dobackwardmark();
  1945.     spush(LOOP+PLUSLOOP);
  1946. }
  1947.  
  1948. COMPILATION_IMMEDIATE_CODE(kernel_qdo, kernel_do, "?do", doqdo);
  1949.  
  1950. void doloop()
  1951. {
  1952.     if (docheck(LOOP)) {
  1953.        spush(&parenloop);
  1954.        dothread();
  1955.        dobackwardresolve();
  1956.        doforwardresolve();
  1957.     }
  1958. }
  1959.  
  1960. COMPILATION_IMMEDIATE_CODE(loop, kernel_qdo, "loop", doloop);
  1961.  
  1962. void doplusloop()
  1963. {
  1964.     if (docheck(PLUSLOOP)) {
  1965.        spush(&parenplusloop);
  1966.        dothread();
  1967.        dobackwardresolve();
  1968.        doforwardresolve();
  1969.     }
  1970. }
  1971.  
  1972. COMPILATION_IMMEDIATE_CODE(plusloop, loop, "+loop", doplusloop);
  1973.  
  1974. void doleave()
  1975. {
  1976.     rdrop(2);
  1977.     jump(rpop);
  1978.     branch(*ip);
  1979. }
  1980.  
  1981. COMPILATION_CODE(leave, plusloop, "leave", doleave);
  1982.  
  1983. void doi()
  1984. {
  1985.     spush(rnth(1));
  1986. }
  1987.  
  1988. COMPILATION_CODE(kernel_i, leave,"i", doi);
  1989.  
  1990. void doj()
  1991. {
  1992.     spush(rnth(4));
  1993. }
  1994.  
  1995. COMPILATION_CODE(kernel_j, kernel_i, "j", doj);
  1996.  
  1997. void doif()
  1998. {
  1999.     spush(&parenqbranch);
  2000.     dothread();
  2001.     doforwardmark();
  2002.     spush(ELSE+THEN);
  2003. }
  2004.  
  2005. COMPILATION_IMMEDIATE_CODE(kernel_if, kernel_j, "if", doif);
  2006.  
  2007. void doelse()
  2008. {
  2009.     if (docheck(ELSE)) {
  2010.        spush(&parenbranch);
  2011.        dothread();
  2012.        doforwardmark();
  2013.        doswap();
  2014.        doforwardresolve();
  2015.        spush(THEN);
  2016.     }
  2017. }
  2018.  
  2019. COMPILATION_IMMEDIATE_CODE(kernel_else, kernel_if, "else", doelse);
  2020.  
  2021. void dothen()
  2022. {
  2023.     if (docheck(THEN)) {
  2024.        doforwardresolve();
  2025.     }
  2026. }
  2027.  
  2028. COMPILATION_IMMEDIATE_CODE(kernel_then, kernel_else, "then", dothen);
  2029.  
  2030. void docase()
  2031. {
  2032.     spush(0);
  2033.     spush(OF+ENDCASE);
  2034. }
  2035.  
  2036. COMPILATION_IMMEDIATE_CODE(kernel_case, kernel_then, "case", docase);
  2037.  
  2038. void doof()
  2039. {
  2040.     if (docheck(OF)) {
  2041.        spush(&over);
  2042.        dothread();
  2043.        spush(&equals);
  2044.        dothread();
  2045.        spush(&parenqbranch);
  2046.        dothread();
  2047.        doforwardmark();
  2048.        spush(&drop);
  2049.        dothread();
  2050.        spush(ENDOF);
  2051.     }
  2052. }
  2053.  
  2054. COMPILATION_IMMEDIATE_CODE(kernel_of, kernel_case, "of", doof);
  2055.  
  2056. void doendof()
  2057. {
  2058.     if (docheck(ENDOF)) {
  2059.        spush(&parenbranch);
  2060.        dothread();
  2061.        doforwardmark();
  2062.        doswap();
  2063.        doforwardresolve();
  2064.        spush(OF+ENDCASE);
  2065.     }
  2066. }
  2067.  
  2068. COMPILATION_IMMEDIATE_CODE(endof, kernel_of, "endof", doendof);
  2069.  
  2070. void doendcase()
  2071. {
  2072.     if (docheck(ENDCASE)) {
  2073.        spush(&drop);
  2074.        dothread();
  2075.        while (tos) doforwardresolve();
  2076.        dodrop();
  2077.     }
  2078. }
  2079.  
  2080. COMPILATION_IMMEDIATE_CODE(endcase, endof, "endcase", doendcase);
  2081.  
  2082. void dobegin()
  2083. {
  2084.     dobackwardmark();
  2085.     spush(AGAIN+UNTIL+WHILE);
  2086. }
  2087.  
  2088. COMPILATION_IMMEDIATE_CODE(begin, endcase, "begin", dobegin);
  2089.  
  2090. void dountil()
  2091. {
  2092.     if (docheck(UNTIL)) {
  2093.        spush(&parenqbranch);
  2094.        dothread();
  2095.        dobackwardresolve();
  2096.     }
  2097. }
  2098.  
  2099. COMPILATION_IMMEDIATE_CODE(until, begin, "until", dountil);
  2100.  
  2101. void dowhile()
  2102. {
  2103.     if (docheck(WHILE)) {
  2104.        spush(&parenqbranch);
  2105.        dothread();
  2106.        doforwardmark();
  2107.        spush(REPEAT);
  2108.     }
  2109. }
  2110.  
  2111. COMPILATION_IMMEDIATE_CODE(kernel_while, until, "while", dowhile);
  2112.  
  2113. void dorepeat()
  2114. {
  2115.     if (docheck(REPEAT)) {
  2116.        spush(&parenbranch);
  2117.        dothread();
  2118.        doswap();
  2119.        dobackwardresolve();
  2120.        doforwardresolve();
  2121.     }
  2122. }
  2123.  
  2124. COMPILATION_IMMEDIATE_CODE(repeat, kernel_while, "repeat", dorepeat);
  2125.  
  2126. void doagain()
  2127. {
  2128.     if (docheck(AGAIN)) {
  2129.        spush(&parenbranch);
  2130.        dothread();
  2131.        dobackwardresolve();
  2132.     }
  2133. }
  2134.  
  2135. COMPILATION_IMMEDIATE_CODE(again, repeat, "again", doagain);
  2136.  
  2137. void dorecurse()
  2138. {
  2139.     dolast();
  2140.     dothread();
  2141. }
  2142.  
  2143. COMPILATION_IMMEDIATE_CODE(recurse, again, "recurse", dorecurse);
  2144.  
  2145. void dotailrecurse()
  2146. {
  2147.     if (theframed) {
  2148.        spush(&parenunlink);
  2149.        dothread();
  2150.     }
  2151.     dolast();
  2152.     dotobody();
  2153.     spush(&parenbranch);
  2154.     dothread();
  2155.     dobackwardresolve();
  2156. }
  2157.  
  2158. COMPILATION_IMMEDIATE_CODE(tailrecurse, recurse, "tail-recurse", dotailrecurse);
  2159.  
  2160. void doexit()
  2161. {
  2162.     jump(rpop);
  2163. }
  2164.  
  2165. COMPILATION_CODE(kernel_exit, tailrecurse, "exit", doexit);
  2166.  
  2167. void doexecute()
  2168. {
  2169.     long t = spop;
  2170.  
  2171.     docall((ENTRY *) t);
  2172. }
  2173.  
  2174. NORMAL_CODE(execute, kernel_exit, "execute", doexecute);
  2175.  
  2176. void dobye()
  2177. {
  2178.     quited = FALSE;
  2179. }
  2180.  
  2181. NORMAL_CODE(bye, execute, "bye", dobye);
  2182.  
  2183.  
  2184. /* TERMINAL INPUT-OUTPUT */
  2185.  
  2186. void dodot()
  2187. {
  2188.     if (tos < 0) {
  2189.        (void) putchar('-');
  2190.        tos = -tos;
  2191.     }
  2192.     doudot();
  2193. }
  2194.  
  2195. NORMAL_CODE(dot, bye, ".", dodot);
  2196.  
  2197. void doudot()
  2198. {
  2199.     dolesssharp();
  2200.     dosharps();
  2201.     dosharpgreater();
  2202.     dotype();
  2203.     dospace();
  2204. }
  2205.  
  2206. NORMAL_CODE(udot, dot, "u.", doudot);
  2207.  
  2208. void doascii()
  2209. {
  2210.     spush(' ');
  2211.     doword();
  2212.     docfetch();
  2213.     doliteral();
  2214. }
  2215.  
  2216. IMMEDIATE_CODE(ascii, udot, "ascii", doascii);
  2217.  
  2218. void dodotquote()
  2219. {
  2220.     (void) io_scan(thetib, '"');
  2221.     spush(thetib);
  2222.     dostringcopy();
  2223.     spush(&parendotquote);
  2224.     dothread();
  2225.     docomma();
  2226. }
  2227.  
  2228. COMPILATION_IMMEDIATE_CODE(dotquote, ascii, ".\"", dodotquote);
  2229.  
  2230. void dodotparen()
  2231. {
  2232.     (void) io_scan(thetib, ')'); 
  2233.     spush(thetib);
  2234.     dostringprint();
  2235. }
  2236.  
  2237. IMMEDIATE_CODE(dotparen, dotquote, ".(", dodotparen);
  2238.  
  2239. void docr()
  2240. {
  2241.     (void) putchar('\n');
  2242. }
  2243.  
  2244. NORMAL_CODE(cr, dotparen, "cr", docr);
  2245.  
  2246. void doemit()
  2247. {
  2248.     char c = (char) spop;
  2249.     
  2250.     (void) putchar(c);
  2251. }
  2252.  
  2253. NORMAL_CODE(emit, cr, "emit", doemit);
  2254.  
  2255. void dotype()
  2256. {
  2257.     long n;
  2258.     char *s;
  2259.  
  2260.     n = spop;
  2261.     s = (char *) spop;
  2262.     while (n--) (void) putchar(*s++);
  2263. }
  2264.  
  2265. NORMAL_CODE(type, emit, "type", dotype);
  2266.  
  2267. void dospace()
  2268. {
  2269.     (void) putchar(' ');
  2270. }
  2271.  
  2272. NORMAL_CODE(space, type, "space", dospace);
  2273.  
  2274. void dospaces()
  2275. {
  2276.     long n = spop;
  2277.  
  2278.     while (n--) (void) putchar(' ');
  2279. }
  2280.  
  2281. NORMAL_CODE(spaces, space, "spaces", dospaces);
  2282.  
  2283. void dokey()
  2284. {
  2285.     spush(io_getchar());
  2286. }
  2287.  
  2288. NORMAL_CODE(key, spaces, "key", dokey);
  2289.  
  2290. void doexpect()
  2291. {
  2292.     char *s0;
  2293.     char *s1;
  2294.     char  c;
  2295.     long  n;
  2296.     
  2297.     /* Pop buffer pointer and size */
  2298.     n = spop;
  2299.     s0 = s1 = (char *) spop;
  2300.     
  2301.     /* Fill buffer until end of line or buffer */
  2302.     while (io_not_eof() && (n-- > 0) && ((c = io_getchar()) != '\n')) *s1++ = c;
  2303.  
  2304.     /* Set span to number of characters received */
  2305.     span.parameter = (long) (s1 - s0);
  2306. }
  2307.  
  2308. NORMAL_CODE(expect, key, "expect", doexpect);
  2309.  
  2310. NORMAL_VARIABLE(span, expect, "span", 0);
  2311.  
  2312.  
  2313. /* PROGRAM BEGINNING AND TERMINATION */
  2314.  
  2315. void doforth83()
  2316. { }
  2317.  
  2318. NORMAL_CODE(forth83, span, "forth-83", doforth83);
  2319.     
  2320. void dointerpret()
  2321. {
  2322.     long flag;                 /* Flag value returned by for words */
  2323.     long cast;                 /* Casting operation flag */
  2324.  
  2325.     quited = TRUE;             /* Iterate until bye or end of input */
  2326.  
  2327.     while (quited) {
  2328.  
  2329.        /* Check stack underflow */
  2330.        if (s0 < sp) {
  2331.            (void) printf("interpret: stack underflow\n");
  2332.            doabort();
  2333.        }
  2334.  
  2335.        /* Scan for the next symbol */
  2336.        spush(' ');
  2337.        doword();
  2338.  
  2339.        /* Exit top loop if end of input stream */
  2340.        if (io_eof()) {
  2341.            spop;
  2342.            return;
  2343.        }
  2344.  
  2345.        /* Search for the symbol in the current vocabulary search set*/
  2346.        dofind();
  2347.        flag = spop;
  2348.  
  2349.        /* Check for vocabulary casting prefix */
  2350.        for (cast = flag; !cast;) {
  2351.            char *s = (char *) tos;
  2352.            long l = strlen(s) - 1;
  2353.  
  2354.            /* Assume casting prefix */
  2355.            cast = TRUE;
  2356.  
  2357.            /* Check casting syntax, vocabulary name within parethesis */ 
  2358.            if ((s[0] == '(') && (s[l] == ')')) {
  2359.  
  2360.                /* Remove the parenthesis from the input string */
  2361.                s[l] = 0;
  2362.                tos++;
  2363.  
  2364.                /* Search for the symbol again */
  2365.                dofind();
  2366.                flag = spop;
  2367.                
  2368.                /* If found check that its a vocabulary */
  2369.                if (flag) {
  2370.                    ENTRY *v = (ENTRY *) spop;
  2371.  
  2372.                    /* Check that the symbol is really a vocabulary */
  2373.                    if (v -> code == VOCABULARY) {
  2374.  
  2375.                        /* Scan for a new symbol */
  2376.                        spush(' ');
  2377.                        doword();
  2378.  
  2379.                        /* Exit top loop if end of input stream */
  2380.                        if (io_eof()) {
  2381.                            spop;
  2382.                            return;
  2383.                        }
  2384.  
  2385.                        /* And look for it in the given vocabulary */
  2386.                        spush(v);
  2387.                        dolookup();
  2388.                        flag = spop;
  2389.                        cast = flag;
  2390.                    }
  2391.                }
  2392.            }
  2393.        }
  2394.        
  2395.        /* If found then execute or thread the symbol */
  2396.        if (flag) {
  2397.            if (state.parameter == flag)
  2398.                dothread();
  2399.            else
  2400.                docommand();
  2401.        }
  2402.        else {
  2403.            /* Else check if it is a number */
  2404.            doqnumber();
  2405.            flag = spop;
  2406.            if (flag) {
  2407.                doliteral();
  2408.            }
  2409.            else {
  2410.                /* If not print error message and abort */
  2411.                (void) printf("%s ??\n", tos);
  2412.                doabort();
  2413.            }
  2414.        }
  2415.     }
  2416.     quited = TRUE;
  2417. }
  2418.  
  2419. NORMAL_CODE(interpret, forth83, "interpret", dointerpret);
  2420.  
  2421. void doquit()
  2422. {
  2423.     long e;
  2424.  
  2425.     /* Exception marking and handler */
  2426.     if (e = setjmp(restart)) {
  2427.        spush(e);
  2428.        doraise();
  2429.     }
  2430.     rinit;
  2431.     doleftbracket();
  2432.     dointerpret();
  2433. }
  2434.  
  2435. NORMAL_CODE(quit, interpret, "quit", doquit);
  2436.  
  2437. void doabort()
  2438. {
  2439.     /* Check if it is the foreground task */
  2440.     if (tp == foreground) {
  2441.        sinit; 
  2442.        doleftbracket();
  2443.        io_flush();
  2444.     }
  2445.  
  2446.     /* Terminate aborted tasks */
  2447.     doterminate();
  2448. }
  2449.  
  2450. NORMAL_CODE(kernel_abort, quit, "abort", doabort);
  2451.  
  2452. void doabortquote()
  2453. {
  2454.     spush('"');
  2455.     doword();
  2456.     dostringcopy();
  2457.     spush(&parenabortquote);
  2458.     dothread();
  2459.     docomma();
  2460. }
  2461.  
  2462. COMPILATION_IMMEDIATE_CODE(abortquote, kernel_abort, "abort\"", doabortquote);
  2463.     
  2464.  
  2465. /* DICTIONARY ADDRESSES */
  2466.  
  2467. void dohere()
  2468. {
  2469.     spush(dp);
  2470. }
  2471.  
  2472. NORMAL_CODE(here, abortquote, "here", dohere);
  2473.  
  2474. static char thepad[PADSIZE];
  2475.  
  2476. NORMAL_CONSTANT(pad, here, "pad", (long) thepad);
  2477.  
  2478. static char thetib[TIBSIZE];
  2479.  
  2480. NORMAL_CONSTANT( tib, pad, "tib", (long) thetib);
  2481.  
  2482. void dotobody()
  2483. {
  2484.     tos = ((ENTRY *) tos) -> parameter;
  2485. }
  2486.  
  2487. NORMAL_CODE(tobody, tib, ">body", dotobody);
  2488.  
  2489. void dodotname()
  2490. {
  2491.     ENTRY *e = (ENTRY *) spop;
  2492.     
  2493.     (void) printf("%s", e -> name);
  2494. }
  2495.  
  2496. NORMAL_CODE(dotname, tobody, ".name", dodotname);
  2497.  
  2498.  
  2499. /* COMPILER AND INTERPRETER WORDS */
  2500.  
  2501. void dosharpif()
  2502. {
  2503.     long symbol;
  2504.     long flag = spop;
  2505.  
  2506.     if (!flag) {
  2507.        do {
  2508.            spush(' ');
  2509.            doword();
  2510.            symbol = spop;
  2511.            if (STREQ(symbol, "#if")) {
  2512.                dosharpelse();
  2513.                spush(' ');
  2514.                doword();
  2515.                symbol = spop;
  2516.            }
  2517.        } while (!((STREQ(symbol, "#else") || STREQ(symbol, "#then"))));
  2518.     }
  2519. }
  2520.  
  2521. IMMEDIATE_CODE(sharpif, dotname, "#if", dosharpif);
  2522.  
  2523. void dosharpelse()
  2524. {
  2525.     long symbol;
  2526.     
  2527.     do {
  2528.        spush(' ');
  2529.        doword();
  2530.        symbol = spop;
  2531.        if (STREQ(symbol, "#if")) {
  2532.            dosharpelse();
  2533.            spush(' ');
  2534.            doword();
  2535.            symbol = spop;
  2536.        }
  2537.     } while (!STREQ(symbol, "#then"));
  2538. }
  2539.  
  2540. IMMEDIATE_CODE(sharpelse, sharpif, "#else", dosharpelse);
  2541.  
  2542. void dosharpthen()
  2543. {
  2544.  
  2545. }
  2546.  
  2547. IMMEDIATE_CODE(sharpthen, sharpelse, "#then", dosharpthen);
  2548.  
  2549. void dosharpifdef()
  2550. {
  2551.     spush(' ');
  2552.     doword();
  2553.     dofind();
  2554.     doswap();
  2555.     spop;
  2556.     dosharpif();
  2557. }
  2558.  
  2559. IMMEDIATE_CODE(sharpifdef, sharpthen, "#ifdef", dosharpifdef);
  2560.  
  2561. void dosharpifundef()
  2562. {
  2563.     spush(' ');
  2564.     doword();
  2565.     dofind();
  2566.     doswap();
  2567.     spop;
  2568.     dozeroequals();
  2569.     dosharpif();
  2570. }
  2571.  
  2572. IMMEDIATE_CODE(sharpifundef, sharpifdef, "#ifundef", dosharpifundef);
  2573.  
  2574. void dosharpinclude()
  2575. {
  2576.     int  flag;
  2577.     char *fname;
  2578.     
  2579.     spush(' ');
  2580.     doword();
  2581.     fname = (char *) spop;
  2582.     if (flag = io_infile(fname) == IO_UNKNOWN_FILE)
  2583.        (void) printf("%s: file not found\n", fname);
  2584.     else if (flag == IO_TOO_MANY_FILES)
  2585.        (void) printf("%s: too many files open\n", fname);
  2586. }
  2587.  
  2588. NORMAL_CODE(sharpinclude, sharpifundef, "#include", dosharpinclude);
  2589.  
  2590. void dosharppath()
  2591. {
  2592.     int flag;
  2593.     
  2594.     spush(' ');
  2595.     doword();
  2596.     if (flag = io_path((char *) tos, IO_PATH_FIRST) == IO_UNKNOWN_PATH)
  2597.        (void) printf("%s: unknown environment variable\n", tos);
  2598.     else if (flag == IO_TOO_MANY_PATHS)
  2599.        (void) printf("%s: too many paths defined\n", tos);
  2600.     spop;
  2601. }
  2602.  
  2603. NORMAL_CODE(sharppath, sharpinclude, "#path", dosharppath);
  2604.  
  2605. void doparen()
  2606. {
  2607.     char c;
  2608.     
  2609.     while (c = io_getchar())
  2610.        if (c == ')') return;
  2611.        else if (c == '(') doparen();
  2612.        else if (io_eof()) return;
  2613. }
  2614.  
  2615. IMMEDIATE_CODE(paren, sharppath, "(", doparen);
  2616.  
  2617. void dobackslash()
  2618. {
  2619.     io_skip('\n');
  2620. }
  2621.  
  2622. IMMEDIATE_CODE(backslash, paren, "\\", dobackslash);
  2623.  
  2624. void docomma()
  2625. {
  2626.     *dp++ = spop;
  2627. }
  2628.  
  2629. NORMAL_CODE(comma, backslash, ",", docomma);
  2630.  
  2631. void doallot()
  2632. {
  2633.     long n = spop;
  2634.  
  2635.     dp = (long *) ((char *) dp + n);
  2636. }
  2637.  
  2638. NORMAL_CODE(allot, comma, "allot", doallot);
  2639.  
  2640. void dodoes()
  2641. {
  2642.     spush((theframed ? &parenunlinkdoes: &parendoes));
  2643.     dothread();
  2644.     doremovelocals();
  2645. }
  2646.  
  2647. COMPILATION_IMMEDIATE_CODE(does, allot, "does>", dodoes);
  2648.  
  2649. void doimmediate()
  2650. {
  2651.     ((ENTRY *) current -> parameter) -> mode |= IMMEDIATE;
  2652. }
  2653.  
  2654. NORMAL_CODE(immediate, does, "immediate", doimmediate);
  2655.  
  2656. void doexecution()
  2657. {
  2658.     ((ENTRY *) current -> parameter) -> mode |= EXECUTION;
  2659. }
  2660.  
  2661. NORMAL_CODE(execution, immediate, "execution", doexecution);
  2662.  
  2663. void docompilation()
  2664. {
  2665.     ((ENTRY *) current -> parameter) -> mode |= COMPILATION;
  2666. }
  2667.  
  2668. NORMAL_CODE(compilation, execution, "compilation", docompilation);
  2669.  
  2670. void doprivate()
  2671. {
  2672.     ((ENTRY *) current -> parameter) -> mode |= PRIVATE;
  2673. }
  2674.  
  2675. NORMAL_CODE(private, compilation, "private", doprivate);
  2676.  
  2677. void dobracketcompile()
  2678. {
  2679.     dotick();
  2680.     dothread();
  2681. }
  2682.  
  2683. COMPILATION_IMMEDIATE_CODE(bracketcompile, private, "[compile]", dobracketcompile);
  2684.  
  2685. void docompile()
  2686. {
  2687.     spush(*ip++);
  2688.     dothread();
  2689. }
  2690.  
  2691. COMPILATION_CODE(compile, bracketcompile, "compile", docompile);
  2692.  
  2693. void doqcompile()
  2694. {
  2695.     if (state.parameter) docompile();
  2696. }
  2697.  
  2698. COMPILATION_CODE(qcompile, compile, "?compile", doqcompile);
  2699.  
  2700. NORMAL_VARIABLE(state, qcompile, "state", FALSE);
  2701.  
  2702. void docompiling()
  2703. {
  2704.     spush(state.parameter);
  2705. }
  2706.  
  2707. NORMAL_CODE(compiling, state, "compiling", docompiling);
  2708.  
  2709. void doliteral()
  2710. {
  2711.     if (state.parameter) {
  2712.        spush(&parenliteral);
  2713.        dothread();
  2714.        docomma();
  2715.     }
  2716. }
  2717.  
  2718. COMPILATION_IMMEDIATE_CODE(literal, compiling, "literal", doliteral);
  2719.  
  2720. void doleftbracket()
  2721. {
  2722.     state.parameter = FALSE;
  2723. }
  2724.  
  2725. IMMEDIATE_CODE(leftbracket, literal, "[", doleftbracket);
  2726.  
  2727. void dorightbracket()
  2728. {
  2729.     state.parameter = TRUE;
  2730. }
  2731.  
  2732. NORMAL_CODE(rightbracket, leftbracket, "]", dorightbracket);
  2733.  
  2734. void doword()
  2735. {
  2736.     char brkchr = (char) spop;
  2737.     
  2738.     (void) io_skipspace();
  2739.     (void) io_scan(thetib, brkchr);
  2740.     spush(thetib);
  2741. }
  2742.  
  2743. NORMAL_CODE(kernel_word, rightbracket, "word", doword);
  2744.  
  2745.  
  2746. /* VOCABULARIES */
  2747.  
  2748. NORMAL_CONSTANT(kernel_context, kernel_word, "context", (long) context);
  2749.  
  2750. NORMAL_CONSTANT(kernel_current, kernel_context, "current", (long) ¤t);
  2751.  
  2752. void dolast()
  2753. {
  2754.     spush((theframed ? (long) theframed : current -> parameter));
  2755. }
  2756.  
  2757. NORMAL_CODE(last, kernel_current, "last", dolast);
  2758.  
  2759. void dodefinitions()
  2760. {
  2761.     current = context[0];
  2762. }
  2763.  
  2764. NORMAL_CODE(definitions, last, "definitions", dodefinitions);
  2765.  
  2766. void doonly()
  2767. {
  2768.     long v;
  2769.  
  2770.     /* Flush the entry cache */
  2771.     spush(FALSE);
  2772.     dorestore();
  2773.  
  2774.     /* Remove all vocabularies except the first */
  2775.     for (v = 1; v < CONTEXTSIZE; v++) context[v] = (ENTRY *) NIL;
  2776.  
  2777.     /* And make it definition vocabulary */
  2778.     current = context[0];
  2779. }
  2780.  
  2781. NORMAL_CODE(only, definitions, "only", doonly);
  2782.  
  2783. void dorestore()
  2784. {
  2785.     register long i;           /* Iteration variable */
  2786.     register ENTRY *e;         /* Pointer to parameter entry */
  2787.     register ENTRY *p;         /* Pointer to current entry */
  2788.  
  2789.     /* Access parameter and check if an entry */
  2790.     e = (ENTRY *) spop;
  2791.     if (e) {
  2792.  
  2793.        /* Flush all enties until the parameter symbol */
  2794.        for (p = (ENTRY *) current -> parameter; p && (p != e); p = p -> link)
  2795.            cache[hash(p -> name)] = (ENTRY *) NIL;
  2796.  
  2797.        /* If the entry was found remove all symbols until this entry */
  2798.        if (p == e) current -> parameter = (long) e;
  2799.     }
  2800.     else {
  2801.        
  2802.        /* Flush the entry cache */
  2803.        for (i = 0; i < CACHESIZE; i++) cache[i] = (ENTRY *) NIL;
  2804.     }
  2805. }
  2806.  
  2807. NORMAL_CODE(restore, only, "restore", dorestore);
  2808.  
  2809. void dotick()
  2810. {
  2811.     long flag;
  2812.  
  2813.     spush(' ');
  2814.     doword();
  2815.     dofind();
  2816.     flag = spop;
  2817.     if (!flag) {
  2818.        (void) printf("%s: unknown symbol\n", tos);
  2819.        doabort();
  2820.     }
  2821. }
  2822.  
  2823. NORMAL_CODE(tick, restore, "'", dotick);
  2824.  
  2825. void dobrackettick()
  2826. {
  2827.     dotick();
  2828.     doliteral();
  2829. }
  2830.  
  2831. COMPILATION_IMMEDIATE_CODE(brackettick, tick, "[']", dobrackettick);
  2832.  
  2833. void dolookup() 
  2834. {
  2835.     register ENTRY *v;         /* Vocabulary pointer */
  2836.     register ENTRY *e;         /* Entry pointer */
  2837.     register char  *s;         /* Symbol to be found */
  2838.     
  2839.     /* Fetch parameters and initate entry pointer */
  2840.     v = (ENTRY *) spop;
  2841.     s = (char *) tos;
  2842.     
  2843.     /* Iterate over the linked list of entries */
  2844.     for (e = (ENTRY *) v -> parameter; e; e = e -> link)
  2845.  
  2846.        /* Compare the symbol and entry string */
  2847.        if (STREQ(s, e -> name)) {
  2848.  
  2849.            /* Check if the entry is currently visible */
  2850.            if (!(((e -> mode & COMPILATION) && (!state.parameter)) ||
  2851.                  ((e -> mode & EXECUTION) && (state.parameter))  ||
  2852.                  ((e -> mode & PRIVATE) && (v != current)))) {
  2853.  
  2854.                /* Return the entry and compilation mode */
  2855.                tos = (long) e;
  2856.                spush((e -> mode & IMMEDIATE ? 1 : -1));
  2857.                return;
  2858.            }
  2859.        }
  2860.     spush(FALSE);
  2861. }
  2862.  
  2863. NORMAL_CODE(lookup, brackettick, "lookup", dolookup);
  2864.  
  2865. #ifdef PROFILE
  2866. void docollision()
  2867. {
  2868.     /* Add collision statistics to profile information */
  2869. }
  2870. #endif
  2871.  
  2872. void dofind()
  2873. {
  2874.     ENTRY *e;                  /* Entry in the entry cache */
  2875.     char  *n;                  /* Name string of entry to be found */
  2876.     long  v;                   /* Index into vocabulary set */
  2877.     
  2878.     /* Access the string to be found */
  2879.     n = (char *) tos;
  2880.  
  2881.     /* Check for cached entry */
  2882.     if (e = cache[hash(n)]) {
  2883.  
  2884.        /* Compare the string and the entry name */
  2885.        if (STREQ(tos, e -> name)) {
  2886.  
  2887.            /* Check if the entry is currently visible */
  2888.            if (!(((e -> mode & COMPILATION) && (!state.parameter)) ||
  2889.                  ((e -> mode & EXECUTION) && (state.parameter)))) {
  2890.                tos = (long) e;
  2891.                spush((e -> mode & IMMEDIATE ? 1 : -1));
  2892.                return;
  2893.            }
  2894.        }
  2895. #ifdef PROFILE
  2896.        else {
  2897.            docollision();
  2898.        }
  2899. #endif 
  2900.     }
  2901.     
  2902.     /* For each vocabulary in the current search chain */
  2903.     for (v = 0; context[v] && v < CONTEXTSIZE; v++) {
  2904.        spush(context[v]);
  2905.        dolookup();
  2906.        if (tos) {
  2907.            cache[hash(n)] = (ENTRY *) snth(0);
  2908.            return;
  2909.        }
  2910.        else {
  2911.            spop;
  2912.        }
  2913.     }
  2914.     spush(FALSE);
  2915. }
  2916.  
  2917. NORMAL_CODE(find, lookup, "find", dofind);
  2918.  
  2919. void doforget()
  2920. {
  2921.     dotick();
  2922.     tos = (long) ((ENTRY *) tos) -> link; 
  2923.     dorestore();
  2924. }
  2925.  
  2926. NORMAL_CODE(forget, find, "forget", doforget);
  2927.  
  2928. void dowords()
  2929. {
  2930.     ENTRY *e;                  /* Pointer to entries */
  2931.     long   v;                  /* Index into vocabulary set */
  2932.     long   l;                  /* String length */
  2933.     long   s;                  /* Spaces between words */
  2934.     long   c;                  /* Column counter */
  2935.     long   i;                  /* Loop index */
  2936.     
  2937.     /* Iterate over all vocabularies in the search set */
  2938.     for (v = 0; v < CONTEXTSIZE && context[v]; v++) {
  2939.  
  2940.        /* Print vocabulary name */
  2941.        (void) printf("VOCABULARY %s", context[v] -> name);
  2942.        if (context[v] == current) (void) printf(" DEFINITIONS");
  2943.        (void) putchar('\n');
  2944.  
  2945.        /* Access linked list of enties and initiate column counter */
  2946.        c = 0;
  2947.  
  2948.        /* Iterate over all entries in the vocabulary */
  2949.        for (e = (ENTRY *) context[v] -> parameter; e; e = e -> link) {
  2950.  
  2951.            /* Check if the entry is current visible */
  2952.            if (!(((e -> mode & COMPILATION) && (!state.parameter)) ||
  2953.                  ((e -> mode & EXECUTION) && (state.parameter))  ||
  2954.                  ((e -> mode & PRIVATE) && (context[v] != current)))) {
  2955.                
  2956.                /* Print the entry string. Check that space is available */
  2957.                l = strlen(e -> name);
  2958.                s = (c ? (COLUMNWIDTH - (c % COLUMNWIDTH)) : 0);
  2959.                c = c + s + l;
  2960.                if (c < LINEWIDTH) {
  2961.                    for (i = 0; i < s; i++) (void) putchar(' '); 
  2962.                }
  2963.                else {
  2964.                    (void) putchar('\n');
  2965.                    c = l;
  2966.                }
  2967.                (void) printf("%s", e -> name);
  2968.            }
  2969.        }
  2970.  
  2971.        /* End the list of words and separate the vocabularies */
  2972.        (void) putchar('\n');
  2973.        (void) putchar('\n');
  2974.     }
  2975. }
  2976.  
  2977. IMMEDIATE_CODE(words, forget, "words", dowords);
  2978.  
  2979.  
  2980. /* DEFINING NEW VOCABULARY ENTRIES */
  2981.  
  2982. ENTRY *makeentry(name, code, mode, parameter)
  2983.     char *name;                        /* String for the new entry */
  2984.     long code, mode, parameter; /* Entry parameters */
  2985. {
  2986.     /* Allocate space for the entry */
  2987.     ENTRY *e = (ENTRY *) malloc(sizeof(ENTRY));
  2988.  
  2989.     /* Insert into the current vocabulary and set parameters */
  2990.     e -> link = (ENTRY *) current -> parameter;
  2991.     current -> parameter = (long) e;
  2992.  
  2993.     /* Set entry parameters */
  2994.     e -> name = strcpy(malloc((unsigned) strlen(name) + 1), name);
  2995.     e -> code = code;
  2996.     e -> mode = mode;
  2997.     e -> parameter = parameter;
  2998.  
  2999.     /* Cache entry */
  3000.     cache[hash(name)] = e;
  3001.     
  3002.     /* Return pointer to the new entry */
  3003.     return e;
  3004. }
  3005.  
  3006. void doentry()
  3007. {
  3008.     long flag, name, code, mode, parameter;
  3009.     ENTRY *forward;
  3010.     
  3011.     /* Try to find entry to check for forward declarations */
  3012.     forward = (ENTRY *) NIL;
  3013.     dodup();
  3014.     dofind();
  3015.     flag = spop;
  3016.     if (flag) {
  3017.        forward = (ENTRY *) spop;
  3018.     }
  3019.     else {
  3020.        spop;
  3021.     }
  3022.     
  3023.     /* Access name, code, mode and parameter field parameters */
  3024.     name = spop;
  3025.     code = spop;
  3026.     mode = spop;
  3027.     parameter = spop;
  3028.  
  3029.     /* Create the new entry */
  3030.     (void) makeentry((char *) name, code, mode, parameter);
  3031.  
  3032.     /* If found and forward the redirect parameter field of initial entry */
  3033.     if (forward && forward -> code == FORWARD) {
  3034.        forward -> parameter = current -> parameter;
  3035.        if (verbose)
  3036.            (void) printf("%s: forward definition resolved\n", forward -> name);
  3037.     }
  3038. }
  3039.  
  3040. NORMAL_CODE(kernel_entry, words, "entry", doentry);
  3041.  
  3042. void doforward()
  3043. {
  3044.     spush(0);
  3045.     spush(NORMAL);
  3046.     spush(FORWARD);
  3047.     spush(' ');
  3048.     doword();
  3049.     doentry();
  3050. }
  3051.  
  3052. NORMAL_CODE(forward, kernel_entry, "forward", doforward);
  3053.  
  3054. static ENTRY *thelast = (ENTRY *) NIL;
  3055.  
  3056. void docolon()
  3057. {
  3058.     align(dp);
  3059.     dohere();
  3060.     spush(HIDDEN);
  3061.     spush(COLON);
  3062.     spush(' ');
  3063.     doword();
  3064.     doentry();
  3065.     dorightbracket();
  3066.     thelast = (ENTRY *) current -> parameter;
  3067. }
  3068.  
  3069. NORMAL_CODE(colon, forward, ":", docolon);
  3070.  
  3071. void dosemicolon()
  3072. {
  3073.     spush((theframed ? &parenunlinksemicolon : &parensemicolon));
  3074.     dothread();
  3075.     doleftbracket();
  3076.     doremovelocals();
  3077.     if (thelast) {
  3078.        thelast -> mode = NORMAL;
  3079.        cache[hash(thelast -> name)] = thelast;
  3080.        thelast = (ENTRY *) NIL;
  3081.     }
  3082. }
  3083.  
  3084. COMPILATION_IMMEDIATE_CODE(semicolon, colon, ";", dosemicolon);
  3085.  
  3086. void docreate()
  3087. {
  3088.     align(dp);
  3089.     dohere();
  3090.     spush(NORMAL);
  3091.     spush(CREATE);
  3092.     spush(' ');
  3093.     doword();
  3094.     doentry();
  3095. }
  3096.  
  3097. NORMAL_CODE(create, semicolon, "create", docreate);
  3098.  
  3099. void dovariable()
  3100. {
  3101.     spush(0);
  3102.     spush(NORMAL);
  3103.     spush(VARIABLE);
  3104.     spush(' ');
  3105.     doword();
  3106.     doentry();
  3107. }
  3108.  
  3109. NORMAL_CODE(variable, create, "variable", dovariable);
  3110.  
  3111. void doconstant()
  3112. {
  3113.     spush(NORMAL);
  3114.     spush(CONSTANT);
  3115.     spush(' ');
  3116.     doword();
  3117.     doentry();
  3118. }
  3119.  
  3120. NORMAL_CODE(constant, variable, "constant", doconstant);
  3121.  
  3122. void dovocabulary()
  3123. {
  3124.     spush(&forth);
  3125.     spush(NORMAL);
  3126.     spush(VOCABULARY);
  3127.     spush(' ');
  3128.     doword();
  3129.     doentry();
  3130. }
  3131.  
  3132. NORMAL_CODE(vocabulary, constant, "vocabulary", dovocabulary);
  3133.  
  3134. void dofield()
  3135. {
  3136.     spush(NORMAL);
  3137.     spush(FIELD);
  3138.     spush(' ');
  3139.     doword();
  3140.     doentry();
  3141. }
  3142.  
  3143. NORMAL_CODE(field, vocabulary, "field", dofield);
  3144.  
  3145.  
  3146. /* INITIALIZATION OF THE KERNEL */
  3147.  
  3148. void kernel_initiate(first, last, users, parameters, returns)
  3149.     ENTRY *first, *last;
  3150.     int users, parameters, returns;
  3151. {
  3152.     /* Link user symbols into vocabulary chain if given */
  3153.     if (first && last) {
  3154.        forth.parameter = (long) first;
  3155.        last -> link = (ENTRY *) &field;
  3156.     }
  3157.     
  3158.     /* Create the foreground task object */
  3159.     foreground = maketask((long) users, (long) parameters, (long) returns, NIL);
  3160.     
  3161.     s0 = foreground -> s0;
  3162.     sp = foreground -> sp;
  3163.     r0 = foreground -> r0;
  3164.     rp = foreground -> rp;
  3165.     ip = foreground -> ip;
  3166.     fp = foreground -> fp;
  3167.     ep = foreground -> ep;
  3168.  
  3169.     /* Make the foreground task the current task */
  3170.     tp = foreground;
  3171.  
  3172. }
  3173.  
  3174. void kernel_finish()
  3175. {
  3176.     /* Future clean up function for kernel */
  3177. }
  3178.