home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / Apps / DevTools / COWS / Code / COWSInterpreter.m < prev    next >
Encoding:
Text File  |  1994-03-23  |  50.4 KB  |  2,417 lines

  1. /*
  2.     Copyright (C) 1994 Sean Luke
  3.  
  4.     COWSInterpreter.m
  5.     Version 1.0
  6.     Sean Luke
  7.     
  8. */
  9.  
  10.  
  11.  
  12.  
  13. #import "COWSInterpreter.h"
  14.  
  15.  
  16.  
  17.  
  18. // Convenience String Functions
  19. // These functions are used by the interpreter and by other objects 
  20. // (most notably COWSStringNode) to generate new strings from old ones.
  21.  
  22.  
  23. char* newstr(const char* ct)        
  24.  
  25. /*    
  26. New-string version of strcpy.  Assumes ct is properly \0-terminated.  Allocates enough memory (1 more than length of ct), then copies ct into the new memory area.  Returns a pointer to the new area.
  27. */
  28.     {
  29.     char* t=malloc(strlen(ct)+1);
  30.     strcpy(t,ct);
  31.     return t;
  32.     }
  33.     
  34.  
  35.  
  36. char* newstrn(const char* ct,int size)
  37.  
  38. /*
  39. New-string version of strncpy.  Allocates enough memory (1 more than length of ct), then copies size characters of ct into the new memory area, tacking on a \0 at the end to complete the new string.  Returns a pointer to the new area.
  40. */
  41.     {
  42.     char* t=malloc(size+1);
  43.     strncpy(t,ct,size);
  44.     t[size]='\0';
  45.     return t;
  46.     }
  47.  
  48.  
  49.  
  50.  
  51.  
  52. // Timed Entry
  53.  
  54. DPSTimedEntryProc _COWS_timer
  55.     (DPSTimedEntry teNum, double now, void* interpreter)
  56.     {
  57.     COWSInterpreter* the_interpreter=(COWSInterpreter*) interpreter;
  58.     [the_interpreter _go];
  59.     return (void*) NULL;
  60.     }
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71. @implementation COWSInterpreter
  72.  
  73. - init
  74.     {
  75.     program=[[COWSStringNode alloc] init];
  76.     stack=[[COWSStack alloc] init];
  77.     running=NO;
  78.     foreground=NO;
  79.     locked=NO;
  80.     delegate=NULL;
  81.     function_completed=NO;
  82.     repeats=100;
  83.     teNum=0;
  84.     te_speed=0.1;
  85.     current_dictionary=NULL;
  86.     current_function=[[COWSStringNode alloc] init];
  87.     current_position=0;
  88.     library_dictionary=[[HashTable alloc] initKeyDesc:"*"valueDesc:"@"];
  89.      function_dictionary=[[HashTable alloc] initKeyDesc:"*"valueDesc:"@"];
  90.     global_dictionary=[[HashTable alloc] initKeyDesc:"*"valueDesc:"@"];
  91.     pausing_function=NULL;
  92.     return [super init];
  93.     }
  94.     
  95.     
  96.     
  97.     
  98. - printDictionaries
  99. // prints each dictionary.  Internal function dictionary is printed along with
  100. // variables and arguments for each function.
  101.  
  102.     {
  103.     const void * key;
  104.     const char *value;
  105.     id value_node;
  106.     NXHashState state=[global_dictionary initState];
  107.     printf ("GLOBAL VARIABLES\n\n");
  108.     while ([global_dictionary nextState: &state key: &key value: 
  109.         (void*) &value_node])
  110.         {
  111.         value=[value_node string];
  112.         printf ("KEY:   #%s#\nVALUE: #%s#\n",(char*) key, 
  113.             (const char*) value);
  114.         }
  115.     state=[function_dictionary initState];
  116.     printf ("\n\nINTERNAL FUNCTIONS\n\n");
  117.     while ([function_dictionary nextState: &state key: &key value: 
  118.         (void*) &value_node])
  119.         {
  120.         value=[value_node string];
  121.         printf ("KEY:   #%s#\nVALUE: #%s#\n",(char*) key, 
  122.             (const char*) value);
  123.         [value_node printContents];
  124.         }
  125.     state=[library_dictionary initState];
  126.     printf ("\n\nLIBRARY FUNCTIONS\n\n");
  127.     while ([library_dictionary nextState: &state key: &key value: 
  128.         (void*) &value_node])
  129.         {
  130.         printf ("KEY:   #%s#\n",(char*) key);
  131.         }
  132.     printf ("\n\n");
  133.     return self;
  134.     }
  135.     
  136.     
  137.     
  138.     
  139. - printProgram
  140. // prints the current COWS program.
  141.  
  142.     {
  143.     printf ("PROGRAM\n\n#%s#\n\n",[program string]);
  144.     return self;
  145.     }
  146.     
  147.     
  148.     
  149.     
  150. - (int) setProgram:(const char*) this_string
  151.     // clears out dictionaries, sets up COWS Program, and interprets it.
  152.     // returns an error code if unable to at least initially parse the
  153.     // program enough to break it into functions and global variables
  154.     // for storage in dictionaries.  Must also stop any currently running
  155.     // COWS program.
  156.     {
  157.     int error;
  158.     
  159.     // zeroth, stop any current program...
  160.     
  161.     [self stopInterpreting];
  162.     
  163.     // first, clear out dictionaries
  164.     
  165.     [function_dictionary freeObjects];
  166.     [global_dictionary freeObjects];
  167.     [function_dictionary empty];
  168.     [global_dictionary empty];
  169.     [program setString:this_string];    
  170.         // Sets up program
  171.     error=[self _program:[program string]:0];
  172.         // Uses the new program string instead of this_string for safety.
  173.     return error;
  174.     }
  175.     
  176.     
  177.     
  178.     
  179. - addLibrary:this_library
  180.     {
  181.     if (this_library!=NULL)
  182.         //if ([this_library conformsTo:@protocol(InterpreterToLibrary)])
  183.             {
  184.             [this_library loadLibrary:self];
  185.             return self;
  186.             }
  187.     return NULL;
  188.     }
  189.     
  190.     
  191.     
  192. - clearLibraryFunctions
  193.     // clears out all library functions.  Must stop any current program.
  194.     {
  195.     [self stopInterpreting];
  196.     [library_dictionary freeObjects];
  197.     [library_dictionary empty];
  198.     return self;
  199.     }
  200.  
  201.  
  202.  
  203.  
  204. - setTimedEntrySpeed:(float) this_speed
  205.     {
  206.     if (this_speed>0) te_speed=this_speed;
  207.     return self;
  208.     }
  209.     
  210. - (float) timedEntrySpeed
  211.     {
  212.     return te_speed;
  213.     }
  214.  
  215.  
  216. - addLibraryFunction:(const char*) this_name
  217.     selector: (SEL) this_selector
  218.     target: this_target
  219.     // adds a library function to the library dictionary.
  220.     {
  221.     id new_node=[[COWSLibraryFunctionNode alloc] init];
  222.     [new_node setTarget:this_target];
  223.     [new_node setSelector:this_selector];
  224.     [library_dictionary insertKey:(const void*) this_name 
  225.         value:(void*)new_node];
  226.     return self;
  227.     }
  228.     
  229.     
  230.     
  231.     
  232. - interpretFunction:(const char*) this_name 
  233.     arguments:(COWSArgumentList*)these_arguments
  234.     // Starts interpreter up.  Currently, the interpreter is _not_
  235.     // reentrant, so please don't call this function if the interpreter's
  236.     // not stopped.  It is your responsibility to free your own argument
  237.     // list after calling this method.
  238.         
  239.     {
  240.     COWSStringNode* temp=[[COWSStringNode alloc] init];
  241.     if (working)        // i.e., already working on something
  242.         {
  243.         [temp free];
  244.         printf ("Whoops!  Already working on something!\n");
  245.         return NULL;
  246.         }
  247.     running=YES;
  248.     working=YES;
  249.     
  250.     
  251.     // remove old timed entry if any, then install new one.
  252.     if (teNum) DPSRemoveTimedEntry(teNum);
  253.     if (!foreground)                        // else, don't need a timed entry
  254.         teNum=DPSAddTimedEntry(te_speed, 
  255.             (DPSTimedEntryProc) _COWS_timer,
  256.             (void*) self, (int) NX_RUNMODALTHRESHOLD);
  257.     
  258.     // then clean out stack
  259.     [stack clear];
  260.     
  261.     [temp setString:this_name];
  262.     [self _executeProgram:these_arguments:temp];
  263.     return [self _go];    // this is just "one try" in the background
  264.                         // version, but the whole program execution
  265.                         // in the foreground version...
  266.     }    
  267.  
  268.  
  269.  
  270.  
  271.  
  272. - stopInterpreting
  273.     // Stops interpreter.  This could happen from outside, if the user
  274.     // wants to cancel the interpreter, or from inside, if the interpreter
  275.     // is finished and wants to clean up.
  276.     {
  277.     running=NO;
  278.     working=NO;
  279.     function_completed=NO;
  280.     if (teNum) DPSRemoveTimedEntry(teNum);
  281.     teNum=0;
  282.     [current_function setString:""]; // since it's just a copy of a dictionary
  283.     if (pausing_function!=NULL) [pausing_function pauseCancelled:self];
  284.     current_position=0;
  285.     return self;
  286.     }
  287.  
  288.  
  289.  
  290.  
  291. - pauseInterpreting:calling_function;
  292.     // Pauses interpreter.  Why would you want to do this?  In case you had
  293.     // a reentrant library function, which needed more information from a
  294.     // COWS function, you could simulate reentrance by pausing this
  295.     // interpreter, instantiating another, feeding that one the function
  296.     // request, getting a response back, destroying it, and resuming
  297.     // this interpreter with the appropriate value (to push on the stack).
  298.     {
  299.     if (foreground) return NULL;        // this function should not work
  300.                                         // in foreground mode!
  301.                                         
  302.     if (teNum) DPSRemoveTimedEntry(teNum);
  303.     pausing_function=calling_function;
  304.     teNum=0;
  305.     running=NO;
  306.     return self;
  307.     }
  308.  
  309.  
  310.  
  311.  
  312. - resumeInterpretingWithValue:(COWSStringNode*) this_value
  313.     // See pauseInterpreting above
  314.     // it is the responsibility of the calling function to destroy this_value
  315.     {
  316.     id push_val;
  317.     if (foreground) return NULL;        // this function should not work
  318.                                         // in foreground mode!
  319.     if (running) return NULL;            // can't resume if not paused!
  320.     if (!working) return NULL;            // can't resume if stopped!
  321.                                         
  322.     push_val=[[COWSStringNode init] alloc];
  323.     [push_val setString:[this_value string]];
  324.     [stack push:push_val];
  325.     
  326.     // remove old timed entry if any, then install new one.
  327.     if (teNum) DPSRemoveTimedEntry(teNum);
  328.     teNum=DPSAddTimedEntry(te_speed, 
  329.         (DPSTimedEntryProc) _COWS_timer,
  330.         (void*) self, (int) NX_RUNMODALTHRESHOLD);
  331.     pausing_function=NULL;
  332.     running=YES;
  333.     [self _doKeywords];
  334.     return self;
  335.     }
  336.  
  337.  
  338.  
  339. - free
  340.     // frees interpreter, all dictionaries, and stack.  Removes timed entry.
  341.     {
  342.     running=NO;
  343.     working=NO;
  344.     function_completed=NO;
  345.     if (teNum) DPSRemoveTimedEntry(teNum);
  346.     teNum=0;
  347.     if (pausing_function!=NULL) [pausing_function pauseCancelled:self];
  348.  
  349.     [function_dictionary freeObjects];
  350.     [global_dictionary freeObjects];
  351.     [library_dictionary freeObjects];
  352.     [function_dictionary empty];
  353.     [global_dictionary empty];
  354.     [library_dictionary empty];
  355.     [function_dictionary free];
  356.     [global_dictionary free];
  357.     [library_dictionary free];
  358.     
  359.     [stack free];
  360.     return [super free];
  361.     }
  362.  
  363.  
  364.  
  365. - setDelegate:this_delegate
  366.     {
  367.     // sets the delegate for the delegate message below.  The
  368.     // delegate receives this message when the interpreter is done
  369.     // performing an interpretFunction:arguments: loop.
  370.     
  371.     delegate=this_delegate;
  372.     return self;
  373.     }
  374.     
  375.     
  376. - delegate
  377.     // returns the current delegate
  378.     {
  379.     return delegate;
  380.     }
  381.     
  382.  
  383. - setRepeats:(int) this_number
  384.     {
  385.     // sets the number of operations the interpreter will attempt to
  386.     // do per timed entry.  A higher number is more efficient, but
  387.     // takes more control away from the user.
  388.     
  389.     if (this_number)
  390.         {
  391.         repeats=this_number;
  392.         return self;
  393.         }
  394.     return NULL;
  395.     }
  396.  
  397.  
  398.  
  399.  
  400. - (int) repeats
  401.     // returns the number of operations the interpreter will attempt to
  402.     // do per timed entry.  A higher number is more efficient, but
  403.     // takes more control away from the user.
  404.     {
  405.     return repeats;
  406.     }
  407.  
  408.  
  409.  
  410.  
  411. - setForeground:(BOOL) yes_or_no
  412.     {
  413.     [self stopInterpreting];        // otherwise it could jump
  414.                                     // into foreground mode with dire
  415.                                     // consequences!
  416.     foreground=yes_or_no;
  417.     return self;
  418.     }
  419.     
  420.     
  421. - (BOOL) foreground
  422.     {
  423.     return foreground;
  424.     }
  425.     
  426. - setLocked:(BOOL) yes_or_no
  427.     {
  428.     locked=yes_or_no;
  429.     return self;
  430.     }    
  431.     
  432. - (BOOL) locked
  433.     {
  434.     return locked;
  435.     }
  436.     
  437. - (BOOL) running
  438.     {
  439.     return running;
  440.     }
  441.     
  442. - (BOOL) working
  443.     {
  444.     return working;
  445.     }
  446.     
  447.     
  448. // DELEGATE MESSAGES
  449.  
  450. - finishedInterpreting:(const char*)returnValue:(int)thisMessage:sender
  451.     // this message is sent to the delegate, if it can receive it, after
  452.     // the interpreter has finished interpreting a function request.
  453.     {
  454.     return self;
  455.     }
  456.  
  457. - errorInterpreting:(int) thisError:(const char*)thisFunction:
  458.     (int)thisPosition:(const char*)thisString:sender
  459.     // this message is sent to the delegate, if it can receiive it, after
  460.     // the interpreter has encountered an error while interpreting.
  461.     {
  462.     return self;
  463.     }
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471. // TOKENIZER
  472. // Chews through string starting at pos, placing the next token in string into 
  473. // token, returning the new position in the string after token is out.  Skips 
  474. // white space, comments.  Considers a "string" to be one token.  Parentheses 
  475. // are also tokens, as are keywords.  Is not destructive to string.
  476.  
  477. // Returns Error or next token position.
  478.  
  479.  
  480. - (int) _tokenize:(const char*) string:(int) pos:(COWSStringNode*) token
  481.     {
  482.     int x=pos;
  483.     int length=strlen(string);
  484.     int start;
  485.     
  486.     // Skip through white space and comments
  487.     while (1)
  488.         {
  489.         if (x>=length) return COWSERRORNOMORETOKENS;
  490.         if (string[x]=='[')
  491.             {
  492.             while (1)
  493.                 {
  494.                 x++;
  495.                 if (x>=length) return COWSERRORNOMORETOKENS;
  496.                 if (string[x]==']') break;
  497.                 }
  498.             }
  499.         else if (string[x]!=' '&&string[x]!='\t'&&string[x]!='\n') break;
  500.         x++;
  501.         }
  502.     
  503.     // Determine Type
  504.     if (x>=length) return COWSERRORNOMORETOKENS;
  505.     if (string[x]=='\"')
  506.         {
  507.         start=x;
  508.         while (1)
  509.             {
  510.             x++;
  511.             if (x>=length) return COWSERRORNOCLOSINGQUOTE;
  512.             if (string[x]=='\"') break;
  513.             }
  514.         x++;
  515.         [token setString:&string[start] size:x-start];
  516.         return x;
  517.         }
  518.     else if (string[x]=='('||string[x]==')') 
  519.         {
  520.         [token setString:&string[x] size:1];
  521.         x++;
  522.         return x;
  523.         }
  524.     else        // symbol
  525.         {
  526.         start=x;
  527.         while (1)
  528.             {
  529.             x++;
  530.             if (x>=length) break;
  531.             if (string[x]==' '||string[x]=='\t'||string[x]=='\n') break;
  532.             if (string[x]=='['||string[x]=='\"') break;
  533.             if (string[x]=='('||string[x]==')') break;
  534.             }
  535.         [token setString:&string[start] size:x-start];
  536.         return x;
  537.         }
  538.     }
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546. // RECURSIVE DECENT PARSER
  547. // Used to break up globals and functions into dictionaries
  548. // Entry is by passing _program the program string and 0 as a position
  549. // The parser is straight forward but fairly uncommented.  Sorry!
  550.  
  551. // variablelist loads globals into global_dictionary
  552. // localvariablelist loads variables into a local dictionary
  553. // argumentlist loads arguments into a local argument list
  554. // itemlist grabs the remainder of the function
  555. // functionform loads arguments from the argument list into the local
  556. //        dictionary and puts the local dictionary and item list into
  557. //        function_dictionary
  558.  
  559.  
  560. /* Parsing Grammar:
  561.  
  562. NonTerminals:
  563.  
  564. program                :-    <programlist>
  565. programlist            :-    EOF | <globalform> <programlist> | <functionform>
  566.                                 <programlist>
  567. globalform            :-    ( <globalkeyword> <variablelist> )
  568. functionform        :-     (function <functionname> <argumentlist> 
  569.                                 variable <localvariablelist> begin <itemlist> |
  570.                         (function <functionname> <argumentlist> 
  571.                                 begin <itemlist>
  572. variablelist        :- <symbolname> <variablelist> | NULL
  573. localvariablelist    :- <symbolname> <localvariablelist> | NULL
  574. argumentlist        :- <symbolname> <argumentlist> | NULL
  575. itemlist            :-    <item>* )    <--note I use a while here. Less recursive.
  576. item                :-    <atom> | ( <itemlist>
  577.  
  578. Terminals:
  579. globalkeyword is the word "variable"
  580. functionkeyword    is the word "function"
  581. symbolname is any non-string, non-truth, non-number, non-keyword, non-delimiter
  582. atom is any non-delimiter
  583.  
  584. */
  585.  
  586.  
  587.  
  588.  
  589. - (int) _program:(const char*)string:(int)pos
  590.     {
  591.     return [self _programList:string:pos];
  592.     }
  593.     
  594.     
  595.     
  596.     
  597. - (int) _programList:(const char*)string:(int)pos
  598.     {
  599.     int rv;
  600.     COWSStringNode* s=[[COWSStringNode alloc] init];
  601.     
  602.     // NULL
  603.     
  604.     rv=[self _tokenize:string:pos:s];
  605.     if (rv==COWSERRORNOMORETOKENS) 
  606.         {
  607.         [s free];
  608.         return COWSSUCCESS;
  609.         }
  610.     
  611.     // <function-form> <program-list> 
  612.     
  613.     rv=[self _functionForm:string:pos];
  614.     if (rv>=0)
  615.         {
  616.         rv=[self _programList:string:rv];
  617.         if (rv>=0) 
  618.             {
  619.             [s free];
  620.             return rv;
  621.             }
  622.         }
  623.  
  624.     // <global-form> <program-list> 
  625.     
  626.     rv=[self _globalForm:string:pos];
  627.     if (rv>=0)
  628.         {
  629.         rv=[self _programList:string:rv];
  630.         if (rv>=0) 
  631.             {
  632.             [s free];
  633.             return rv;
  634.             }
  635.         }
  636.      [s free];    
  637.     return rv;
  638.     }
  639.     
  640.     
  641.     
  642.     
  643. - (int) _functionForm:(const char*)string:(int)pos
  644.     {
  645.     int rv;
  646.     int rvstart;
  647.     COWSStringNode* s=[[COWSStringNode alloc] init];
  648.     id func=[[COWSStateNode alloc] init];
  649.     COWSArgumentList* arguments=[func arguments];
  650.     HashTable* variables=[func dictionary];
  651.     
  652.     // (function <function-name> <argument-list> 
  653.     //        variable <local-variable-list> begin <value-list>) 
  654.     // this version has both variables and arguments
  655.     
  656.     rv=[self _openParen:string:pos];
  657.     if (rv>=0)
  658.         {
  659.         rv=[self _functionKeyword:string:rv];
  660.         if (rv>=0)
  661.             {
  662.             rv=[self _symbolName:string:s:rv];
  663.             if (rv>=0)
  664.                 {
  665.                 rv=[self _argumentList:string:rv:arguments];
  666.                 if (rv>=0)
  667.                     {
  668.                     // load argument list into dictionary as well!
  669.                     [arguments first];
  670.                     while([arguments now]!=NULL)
  671.                         {
  672.                         const char* argstr=[[arguments now] string];
  673.                         id var;
  674.                         if ([variables isKey:(const void*)
  675.                                 argstr])
  676.                             {
  677.                             [func free];
  678.                             [s free];
  679.                             return COWSERRORDUPLICATEARGUMENT;
  680.                             }
  681.                         var=[[COWSStringNode alloc] init];
  682.                         [var setString:""];
  683.                         [variables insertKey:newstr(argstr) value:var];                        
  684.                         [arguments next];
  685.                         }
  686.                     [arguments first];                        // just in case
  687.                     rv=[self _variableKeyword:string:rv];
  688.                     if (rv>=0)
  689.                         {
  690.                         rv=[self _localVariableList:string:rv:variables];
  691.                         if (rv>=0)
  692.                             {
  693.                             rv=[self _beginKeyword:string:rv];
  694.                             if (rv>=0)
  695.                                 {
  696.                                 rvstart=rv;
  697.                                 rv=[self _itemList:string:rv];
  698.                                 if (rv>=0)
  699.                                     {
  700.                                     if ([function_dictionary isKey:
  701.                                             (const void*) [s string]])
  702.                                         {
  703.                                         [s free];
  704.                                         [func free];
  705.                                         return COWSERRORDUPLICATEFUNCTION;
  706.                                         }
  707.                                     [func setString:&string[rvstart]
  708.                                          size:rv-rvstart];
  709.                                     [function_dictionary insertKey:
  710.                                         newstr([s string]) value:func];
  711.                                     [s free];                        
  712.                                     return rv;
  713.                                     }
  714.                                 }
  715.                             }
  716.                         }
  717.                     }
  718.                 }
  719.             }
  720.         }
  721.  
  722.     [arguments clear];
  723.     [variables freeObjects];
  724.     [variables empty];
  725.  
  726.  
  727.     // (function <function-name> <argument-list> begin <value-list>) 
  728.     // this version has no variables
  729.     
  730.     rv=[self _openParen:string:pos];
  731.     if (rv>=0)
  732.         {
  733.         rv=[self _functionKeyword:string:rv];
  734.         if (rv>=0)
  735.             {
  736.             rv=[self _symbolName:string:s:rv];
  737.             if (rv>=0)
  738.                 {
  739.                 rv=[self _argumentList:string:rv:arguments];
  740.                 if (rv>=0)
  741.                     {
  742.                     // load argument list into dictionary as well!
  743.                     [arguments first];
  744.                     while([arguments now]!=NULL)
  745.                         {
  746.                         const char* argstr=[[arguments now] string];
  747.                         id var;
  748.                         if ([variables isKey:(const void*)
  749.                                 argstr])
  750.                             {
  751.                             [func free];
  752.                             [s free];
  753.                             return COWSERRORDUPLICATEARGUMENT;
  754.                             }
  755.                         var=[[COWSStringNode alloc] init];
  756.                         [var setString:""];
  757.                         [variables insertKey:newstr(argstr) value:var];                        
  758.                         [arguments next];
  759.                         }
  760.                     [arguments first];                        // just in case
  761.                     rv=[self _beginKeyword:string:rv];
  762.                         if (rv>=0)
  763.                         {
  764.                         rvstart=rv;
  765.                         rv=[self _itemList:string:rv];
  766.                         if (rv>=0)
  767.                             {
  768.                             if ([function_dictionary isKey:
  769.                                     (const void*) [s string]])
  770.                                 {
  771.                                 [s free];
  772.                                 [func free];
  773.                                 return COWSERRORDUPLICATEFUNCTION;
  774.                                 }
  775.                             [func setString:&string[rvstart]
  776.                                  size:rv-rvstart];
  777.                             [function_dictionary insertKey:
  778.                                 newstr([s string]) value:func];
  779.                             [s free];                        
  780.                             return rv;
  781.                             }
  782.                         }
  783.                     }
  784.                 }
  785.             }
  786.         }
  787.  
  788.  
  789.  
  790.     // otherwise...
  791.     [s free];
  792.     [func free];
  793.     return rv;
  794.     }
  795.  
  796.  
  797.     
  798.         
  799. - (int) _itemList:(const char*)string:(int)pos
  800.     {
  801.     int rv=pos;
  802.     int temp;
  803.     // an item list is lots of items ending with a )...
  804.     
  805.     while(1)
  806.         {
  807.         temp=[self _closeParen:string:rv];
  808.         if (temp>=0) return temp;
  809.         //else...
  810.         rv=[self _item:string:rv];
  811.         if (!(rv>=0)) return rv;
  812.         }
  813.     return rv;
  814.     }
  815.     
  816.     
  817.     
  818.  
  819. - (int) _item:(const char*)string:(int)pos
  820.     {
  821.     int rv;
  822.  
  823.     // either an item is an atom... 
  824.     
  825.     rv=[self _atom:string:pos];
  826.     if (rv>=0) return rv;
  827.     
  828.     // or it is a list of items beginning with a (...
  829.  
  830.     rv=[self _openParen:string:pos];
  831.     if (rv>=0) 
  832.         {
  833.         rv=[self _itemList:string:rv];
  834.         return rv;
  835.         }
  836.     return rv;
  837.     }
  838.     
  839.     
  840.     
  841.     
  842. - (int) _globalForm:(const char*)string:(int)pos
  843.     {
  844.     int rv;
  845.     
  846.     // (variable <variable-name>) 
  847.     
  848.     rv=[self _openParen:string:pos];
  849.     if (rv>=0)
  850.         {
  851.         rv=[self _variableKeyword:string:rv];
  852.         if (rv>=0)
  853.             {
  854.             rv=[self _variableList:string:rv];
  855.             if (rv>=0)
  856.                 {
  857.                 rv=[self _closeParen:string:rv];
  858.                 if (rv>=0) 
  859.                     {
  860.                     return rv;
  861.                     }
  862.                 }
  863.             }
  864.         }
  865.     return rv;
  866.     }
  867.     
  868.     
  869.     
  870.  
  871. - (int) _variableList:(const char*) string:(int)pos
  872.     {
  873.     int rv;
  874.     COWSStringNode* s=[[COWSStringNode alloc] init];
  875.     id var;
  876.     
  877.     // NULL        variable lists always end with ")"
  878.     
  879.     rv=[self _tokenize:string:pos:s];
  880.     if (!strcmp([s string],")")) 
  881.         {
  882.         [s free];
  883.         return pos;            // note _not_ rv
  884.         }
  885.     
  886.     // <variable-name> <variable-list>  
  887.     
  888.     rv=[self _symbolName:string:s:pos];    // a variable is identical to a symbol
  889.     if (rv>=0)
  890.         {
  891.         rv=[self _variableList:string:rv];
  892.         if (rv>=0) 
  893.             {
  894.             var=[[COWSStringNode alloc] init];
  895.             [var setString:""];
  896.             [global_dictionary insertKey:newstr([s string]) value:var];
  897.             [s free];
  898.             return rv;
  899.             }
  900.         }
  901.     [s free];
  902.     return rv;
  903.     }
  904.     
  905.     
  906.     
  907.     
  908.     
  909. - (int) _localVariableList:(const char*) string:(int)pos:(HashTable*) arguments
  910.     {
  911.     // arguments is hash table in which to place arguments
  912.     int rv;
  913.     COWSStringNode* s=[[COWSStringNode alloc] init];
  914.     id var;
  915.     
  916.     // NULL        local variable lists always end with "do"
  917.     
  918.     rv=[self _tokenize:string:pos:s];
  919.     if (!strcmp([s string], "do")) 
  920.         {
  921.         [s free];
  922.         return pos;    // note _not_ rv
  923.         }
  924.     
  925.     // <variable-name> <local-variable-list>  
  926.     
  927.     rv=[self _symbolName:string:s:pos];    // a variable is identical to a symbol
  928.     if (rv>=0)
  929.         {
  930.         rv=[self _localVariableList:string:rv:arguments];
  931.         if (rv>=0) 
  932.             {
  933.             if ([arguments valueForKey:(const void*)[s string]]!=nil)
  934.                 { 
  935.                 [s free];
  936.                 return COWSERRORDUPLICATEVARIABLE;
  937.                 }
  938.             var=[[COWSStringNode alloc] init];
  939.             [var setString:""];
  940.             [arguments insertKey:newstr([s string]) value:var];
  941.             [s free];
  942.             return rv;
  943.             }
  944.         }
  945.     [s free];
  946.     return rv;
  947.     }
  948.  
  949.  
  950.  
  951.  
  952.     
  953. - (int) _argumentList:(const char*) string:(int)pos:
  954.         (COWSArgumentList*) arguments
  955.     {
  956.     // arguments is an argument-list in which to place arguments
  957.     int rv;
  958.     COWSStringNode* s=[[COWSStringNode alloc] init];
  959.     const char* token;
  960.     
  961.     // NULL        argument lists always end with "variable" or "do"
  962.     
  963.     rv=[self _tokenize:string:pos:s];
  964.     token=[s string];
  965.     if (!strcmp(token, "variable") || !strcmp(token, "do")) 
  966.         {
  967.         [s free];
  968.         return pos;    // note _not_ rv
  969.         }
  970.     
  971.     // <argument> <argument-list>  
  972.     
  973.     rv=[self _symbolName:string:s:pos];    // a variable is identical to a symbol
  974.     if (rv>=0)
  975.         {
  976.         rv=[self _argumentList:string:rv:arguments];
  977.         if (rv>=0) 
  978.             {
  979.             id arg=[[COWSStringNode alloc] init];
  980.             [arg setString:[s string]];
  981.             [arguments push:arg];
  982.             [s free];
  983.             return rv;
  984.             }
  985.         }
  986.     [s free];
  987.     return rv;
  988.     }
  989.     
  990.     
  991.     
  992.     
  993.  
  994. // TERMINAL HELPER FUNCTIONS
  995. // Help terminals decide if a string is what it's supposed to be.
  996.  
  997. int anumber(const char* string)
  998.     {
  999.     int x=0;
  1000.         // assumes that numbers begin with a digit, or a -,+, or . (or ")
  1001.     if (string[x]=='\0') return 0;
  1002.     if (string[x]=='\"') x++;
  1003.     if (string[x]=='\0') return 0;
  1004.     if (string[x]=='-'||string[x]=='+') x++;
  1005.     if (string[x]=='\0') return 0;
  1006.     if (string[x]=='.') x++;
  1007.     if (string[x]=='\0') return 0;
  1008.     if (string[x]>=0x30&&string[x]<=0x39) return 1;    
  1009.     return 0;
  1010.     }
  1011.  
  1012.  
  1013.  
  1014. int astring(const char* string)
  1015.     {
  1016.     int x=0;
  1017.         // assumes that strings begin with a "
  1018.     if (string[x]=='\0') return 0;
  1019.     if (string[x]=='\"') return 1;
  1020.     return 0;
  1021.     }
  1022.  
  1023.  
  1024.  
  1025. int atruth(const char* string)
  1026.     {
  1027.         // assumes that truths are t, f, "t", or "f"
  1028.     if (!strcmp(string,"t")||
  1029.         !strcmp(string,"f")||
  1030.         !strcmp(string,"\"t\"")||
  1031.         !strcmp(string,"\"f\"")) return 1;
  1032.     return 0;
  1033.     }
  1034.     
  1035. int asymbol(const char* string)
  1036.     // a symbol isn't a number, a string, or a truth, nor ( or )
  1037.     {
  1038.     if (!atruth(string)
  1039.         &&!anumber(string)
  1040.         &&!astring(string)
  1041.         &&strcmp(string,"(")
  1042.         &&strcmp(string,")")) return 1;
  1043.     return 0;
  1044.     }
  1045.  
  1046.  
  1047.  
  1048. //  TERMINALS
  1049. //    Terminals check tokens for being a certain kind of token, returning
  1050. //    truth or not.  The only exception is _symbolName, which not only 
  1051. //    checks to see if a token is valid, but also returns the token to be
  1052. //    used elsewhere.
  1053.  
  1054. - (int) _symbolName:(const char*)string:(COWSStringNode*)s:(int)pos
  1055.     {
  1056.     // a symbol is anything that's not (, ), a keyword, a truth,
  1057.     // a number, or a string.  _symbolName returns the name
  1058.     // in s.
  1059.     int rv=pos;
  1060.     const char* temp;
  1061.     rv=[self _tokenize:string:pos:s];
  1062.     if (rv<0) return rv;
  1063.     temp=[s string];
  1064.     if (strcmp(temp,"(")&&
  1065.         strcmp(temp,")")&&
  1066.         strcmp(temp,"function")&&
  1067.         strcmp(temp,"variable")&&
  1068.         strcmp(temp,"set")&&
  1069.         strcmp(temp,"if")&&
  1070.         strcmp(temp,"else")&&
  1071.         strcmp(temp,"do")&&
  1072.         strcmp(temp,"for")&&
  1073.         strcmp(temp,"then")&&
  1074.         strcmp(temp,"while")&&
  1075.         !astring(temp)&&
  1076.         !atruth(temp)&&
  1077.         !anumber(temp))
  1078.         {
  1079.         return rv;
  1080.         }
  1081.     return COWSERRORSYNTAX;
  1082.     }
  1083.  
  1084.  
  1085.  
  1086.  
  1087. - (int) _openParen:(const char*)string:(int)pos
  1088.     {
  1089.     // an openparen is a "("
  1090.     
  1091.     int rv=pos;
  1092.     COWSStringNode*s=[[COWSStringNode alloc] init];
  1093.     rv=[self _tokenize:string:pos:s];
  1094.     if (rv<0) 
  1095.         {
  1096.         [s free];
  1097.         return rv;
  1098.         }
  1099.     if (!strcmp([s string],"(")) 
  1100.         {
  1101.         [s free];
  1102.         return rv;
  1103.         }
  1104.     [s free];
  1105.     return COWSERRORSYNTAX;
  1106.     }
  1107.     
  1108.     
  1109.             
  1110.             
  1111. - (int) _closeParen:(const char*)string:(int)pos
  1112.     {
  1113.     // a closeparen is a ")"
  1114.     
  1115.     int rv=pos;
  1116.     COWSStringNode*s=[[COWSStringNode alloc] init];
  1117.     rv=[self _tokenize:string:pos:s];
  1118.     if (rv<0) 
  1119.         {
  1120.         [s free];
  1121.         return rv;
  1122.         }
  1123.     if (!strcmp([s string],")")) 
  1124.         {
  1125.         [s free];
  1126.         return rv;
  1127.         }
  1128.     [s free];
  1129.     return COWSERRORSYNTAX;
  1130.     }
  1131.             
  1132.  
  1133.  
  1134.             
  1135. - (int) _variableKeyword:(const char*)string:(int)pos
  1136.     {
  1137.     // a variablekeyword is the word "variable"
  1138.     
  1139.     int rv=pos;
  1140.     COWSStringNode*s=[[COWSStringNode alloc] init];
  1141.     rv=[self _tokenize:string:pos:s];
  1142.     if (rv<0) 
  1143.         {
  1144.         [s free];
  1145.         return rv;
  1146.         }
  1147.     if (!strcmp([s string],"variable")) 
  1148.         {
  1149.         [s free];
  1150.         return rv;
  1151.         }
  1152.     [s free];
  1153.     return COWSERRORSYNTAX;
  1154.     }
  1155.             
  1156.  
  1157.  
  1158.             
  1159. - (int) _functionKeyword:(const char*)string:(int)pos
  1160.     {
  1161.     // a functionkeyword is the word "function"
  1162.     
  1163.     int rv=pos;
  1164.     COWSStringNode*s=[[COWSStringNode alloc] init];
  1165.     rv=[self _tokenize:string:pos:s];
  1166.     if (rv<0) 
  1167.         {
  1168.         [s free];
  1169.         return rv;
  1170.         }
  1171.     if (!strcmp([s string],"function")) 
  1172.         {
  1173.         [s free];
  1174.         return rv;
  1175.         }
  1176.     [s free];
  1177.     return COWSERRORSYNTAX;
  1178.     }
  1179.  
  1180.  
  1181.  
  1182.  
  1183. - (int) _beginKeyword:(const char*)string:(int)pos
  1184.     {
  1185.     // a beginkeyword is the word "do"
  1186.     
  1187.     int rv=pos;
  1188.     COWSStringNode*s=[[COWSStringNode alloc] init];
  1189.     rv=[self _tokenize:string:pos:s];
  1190.     if (rv<0) 
  1191.         {
  1192.         [s free];
  1193.         return rv;
  1194.         }
  1195.     if (!strcmp([s string],"do")) 
  1196.         {
  1197.         [s free];
  1198.         return rv;
  1199.         }
  1200.     [s free];
  1201.     return COWSERRORSYNTAX;
  1202.     }
  1203.  
  1204.  
  1205.  
  1206.  
  1207. - (int) _atom:(const char*)string:(int)pos
  1208.     {
  1209.     // atoms are used only when doing 1st level parsing.
  1210.     // an atom is anything that's not a ( or ).
  1211.     
  1212.     int rv=pos;
  1213.     COWSStringNode*s=[[COWSStringNode alloc] init];
  1214.     rv=[self _tokenize:string:pos:s];
  1215.     if (rv<0) 
  1216.         {
  1217.         [s free];
  1218.         return rv;
  1219.         }
  1220.     if (strcmp([s string],"(")&&strcmp([s string],")")) 
  1221.         {
  1222.         [s free];
  1223.         return rv;
  1224.         }
  1225.     [s free];
  1226.     return COWSERRORSYNTAX;
  1227.     }
  1228.     
  1229.     
  1230.     
  1231.     
  1232.     
  1233.     
  1234.     
  1235.     
  1236.     
  1237.     
  1238.     
  1239.     
  1240.     
  1241.     
  1242.     
  1243.     
  1244.     
  1245.     
  1246.     
  1247.     
  1248.     
  1249.     
  1250.     
  1251.     
  1252.     
  1253.     
  1254.     
  1255.  
  1256.     
  1257. // INTERPRETER    
  1258.     
  1259.     
  1260. - _executeProgram:(COWSArgumentList*) arguments:(COWSStringNode*) symbol
  1261.     // Starts executing function <symbol> in the current COWS Program, 
  1262.     // passing the function arguments <arguments>
  1263.     {
  1264.     id temp_sym=[[COWSSymbolNode alloc] init];
  1265.     id temp_val;
  1266.     interpretation=COWSINTERPRETATIONUNDEFINED;
  1267.     [temp_sym setString:[symbol string]];
  1268.     [stack push:temp_sym];
  1269.     [arguments first];
  1270.     while ([arguments now])
  1271.         {
  1272.         temp_val=[[COWSStringNode alloc] init];
  1273.         [temp_val setString:[[arguments now] string]];
  1274.         [stack push:temp_val];
  1275.         [arguments next];
  1276.         }
  1277.     return [self _performFunction];
  1278.     }
  1279.     
  1280.     
  1281.  
  1282. - _performFunction
  1283.     // Begins performing a function.  It is assumed that the Symbol Name
  1284.     // for the function is on the stack, as well as the arguments (which
  1285.     // are on top).
  1286.     {
  1287.     id arguments=[[COWSArgumentList alloc] init];
  1288.     id symbol_name;
  1289.     const char* string;
  1290.     while ([[stack top] isMemberOf:[COWSStringNode class]])
  1291.         // eats down to the nearest non-string node, which should be a
  1292.         // symbol node...
  1293.         // this should put the arguments in forward order...
  1294.         // that is, the first argument is on top, and the last
  1295.         // (rightmost) argument is on bottom.
  1296.         {
  1297.         [arguments push:[stack pop]];
  1298.         }
  1299.     symbol_name=[stack pop];    // this assumes that symbol_name is a Symbol
  1300.     string=[symbol_name string];
  1301.     if ([function_dictionary isKey:string])
  1302.         {
  1303.         id returnval=[self _performInternalFunction:arguments:symbol_name];
  1304.         if (returnval!=NULL) [symbol_name free];    // else it's on the stack!
  1305.         [arguments free];
  1306.         return returnval;
  1307.         }
  1308.     else if ([library_dictionary isKey:string])
  1309.         {
  1310.         id returnval=[self _performLibraryFunction:arguments:symbol_name];
  1311.         if (returnval!=NULL) [symbol_name free];    // else it's on the stack!
  1312.         [arguments free];
  1313.         return returnval;
  1314.         }
  1315.     else                         // missing function
  1316.         {
  1317.         [self _error:COWSERRORNOSUCHFUNCTION:
  1318.             [current_function string]:current_position:[symbol_name string]];
  1319.         [arguments free];
  1320.         return NULL;
  1321.         }
  1322.     }
  1323.     
  1324.     
  1325.     
  1326. - _performInternalFunction:
  1327.         (COWSArgumentList*) arguments:(COWSStringNode*) symbol
  1328.         
  1329.     // performs an internal function (a function defined in COWS script)
  1330.     // this is always called by _performFunction.
  1331.     
  1332.     {
  1333.     id function_node=(COWSStateNode*)
  1334.         [function_dictionary valueForKey:(const void*)[symbol string]];
  1335.     id new_state=[function_node copy];
  1336.     id new_args=[new_state arguments];
  1337.     id new_dict=[new_state dictionary];
  1338.     id val;
  1339.     id old_state=[stack topState];
  1340.     
  1341.     if (interpretation==COWSINTERPRETATIONUNDEFINED)
  1342.         interpretation=COWSINTERPRETATIONFUNCTION;
  1343.     
  1344.     if (old_state!=NULL)    // i.e., if it's not the beginning of the program
  1345.         {
  1346.         [old_state setPos:current_position];        // saves old state away...
  1347.         }
  1348.     [arguments first];
  1349.     [new_args first];
  1350.     while([arguments now])
  1351.         {
  1352.         if ([new_args now]==NULL)
  1353.             {
  1354.             [self _error:COWSERRORTOOMANYARGUMENTS
  1355.                 :[current_function string]:current_position:[symbol string]];
  1356.             return NULL;
  1357.             }
  1358.         val=(COWSStringNode*)
  1359.             [new_dict valueForKey:(const void*)[[new_args now] string]];
  1360.         if (val==nil)
  1361.             {
  1362.             [self _error:COWSINTERNALERROR
  1363.                 :[current_function string]:current_position:[symbol string]];
  1364.             return NULL;
  1365.             }
  1366.         else
  1367.             {
  1368.             [val setString:[[arguments now] string]];
  1369.             }
  1370.         [arguments next];
  1371.         [[new_state arguments] next];
  1372.         }
  1373.     if ([new_args now]!=NULL)
  1374.         {
  1375.         [self _error: COWSERRORNOTENOUGHARGUMENTS
  1376.                 :[current_function string]:current_position:[symbol string]];
  1377.         return NULL;
  1378.         }
  1379.     [stack push:new_state];
  1380.     [new_state setPos:0];
  1381.     [current_function setString:[new_state string]];
  1382.     current_dictionary=[new_state dictionary];
  1383.     current_position=[new_state pos];        // which should always be 0, tho
  1384.     return self;
  1385.     }
  1386.     
  1387.     
  1388.     
  1389.     
  1390. - _performLibraryFunction:
  1391.         (COWSArgumentList*) arguments:(COWSStringNode*) symbol
  1392.         
  1393.     // performs a library function; that is, one defined by the application
  1394.     // before the COWS program was run.  Always called by _performFunction.
  1395.     
  1396.     {
  1397.     id temp_node=[library_dictionary valueForKey:[symbol string]];
  1398.     id returnval;
  1399.  
  1400.     if (temp_node==NULL)
  1401.         {
  1402.         [self _error:COWSINTERNALERROR
  1403.                 :[current_function string]:current_position:[symbol string]];
  1404.         return NULL;
  1405.         }
  1406.         
  1407.     if (interpretation==COWSINTERPRETATIONUNDEFINED)
  1408.         interpretation=COWSINTERPRETATIONLIBRARY;
  1409.  
  1410.     returnval=[[temp_node target] perform:[temp_node selector] with:arguments];
  1411.     
  1412.     // since we didn't use arguments to pass to the target, but built our own
  1413.     // arguments, we must free our own arguments here.
  1414.     
  1415.     if ([returnval error])
  1416.         {
  1417.         [self _error:COWSLIBRARYFUNCTIONERROR
  1418.                 :[current_function string]:current_position:[returnval string]];
  1419.         return NULL;
  1420.         }
  1421.     if (running)    // not paused...resumes push their own stuff on stack
  1422.         {
  1423.         
  1424.         [stack push:returnval];
  1425.         return [self _doKeywords];
  1426.         }
  1427.     return self;
  1428.     }
  1429.     
  1430.     
  1431.     
  1432.     
  1433.     
  1434. - _completeFunction
  1435.     // finishes out an internal function
  1436.     // and cleans up before interpreter continues parent function.
  1437.     {
  1438.     id return_value;
  1439.     id new_state;
  1440.     if ([[stack top] isMemberOf:[COWSStringNode class]])
  1441.         {
  1442.         return_value=[stack pop];
  1443.         }
  1444.     else return_value=[[COWSStringNode alloc] init];
  1445.     while ([[stack top] isMemberOf:[COWSStringNode class]])
  1446.         {
  1447.         [[stack pop] free];    // clears out non-return values
  1448.         }
  1449.     if ([stack top]!=NULL)        // else, could be a library function finishing
  1450.         [[stack pop] free];        // clears out Local State
  1451.     new_state=[stack topState];
  1452.     if (new_state!=NULL)
  1453.         {
  1454.         [current_function setString:[new_state string]];
  1455.         current_position=[new_state pos];
  1456.         current_dictionary=[new_state dictionary];
  1457.         [stack push:return_value];
  1458.         return [self _doKeywords];
  1459.         }
  1460.     else            // program is finished!
  1461.         {
  1462.         /*if (delegate!=NULL&&[delegate conformsTo:@protocol (InterpreterToAppDelegate)])*/
  1463.             [delegate finishedInterpreting:
  1464.                 [return_value string]:(int)COWSSUCCESS:self];
  1465.         [return_value free];
  1466.         return [self stopInterpreting];
  1467.         }
  1468.     }    
  1469.     
  1470.     
  1471.     
  1472.     
  1473.     
  1474.     
  1475. - _evaluateVariable:(COWSStringNode*) symbol
  1476.     // evaluates the variable <symbol> to its value, either in the current
  1477.     // dictionary or in the global dictionary
  1478.     
  1479.     {
  1480.     // this assumes current dictionary is proper...
  1481.     id temp_val=[current_dictionary valueForKey:(void*) [symbol string]];
  1482.     if (temp_val==NULL) temp_val=
  1483.         [global_dictionary valueForKey:(void*) [symbol string]];
  1484.     if (temp_val==NULL)
  1485.         {
  1486.         [self _error:COWSERRORNOSUCHVARIABLE
  1487.                 :[current_function string]:current_position:[symbol string]];
  1488.         return NULL;        
  1489.         }
  1490.     else
  1491.         {
  1492.         id new_val=[[COWSStringNode alloc] init];
  1493.         [new_val setString:[temp_val string]];
  1494.         [stack push:new_val];
  1495.         [self _doKeywords];
  1496.         return self;
  1497.         }
  1498.     }    
  1499.     
  1500.     
  1501.     
  1502.     
  1503.     
  1504. - _doKeywords
  1505.     // continues keywords, if there are any.
  1506.     // this happens every time a value if finished out; a keyword may need
  1507.     // to use it to set something up (like <for> needs 4 values)
  1508.     {
  1509.     id top=[stack topSymbol];
  1510.     const char* string;
  1511.     if (top==NULL) return self;
  1512.     string=[top string];
  1513.     if (!strcmp(string,"if"))
  1514.         {
  1515.         return [self _doIf];
  1516.         }
  1517.     if (!strcmp(string,"set"))
  1518.         {
  1519.         return [self _doSet];
  1520.         }
  1521.     if (!strcmp(string,"for"))
  1522.         {
  1523.         return [self _doFor];
  1524.         }
  1525.     if (!strcmp(string,"while"))
  1526.         {
  1527.         return [self _doWhile];
  1528.         }
  1529.     return self;
  1530.     }
  1531.     
  1532.     
  1533.  
  1534.     
  1535. - _go
  1536.     // Drives _readEval, the main interpreter function
  1537.     // this superfunction allows the interpreter to perform <repeats> number
  1538.     // of _readEvals each clock cycle.  If the interpreter has stopped before
  1539.     // the clock did, _go breaks out automatically so it doesn't waste time.
  1540.     
  1541.     // NEW IN 1.2:  If the interpreter is foreground, _go works until it
  1542.     // encounters a command-period.  If it's background, _go works until
  1543.     // it encounters an event.  The event stuff is provided by Don Yacktman.
  1544.     
  1545.     // Foreground mode does _not_ work properly with pause and resume!
  1546.     // An interpreter _must_ be background for this to work.
  1547.     
  1548.     {
  1549.     int x;
  1550.     
  1551.     if (foreground)
  1552.         {
  1553.         while (running)
  1554.             {
  1555.             if (NXUserAborted())
  1556.                 {
  1557.                 [self stopInterpreting];
  1558.                 return self;
  1559.                 }
  1560.             else for (x=0;x<repeats;x++)
  1561.                 {
  1562.                 if (!running) break;
  1563.                 [self _readEval];
  1564.                 }
  1565.             }
  1566.         }
  1567.     else        // background
  1568.         {
  1569.         if (!running) return self;
  1570.         for (x=0;x<repeats;x++)
  1571.             {
  1572.             if (!running) break;
  1573.             [self _readEval];
  1574.             }
  1575.         }
  1576.     return self;
  1577.     }    
  1578.  
  1579.  
  1580.  
  1581. - _readEval
  1582.     // Reads a token and evaluates it by calling one of several subordinate
  1583.     // functions.  This function is ultimately driven by the clock through _go.
  1584.     
  1585.     {
  1586.     id token=[[COWSStringNode alloc] init];
  1587.     const char* string;
  1588.     current_position=[self _tokenize:[current_function string]:
  1589.         current_position:token];
  1590.     string=[token string];
  1591.     if (!strcmp(string,""))        // token is empty...
  1592.         {
  1593.         if (interpretation==COWSINTERPRETATIONLIBRARY)    
  1594.             // it was a library function
  1595.             {
  1596.             return [self _completeFunction];
  1597.             }
  1598.         [self _error:COWSERRORNOMORETOKENS
  1599.                 :[current_function string]:current_position:""];
  1600.         [token free];
  1601.         return NULL;        
  1602.         }
  1603.     else if (atruth(string))
  1604.         {
  1605.         // prepare string
  1606.         [self _makeTruth:token];
  1607.         [stack push:token];
  1608.         return [self _doKeywords];
  1609.         }
  1610.     else if (anumber(string))
  1611.         {
  1612.         // prepare string
  1613.         [self _makeNumber:token];
  1614.         [stack push:token];
  1615.         return [self _doKeywords];
  1616.         }
  1617.     else if (astring(string))
  1618.         {
  1619.         // prepare string
  1620.         [self _strip:token];
  1621.         [stack push:token];
  1622.         return [self _doKeywords];
  1623.         }
  1624.     else if (asymbol(string))            // token is a variable...
  1625.         {
  1626.         [self _evaluateVariable:token];
  1627.         [token free];
  1628.         return self;
  1629.         }
  1630.     else if (!strcmp(string,"("))
  1631.         {
  1632.         id new_node;
  1633.         current_position=[self _tokenize:[current_function string]:
  1634.             current_position:token];
  1635.         string=[token string];
  1636.         if (!strcmp(string,""))        // token is empty...
  1637.             {
  1638.             [self _error:COWSERRORNOMORETOKENS
  1639.                 :[current_function string]:current_position:""];
  1640.             [token free];
  1641.             return NULL;        
  1642.             }
  1643.         else if (!asymbol(string))        // token ain't a symbol
  1644.             {
  1645.             [self _error:COWSERRORNOFUNCTIONNAME
  1646.                 :[current_function string]:current_position:[token string]];
  1647.             [token free];
  1648.             return NULL;
  1649.             }
  1650.         else if (!strcmp(string,"if"))
  1651.             {
  1652.             [self _startIf];
  1653.             [token free];
  1654.             return self;
  1655.             }
  1656.         else if (!strcmp(string,"set"))
  1657.             {
  1658.             [self _startSet];
  1659.             [token free];
  1660.             return self;
  1661.             }
  1662.         else if (!strcmp(string,"for"))
  1663.             {
  1664.             [self _startFor];
  1665.             [token free];
  1666.             return self;
  1667.             }
  1668.         else if (!strcmp(string,"while"))
  1669.             {
  1670.             [self _startWhile];
  1671.             [token free];
  1672.             return self;
  1673.             }
  1674.         // otherwise, token is a symbol but isn't a keyword, so it's a function
  1675.         // so push it for use later
  1676.         new_node=[[COWSSymbolNode alloc] init];
  1677.         [new_node setString:[token string]];
  1678.         [stack push:new_node];
  1679.         [token free];
  1680.         return self;
  1681.         }
  1682.     else if (!strcmp(string,")"))
  1683.         {
  1684.         id symbol=[stack topSymbol];
  1685.         if (symbol==NULL)
  1686.             {
  1687.             [self _completeFunction];
  1688.             [token free];
  1689.             return self;
  1690.             }
  1691.         string=[symbol string];
  1692.         if (!strcmp(string,"if"))
  1693.             {
  1694.             id temp=[self _finishIf];
  1695.             [token free];
  1696.             if (temp!=NULL) [self _doKeywords];
  1697.             return self;
  1698.             }
  1699.         else if (!strcmp(string,"set"))
  1700.             {
  1701.             id temp=[self _finishSet];
  1702.             [token free];
  1703.             if (temp!=NULL) [self _doKeywords];
  1704.             return self;
  1705.             }
  1706.         else if (!strcmp(string,"for"))
  1707.             {
  1708.             id temp=[self _finishFor];
  1709.             [token free];
  1710.             if (temp!=NULL) [self _doKeywords];
  1711.             return self;
  1712.             }
  1713.         else if (!strcmp(string,"while"))
  1714.             {
  1715.             id temp=[self _finishWhile];
  1716.             [token free];
  1717.             if (temp!=NULL) [self _doKeywords];
  1718.             return self;
  1719.             }
  1720.         // else function is ready to be performed
  1721.         [self _performFunction];
  1722.         }
  1723.     [token free];
  1724.     return self;
  1725.     }
  1726.  
  1727.  
  1728. -_startSet
  1729.     // starts processing a "set" token
  1730.     {
  1731.     const char* string;
  1732.     id token=[[COWSStringNode alloc] init];
  1733.     id node;
  1734.     current_position=[self _tokenize:[current_function string]:
  1735.         current_position:token];
  1736.     string=[token string];
  1737.     if (asymbol(string))
  1738.         {
  1739.         node=[[COWSSymbolNode alloc] init];
  1740.         [node setState:COWSSTARTSET];
  1741.         [node setString:"set"];
  1742.         [[node variable] setString:[token string]];
  1743.         [token free];
  1744.         [stack push:node];
  1745.         return self;
  1746.         }
  1747.     [self _error:COWSERRORSETNOTVARIABLE
  1748.                 :[current_function string]:current_position:[token string]];
  1749.     [token free];
  1750.     return NULL;        
  1751.     }
  1752.  
  1753.  
  1754.  
  1755. -_doSet
  1756.     // continues processing a "set" token
  1757.     {
  1758.     id node=[stack topSymbol];
  1759.     if ([node state]==COWSSTARTSET)
  1760.         {
  1761.         [node setState:COWSDONESET];
  1762.         return self;
  1763.         }
  1764.     [self _error:COWSERRORSETTOOMANYVALUES
  1765.                 :[current_function string]:current_position:""];
  1766.     return NULL;        
  1767.     }
  1768.  
  1769.  
  1770. -_finishSet
  1771.     // finishes processing a "set" token
  1772.     {
  1773.     id node=[stack topSymbol];
  1774.     if ([node state]==COWSDONESET)
  1775.         {
  1776.         const char* string=[[node variable] string];
  1777.         id value=[stack pop];
  1778.  
  1779.         if ([current_dictionary isKey: (const void*) string])
  1780.             {
  1781.             [(COWSStringNode*)[current_dictionary 
  1782.                     valueForKey:(const void*)string] setString:
  1783.                     [value string]];
  1784.             [[stack pop] free];        // pops and frees set node
  1785.             [stack push:value];        // returns value
  1786.             return self;
  1787.             }
  1788.         else if ([global_dictionary isKey: (const void*) string])
  1789.             {
  1790.             [(COWSStringNode*)[global_dictionary 
  1791.                     valueForKey:(const void*)string] setString:
  1792.                     [value string]];
  1793.             [[stack pop] free];        // pops and frees set node
  1794.             [stack push:value];        // returns value
  1795.             return self;
  1796.             }
  1797.         else
  1798.             {
  1799.             [self _error:COWSERRORSETNOSUCHVARIABLE
  1800.                 :[current_function string]:current_position:string];
  1801.             [value free];
  1802.             return NULL;        
  1803.             }
  1804.         }
  1805.     [self _error:COWSERRORSETNOVALUE
  1806.                 :[current_function string]:current_position:""];
  1807.     return NULL;        
  1808.     }
  1809.  
  1810.  
  1811. -_startIf
  1812.     // begins processing "if" token
  1813.     {
  1814.     id node;
  1815.     node=[[COWSSymbolNode alloc] init];
  1816.     [node setState:COWSSTARTIF];
  1817.     [node setString:"if"];
  1818.     [stack push:node];
  1819.     return self;
  1820.     }
  1821.     
  1822.     
  1823.  
  1824. -_doIf
  1825.     // continues processing "if" token
  1826.     {
  1827.     id node=[stack topSymbol];
  1828.     int state=[node state];
  1829.     if (state==COWSSTARTIF)
  1830.         {
  1831.         id value=[stack pop];
  1832.         if (!strcmp([value string],"t"))
  1833.             {
  1834.             [node setState:COWSSTARTTHEN];
  1835.             [value free];
  1836.             return self;
  1837.             }
  1838.         else        // "f" or other
  1839.             {
  1840.             int x=current_position;
  1841.             [node setState:COWSSTARTELSE];
  1842.             [value free];
  1843.             [self _skip];
  1844.             if (x==current_position)    // couldn't skip over the then!
  1845.                 {
  1846.                 [self _error:COWSERRORIFNOTHENCLAUSE
  1847.                     :[current_function string]:current_position:""];
  1848.                 return NULL;        
  1849.                 } 
  1850.             return self;
  1851.             }
  1852.         }
  1853.     else if (state==COWSSTARTTHEN)
  1854.         {
  1855.         [node setState:COWSDONEIF];
  1856.         [self _skip];
  1857.         return self;
  1858.         }
  1859.     else if (state==COWSSTARTELSE)
  1860.         {
  1861.         [node setState:COWSDONEIF];
  1862.         return self;
  1863.         }
  1864.     else            // COWSDONEIF
  1865.         {
  1866.         [self _error:COWSERRORIFTOOMANYVALUES
  1867.                 :[current_function string]:current_position:""];
  1868.         return NULL;        
  1869.         }
  1870.     }
  1871.     
  1872.     
  1873. -_finishIf
  1874.     // completes processing "if" token
  1875.     {
  1876.     id node=[stack topSymbol];
  1877.     id value;
  1878.     int state=[node state];
  1879.     if (state==COWSSTARTIF||state==COWSSTARTTHEN)
  1880.         {
  1881.         [self _error:COWSERRORIFNOTENOUGHVALUES
  1882.                 :[current_function string]:current_position:""];
  1883.         return NULL;        
  1884.         }
  1885.     else if (state==COWSDONEIF)    // finished a value    
  1886.         {
  1887.         value=[stack pop];
  1888.         }
  1889.     else // state= COWSSTARTELSE; no value
  1890.         {
  1891.         value=[[COWSStringNode alloc] init];        // empty value to push
  1892.         }
  1893.         
  1894.     while(1) 
  1895.         {
  1896.         id top=[stack top];
  1897.         if ([top isMemberOf: [COWSSymbolNode class]])
  1898.             if (!strcmp([top string],"if"))
  1899.                 break;
  1900.         [[stack pop] free];        // pops and frees to if node
  1901.         }
  1902.     [[stack pop] free];            // pops if node
  1903.     [stack push:value];
  1904.     return self;
  1905.     }
  1906.     
  1907.  
  1908.  
  1909.  
  1910. - _startWhile
  1911.     // begins processing "while" token
  1912.     {
  1913.     id node;
  1914.     node=[[COWSSymbolNode alloc] init];
  1915.     [node setState:COWSSTARTWHILE];
  1916.     [node setString:"while"];
  1917.     [node setPos:current_position];
  1918.     [stack push:node];
  1919.     return self;
  1920.     }
  1921.     
  1922.     
  1923.     
  1924.     
  1925. -_doWhile
  1926.     // continues processing "while" token
  1927.     {
  1928.     id node=[stack topSymbol];
  1929.     int state=[node state];
  1930.     if (state==COWSSTARTWHILE)
  1931.         {
  1932.         id test=[stack pop];
  1933.         const char* teststring=[test string];
  1934.         if (!strcmp(teststring,"t"))
  1935.             {
  1936.             [node setState:COWSTRUEWHILE];
  1937.             }
  1938.         else        // false...
  1939.             {
  1940.             [node setState:COWSFALSEWHILE];
  1941.             [self _skip];
  1942.             }
  1943.         [stack push:test];    // placed back on stack in case need to return it
  1944.         return self;
  1945.         }
  1946.     else if (state==COWSTRUEWHILE)
  1947.         {
  1948.         [node setState:COWSDONEWHILE];
  1949.         return self;
  1950.         }
  1951.     else    // state==COWSDONEWHILE or COWSFALSEWHILE
  1952.         {
  1953.         [self _error:COWSERRORWHILETOOMANYVALUES
  1954.                 :[current_function string]:current_position:""];
  1955.         return NULL;        
  1956.         }
  1957.     }
  1958.     
  1959.     
  1960.     
  1961.     
  1962. -_finishWhile
  1963.     // finishes processing "while" token
  1964.     {
  1965.     id node=[stack topSymbol];
  1966.     int state=[node state];
  1967.     if (state==COWSTRUEWHILE||state==COWSDONEWHILE)
  1968.         {
  1969.         while(1) 
  1970.             {
  1971.             id top=[stack top];
  1972.             if ([top isMemberOf: [COWSSymbolNode class]])
  1973.                 if (!strcmp([top string],"while"))
  1974.                     break;
  1975.             [[stack pop] free];        // pops and frees to while node
  1976.             }
  1977.         current_position=[node pos];
  1978.         [node setState:COWSSTARTWHILE];
  1979.         return NULL;                // we don't want _doKeywords called again.
  1980.         }
  1981.     else if (state==COWSSTARTWHILE)
  1982.         {
  1983.         [self _error:COWSERRORWHILENOTENOUGHVALUES
  1984.                 :[current_function string]:current_position:""];
  1985.         return NULL;        
  1986.         }
  1987.     else                    // ==COWSFALSEWHILE
  1988.         {
  1989.         id return_val=[stack pop];
  1990.         while(1) 
  1991.             {
  1992.             id top=[stack top];
  1993.             if ([top isMemberOf: [COWSSymbolNode class]])
  1994.                 if (!strcmp([top string],"while"))
  1995.                     break;
  1996.             [[stack pop] free];        // pops and frees to while node
  1997.             }
  1998.         [[stack pop] free];            // pops and frees while node
  1999.         [stack push:return_val];
  2000.         return self;
  2001.         }
  2002.     }
  2003.     
  2004.  
  2005.  
  2006. - _startFor
  2007.     // begins processing "for" token
  2008.     {
  2009.     const char* string;
  2010.     id token=[[COWSStringNode alloc] init];
  2011.     id node;
  2012.     current_position=[self _tokenize:[current_function string]:
  2013.         current_position:token];
  2014.     string=[token string];
  2015.     if (asymbol(string))
  2016.         {
  2017.         node=[[COWSSymbolNode alloc] init];
  2018.         [node setState:COWSSTARTFOR];
  2019.         [node setString:"for"];
  2020.         [[node variable] setString:[token string]];
  2021.         [token free];
  2022.         [stack push:node];
  2023.         return self;
  2024.         }
  2025.     [self _error:COWSERRORFORNOTAVARIABLE
  2026.                 :[current_function string]:current_position:[token string]];
  2027.     [token free];
  2028.     return NULL;        
  2029.     }
  2030.     
  2031.     
  2032.     
  2033. -_doFor
  2034.     // continues processing "for" token
  2035.     {
  2036.     id node=[stack topSymbol];
  2037.     int state=[node state];
  2038.     if (state==COWSSTARTFOR)
  2039.         {
  2040.         id val=[stack pop];
  2041.         const char* string=[val string];
  2042.         if (anumber(string))
  2043.             {
  2044.             [node setStart:atof(string)];
  2045.             [node setState:COWSENDFOR];
  2046.             [val free];
  2047.             return self;
  2048.             }
  2049.         else
  2050.             {
  2051.             [self _error:COWSERRORFORSTARTNOTNUMBER
  2052.                 :[current_function string]:current_position:[val string]];
  2053.             [val free];
  2054.             return NULL;
  2055.             }    
  2056.         }
  2057.     else if (state==COWSENDFOR)
  2058.         {
  2059.         id val=[stack pop];
  2060.         const char* string=[val string];
  2061.         if (anumber(string))
  2062.             {
  2063.             [node setEnd:atof(string)];
  2064.             [node setState:COWSSTEPFOR];
  2065.             [val free];
  2066.             return self;
  2067.             }
  2068.         else
  2069.             {
  2070.             [self _error:COWSERRORFORSTOPNOTNUMBER
  2071.                 :[current_function string]:current_position:[val string]];
  2072.             [val free];
  2073.             return NULL;
  2074.             }    
  2075.         }
  2076.     else if (state==COWSSTEPFOR)
  2077.         {
  2078.         id val=[stack pop];
  2079.         const char* string=[val string];
  2080.         if (anumber(string))
  2081.             {
  2082.             BOOL test;
  2083.             id var=[node variable];
  2084.             const char* var_str=[var string];
  2085.             [node setStep:atof(string)];
  2086.             [node setState:COWSDOFOR];
  2087.             [val free];
  2088.             if ([current_dictionary isKey: (const void*) var_str])
  2089.                 {
  2090.                 char start_val[COWSLARGENUMBER];
  2091.                 sprintf(start_val,"%f",[node start]);
  2092.                 [(COWSStringNode*)[current_dictionary 
  2093.                         valueForKey:(const void*)var_str] setString:
  2094.                         start_val];
  2095.                 [node setPos:current_position];
  2096.                 }
  2097.             else if ([global_dictionary isKey: (const void*) var_str])
  2098.                 {
  2099.                 char start_val[COWSLARGENUMBER];
  2100.                 sprintf(start_val,"%f",[node start]);
  2101.                 [(COWSStringNode*)[global_dictionary 
  2102.                         valueForKey:(const void*)var_str] setString:
  2103.                         start_val];
  2104.                 [node setPos:current_position];
  2105.                 }
  2106.             else
  2107.                 {
  2108.                 [self _error:COWSERRORFORNOSUCHVARIABLE
  2109.                     :[current_function string]:current_position:[val string]];
  2110.                 return NULL;        
  2111.                 }
  2112.  
  2113.             // now test limits
  2114.             
  2115.             if ([node step]>=0)
  2116.                 {
  2117.                 if ([node start] > [node end]) 
  2118.                     {
  2119.                     test=YES;
  2120.                     }
  2121.                 else test=NO;
  2122.                 }
  2123.             else
  2124.                 {
  2125.                 if ([node start] < [node end])
  2126.                     {
  2127.                     test=YES;
  2128.                     }
  2129.                 else test=NO;
  2130.                 }
  2131.             // and act on test by skipping ahead to finish
  2132.             if (test)
  2133.                 {
  2134.                 [node setState:COWSFALSEFOR];
  2135.                 [self _skip];
  2136.                 }
  2137.             return self;
  2138.             }
  2139.         else
  2140.             {
  2141.             [self _error:COWSERRORFORSTEPNOTNUMBER
  2142.                 :[current_function string]:current_position:[val string]];
  2143.             return NULL;
  2144.             }    
  2145.         }
  2146.     else if (state==COWSDOFOR)
  2147.         {
  2148.         [node setState:COWSTESTFOR];
  2149.         return self;
  2150.         }
  2151.     else if (state==COWSCONTINUEFOR)
  2152.         {
  2153.         [node setState:COWSTESTFOR];
  2154.         return self;
  2155.         }
  2156.     else        // state==COWSFALSEFOR||state==COWSTESTFOR
  2157.         {
  2158.         [self _error:COWSERRORFORTOOMANYVALUES
  2159.                 :[current_function string]:current_position:""];
  2160.         return NULL;
  2161.         }
  2162.     }
  2163.     
  2164.  
  2165.  
  2166. -_finishFor
  2167.     // finishes processing "for" token
  2168.     {
  2169.     id node=[stack topSymbol];
  2170.     int state=[node state];
  2171. /*    if (state==COWSTRUEFOR)
  2172.         {
  2173.         [[stack pop] free];        // removes for value
  2174.         current_position=[node pos];
  2175.         [node setState:COWSCONTINUEFOR];
  2176.         return NULL;                // we don't want _doKeywords running again.
  2177.         }
  2178.     else*/ if (state==COWSFALSEFOR)
  2179.         {
  2180.         id return_val=[stack pop];
  2181.         [[stack pop] free];                // removes for node
  2182.         [stack push:return_val];
  2183.         return self;
  2184.         }
  2185.     else if (state==COWSTESTFOR)
  2186.         {
  2187.         char new_val[COWSLARGENUMBER];
  2188.         BOOL test;
  2189.         float nv;
  2190.         id variable;
  2191.         id var=[node variable];
  2192.         const char* var_str=[var string];
  2193.         
  2194.         [node setState:COWSCONTINUEFOR];
  2195.         
  2196.         // first, find variable
  2197.         
  2198.         if ([current_dictionary isKey: (const void*) var_str])
  2199.             {
  2200.             variable=(COWSStringNode*)[current_dictionary 
  2201.                     valueForKey:(const void*)var_str];
  2202.             }
  2203.         else if ([global_dictionary isKey: (const void*) var_str])
  2204.             {
  2205.             variable=(COWSStringNode*)[global_dictionary 
  2206.                     valueForKey:(const void*)var_str];
  2207.             }
  2208.         else
  2209.             {
  2210.             [self _error:COWSERRORFORNOSUCHVARIABLE
  2211.                 :[current_function string]:current_position:var_str];
  2212.             return NULL;        
  2213.             }
  2214.         
  2215.         // then, increment variable
  2216.         sprintf(new_val,"%f",atof([variable string])+[node step]);
  2217.         [variable setString:new_val];
  2218.         nv=atof(new_val);
  2219.             
  2220.         // now test limits
  2221.         
  2222.         if ([node step]>=0)
  2223.             {
  2224.             if (nv > [node end]) 
  2225.                 {
  2226.                 test=YES;
  2227.                 }
  2228.             else test=NO;
  2229.             }
  2230.         else
  2231.             {
  2232.             if (nv < [node end])
  2233.                 {
  2234.                 test=YES;
  2235.                 }
  2236.             else test=NO;
  2237.             }
  2238.             
  2239.         // and act on test by killing for or continuing
  2240.         if (test)
  2241.             {
  2242.             id return_val=[stack pop];
  2243.             [[stack pop] free];                // removes for node
  2244.             [stack push:return_val];
  2245.             return self;
  2246.             }
  2247.         else 
  2248.             {
  2249.             [[stack pop] free];        // removes for value
  2250.             current_position=[node pos];
  2251.             return NULL;        // we don't want _doKeywords running again.
  2252.             }
  2253.         }
  2254.     else    // state== anything else
  2255.         {
  2256.         [self _error:COWSERRORFORNOTENOUGHVALUES
  2257.                 :[current_function string]:current_position:""];
  2258.         return NULL;
  2259.         }
  2260.     }
  2261.  
  2262.  
  2263.  
  2264. - _makeTruth:(COWSStringNode*) string
  2265.     // strips a truth of any quotes
  2266.     
  2267.     {
  2268.     char* str=newstr([string string]);
  2269.     if (str[0]=='\"')
  2270.         {
  2271.         str[0]=str[1];
  2272.         str[1]='\0';
  2273.         }
  2274.     [string setString:str];
  2275.     free(str);
  2276.     return self;
  2277.     }
  2278.     
  2279.     
  2280.     
  2281.     
  2282.             
  2283. - _makeNumber:(COWSStringNode*) string
  2284.     // prepares a number.  If the number's bad, it may turn out zero
  2285.     // or something different than the user expected
  2286.     
  2287.     {
  2288.     char str[256];                    // a number big enough to hold any float
  2289.     float x=atof([string string]);
  2290.     sprintf(str,"%f",x);
  2291.     [string setString:str];
  2292.     return self;
  2293.     }
  2294.             
  2295.             
  2296.             
  2297.             
  2298. - _strip:(COWSStringNode*) string
  2299.     // strips a string of its "s
  2300.     
  2301.     {
  2302.     const char* str=[string string];
  2303.     char* new_str=newstr(&str[1]);            // gets rid of first "
  2304.     int x=strlen(new_str);
  2305.     if (x>0) new_str[x-1]='\0';                // gets rid of second "
  2306.     [string setString:new_str];
  2307.     free(new_str);
  2308.     return self;
  2309.     }
  2310.     
  2311.     
  2312.     
  2313.     
  2314. - (int) _skip        
  2315.     // skips one value, if there is one    
  2316.     // returns new position if successful, error if not.
  2317.     
  2318.     {
  2319.     int result=[self _item:[current_function string]:current_position];
  2320.     if (result>=0)        // not an error
  2321.         {
  2322.         current_position=result;
  2323.         }
  2324.     return result;
  2325.     }
  2326.     
  2327.     
  2328.     
  2329. - (int) _error:(int) this_error:(const char*) this_function:
  2330.     (int) this_position: (const char*) this_string
  2331.     
  2332.     // performs error-reporting
  2333.     // this may entail sending an error message to a delegate
  2334.     // returns the error
  2335.     
  2336.     {
  2337.     // need to stop also...
  2338.     
  2339.     printf("\n================ERROR================\n");
  2340.     switch (this_error)
  2341.         {
  2342.         case COWSERRORNOSUCHFUNCTION : 
  2343.             printf ("No Such Function\n"); break;
  2344.         case COWSERRORNOTENOUGHARGUMENTS : 
  2345.             printf ("Not Enough Arguments\n"); break;
  2346.         case COWSERRORTOOMANYARGUMENTS : 
  2347.             printf ("Too Many Arguments\n"); break;
  2348.         case COWSLIBRARYFUNCTIONERROR : 
  2349.             printf ("Library Function Error\n"); break;
  2350.         case COWSERRORNOSUCHVARIABLE : 
  2351.             printf ("No Such Variable\n"); break;
  2352.         case COWSERRORNOMORETOKENS : 
  2353.             printf ("No More Tokens\n"); break;
  2354.         case COWSERRORNOFUNCTIONNAME : 
  2355.             printf ("No Function Name\n"); break;
  2356.         case COWSERRORSETNOTVARIABLE : 
  2357.             printf ("Set: Not a Variable\n"); break;
  2358.         case COWSERRORSETTOOMANYVALUES : 
  2359.             printf ("Set: Too Many Values\n"); break;
  2360.         case COWSERRORSETNOVALUE : 
  2361.             printf ("Set: No Value to Set\n"); break;
  2362.         case COWSERRORSETNOSUCHVARIABLE : 
  2363.             printf ("Set: No Such Variable\n"); break;
  2364.         case COWSERRORIFNOTHENCLAUSE : 
  2365.             printf ("If: No Then Clause\n"); break;
  2366.         case COWSERRORIFTOOMANYVALUES : 
  2367.             printf ("If: Too Many Values\n"); break;
  2368.         case COWSERRORIFNOTENOUGHVALUES : 
  2369.             printf ("If: Not Enough Values\n"); break;
  2370.         case COWSERRORWHILETOOMANYVALUES : 
  2371.             printf ("While: Too Many Values\n"); break;
  2372.         case COWSERRORWHILENOTENOUGHVALUES : 
  2373.             printf ("While: Not Enough Values\n"); break;
  2374.         case COWSERRORFORNOTAVARIABLE : 
  2375.             printf ("For: Not a Variable\n"); break;
  2376.         case COWSERRORFORSTARTNOTNUMBER : 
  2377.             printf ("For: Start Value Not a Number\n"); break;
  2378.         case COWSERRORFORSTOPNOTNUMBER : 
  2379.             printf ("For: Stop Value Not a Number\n"); break;
  2380.         case COWSERRORFORSTEPNOTNUMBER : 
  2381.             printf ("For: Step Value Noe a Number\n"); break;
  2382.         case COWSERRORFORNOSUCHVARIABLE : 
  2383.             printf ("For: No Such Variable\n"); break;
  2384.         case COWSERRORFORTOOMANYVALUES : 
  2385.             printf ("For: Too Many Values\n"); break;
  2386.         case COWSERRORFORNOTENOUGHVALUES : 
  2387.             printf ("For: Not Enough Values\n"); break;
  2388.         case COWSINTERNALERROR : 
  2389.             printf ("Interpreter Internal Error\n"); break;
  2390.         default : 
  2391.             printf ("Unknown Error\n"); break;
  2392.         }
  2393.     if (strlen(this_string) && this_error!=COWSLIBRARYFUNCTIONERROR)
  2394.         {
  2395.         printf ("Offending Symbol:  %s\n",this_string);
  2396.         }
  2397.     if (this_error==COWSLIBRARYFUNCTIONERROR)
  2398.         {
  2399.         printf ("Message:  %s\n",this_string);
  2400.         }
  2401.     printf ("In Function: %s\n", this_function);
  2402.     printf ("At Position: %d\n",this_position);
  2403.     printf ("=====================================\n\n");
  2404.      
  2405.     if (delegate!=NULL&&[delegate conformsTo:@protocol (InterpreterToAppDelegate)])
  2406.             [delegate errorInterpreting:this_error:this_function:
  2407.         this_position:this_string:self];
  2408.     
  2409.     [self stopInterpreting];
  2410.         
  2411.     return this_error;
  2412.     }
  2413.         
  2414.         
  2415.         
  2416.             
  2417. @end