home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / m / me_cd25.zip / DOC.ZIP / MM2.DOC < prev    next >
Text File  |  1992-11-09  |  30KB  |  961 lines

  1. ========================================================================
  2. ==        The Mutt2 Machine          Craig Durland 88, 10/91 ==
  3. ========================================================================
  4.  
  5. Here is info on embedding the Mutt2 machine in a application and the
  6. Mutt2 machine itself.
  7.  
  8. The Mutt2 Machine is a virtual machine ment to be an embedded language.
  9. It is written in C for ease of porting.
  10.  
  11.  
  12.              Copyright 1991 Craig Durland
  13.     Distributed under the terms of the GNU General Public License.
  14.   Distributed "as is", without warranties of any kind, but comments,
  15.            suggestions and bug reports are welcome.
  16.  
  17. ========================================================================
  18. ==        Embedding the Mutt2 Machine                  ==
  19. ========================================================================
  20.  
  21. Data Types:
  22.   maddr
  23.   uint8
  24.  
  25. Example data structures:
  26.   block :
  27.     typedef struct
  28.     {
  29.       char  *name;        /* Name of the block (munged file name) */
  30.       uint8 *global_vars;    /* Where the global vars are in this block */
  31.       maddr code;        /* The start of the code in this block */
  32.       void *global_object_table;
  33.       int num_global_objects;
  34.     } CodeBlock;
  35.  
  36.   Programs:
  37.     typedef struct        /* program address table */
  38.     {
  39.       maddr addr;        /* address of routine */
  40.       short int block;    /* link to programs code block. 0 => dead */
  41.     } Pgm;
  42.   
  43. To embed the Mutt2 Machine in your C program, write the following
  44. routines:
  45.  
  46. Function:    FILE *MMopen_code_file(char *file_name)
  47. Description:
  48.   Open a Mutt code (.mco) file so that it can be loaded by the Mutt
  49.     Machine.
  50. Input:
  51.   name: Name of code file to open.  The extension is ".mco".  May have
  52.     a leading path.
  53. Returns:
  54.   FILE : Pointer to the opened code file.
  55.   NULL : Couldn't find the file.
  56. Notes:
  57.   You might want to parse a PATH environment variable.
  58.  
  59.  
  60. Function:    maddr MMpgm_addr(int pgm_id)
  61. Description:
  62.   Return the address of the Mutt routine that has pgm_id.  Also update 
  63.     MMglobal_vars, and MMglobal_object_table to point to the proper
  64.     areas.
  65. Input:
  66.   pgm_id : The id of a Mutt program.
  67. Returns:
  68.   Address of the start of the Mutt program code.
  69. Munges:
  70.   MMglobal_vars
  71.   MMglobal_object_table
  72. Notes:
  73.   You only need to update the globals if they will change.
  74.  
  75.   
  76. Function:    int MMpgm_lookup(char *pgm_name)
  77. Description:
  78.   Return the program id of the program that is named pgm_name.
  79. Input:
  80.   pgm_name: 
  81. Returns:
  82.   Program id.
  83. Notes:
  84.  
  85.  
  86. Function:    void MMblock_name(char *buf, *file_name)
  87. Description:
  88.   Create a block name (using file_name if you want) and put it into buf.
  89. Input:
  90.   buf:
  91.   file_name: 
  92. Munges:
  93.   buf
  94. Notes:
  95.  
  96.  
  97. Function:  int MMadd_block(
  98.         char *block_name;
  99.         maddr code;
  100.         uint8 *global_vars;
  101.         void *global_object_table;
  102.         int num_global_objects)
  103. Description:
  104.   Save some information that the Mutt Machine might need to use later.
  105. Input:
  106.   block_name:  A name returned by MMblock_name.  Useful to check to see
  107.     if a block is being reloaded.
  108.   code:  Pointer to the Mutt code.  MMpgm_addr() wants this.
  109.   global_vars:  Pointer to the block-global non-object variables.  Also
  110.     used by MMpgm_addr().
  111.   global_object_table:  Pointer to the block-global objects.  Used by
  112.     MMpgm_addr().
  113.   num_global_objects:  Number of block-global objects.  Used when
  114.     calling MMfree_block().
  115. Returns:
  116.   A block id that be used in MMadd_pgm().  You need block ids so you can
  117.     cross index the program table and the block table.  You save to save
  118.     memory by keeping a (program-name, block-id) tuple and using the
  119.     block table in MMpgm_addr().
  120. Notes:
  121.  
  122.  
  123. Function:  int MMadd_pgm(char *pgm_name; int block_id; maddr code_addr)
  124. Description:
  125.   Add a program to your program table.  This so MMpgm_addr() can get the
  126.     info.
  127. Input:
  128.   pgm_name:  Pointer the name of the program.  You only need to save a
  129.     copy of the pointer, the name itself is in the code block name table.
  130.   block_id:  Returned by MMadd_block.
  131.   code_addr: Start address of the code in the program.  Used by
  132.     MMpgm_addr().
  133. Returns:
  134.   TRUE:  Everything went as expected.
  135.   FALSE: Ran out of memory or some other real bad thing.
  136. Notes:
  137.  
  138.  
  139. Function:    void MMset_hooks()
  140. Description:
  141.   Hooks for Mutt programs.  When certain events occur in the
  142.     application, you might want to call a hook so your application can
  143.     be extended in useful ways.
  144. Notes:
  145.   Called from MM after every Mutt code block is loaded.
  146.   Call this at start up to make sure all hooks are
  147.     properly initialized to no hook.
  148.  
  149.   
  150. Function:    void MMbitch(char *message)
  151. Description:
  152.   A fatal error has occurred when running a Mutt program.  Inform the
  153.     user and bail out of the Mutt Machine (usually by calling
  154.     MMabort_pgm()).
  155. Input:
  156.   message:  Text that has some information about what happened.  You
  157.     might want to add some verbiage saying that the program is aborting.
  158. Notes:
  159.   Only the Mutt Machine aborts.  The application should be OK (it is up
  160.     to the application to decide).
  161.  
  162.  
  163. Function:    void MMmoan(char *message)
  164. Description:
  165.   Inform the user that the Mutt program has errored.
  166. Input:
  167.   message:  Text that has some information about what happened.
  168. Notes:
  169.   This is used for those times when MMabort_pgm() can't be called.
  170.   
  171.  
  172. Function:    void MMmsg(char *message)
  173. Description:
  174.   Give the user a message.  Used by MSG:  (msg "hoho") will result in
  175.     MMmsg("hoho");
  176. Input:
  177.   message:  Text for the user.
  178. Notes:
  179.  
  180.  
  181. Function:    void MMask(char *prompt, *buf)
  182. Description:
  183.   Ask the user for a response.  Used by ASK:  (ask "Press a key ") will
  184.     result in MMask("Press a key ", &buf);
  185. Input:
  186.   prompt:  
  187.   buf: where to put the reply.
  188. Munges:
  189.   buf
  190. Notes:
  191.  
  192.   
  193. Function:    int MMaux_fcn(char *aux_fcn_name)
  194. Description:
  195.   Run a aux function by name.  Aux functions are the functions that the
  196.     application defines and MM knows nothing about.  For example, say
  197.     the application is a spread sheet, you have C code that sums a
  198.     column and you want the Mutt name for this to be "sum-column".  Now,
  199.     when a Mutt program does a (sum-column n), MM looks around, can't
  200.     find a program named "sum-column", thinks it might be part of the
  201.     application and calls MMaux_fcn("sum-column").  Your C code can then
  202.     access the Mutt stack (see MMpull_nth_arg()) and sum that column.
  203. Input:
  204. Returns:
  205.   TRUE:  aux_fcn_name is real and I did it.
  206.   FALSE: aux_fcn_name is not something I know about.
  207. Notes:
  208.  
  209.  
  210. Function:    void MMxtoken(int token)
  211. Description:
  212.   Execute a token defined by the application.  If you compile a Mutt
  213.     program with a token file ("mc2 -t<token-file>"), MM will call
  214.     MMxtoken(token).  Using the MMaux_fcn() example, if you created a
  215.     token file with the entry "123 sum-column" in it, used that file to
  216.     compile a Mutt program with (sum-column 3) in it, then, when MM
  217.     executes that line, MMxtoken(123) will be called.  You then take 123
  218.     and figure out you need to call sum_column(3).
  219. Input:
  220.   token: 
  221. Notes:
  222.   MMxtoken() is short hand for MMaux_fcn().
  223.   Its assumed that token file is correct - you might want to do some
  224.     token checking if this is a bad assumption (it usually is).
  225.   Token files can really reduce the (static) space used by a Mutt
  226.     program and speed things up (because it gets rid of string lookups).
  227.   Token is usually an index into a array of function pointers or a case
  228.     in a switch statement.
  229.  
  230.  
  231. Function:    void MMgc_external_objects()
  232. Description:
  233.   Garbage collect all mortal (temporary) objects that may have been
  234.     created by Mutt programs and not freed by them.
  235.   This is typically called (by the Mutt Machine) after a pgm has been
  236.     run or aborted to clean up stuff the programmer forgot to or was
  237.     unable to (as in the case where the pgm was aborted).
  238. See also:  Section on garbage collection.
  239.  
  240.  
  241.  
  242.         Internal Routines of External Interest
  243.         -------- -------- -- -------- --------
  244.  
  245. Routines Mutt extension writers are interested in:
  246.  
  247. Function:    int MMpull_nth_arg(vsitem *val; int n)
  248. Description:
  249.  Pull the nth arg out of the stack frame.
  250.  This routine is used to get parameters off the stack.  For example, if
  251.    you are writing the C code for "foo" and it is called like so:  (foo
  252.    123), then when your foo code is called, you can
  253.    MMpull_nth_arg(&RV,0) and RV will be a number with value 123.
  254. Input:
  255.   val:  Pointer to a var (vsitem).  Arg will be stashed there.  Usually
  256.     &RV.
  257.   n:  The arg you want to pull.  0 is the first and numargs is 1+ the
  258.     last (not that it helps you - you have to use (nargs) or
  259.     MMpull_nth_arg() until it returns false.
  260. Output:
  261.   val:  vsitem is filled in with pointers to nth stack arg.  If it is an
  262.     object string, it points to the contents of the string.
  263. Returns:
  264.   TRUE:   Got to the arg
  265.   FALSE:  n if out range (less than 0 or greater than the number of
  266.       args)
  267. Notes:
  268.  See also:  MMnext_arg().
  269.  
  270.  
  271. Function:    int MMnext_arg(char *buf)
  272. Description:
  273.   Get the next arg in the stack frame, convert it to a string and store
  274.     it in a buffer.
  275.   Ment for stuff that wants a bunch of ascii info from something and
  276.     does the conversions itself (like (ask)).  Use this routine when
  277.     writing a routine that can get info from either a user or Mutt
  278.     program.
  279. Input:
  280.   buf: Pointer to a area to store the ascii form of the var in.
  281. Returns:
  282.   FALSE: No more args
  283.   TRUE:  all OK
  284. Munges:
  285.   TV
  286.  
  287.  
  288. Function:    void MMset_ask_frame()
  289. Description:
  290.   ???
  291.   This is ment for self contained opcodes (like ask).
  292. Notes:
  293.   Don't use this if you turn around and call MM().
  294.   Set MMask_pgm to TRUE after you do the ask.
  295.  
  296.  
  297. Function:    void MMreset_ask_frame()
  298. Description:
  299. Notes:
  300.  
  301.   
  302. Function:    int MMgonna_ask_pgm()
  303. Description:
  304. Returns:
  305. Notes:
  306.  
  307.  
  308. Function:    char *MMvtoa(vsitem *val)
  309. Description:
  310. Input:
  311. Returns:
  312. Notes:
  313.  
  314.  
  315. Function:    void MMconcat()
  316. Description:
  317. Returns:
  318. Munges:
  319.   TV
  320. Notes:
  321.  
  322.  
  323. Function:    mmaddr MMload_code(char *fname; int f)
  324. Description:
  325.   Load a compiled code file and run the code at the entry point.
  326. Input:
  327. Returns:
  328. Notes:
  329.  
  330.  
  331. Function:    void MMfree_block(
  332.     maddr code; Object *block_object_table[]; int objects_in_table)
  333. Description:
  334. Input:
  335. Returns:
  336. Notes:
  337.  
  338.   
  339. Function:    int MMpgm_running()
  340. Description:
  341.   Is a pgm running?
  342. Returns:
  343.   FALSE: no pgm running.
  344.   n :  n pgms are running (interrupts, (load) can cause more than one
  345.        pgm to be running at the same time.
  346.  
  347.  
  348. Function:    int MMrun_pgm(int n)
  349. Description:
  350.   Heres where the outside world fires off a Mutt pgm.
  351. Input:
  352.   n : 
  353. Returns:
  354.   FALSE if pgm aborts.
  355. Notes:
  356.   If MMrun_pgm() gets called recursively and then aborts, everything is
  357.     aborted.
  358.  
  359.  
  360. Function:    void MMopen_frame(stkframe *mark)
  361. Description:
  362. Input:
  363. Notes:
  364.  
  365.  
  366. Function:     void MMpush_arg(vsitem *RV)
  367. Description:
  368. Input:
  369. Notes:
  370.  
  371.   
  372. Function:    void MMclose_frame(stkframe *mark)
  373. Description:
  374. Input:
  375. Notes:
  376.  
  377.  
  378. Function:    int MMrun_pgm_with_args(int n; stkframe *mark)
  379. Description:
  380. Input:
  381. Returns:
  382. Notes:
  383. See also: MMrun_pgm()
  384.  
  385.  
  386. Function:    int MMload(char *fname; int f)
  387. Description:
  388.   Load a code file (block) and run the MAIN code.
  389. Input:
  390.   fname:  Name of the file that contains the code.  The application
  391.     knows how to interpret this (see MMopen_code_file()).
  392.   f:  TRUE:  Complain if can't open fname.
  393. Output:
  394.   TRUE:   Block loaded and MAIN code ran to completion.
  395.   FALSE:  Block didn't load, MAIN didn't run or something else failed.
  396.      A message was probably issued.
  397.  
  398.  
  399. Function:    int MMinitialize()
  400. Description:
  401. Initialize the Mutt Machine.  This is called by the application ONCE so
  402.   MM can set things up.
  403. Call this AFTER everything else in your application has been initialized
  404.   (this might call back into the application).
  405. Returns:
  406.   TRUE:   Everything went as expected.
  407.   FALSE:  Mutt Machine can't be initialized, don't use it!
  408.   
  409.  
  410. Function:    void MMabort_pgm(int dump_level)
  411. Description:
  412. Input:
  413. Notes:
  414.  
  415.  
  416.  
  417.  
  418.             Variables of Interest
  419.             --------- -- --------
  420.  
  421. Variable:        char result[]
  422. Description:
  423. Initial value: ""
  424. Notes:
  425.  
  426.  
  427. Variable:        int MMask_pgm
  428. Description:
  429. Initial value: FALSE
  430. Notes:
  431.  
  432.  
  433. Variable:        uint8 *MMglobal_vars
  434. Description:
  435. Initial value: NULL
  436. Notes:
  437.  
  438.  
  439. Variable:        Object *MMglobal_object_table[]
  440. Description:
  441. Initial value: NULL
  442. Notes:
  443.  
  444.  
  445. ========================================================================
  446. ==        Mutt2 Machine Porting Notes                  ==
  447. ========================================================================
  448.  
  449.  
  450. ========================================================================
  451. ==        Mutt2 Machine Data Types                  ==
  452. ========================================================================
  453.  
  454. C typedef    What it is
  455. - -------    ---- --    --
  456. num8        8 bit unsigned int
  457. num16        16 bit signed int
  458. num32         32 bit signed int
  459. addr        num16
  460. offset        Offset from start of var storage (num16)
  461.  
  462.  
  463. type        8 bit type coding
  464. vpop: pop val stack
  465. vpush(n): push n on val stack
  466. strings are C-strings ie text with a terminating \0. len is num8.
  467. dString:  Dynamic string.  Grows to fit whatever is placed in it.
  468. (opcode operands) : instruction stream in memory.
  469. GVars : global variable memory
  470.  
  471. External tokens        !!!???
  472.  
  473. ********************************************************************
  474.  
  475. ========================================================================
  476. ==        Mutt2 Machine Objects and Garbage Collection          ==
  477. ========================================================================
  478.  
  479. Most Mutt data is is a fixed size (such as numbers) and can be kept on
  480.   the stack or in fixed size data storage areas.  Strings and lists are
  481.   dynamic and can grow or shrink at the whim of a program.  These data
  482.   types have to be handled differently from the fixed sized data.  For
  483.   these types, I use an object manager manipulate the objects and
  484.   garbage collection to reclaim "dead" objects.
  485.  
  486. Garbage collect all mortal (temporary) objects that may have been
  487.   created by Mutt programs and not freed by them.
  488. This is typically called (by the Mutt Machine) after a pgm has been run
  489.   or aborted to clean up stuff the programmer forgot to or was unable to
  490.   (as in the case where the pgm was aborted).
  491. Problems with this method of GC:
  492.   I won't notice some dependences between Mutt objects and external
  493.     objects.  For example, if a global Mutt object creates external
  494.     objects, the block GC code will have to be smart enough to free
  495.     the external objects.  Which ain't goona happen until I add OOP
  496.     support and pass the burden back to the programmer (by having
  497.     destructors that can be called from the block GC code).
  498.   MMgc_external_objects() can only be called when the root pgm has
  499.     been terminated (and control returns from MM to the application)
  500.     to ensure objects aren't freed while they are still in use.  This
  501.     means I can't GC when low on memory in hopes of getting some
  502.     memory back.  This might be a real problem for an application
  503.     that just fires off MM and doesn't expect it to return.
  504.   Since this might be called quite a lot, it might be expensive to
  505.     look though all objects to try and find dead ones (especially if
  506.     the Mutt programmer was good and cleaned things up).  On the
  507.     other hand, it is probably called from a wait-for-keyboard loop
  508.     and thats when we have time to burn.
  509. Pros:
  510.   This style of GC works well with applications like ME2 - the user
  511.     won't see dead buffers and ME2 won't waste time updating dead
  512.     marks.
  513.   If you have a real GC, you can ignore this call.
  514.  
  515. Object tables ala Smalltalk
  516. GC is used because too expensive to free objects at the end of each
  517.   function.
  518.  
  519.            Garbage Collection for Embedded Systems
  520.            ------- ---------- --- -------- -------
  521.  
  522. Need GC because:
  523.   If a program tanks, all the objects allocated so far won't be freed.
  524.   Less for the programmer to worry about or forget.
  525.   Programmers are bound to forget a few frees and never notice.
  526.   Mutt strings.
  527.  
  528. Domains:
  529.   Internal Mutt:
  530.     dStrings.
  531.     OOP:  Probably don't need gc - constructors and destructors can
  532.       handle the normal cases.  GC is needed for when the program is
  533.       aborted.
  534.   External Mutt:
  535.     Objects can be allocated that Mutt will never know how to deal with.
  536.     For example: Bags, Marks, Buffers.
  537.  
  538. Constraints:
  539.   Don't want to slow down programs.
  540.  
  541. Solutions:
  542.   Internal:
  543.     Pool strings so can gc on abort or program termination.  Handle like
  544.       external objects (or OOP):
  545.         {
  546.       (string foo bar)
  547.       (foo "this is a test")
  548.       (done)
  549.       (bar foo)
  550.     }
  551.       generates code:
  552.         {
  553.       (int foo bar)
  554.       (foo (create-string)) (bar (create-string))
  555.  
  556.       (copy-to-string foo "this is a test")    ;; (foo "this is a test")
  557.       (goto gc-strings)            ;; (done)
  558.       (copy-to-string bar (get-string foo))    ;; (bar foo)
  559.  
  560.       (label gc-strings)
  561.       (free-string foo bar)
  562.       (done)
  563.     }
  564.  
  565.   External:
  566.     When external objects are allocated, they are flagged Mortal or
  567.       Immortal.  When a program stops running or aborts,
  568.       MMgc_foreign_objects() is called.  The external "process" can then
  569.       sweep the object lists and remove all objects marked Mortal.
  570.     Pros:
  571.       Easy.  Doesn't slow program execution.
  572.     Cons:
  573.       Not real GC.  If the programmer is lazy and doesn't free stuff, it
  574.     could be while before the resources are freed (programs that
  575.     repeatedly call a routine that creates objects).
  576.  
  577. ========================================================================
  578. ==        Mutt2 Machine Code File Layout                  ==
  579. ========================================================================
  580.  
  581. What the MC2 compiler puts into a .mco file:
  582.  
  583. <Header><Code><Program_Name_Table><String_Table><Program_Address_Table>
  584.  
  585.   Header (13 bytes)
  586.     Offset  Bytes  Name
  587.     ------  -----  ----
  588.     0    2  Entry Point
  589.     2    2  Code size
  590.     4    2  Name table offset
  591.     6    2  Number of non-hidden programs contained in this file.
  592.     8    2  Bytes of global variable space needed.
  593.        10    1  Magic number.
  594.        11    2  Number of global objects.
  595.  
  596.     Entry Point:  the is a offset from code start.
  597.     Code Size:  Size (in bytes) of Code, Program-Name-Table and
  598.       String-Table.  Does not include the Program-Address-Table.
  599.     Name table offset:  Offset (from the start of the code) of the name
  600.       table.
  601.     ...
  602. !!!
  603.  
  604.   Code
  605.     Mutt Machine code.
  606.   Program_Name_Table (starts at code + name_table (from header))
  607.     A bunch of C strings (text\0text\0 ...).  The header contains the
  608.       number of these strings.
  609.   String_Table
  610.     All the string constants used by the programs in this file.  C
  611.       strings.  Dumped in reverse order ie the string at offset 0 is the
  612.       last string in this table. 
  613.     See (set-RV-to-string).
  614. !!!
  615.   Program_Address_Table
  616.     A bunch of addresses, 1 per program name.  You can create 
  617.     (program_name, program_address) tuples with this data.  With that
  618.     info, you can run any program given its name.
  619.  
  620. Notes:
  621.   Malloc() code_size + global_space + global_object_table so
  622.     String_Table is is the correct place.
  623.  
  624. ========================================================================
  625. ==        Mutt2 Machine Memory Layout                  ==
  626. ========================================================================
  627.  
  628.         Memory Layouts
  629.  
  630. <Code><Program-Names><String-Table><Global-Vars><Global-Object-Table>
  631.   ^ 0                    ^ GVars
  632.   op stack
  633.   var stack (local variables stored in here)
  634.  
  635. ========================================================================
  636. ==        Mutt2 Machine Registers                      ==
  637. ========================================================================
  638. Registers: RV (return value), TV (temp value). tagged types.
  639.  
  640. ========================================================================
  641. ==        Mutt2 Machine Stacks                      ==
  642. ========================================================================
  643.  
  644. Stacks: opcode stack, arg stack
  645.  
  646.         Notes on stack frames
  647. - A stack frame consists of all the data for a pgm
  648. - A stack frame looks like:
  649.   *--| vsitem args[]; byte flotsam[]; byte vars[]; |--jetsam--| frame |--
  650.   |    ^abase                         ^vbase
  651.   ^varstack
  652.   LVars = varstack + vbase == the start of the local vars.
  653.   args are args to a pgm, fcn, etc and are typed.
  654.   flotsam: strings and other variable sized stuff attached to a arg.
  655.   vars: the local vars.  Untyped and "packed".
  656.   jetsam: stack usage while a pgm is running.
  657. - Flow
  658.   Find out going to be running a pgm:
  659.     a stack frame is opened.
  660.     args pushed on the frame.  flotsam placed after the args.
  661.   Pgm is run:
  662.     local vars are allocated (must happen before any code is run
  663.       or the stack frame could be munged.
  664.     frame is closed.
  665.     as pgm runs, jetsam accumulates.
  666.   Pgm terminates:
  667.     frame is removed by "popping" ie the previous frame is restored
  668.       (jetsam and all).
  669.  
  670.         Notes on the OP stack
  671. !!!
  672. - opush
  673.  
  674. ========================================================================
  675. ==        Mutt2 Machine Instruction Set                  ==
  676. ========================================================================
  677.  
  678. NAME        ACTION                    OPCODE
  679. ----        ------                    ------
  680. (add)        RV = vpop + RV                ADD
  681. (sub)        RV = vpop - RV                SUB
  682. (mul)        RV = vpop * RV                MUL
  683. (div)        RV = vpop / RV                DIV
  684. (<)        RV = vpop < RV                LT
  685. (<=)        RV = vpop <= RV                LTE
  686. (arg)        RV = RVth arg                ARG
  687. (ask-user)                        ASKUSER
  688.     Force query of user on next (ask).
  689.  
  690. (cmp)                            CMP
  691.     Input:   RV, TV (top of stack == vpop)
  692.     Result:  RV (boolean: (RV == TV))
  693.     Notes:  No type checking.  Its up to the compiler to make sure
  694.        that RV and TV have the same type.
  695. (convert-to)                        CONVERT_TO
  696.     Input:  type (number, on stack), RV (anything)
  697.     Result: RV (type)
  698.     Example: See mutt2.doc
  699.  
  700. (do-OP)    eval(opop)                    DOOP    ???!!!???
  701.     Input:  top of op stack
  702.     Result:
  703.       case OPADDRESS: 
  704.       case OPTOKEN:   
  705.       case OPNAME:    
  706.       case OPXTOKEN:  
  707.  
  708. (done)                            DONE
  709.   Return (exit) from the current routine.
  710.     Result:
  711.       Restore previous stack frame and continue execution.
  712.       If no previous stack frame, ???!!!???
  713.  
  714. (halt)        Stop MM                    HALT
  715.     Stop all pgms no matter how deeply nested or recursed MM is.
  716.  
  717. (stop)        Kinder, gentler halt            STOP
  718.     Return from MM().  Only need this if trying to make MM non
  719.       recursive.  Not generated by the compiler.  The initial
  720.       stackframe (set in init_stacks()) will need to set pc to point
  721.       to some code that contains { STOP, STOP }.  Thus when the last
  722.       stack frame is popped, stop will be executed and MM() will
  723.       return to the caller.  Need 2 stops because the pc may or may
  724.       not (I'm not sure about this) be incremented.
  725.  
  726. (dup)                            DUP
  727.     Duplicate the top of the val stack.
  728.     TV = vpop, vpush(TV), vpush(TV)
  729.  
  730. (jmp addr)    pc = addr                JMP
  731. (jmp-FALSE addr)                    JMPFALSE
  732.     Input:  RV (BOOLEAN)
  733.     Result: if (RV == FALSE) pc = addr
  734.     Notes:  No type checking.  Its up to the compiler.
  735. (jmp-TRUE addr)                        JMPTRUE
  736.     Input:  RV (BOOLEAN)
  737.     Result: if (RV == TRUE) pc = addr
  738.     Notes:  No type checking.  Its up to the compiler.
  739.  
  740. (length-of)                        LEN_OF
  741.     Input:  RV (anything)
  742.     Result: RV (NUMBER)
  743.     Notes:
  744.       length-of string is strlen(string).
  745.       length-of list is number of elements in the list.
  746.       length-of anything else is 0.
  747.  
  748. (nargs)                            NARGS
  749.     Result:  RV (NUMBER:  number of args passed to this function)
  750. (not)                            NOT
  751.     Input:  RV (BOOLEAN)
  752.     Result: RV = !RV
  753.     Notes:  No type checking.  Its up to the compiler.
  754. (pop)        discard ToS                POP
  755. (push-args)                        PUSHARGS
  756.     Input: RV (NUMBER: first arg to push)
  757.     Result:
  758.       Push arg (n, n+1, ..., all args) from the current stack frame
  759.       are pushed onto the next stack frame.  This is used to quickly
  760.       duplicate the stack so you can pass the arg list to another
  761.       function.
  762. (push-name name_offset)                    PUSHNAME
  763.     Input: name_offset (num16:  offset of name in string table)
  764.     Result:
  765.       char *ptr = &GVars[-name_offset];
  766.       opush(ptr)
  767. (push-token token)                    PUSHTOKEN
  768.     input: token (num16)
  769.     Result: opush(token)
  770. !!!what is a token?????
  771. (push-address address)                    PUSHADDR
  772.     input: address (addr)
  773.     Result: opush(addr)
  774. (fcn-addr type [token | address])            FADDR     ???!!!???
  775.     input:
  776.       type (num8:  type of function call:  OPTOKEN, OPXTOKEN,
  777.         OPADDRESS or OPNAME)
  778.       case type:
  779.         OPTOKEN    (num16: token)
  780.         OPXTOKEN:  (num16: token)
  781.         OPADDRESS: (addr:  fcn address)
  782.         OPNAME:    (RV: STRING: fcn name), not type checked
  783.     result:  RV contains a function address.  To call the function,
  784.       (push-RV) and (do-OP).
  785.  
  786. (shove-RV)                        SHOVERV
  787.     Input:  RV
  788.     Result:  RV pushed onto the val stack (vpush(RV)).
  789. (push-RV)                        PUSHRV    ???!!!???
  790.     Input:  RV
  791.     Result:
  792.       case RV.type
  793.         STRING:  If text is stored in RV, allocate space (in the
  794.           current stack frame) and copy text.  Then [in all cases]
  795.           (shove-RV).
  796.         OSTRING:  Get pointer to text, shove that    ???!!!
  797.         default: (shove-RV)
  798.         case OPTOKEN, OPXTOKEN: 
  799.         case OPADDRESS:
  800.         case OPNAME:
  801.  
  802. (set-RV-to num8)                    RVNUM8
  803.     Input: number (num8)
  804.     Result:  RV (NUMBER)
  805. (set-RV-to num16)                    RVNUM16
  806.     Input: number (num16)
  807.     Result:  RV (NUMBER)
  808. (set-RV-to num32)                    RVNUM32
  809.     Input: number (num32)
  810.     Result:  RV (NUMBER)
  811. (set-RV-to-string offset)                RVSTR
  812.     String starts offset bytes in front of GVars.
  813.     Input:  offset (num16)
  814.     Result: RV = (STRING *)&GVars[-offset] == address of string
  815.  
  816. (set-RV-to Bool)                    RVBOOL
  817.     Input:  Bool (num8)
  818.     Result: RV (BOOLEAN: Bool)
  819. (set-RV-to-VOID)    RV = VOID            RVVOID
  820. (typecheck num8)                    TYPECHECK
  821. !!!???? strings, ostrings
  822.     Input:  type (num8)
  823.     Result:
  824.       noop if RV has type type.
  825.       pgm abort if RV has wrong type, message printed.
  826.  
  827. (get-local-var type offset)                GETLVAR
  828.     Get the nth var out of the current stack frame
  829.     Input:
  830.        type   (num8)
  831.        offset (num16).  what is offset!!!???
  832.     Result:
  833.       Type is:
  834.         STRING:
  835.           object_pointer = local_object_table[offset]
  836.           get_object(object_pointer, RV.string)
  837.           RV = object
  838.         LIST:
  839.         other:  RV = *(type *)&LVars[offset]
  840. (get-global-var type offset)                GETGVAR
  841.     Get the nth global var 
  842.     Input:
  843.        type   (num8)
  844.        offset (num16).  what is offset!!!???
  845.     Result:
  846.       Type is:
  847.         STRING:
  848.       !!! if string, n = *(int16 *)&GVars[offset], RV = get_dString(n)
  849.         other:  RV = *(type *)&GVars[offset]
  850.  
  851. (set-local-var type offset)                SETLVAR
  852.     Set the nth var in the current stack frame.
  853.     Input:
  854.        type   (num8)
  855.        offset (num16).  what is offset!!!???
  856.        RV: value
  857.     Result:
  858.       Type is:
  859.         STRING:
  860.           object_pointer = local_object_table[offset]
  861.           set_object(object_pointer, RV.string)
  862.         LIST:
  863.         other:  *(type *)&LVars[offset] = RV
  864.     Notes:
  865.       No type checking is done.  The compiler does it if needed.
  866.       Don't have to worry about NUMBER, INT16, etc mismatches.
  867. (set-global-var type offset)                SETGVAR
  868.     Set the nth global var.
  869.     Input:
  870.        type   (num8)
  871.        offset (num16).  what is offset!!!???
  872.        RV: value
  873.     Result:
  874.       Type is:
  875.         STRING:
  876.       !!! if string, n = *(int16 *)&GVars[offset], set_dString(n,RV)
  877.         other:  GVars[offset] = RV
  878.     Notes:
  879.       No type checking is done.  The compiler does it if needed.
  880.       Don't have to worry about NUMBER, INT16, etc mismatches.
  881.  
  882. (get-var-relative type)                    GETRVAR
  883.     Input:
  884.        type (num8)
  885.        RV (address: base address, GVars or LVars)
  886.        vpop (NUMBER: offset from base of variable)
  887.     Result:
  888.       Type is:
  889.         STRING:
  890.         other:  RV = *(type *)&MEM[base + offset]
  891.     Note: Use global-vars or local-vars to get the base address.
  892. (set-var-relative type)                    SETRVAR
  893.     Input:
  894.        type (num8)
  895.        RV (type: variable)
  896.        vpop1 (address:  base address, GVars or LVars)
  897.        vpop2 (NUMBER:  offset from base of variable)
  898.     Result:
  899.       Type is:
  900.         STRING:
  901.         other:  *(type *)&MEM[base + offset] = RV
  902.     Notes:
  903.       No type checking is done.  The compiler does it if needed.
  904.       Don't have to worry about NUMBER, INT16, etc mismatches.
  905.       Use global-vars or local-vars to get the base address.
  906.  
  907. (global-vars offset)                    RVGBASE
  908.     Input: offset (num16)
  909.     Result: RV = (Blob: GVars + offset)
  910. (local-vars offset)                    RVLBASE
  911.     Input: offset (num16)
  912.     Result: RV = (Blob: LVars + offset)
  913.  
  914. (lalloc num16)                        LALLOC
  915.     Allocate n bytes in the current stack frame
  916.     Input: bytes to allocate (num16)
  917.     Result: RV = (Blob: LVars + offset)
  918.     Note:  (lalloc 0) is a no-op.
  919.  
  920. (create-object global/local object-type offset)        CREATE_OBJ
  921.     Allocate objects.
  922.     Input:
  923.       global/local (num8: 1 (global), 0 (local))
  924.       object-type (num8:  STRING, LIST)
  925.       offset (num16: where in the object table to save object pointer)
  926.     Result:
  927.       None.  RV might be mashed.
  928.     Errors: No memory.
  929.     Notes:
  930.       When creating local objects, must be created in same order as
  931.         offset.
  932.       There is no instruction to free an object - that can only be
  933.         done by garbage collection (ie don't worry, be happy).
  934.  
  935. ========================================================================
  936. ==        Mutt2 Machine Extended Instruction Set              ==
  937. ========================================================================
  938.  
  939. Why not regular instructions:  Need a stack frame 
  940. Internal tokens        !!!???
  941.   Internal tokens are opcodes that need a stack frame:
  942.   - so pgm can use vars and stuff
  943.   - do vararg stuff
  944.   - ???
  945.  
  946. See push-token, OPTOKEN
  947.  
  948.  
  949. NAME        ACTION                    OPCODE
  950. ----        ------                    ------
  951. (ask)                            ASK
  952.     If args, return the next one else ask user
  953.     Input: prompt list on stack (all types)
  954.     Result: RV (STRING)
  955. (msg)                            MSG
  956.     If args, concatenate them and print them out.
  957. (concat)                        CONCAT
  958.  
  959. object routines
  960. ********************************************************************
  961.