Advertisement
ZoriaRPG

ZBasic_Outline.zs

Jun 29th, 2018
280
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 34.19 KB | None | 0 0
  1.  
  2. /*
  3.  
  4. OUTLINE and PREMISE
  5.  
  6. Z.BASIC - An interpreter that runs inside a quest that
  7. facilitates a shell window that allows the player to
  8. modify or write ad-hoc scripts while the game is running.
  9.  
  10. v.0.4.5
  11.  
  12. If function pointers were working, that'd be far simpler,
  13. as I could enqueue instructions into main() in a quest script
  14. In theory though, this would be a useful learning tool, as
  15. the user could encode very small scripts live, and have the
  16. quest execute them.
  17.  
  18. The syntax might be simplified, though.
  19.  
  20. It's the same premise as my TBA parser/interpreter, but with a
  21. different scope.
  22.  
  23. It'd be a for loop.
  24.  
  25. When the user adds instructions, and closes the interpreter,
  26. the instruction loop would be counted that'd be the loop operator.
  27.  
  28. Then the parser string matches the instruction and puts a value
  29. onto a stack. Once done, a switch block would call instructions
  30. based on the case values read from the stack
  31.  
  32. The switch block for those instructions would be huge:
  33. One case per instruction in the engine, hence why *f() would be better.
  34.  
  35. It'd end up as some form of BASIC or Pascal, but the interface
  36. wouldn't allow declaring vars, only using extant, predefined
  37. vars.
  38.  
  39. Probably G0 through G1023, plus a set f 32 for each other
  40. datatype. We'd probably need to count how many values are
  41. set in the script, when the interpreter scans it, then store
  42. each value into an array index.
  43.  
  44. The tricky part, is storing the 'current' vars passed to
  45. instructions
  46.  
  47. Probably would just be the array index of each, plus a set of
  48. temp vars in the parser to use for literals
  49.  
  50. It would be fun to construct it, but it would run at a fraction of the speed of ZScript
  51.  
  52. The parser would need to be able to store the values of
  53. literals to an array, and track when they are used.
  54.  
  55. We'd need to keep a count of the last var used in the switch
  56. block when processing instructions, and for each param,
  57. we increment the count after passing the value:
  58.  
  59. e.g.
  60.  
  61. */
  62.  
  63.  
  64. const int TOP = 1024;
  65.  
  66. int STACK[TOP];
  67. int popmem; //colds the value popped from any stack.
  68.  
  69. const int MAX_STACK_REG = TOP - 1;
  70. //The array pointer to the stack in use.
  71. int curstack;
  72. void CurStack(int a) { curstack = a; }
  73. int CurStack() { return curstack; }
  74.  
  75. int SP; //0 is NULL
  76. int RIP; //0 is NULL, register pointer
  77. int CV; //current global var
  78. int CSR; //current script ram index
  79. int CPV; //current param value
  80. int CVT; //cur vaqr type
  81. int CVV; //current var value
  82. int CVL; //current vartype length
  83.  
  84. int EXP1; //Expr Accumulator 1
  85. int EXP2; //Expr Accumulator 1
  86. int INDX1; //misc 1
  87.  
  88. int ZBASIc[256]; //used for returning arrays.
  89.  
  90. ffc script stack
  91. {
  92.     void run() {}
  93.     int top() { return TOP; }
  94.     int top(int a) { return SizeOfArray(a);; }
  95.     void change(int b) { curstack = b; SP = b[TOP]; }
  96.     void setCurStack(int b) { curstack = b; SP = b[TOP]; }
  97.     int maxSize()
  98.     {
  99.         c = curstack;
  100.         return ( SizeOfArray(c) - 1 );
  101.     }
  102.     void pop()
  103.     {
  104.         int c = curstack;
  105.         if ( c < 1 )
  106.         {
  107.             TraceNL(); TraceS"Invalid stack called by stack.pop: "; Trace(c);
  108.             return;
  109.         }
  110.         if ( isempty(c) )
  111.         {
  112.             TraceNL(); TraceS"Cannot pop from an empty stack. The empty stack was: "; Trace(c);
  113.             return;
  114.         }
  115.         popmem = c[TOP];
  116.         SP = --c[TOP];
  117.         //--c[TOP];
  118.         //SP = c[TOP];
  119.     }
  120.     void pop(int indx)
  121.     {
  122.         //RP = indx;
  123.         int c = curstack;
  124.         if ( c < 1 )
  125.         {
  126.             TraceNL(); TraceS"Invalid stack called by stack.pop: "; Trace(c);
  127.             return;
  128.         }
  129.         if ( isempty(c) )
  130.         {
  131.             TraceNL(); TraceS"Cannot pop from an empty stack. The empty stack was: "; Trace(c);
  132.             return;
  133.         }
  134.         indx = c[TOP];
  135.         SP = --c[TOP];
  136.         RIP = indx; //so, getSArg(RIP);
  137.         //--c[TOP];
  138.         //SP = c[TOP];
  139.     }
  140.     void push(int val)
  141.     {
  142.         int c = curstack;
  143.         if ( c < 1 )
  144.         {
  145.             TraceNL(); TraceS"Invalid stack called by stack.push: "; Trace(c);
  146.             return;
  147.         }
  148.         if ( isfull(c) )
  149.         {
  150.             TraceNL(); TraceS"Cannot push to a full stack. The full stack was: "; Trace(c);
  151.             return;
  152.         }
  153.         c[TOP] = val;
  154.         SP = ++c[TOP];
  155.         //++c[TOP];
  156.         //SP = c[TOP];
  157.         //DO WE HAVE = -- IN zsCRIPT YET (ASSIGN (DECREMENT FIRST ))??
  158.     }
  159.     bool isempty(int a) { return (!a[TOP]); }
  160.     bool isfull(int a) { return ( a[TOP] >= MAX_STACK_REG ); }
  161.    
  162.     void init(int a) { for ( int q = 0; q < TOP; ++q ) { a[q] = 0; }
  163.    
  164.        
  165. }
  166.  
  167. int VARTYPES[TOP]; //0 is null. First valid memory index == 1
  168.  
  169. int count = 0; //the current index for storing or reading back variables when executing stack calls
  170. int G[256];
  171. int I[256];
  172. ffc F[256];
  173. npc N[256];
  174. eweapon E[256];
  175. lweapon L[256];
  176. item IT[256];
  177. itemdata ID[256];
  178. npcdata ND[256];
  179. spritedata WD[256];
  180. combodata CD[256];
  181. shopdata SD[256];
  182. mapdata MD[256];
  183.  
  184. int WORD[64]; //HOLDS THHE CURRENT COMMAND
  185. int PARAM[13]; //11 + sign + dot
  186. int VARIABLE[7]; //type_id + 4 digits
  187.  
  188. int PARAMS[256];
  189.  
  190. int STACK[256]; //instruction IDs
  191.  
  192. int OPERAND[1024];
  193. int OPERATOR[1024];
  194.  
  195. //maths
  196. int operator_type; //current operator
  197.  
  198.  
  199. const int TYPE_NULL = 0;
  200. const int TYPE_GLOBAL = 1;
  201. const int TYPE_INT = 2;
  202. const int TYPE_NPC = 3;
  203. const int TYPE_LWEAPON = 4;
  204. const int TYPE_EWEAPON = 5;
  205. const int TYPE_FFC = 6;
  206. const int TYPE_ITEM = 7;
  207. const int TYPE_ITEMDATA = 8;
  208. const int TYPE_NPCDATA = 9;
  209. const int TYPE_COMBODATA = 10;
  210. const int TYPE_SPRITEDATA = 11;
  211. const int TYPE_SHOPDATA = 12;
  212. const int TYPE_MAPDATA = 13;
  213.  
  214. void RunInstruction()
  215. {
  216.     switch(STACK[SP])
  217.     {
  218.         case FASTTILE:
  219.         {
  220.             Screen->FastTile(GetArg(), GetArg(), GetArg(), GetArg(), GetArg(), GetArg());
  221.             break;
  222.         }
  223.     }
  224. }
  225.  
  226. //Advances a line in the instruction list.
  227. // CR(list[q], 64)
  228. // q = CR(q,64);
  229. int CR(int pos, int linewidth)
  230. {
  231.     return pos - pos%linewidth + linewidth;
  232.  
  233. int GetArg()
  234. {
  235.     int indx = count;
  236.     CVT = VARTYPES[count];
  237.     ++count;
  238.     int rv;
  239.     switch(CVT) //which array to use
  240.     {
  241.         case TYPE_GLOBAL;
  242.         {
  243.             rv = G[indx]; break;
  244.         }
  245.         case TYPE_INT:
  246.         {
  247.             rv = I[indx]; break;
  248.         }
  249.         case TYPE_NPC:
  250.         {
  251.             rv = N[indx]; break;
  252.         }
  253.         case TYPE_LWEAPON:
  254.         {
  255.             rv = L[indx]; break;
  256.         }
  257.         case TYPE_EWEAPON:
  258.         {
  259.             rv = E[indx]; break;
  260.         }
  261.         case TYPE_FFC:
  262.         {
  263.             rv = F[indx]; break;
  264.         }
  265.         case TYPE_ITEM:
  266.         {
  267.             rv = IT[indx]; break;
  268.         }
  269.         case TYPE_ITEMDATA:
  270.         {
  271.             rv = ID[indx]; break;
  272.         }
  273.         case TYPE_NPCDATA:
  274.         {
  275.             rv = ND[indx]; break;
  276.         }
  277.         case TYPE_COMBODATA:
  278.         {
  279.             rv = CD[indx]; break;
  280.         }
  281.         case TYPE_SPRITEDATA:
  282.         {
  283.             rv = WD[indx]; break;
  284.         }
  285.         case TYPE_SHOPDATA:
  286.         {
  287.             rv = SD[indx]; break;
  288.         }
  289.         case TYPE_MAPDATA:
  290.         {
  291.             rv = MD[indx]; break;
  292.         }
  293.         default:
  294.         {
  295.                 TraceS("Invalid datatype supplied to GetArg()");
  296.                 break;
  297.         }
  298.     }
  299.     return rv;
  300. }
  301.  
  302. //sets the arg value to any type of array
  303. void SetArg(int val)
  304. {
  305.     int indx = count;
  306.     CVT = VARTYPES[count];
  307.     ++count;
  308.     int rv;
  309.     switch(CVT) //which array to use
  310.     {
  311.         case TYPE_GLOBAL;
  312.         {
  313.             G[indx] = Untype(val) = Untype(val); break;
  314.         }
  315.         case TYPE_INT:
  316.         {
  317.             I[indx] = Untype(val); break;
  318.         }
  319.         case TYPE_NPC:
  320.         {
  321.             N[indx] = Untype(val); break;
  322.         }
  323.         case TYPE_LWEAPON:
  324.         {
  325.             L[indx] = Untype(val); break;
  326.         }
  327.         case TYPE_EWEAPON:
  328.         {
  329.             E[indx] = Untype(val); break;
  330.         }
  331.         case TYPE_FFC:
  332.         {
  333.             F[indx] = Untype(val); break;
  334.         }
  335.         case TYPE_ITEM:
  336.         {
  337.             IT[indx] = Untype(val); break;
  338.         }
  339.         case TYPE_ITEMDATA:
  340.         {
  341.             ID[indx] = Untype(val); break;
  342.         }
  343.         case TYPE_NPCDATA:
  344.         {
  345.             ND[indx] = Untype(val); break;
  346.         }
  347.         case TYPE_COMBODATA:
  348.         {
  349.             CD[indx] = Untype(val); break;
  350.         }
  351.         case TYPE_SPRITEDATA:
  352.         {
  353.             WD[indx] = Untype(val); break;
  354.         }
  355.         case TYPE_SHOPDATA:
  356.         {
  357.             SD[indx] = Untype(val); break;
  358.         }
  359.         case TYPE_MAPDATA:
  360.         {
  361.             MD[indx] = Untype(val); break;
  362.         }
  363.         default:
  364.         {
  365.                 TraceS("Invalid datatype supplied to GetArg()");
  366.                 break;
  367.         }
  368.     }
  369. }
  370.  
  371.  
  372. //NEWER functions to extract a var value from a token.
  373. //gets the array ID (type) and index ID of the array
  374.  
  375. int _GetVar(int token, int pos) if ( IdentifyVar(token,0)) return GetVarValue(); return 0; }
  376.  
  377. int IdentifyVar(int w, int pos)
  378. {
  379.    
  380.        
  381.     int v[5]; //varid[3]; 1024
  382.     int type[3]; //type 2
  383.     int len = strlen(w)-1;
  384.     if ( len > 7 ) return false;
  385.     int temp = CVL;
  386.     int vartype;
  387.     //copy only the type to this array
  388.     for ( ; temp <= len; ++temp )
  389.     {
  390.         if ( IsNumber(w[temp]) )
  391.         {
  392.             v[temp] = w[temp];
  393.             continue;
  394.         }
  395.         if ( IsAlpha(w[temp]) )
  396.         {
  397.             v[temp] = w[temp];
  398.             continue;
  399.         }
  400.     }
  401.     if ( strcmp(v, "G") ) vartype = TYPE_GLOBAL;
  402.     else if ( strcmp(v, "I") ) vartype =  TYPE_INT;
  403.     else if ( strcmp(v, "N") ) vartype =  TYPE_NPC;
  404.     else if ( strcmp(v, "L") ) vartype =  TYPE_LWEAPON;
  405.     else if ( strcmp(v, "E") ) vartype =  TYPE_EWEAPON;
  406.     else if ( strcmp(v, "F") ) vartype =  TYPE_FFC;
  407.     else if ( strcmp(v, "IT") ) vartype =  TYPE_ITEM;
  408.     else if ( strcmp(v, "ID") ) vartype =  TYPE_ITEMDATA;
  409.     else if ( strcmp(v, "ND") ) vartype =  TYPE_NPCDATA;
  410.     else if ( strcmp(v, "CD") ) vartype =  TYPE_COMBODATA;
  411.     else if ( strcmp(v, "WD") ) vartype =  TYPE_SPRITEDATA;
  412.     else if ( strcmp(v, "SD") ) vartype =  TYPE_SHOPDATA;
  413.     else if ( strcmp(v, "MD") ) vartype =  TYPE_MAPDATA;
  414.     else { vartype = TYPE_WTF; TraceNL(); TracS("Illegal vartype found by IdentifyVar()"); return false;}
  415.    
  416.     CVL = 0; //clear
  417.    
  418.     int id = itoa(v);
  419.     ZBASIC[0] = vartype; ZBASIC[1] = id;
  420.     return true;
  421. }  
  422.  
  423. int GetVarValue();
  424. {   int type = ZBASIC[0];
  425.     int indx = ZBASIC[1];
  426.     int rv;
  427.     switch(type) //which array to use
  428.     {
  429.         case TYPE_GLOBAL;
  430.         {
  431.             rv = G[indx]; break;
  432.         }
  433.         case TYPE_INT:
  434.         {
  435.             rv = I[indx]; break;
  436.         }
  437.         case TYPE_NPC:
  438.         {
  439.             rv = N[indx]; break;
  440.         }
  441.         case TYPE_LWEAPON:
  442.         {
  443.             rv = L[indx]; break;
  444.         }
  445.         case TYPE_EWEAPON:
  446.         {
  447.             rv = E[indx]; break;
  448.         }
  449.         case TYPE_FFC:
  450.         {
  451.             rv = F[indx]; break;
  452.         }
  453.         case TYPE_ITEM:
  454.         {
  455.             rv = IT[indx]; break;
  456.         }
  457.         case TYPE_ITEMDATA:
  458.         {
  459.             rv = ID[indx]; break;
  460.         }
  461.         case TYPE_NPCDATA:
  462.         {
  463.             rv = ND[indx]; break;
  464.         }
  465.         case TYPE_COMBODATA:
  466.         {
  467.             rv = CD[indx]; break;
  468.         }
  469.         case TYPE_SPRITEDATA:
  470.         {
  471.             rv = WD[indx]; break;
  472.         }
  473.         case TYPE_SHOPDATA:
  474.         {
  475.             rv = SD[indx]; break;
  476.         }
  477.         default:
  478.         {
  479.             rv = 0;
  480.             TraceNL();
  481.             TraceS("GetVarValue() encountered an invalid var array type");
  482.             TraceNL();
  483.             break
  484.         }
  485.        
  486.        
  487.     }
  488.     ZBASIC[0] = 0;
  489.     ZBASIC[1] = 0;
  490.     return rv;
  491.    
  492. }
  493.  
  494. //this stores the ID when lexing. Parsing uses the literal stored to the script RAM.
  495. //We could store this directly on the stack, but I would rather have 100 scripts with 1024 max
  496. //instructions each, that we can copy to the stack when they run.
  497.  
  498. //but then, we would need a mechanism to store al of the values used by scripts when they complete execution.
  499. //Grr... That'd be faster, but it would eat quite a lot of array space.
  500.  
  501. //Otherwise, we interpret the scripts each time before execution. No JIT here. :P
  502. int GetInstruction(int word)
  503. {
  504.     /* Would it be faster to do an incremental pattern match?
  505.     //Probably not?
  506.     int wordsize = strlen(word);
  507.     int words[]=
  508.     {
  509.         list each command one at time
  510.         each on its own line
  511.         shortest to longest.
  512.        
  513.         pattern match begins at a specified word size?
  514.        
  515.     }
  516.     */
  517.    
  518.     if ( strcmp(word, "FastTile" ) return FASTTILE;
  519. }
  520.  
  521. //determines the type of array to use
  522. int ExtractVarType(int w)
  523. {
  524.     /*
  525.     int types[]=
  526.     "
  527.         G //global
  528.         I //int
  529.         N //npc
  530.         L //lweapon
  531.         E //eweapon
  532.         It //item
  533.         F //ffc
  534.         ID //itemdata
  535.         ND //npcdata
  536.         CD //combodata
  537.         WD //spritedata
  538.         SD //shopdata
  539.         MD //mapdata
  540.     ";
  541.     */
  542.        
  543.     int v[3]; //vartype[3];
  544.     int len = strlen(w)-1;
  545.     int temp;
  546.     //copy only the type to this array
  547.     for ( ; temp < 2; ++temp )
  548.     {
  549.         if ( !IsNumber(w[temp]) )
  550.         {
  551.             v[temp] = w[temp];
  552.         }
  553.     }
  554.    
  555.     CVL = temp; //set the length of this var,
  556.     //we'll need it for speeding uo extracting its
  557.     //literal value
  558.    
  559.     if ( strcmp(v, "G") ) return TYPE_GLOBAL;
  560.     if ( strcmp(v, "I") ) return TYPE_INT;
  561.     if ( strcmp(v, "N") ) return TYPE_NPC;
  562.     if ( strcmp(v, "L") ) return TYPE_LWEAPON;
  563.     if ( strcmp(v, "E") ) return TYPE_EWEAPON;
  564.     if ( strcmp(v, "F") ) return TYPE_FFC;
  565.     if ( strcmp(v, "IT") ) return TYPE_ITEM;
  566.     if ( strcmp(v, "ID") ) return TYPE_ITEMDATA;
  567.     if ( strcmp(v, "ND") ) return TYPE_NPCDATA;
  568.     if ( strcmp(v, "CD") ) return TYPE_COMBODATA;
  569.     if ( strcmp(v, "WD") ) return TYPE_SPRITEDATA;
  570.     if ( strcmp(v, "SD") ) return TYPE_SHOPDATA;
  571.     if ( strcmp(v, "MD") ) return TYPE_MAPDATA;
  572.    
  573.     I //item
  574.         F //ffc
  575.         ID //itemdata
  576.         ND //npcdata
  577.         CD //combodata
  578.         WD //spritedata
  579.         SD //shopdata
  580.    
  581. }  
  582.        
  583.  
  584.  
  585. //gets the index ID of the array
  586. int ExtractVarID(int w)
  587. {
  588.    
  589.        
  590.     int v[5]; //vartype[3];
  591.     int len = strlen(w)-1;
  592.     int temp = CVL;
  593.     //copy only the type to this array
  594.     for ( ; temp <= len; ++temp )
  595.     {
  596.         if ( IsNumber(w[temp]) )
  597.         {
  598.             v[temp] = w[temp];
  599.         }
  600.     }
  601.    
  602.     CVL = 0; //clear
  603.    
  604.     int id = itoa(v);
  605.     return id;
  606. }  
  607.  
  608. //determines the type of array to use
  609. int ExtractVarType(int w)
  610. {
  611.     /*
  612.     int types[]=
  613.     "
  614.         G //global
  615.         I //int
  616.         N //npc
  617.         L //lweapon
  618.         E //eweapon
  619.         It //item
  620.         F //ffc
  621.         ID //itemdata
  622.         ND //npcdata
  623.         CD //combodata
  624.         WD //spritedata
  625.         SD //shopdata
  626.         MD //mapdata
  627.     ";
  628.     */
  629.        
  630.     int v[3]; //vartype[3];
  631.     int len = strlen(w)-1;
  632.     int temp;
  633.     //copy only the type to this array
  634.     for ( ; temp < 2; ++temp )
  635.     {
  636.         if ( !IsNumber(w[temp]) )
  637.         {
  638.             v[temp] = w[temp];
  639.         }
  640.     }
  641.    
  642.     CVL = temp; //set the length of this var,
  643.     //we'll need it for speeding uo extracting its
  644.     //literal value
  645.    
  646.     if ( strcmp(v, "G") ) return TYPE_GLOBAL;
  647.     if ( strcmp(v, "I") ) return TYPE_INT;
  648.     if ( strcmp(v, "N") ) return TYPE_NPC;
  649.     if ( strcmp(v, "L") ) return TYPE_LWEAPON;
  650.     if ( strcmp(v, "E") ) return TYPE_EWEAPON;
  651.     if ( strcmp(v, "F") ) return TYPE_FFC;
  652.     if ( strcmp(v, "IT") ) return TYPE_ITEM;
  653.     if ( strcmp(v, "ID") ) return TYPE_ITEMDATA;
  654.     if ( strcmp(v, "ND") ) return TYPE_NPCDATA;
  655.     if ( strcmp(v, "CD") ) return TYPE_COMBODATA;
  656.     if ( strcmp(v, "WD") ) return TYPE_SPRITEDATA;
  657.     if ( strcmp(v, "SD") ) return TYPE_SHOPDATA;
  658.     if ( strcmp(v, "MD") ) return TYPE_MAPDATA;
  659.    
  660.     I //item
  661.         F //ffc
  662.         ID //itemdata
  663.         ND //npcdata
  664.         CD //combodata
  665.         WD //spritedata
  666.         SD //shopdata
  667.    
  668. }  
  669.        
  670.  
  671. int GetVarValue(int type, int indx);
  672. {
  673.     int rv;
  674.     switch(type) //which array to use
  675.     {
  676.         case TYPE_GLOBAL;
  677.         {
  678.             rv = G[indx]; break;
  679.         }
  680.         case TYPE_INT:
  681.         {
  682.             rv = I[indx]; break;
  683.         }
  684.         case TYPE_NPC:
  685.         {
  686.             rv = N[indx]; break;
  687.         }
  688.         case TYPE_LWEAPON:
  689.         {
  690.             rv = L[indx]; break;
  691.         }
  692.         case TYPE_EWEAPON:
  693.         {
  694.             rv = E[indx]; break;
  695.         }
  696.         case TYPE_FFC:
  697.         {
  698.             rv = F[indx]; break;
  699.         }
  700.         case TYPE_ITEM:
  701.         {
  702.             rv = IT[indx]; break;
  703.         }
  704.         case TYPE_ITEMDATA:
  705.         {
  706.             rv = ID[indx]; break;
  707.         }
  708.         case TYPE_NPCDATA:
  709.         {
  710.             rv = ND[indx]; break;
  711.         }
  712.         case TYPE_COMBODATA:
  713.         {
  714.             rv = CD[indx]; break;
  715.         }
  716.         case TYPE_SPRITEDATA:
  717.         {
  718.             rv = WD[indx]; break;
  719.         }
  720.         case TYPE_SHOPDATA:
  721.         {
  722.             rv = SD[indx]; break;
  723.         }
  724.        
  725.     }
  726.     return rv;
  727.    
  728. }
  729.  
  730. //stores an instruction string into WORD[] when parsing the script,
  731. int GetInstrString(int word)
  732. {
  733.     int buf[64];
  734.     int sz = strlen(word) -1;
  735.     int temp; bool n; bool token; int q; int paramID;
  736.     for ( ; temp < sz; ++temp )
  737.     {
  738.         //if we find a token before an instruction, exit and report false?
  739.         if ( IsParsingToken(word[q]) continue; //return 0; //break;
  740.        
  741.         //! ...but we need to store tokens onto their own tempstack!!
  742.         if ( IsNumber(word[q]) ) continue; //ignore line numbers and all numerals
  743.         if ( word[q] == ' ' ) continue; //eat WS
  744.         if ( !word[q] ) break; //halt on str term.
  745.         buf[q] = word[q];
  746.     }
  747.     for ( q = 0; q < 64; ++q )
  748.     {
  749.         //tore label into the global word buffer.
  750.         WORD[q] = buf[q];
  751.     }
  752.    
  753.     //! Here we must also store the param values, or any assigns.
  754.    
  755.     //Find the instruction parame
  756.     // We continue to scan, starting at temp:
  757.     int param[64]; int scope;
  758.     do
  759.     {
  760.        
  761.         for ( ; temp < sz; ++temp )
  762.         {
  763.             if ( word[temp] == ' ' ) continue; //eat WS
  764.             //open scope and copy
  765.             if ( word[temp] == '(' )
  766.             {
  767.                 do
  768.                 {
  769.                     ++temp;
  770.                     if ( word[temp] == ' ' ) continue; //eat WS
  771.                     if ( word[temp] == '(' )
  772.                     {
  773.                         ++scope;
  774.                         continue;
  775.                     }
  776.                    
  777.                     if ( word[temp] == ')'
  778.                     {
  779.                         --scope;
  780.                         continue;
  781.                     }
  782.                     param[temp] = word[temp];
  783.                 }
  784.                 while(scope <= 0);
  785.             }
  786.            
  787.             //determine if param is an expression
  788.            
  789.             //if it is:
  790.                 //1. Copy it to the EXPRESSION array.
  791.                 //2 resolve i
  792.                 //store its litral value
  793.            
  794.             //id not, it's a var or a literal
  795.            
  796.             //extract the vallue and move on
  797.            
  798.             //inrement param, so that we can know how many of them we store
  799.             //is this at all useful?
  800.            
  801.             ++paramID;
  802.            
  803.            
  804.             SetArg(atof(param)); //param must be resolved if an expression, so we might need another buffer
  805.         }
  806.         while(word[temp] != ';'); //look for the next param, or $END
  807.     }
  808.        
  809.        
  810.        
  811.    
  812.            
  813.        
  814.    
  815.     /*
  816.    
  817.     This also needs to be in the expression checker.
  818.    
  819.     Assigns in the language will be enclosed by braces or parens
  820.     or some special token.
  821.    
  822.         [I26 = 90;]
  823.    
  824.         Do we need array sntax?
  825.    
  826.     This way, the parser knows that it is about to encounter a variable?
  827.    
  828.     //or shyould we just enclose variables?
  829.    
  830.     Perhaps @var_id?
  831.    
  832.     @G26 = 70
  833.    
  834.     One positive note, is that assign and expr during a function call would work.
  835.    
  836.    
  837.     */
  838.    
  839.    
  840. }
  841.        
  842. float ExpressionChecker(int word)
  843. {
  844.     int rv;
  845.     //convert vars to literals and store
  846.     //store script literals and store
  847.     //store operation signs
  848.    
  849.     //determine operation ordering
  850.     //resolvng scopes
  851.    
  852.     //process expression
  853.    
  854.     //Functions aere in the fake ffc 'class' expr.
  855.     //call as expr.f()
  856.    
  857.     return rv;
  858.    
  859. }
  860.  
  861.  
  862.  
  863.  
  864. void Parse()
  865. {
  866.     int inistack = curstack;
  867.     SP = 0;
  868.     //scan each line
  869.     //prune line number
  870.     prune leading spaces
  871.     //store the text of this line until '(' or 'other tokenm,
  872.         //such as '=' to WORD[]
  873.     if the operator is a maths sign, or a token
  874.         that modifies a var immediately
  875.     UPDATE GLOBAL VARS
  876.     then do the maths here
  877.         store the param:
  878.         1. if a literal, copy the char to PARAM
  879.             then
  880.             CPV = ftoa(PARAM);
  881.         2. otherwise, it's a var:
  882.             read the identifier to VARIABLE[]
  883.             scan the type ID first
  884.        
  885.         //nO, SCREW THAT.
  886.         //Use an UNTYPED array, and we won't need to care about datatypes!
  887.         Otherwise...
  888.        
  889.         CVT = ExtractVarType(PARAM);
  890.         VARTYPES[CSR] = CVT;
  891.        
  892.        
  893.         //extract the param *value* next
  894.        
  895.         //SCRIPTRAM[CSR] = ;
  896.         SetArg(CVT,GetvarValue(CVT,ExtractVarID(PARAM)));
  897.         //now the value of that variable is set and ready to execute
  898.         //with Getparam().
  899.     repeat for next param.
  900.        
  901.     run :
  902.     ++SP; STACK[SP] = GetInstruction(WORD);
  903.    
  904.        
  905. }
  906.  
  907. /*
  908.  
  909. THis wuld allow for truly generic processing of instructions.
  910. Any internal instruction would simply use getArg() to get
  911. the value assignd to it.
  912.  
  913. The parser would not know if there are insufficient parameters
  914. aimed at an instruction, but we could determine this during lexing...
  915.  
  916. The user could assign values to these, and a set of predefined
  917. scripts to edit.
  918.  
  919.  
  920. /*
  921.  
  922. //Expressions
  923.  
  924. /*
  925. 1. While there are still tokens to be read in,
  926.    1.1 Get the next token.
  927.    1.2 If the token is:
  928.        1.2.1 A number: push it onto the value stack.
  929.        1.2.2 A variable: get its value, and push onto the value stack.
  930.        1.2.3 A left parenthesis: push it onto the operator stack.
  931.        1.2.4 A right parenthesis:
  932.          1 While the thing on top of the operator stack is not a
  933.            left parenthesis,
  934.              1 Pop the operator from the operator stack.
  935.              2 Pop the value stack twice, getting two operands.
  936.              3 Apply the operator to the operands, in the correct order.
  937.              4 Push the result onto the value stack.
  938.          2 Pop the left parenthesis from the operator stack, and discard it.
  939.        1.2.5 An operator (call it thisOp):
  940.          1 While the operator stack is not empty, and the top thing on the
  941.            operator stack has the same or greater precedence as thisOp,
  942.            1 Pop the operator from the operator stack.
  943.            2 Pop the value stack twice, getting two operands.
  944.            3 Apply the operator to the operands, in the correct order.
  945.            4 Push the result onto the value stack.
  946.          2 Push thisOp onto the operator stack.
  947. 2. While the operator stack is not empty,
  948.     1 Pop the operator from the operator stack.
  949.     2 Pop the value stack twice, getting two operands.
  950.     3 Apply the operator to the operands, in the correct order.
  951.     4 Push the result onto the value stack.
  952. 3. At this point the operator stack should be empty, and the value
  953.    stack should have only one value in it, which is the final result.
  954.    
  955.   */
  956.  
  957. ffc script expr
  958. {
  959.     void run(){}
  960.     //int precedence(int op) { return Precedence(op); }
  961.     //int applyOp(int a, int b, int op) { return ApplyOp(a, b, op); }
  962.    
  963.    
  964.     // Function to find precedence of
  965.     // operators.
  966.     int Precedence(int op)
  967.     {
  968.         if (op == '+') return 1;
  969.         if ( op == '-') return 1;
  970.         if (op == '*') return 2;
  971.         if ( op == '/') return 2;
  972.         if ( op }== '^') return 3;
  973.         return 0;
  974.     }
  975.      
  976.     // Function to perform arithmetic operations.
  977.     int ApplyOp(int a, int b, int op){
  978.         switch(op)
  979.         {
  980.             case '+': { return a + b; }
  981.             case '-': { return a - b; }
  982.             case '*': { return a * b; }
  983.             case '/': { return a / b; }
  984.             case '^'; { return Pow(a,b); } //No bitwise Xor in Z.Basic.
  985.         }
  986.     }
  987. }
  988.  
  989.  
  990.     /* Parens
  991.     Parens increase precedence by ++ per paren.
  992.     Work similar to scope in other functions.
  993.     */
  994.  
  995.     int FindScopePrecedence(int token, int pos)
  996.     {
  997.         int len = strlen(token);
  998.         int scope; int tempscope;
  999.         do
  1000.         {
  1001.             if ( token[pos] == '(' ) { ++scope; ++tempscope;
  1002.             if ( token[pos] == ')' ) --tempscope;
  1003.         } while ( tempscope > 0 );
  1004.         return scope;
  1005.     }
  1006.  
  1007. /*
  1008. **Find highest precedence from scopes?
  1009. **define scopes
  1010. Store all values and ops in a temp array
  1011. Store precedence of each
  1012. Find all types with precedence
  1013. Apply ordr 2 precedence to val, then clear the value, and operator from a temp list, setting operator to -1.
  1014. Repeat for precedence 1
  1015. then 0.
  1016. */
  1017.     }
  1018.  
  1019. // CPP program to evaluate a given
  1020. // expression where tokens are
  1021. // separated by space.
  1022. //#include <bits/stdc++.h>
  1023. //using namespace std;
  1024.  
  1025.  
  1026. int DoExpr(int word)
  1027. {
  1028.     int inistack = curstack;
  1029.     int buf[1024]; int q; bool foundop; bool sign;
  1030.     int number[14]; bool foundvalue; bool foundnum; bool foundvar;
  1031.     int len = SizeOfArray(word);
  1032.     int varid[4];
  1033.     for ( q = 0; q < len; ++q ) buf[q] = word[q];
  1034.     int place = 0;
  1035.     ++q; buf[q] = 0; //terminate
  1036.     q = -1;
  1037.     while(reading)
  1038.     {
  1039.         ++q;
  1040.        
  1041.         //look for numbers before an operator
  1042.         if ( !foundop && !foundvalue )
  1043.             //first value can be signed
  1044.         {
  1045.             if ( buf[q] == ' '; ) //eat WS
  1046.                 continue;
  1047.            
  1048.             if ( buf[q] == '-' ) { sign = true; ++q; }
  1049.             //read the number portion of the string into a value.
  1050.             //numbers only
  1051.            
  1052.             while ( IsNumber(buf[q]) || buf[q] == '.' )
  1053.             {
  1054.                 foundnum = true;
  1055.                 if ( buf[q] == '.' )
  1056.                 {
  1057.                     if ( !dec )
  1058.                     {
  1059.                         dec = true;
  1060.                         number[place] = buf[q]];
  1061.                         ++place;
  1062.                     }
  1063.                     else continue;
  1064.                 }
  1065.                 else
  1066.                 {
  1067.                     number[place] = buf[q];
  1068.                     ++place;
  1069.                 }
  1070.             }
  1071.            
  1072.             if ( foundnum ) //it isn't a var, but a literal
  1073.             {
  1074.                 if ( sign ) { sign = false; val = atof(number)*-1;  }//store the extracted value.
  1075.                 else val = atof(number); //store the extracted value.
  1076.                 foundvalue = true;
  1077.             }
  1078.             //variables
  1079.             if ( !foundnum ) //is it a variable?
  1080.             {
  1081.                 bool seeking = true;
  1082.                 while(seeking)
  1083.                 {
  1084.                     if ( buf[q] == 'I' ) { foundvar = true; seeking = false; break; }
  1085.                     else if ( buf[q] == 'N' ) { foundvar = true; seeking = false; break; }
  1086.                     else if ( buf[q] == 'L' ) { foundvar = true; seeking = false; break; }
  1087.                     else if ( buf[q] == 'E' ) { foundvar = true; seeking = false; break; }
  1088.                     else if ( buf[q] == 'F' ) { foundvar = true; seeking = false; break; }
  1089.                     else if ( buf[q] == 'C' ) { foundvar = true; seeking = false; break; }
  1090.                     else if ( buf[q] == 'W' ) { foundvar = true; seeking = false; break; }
  1091.                     else if ( buf[q] == 'S' ) { foundvar = true; seeking = false; break; }
  1092.                     else if ( buf[q] == '<' ) { foundvar = true; seeking = false; break; }
  1093.                     else break;
  1094.                 }
  1095.                 if ( foundvar ) //found it, so extract it.
  1096.                 {
  1097.                     for ( int w = q; w < q+2; ++w )
  1098.                     {
  1099.                         varid[w] = buf[q+w];
  1100.                     }
  1101.                     int vartype = ExtractVarType(varid);
  1102.                     int indx = ExtractVarID(varid);
  1103.                     val = GetVarValue(vartype,indx);
  1104.                     foundvalue = true;
  1105.                 }
  1106.                    
  1107.             }
  1108.                
  1109.         }
  1110.         if ( foundvalue )
  1111.         //push value here
  1112.         stack.change(OPERAND);
  1113.         stack.push(val);
  1114.        
  1115.         // 1.2.3 A left parenthesis: push it onto the operator stack.
  1116.      
  1117.      
  1118.         //loop for a lparen
  1119.         if ( buf[q] == '(' )
  1120.         {
  1121.             //push the paren to operators
  1122.             stack.change(OPERATORS);
  1123.             stack.push('(');
  1124.         }
  1125.        
  1126.         //  1.2.4 A right parenthesis:
  1127.         if ( buf[q] == ')' )
  1128.         {
  1129.             /*
  1130.             1 While the thing on top of the operator stack is not a
  1131.            left parenthesis,
  1132.              1 Pop the operator from the operator stack.
  1133.              2 Pop the value stack twice, getting two operands.
  1134.              3 Apply the operator to the operands, in the correct order.
  1135.              4 Push the result onto the value stack.
  1136.          2 Pop the left parenthesis from the operator stack, and discard it.
  1137.             */
  1138.         }
  1139.        
  1140.        
  1141.         /*
  1142.        
  1143.            1.2.5 An operator (call it thisOp):
  1144.          1 While the operator stack is not empty, and the top thing on the
  1145.            operator stack has the same or greater precedence as thisOp,
  1146.            1 Pop the operator from the operator stack.
  1147.         //stack.change(OPERATOR);
  1148.         //stack.pop(INX1);
  1149.            2 Pop the value stack twice, getting two operands.
  1150.         //
  1151.         // stack.change(OPERAND).
  1152.         // stack.pop(EXPR2);
  1153.         // stack.pop(EXPR1);
  1154.            3 Apply the operator to the operands, in the correct order.
  1155.            4 Push the result onto the value stack.
  1156.         //stack.push(EXPR2);
  1157.          2 Push thisOp onto the operator stack.
  1158.     2. While the operator stack is not empty,
  1159.         1 Pop the operator from the operator stack.
  1160.         2 Pop the value stack twice, getting two operands.
  1161.         3 Apply the operator to the operands, in the correct order.
  1162.         4 Push the result onto the value stack.
  1163.     3. At this point the operator stack should be empty, and the value
  1164.        stack should have only one value in it, which is the final result.
  1165.    */
  1166.        
  1167.         if ( !foundop && foundvalue )
  1168.             //the next thing must be an operator
  1169.         {
  1170.             if ( buf[q] == ' '; ) //eat WS
  1171.                 continue;
  1172.            
  1173.             if ( IsOperator(buf[q] )
  1174.             {
  1175.                 //push it and its precedence
  1176.                 foundop = true;
  1177.             }
  1178.            
  1179.         }
  1180.     }
  1181. }
  1182.            
  1183.                
  1184. /*
  1185.  Convert Infix Expression to Post-Fix Expression
  1186.  
  1187. Conventional notation is called infix notation. The arithmetic operators appears between two operands. Parentheses are required to specify the order of the operations. For example: a + (b * c).
  1188. Post fix notation (also, known as reverse Polish notation) eliminates the need for parentheses. There are no precedence rules to learn, and parenthese are never needed. Because of this simplicity, some popular hand-held calculators use postfix notation to avoid the complications of multiple sets of parentheses. The operator is placed directly after the two operands it needs to apply. For example: a b c * +
  1189. This short example makes the move from infix to postfix intuitive. However, as expressions get more complicated, there will have to be rules to follow to get the correct result:
  1190.  
  1191.  
  1192. Simple heuristic algorithm to visually convert infix to postfix
  1193.  
  1194.  •  Fully parenthesize the expression, to reflect correct operator precedence
  1195.  •  Move each operator to replace the right parenthesis to which it belongs
  1196.  •  Remove paretheses
  1197.  
  1198. Evaluating expressions
  1199.  
  1200. A stack is used in two phases of evaluating an expression such as
  1201.  
  1202.        3 * 2 + 4 * (A + B)
  1203. •Convert the infix form to postfix using a stack to store operators and then pop them in correct order of precedence.
  1204. •Evaluate the postfix expression by using a stack to store operands and then pop them when an operator is reached.
  1205. Infix to postfix conversion
  1206. Scan through an expression, getting one token at a time.
  1207.  
  1208. 1 Fix a priority level for each operator. For example, from high to low:
  1209.  
  1210.     3.    - (unary negation)
  1211.     2.    * /
  1212.     1.    + - (subtraction)
  1213. Thus, high priority corresponds to high number in the table.
  1214.  
  1215. 2 If the token is an operand, do not stack it. Pass it to the output.
  1216.  
  1217. 3 If token is an operator or parenthesis, do the following:
  1218.  
  1219.    -- Pop the stack until you find a symbol of lower priority number than the current one. An incoming left parenthesis will be considered to have higher priority than any other symbol. A left parenthesis on the stack will not be removed unless an incoming right parenthesis is found.
  1220. The popped stack elements will be written to output.
  1221.  
  1222.    --Stack the current symbol.
  1223.    -- If a right parenthesis is the current symbol, pop the stack down to (and including) the first left parenthesis. Write all the symbols except the left parenthesis to the output (i.e. write the operators to the output).
  1224.  
  1225.    -- After the last token is read, pop the remainder of the stack and write any symbol (except left parenthesis) to output.
  1226. Example:
  1227. Convert A * (B + C) * D to postfix notation.
  1228.  
  1229. Move
  1230. Curren Ttoken
  1231. Stack
  1232. Output
  1233. 1
  1234. A
  1235. empty
  1236. A
  1237. 2
  1238. *
  1239. *
  1240. A
  1241. 3
  1242. (
  1243. (*
  1244. A
  1245. 4
  1246. B
  1247. (*
  1248. A B
  1249. 5
  1250. +
  1251. +(*
  1252. A B
  1253. 6
  1254. C
  1255. +(*
  1256. A B C
  1257. 7
  1258. )
  1259. *
  1260. A B C +
  1261. 8
  1262. *
  1263. *
  1264. A B C + *
  1265. 9
  1266. D
  1267. *
  1268. A B C + * D
  1269. 10
  1270.  
  1271. empty
  1272.  
  1273. Notes:
  1274. In this table, the stack grows toward the left. Thus, the top of the stack is the leftmost symbol.
  1275. In move 3, the left paren was pushed without popping the * because * had a lower priority then "(".
  1276. In move 5, "+" was pushed without popping "(" because you never pop a left parenthesis until you get an incoming right parenthesis. In other words, there is a distinction between incoming priority, which is very high for a "(", and instack priority, which is lower than any operator.
  1277. In move 7, the incoming right parenthesis caused the "+" and "(" to be popped but only the "+" as written out.
  1278. In move 8, the current "*" had equal priority to the "*" on the stack. So the "*" on the stack was popped, and the incoming "*" was pushed onto the stack.
  1279.  
  1280. Evaluating Postfix Expressions
  1281.  
  1282. Once an expression has been converted to postfix notation it is evaluated using a stack to store the operands.
  1283.    
  1284. •  Step through the expression from left to right, getting one token at a time.
  1285. •  Whenever the token is an operand, stack the operand in the order encountered.
  1286. •  When an operator is encountered:
  1287. •  If the operator is binary, then pop the stack twice
  1288. •  If the operator is unary (e.g. unary minus), pop once
  1289. •  Perform the indicated operation on the operator(s)
  1290. •  Push the result back on the stack.
  1291. •  At the end of the expression, the top of the stack will have the correct value for the expression.
  1292.  
  1293. Example:
  1294.  
  1295. Evaluate the expression 2 3 4 + * 5 * which was created by the previous algorithm for infix to postfix.
  1296.  
  1297. Move
  1298. Current Token
  1299. Stack (grows toward left)
  1300. 1
  1301. 2
  1302.  
  1303. 2
  1304. 2
  1305. 3
  1306.  
  1307. 3 2
  1308. 3
  1309. 4
  1310.  
  1311. 4 3 2
  1312. 4
  1313. +
  1314.  
  1315. 7 2
  1316. 5
  1317. *
  1318.  
  1319. 14
  1320. 6
  1321. 5
  1322.  
  1323. 5 14
  1324. 7
  1325. *
  1326.  
  1327. 70
  1328. Notes:
  1329. Move 4: an operator is encountered, so 4 and 3 are popped, summed, then pushed back onto stack.
  1330. Move 5: operator * is current token, so 7 and 2 are popped, multiplied, pushed back onto stack.
  1331. Move 7: stack top holds correct value.
  1332. Notice that the postfix notation has been created to properly reflect operator precedence. Thus, postfix expressions never need parentheses.
  1333.  
  1334.  
  1335.  
  1336.  */
  1337.  
  1338.  
  1339. //Another implementation...
  1340.  
  1341. public static double eval(final String str) {
  1342.     return new Object() {
  1343.         int pos = -1, ch;
  1344.  
  1345.         void nextChar() {
  1346.             ch = (++pos < str.length()) ? str.charAt(pos) : -1;
  1347.         }
  1348.  
  1349.         boolean eat(int charToEat) {
  1350.             while (ch == ' ') nextChar();
  1351.             if (ch == charToEat) {
  1352.                 nextChar();
  1353.                 return true;
  1354.             }
  1355.             return false;
  1356.         }
  1357.  
  1358.         double parse() {
  1359.             nextChar();
  1360.             double x = parseExpression();
  1361.             if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
  1362.             return x;
  1363.         }
  1364.  
  1365.         // Grammar:
  1366.         // expression = term | expression `+` term | expression `-` term
  1367.         // term = factor | term `*` factor | term `/` factor
  1368.         // factor = `+` factor | `-` factor | `(` expression `)`
  1369.         //        | number | functionName factor | factor `^` factor
  1370.  
  1371.         double parseExpression() {
  1372.             double x = parseTerm();
  1373.             for (;;) {
  1374.                 if      (eat('+')) x += parseTerm(); // addition
  1375.                 else if (eat('-')) x -= parseTerm(); // subtraction
  1376.                 else return x;
  1377.             }
  1378.         }
  1379.  
  1380.         double parseTerm() {
  1381.             double x = parseFactor();
  1382.             for (;;) {
  1383.                 if      (eat('*')) x *= parseFactor(); // multiplication
  1384.                 else if (eat('/')) x /= parseFactor(); // division
  1385.                 else return x;
  1386.             }
  1387.         }
  1388. int VAR[4];
  1389. int word[]
  1390. int temp;
  1391.         double parseFactor() {
  1392.             if (eat('+')) return parseFactor(); // unary plus
  1393.             if (eat('-')) return -parseFactor(); // unary minus
  1394.  
  1395.             double x;
  1396.             int startPos = this.pos;
  1397.             if (eat('(')) { // parentheses
  1398.                 x = parseExpression();
  1399.                 eat(')');
  1400.             } else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
  1401.                 while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
  1402.                 x = Double.parseDouble(str.substring(startPos, this.pos));
  1403.             } else if (ch >= 'a' && ch <= 'z') { // vars
  1404.             temp = 0;
  1405.                 while (ch != ' ') {
  1406.             var[temp] = ch;
  1407.             nextChar();
  1408.         }
  1409.         //if ( vartype = IdentifyVar(var,0) ) varvalue = GetVarValue();
  1410.        
  1411.                 String func = str.substring(startPos, this.pos);
  1412.                 x = parseFactor();
  1413.                 if (func.equals("sqrt")) x = Math.sqrt(x);
  1414.                 else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
  1415.                 else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
  1416.                 else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
  1417.                 else throw new RuntimeException("Unknown function: " + func);
  1418.             } else {
  1419.                 throw new RuntimeException("Unexpected: " + (char)ch);
  1420.             }
  1421.  
  1422.             if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation
  1423.  
  1424.             return x;
  1425.         }
  1426.     }.parse();
  1427. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement