home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / calc / part04 / addop.c next >
C/C++ Source or Header  |  1992-05-09  |  9KB  |  413 lines

  1. /*
  2.  * Copyright (c) 1992 David I. Bell
  3.  * Permission is granted to use, distribute, or modify this source,
  4.  * provided that this copyright notice remains intact.
  5.  *
  6.  * Add opcodes to a function being compiled.
  7.  */
  8.  
  9. #include "calc.h"
  10. #include "opcodes.h"
  11. #include "string.h"
  12. #include "func.h"
  13. #include "token.h"
  14. #include "label.h"
  15. #include "symbol.h"
  16.  
  17.  
  18. #define    FUNCALLOCSIZE    20    /* reallocate size for functions */
  19. #define    OPCODEALLOCSIZE    100    /* reallocate size for opcodes in functions */
  20.  
  21.  
  22. static long maxopcodes;        /* number of opcodes available */
  23. static long newindex;        /* index of new function */
  24. static long oldop;        /* previous opcode */
  25. static long debugline;        /* line number of latest debug opcode */
  26. static long funccount;        /* number of functions */
  27. static long funcavail;        /* available number of functions */
  28. static FUNC *functemplate;    /* function definition template */
  29. static FUNC **functions;    /* table of functions */
  30. static STRINGHEAD funcnames;    /* function names */
  31. static int codeflag;
  32.  
  33. NUMBER *constvalue();
  34.  
  35.  
  36. /*
  37.  * Initialize the table of user defined functions.
  38.  */
  39. void
  40. initfunctions()
  41. {
  42.     initstr(&funcnames);
  43.     maxopcodes = OPCODEALLOCSIZE;
  44.     functemplate = (FUNC *) malloc(funcsize(maxopcodes));
  45.     if (functemplate == NULL)
  46.         error("Cannot allocate function template");
  47.     functions = (FUNC **) malloc(sizeof(FUNC *) * FUNCALLOCSIZE);
  48.     if (functions == NULL)
  49.         error("Cannot allocate function table");
  50.     funccount = 0;
  51.     funcavail = FUNCALLOCSIZE;
  52. }
  53.  
  54.  
  55. /*
  56.  * Show the list of user defined functions.
  57.  */
  58. void
  59. showfunctions()
  60. {
  61.     FUNC **fpp;        /* pointer into function table */
  62.     FUNC *fp;        /* current function */
  63.  
  64.     if (funccount == 0) {
  65.         printf("No user functions defined.\n");
  66.         return;
  67.     }
  68.     printf("Name Arguments\n");
  69.     printf("---- ---------\n");
  70.     for (fpp = &functions[funccount - 1]; fpp >= functions; fpp--) {
  71.         fp = *fpp;
  72.         if (fp == NULL)
  73.             continue;
  74.         printf("%-12s %-2d\n", fp->f_name, fp->f_paramcount);
  75.     }
  76.     printf("\n");
  77. }
  78.  
  79.  
  80. /*
  81.  * Initialize a function for definition.
  82.  * Newflag is TRUE if we should allocate a new function structure,
  83.  * instead of the usual overwriting of the template function structure.
  84.  * The new structure is returned in the global curfunc variable.
  85.  */
  86. void
  87. beginfunc(name, newflag)
  88.     char *name;            /* name of function */
  89.     BOOL newflag;            /* TRUE if need new structure */
  90. {
  91.     register FUNC *fp;        /* current function */
  92.  
  93.     newindex = adduserfunc(name);
  94.     maxopcodes = OPCODEALLOCSIZE;
  95.     fp = functemplate;
  96.     if (newflag) {
  97.         fp = (FUNC *) malloc(funcsize(maxopcodes));
  98.         if (fp == NULL)
  99.             error("Cannot allocate temporary function");
  100.     }
  101.     fp->f_next = NULL;
  102.     fp->f_localcount = 0;
  103.     fp->f_opcodecount = 0;
  104.     fp->f_savedvalue.v_type = V_NULL;
  105.     fp->f_name = namestr(&funcnames, newindex);
  106.     curfunc = fp;
  107.     initlocals();
  108.     initlabels();
  109.     oldop = OP_NOP;
  110.     debugline = 0;
  111.     errorcount = 0;
  112. }
  113.  
  114.  
  115. /*
  116.  * Commit the just defined function for use.
  117.  * This replaces any existing definition for the function.
  118.  * This should only be called for normal user-defined functions.
  119.  */
  120. void
  121. endfunc()
  122. {
  123.     register FUNC *fp;        /* function just finished */
  124.     long size;            /* size of just created function */
  125.  
  126.     checklabels();
  127.     if (errorcount) {
  128.         printf("\"%s\": %ld error%s\n", curfunc->f_name, errorcount,
  129.             ((errorcount == 1) ? "" : "s"));
  130.         return;
  131.     }
  132.     size = funcsize(curfunc->f_opcodecount);
  133.     fp = (FUNC *) malloc(size);
  134.     if (fp == NULL)
  135.         error("Cannot commit function");
  136.     memcpy((char *) fp, (char *) curfunc, size);
  137.     if (curfunc != functemplate)
  138.         free(curfunc);
  139.     if (codeflag) {
  140.         for (size = 0; size < fp->f_opcodecount; ) {
  141.             printf("%ld: ", (long)size);
  142.             size += dumpop(&fp->f_opcodes[size]);
  143.         }
  144.     }
  145.     if (functions[newindex])
  146.         free(functions[newindex]);
  147.     functions[newindex] = fp;
  148.     objuncache();
  149.     if (inputisterminal())
  150.         printf("\"%s\" defined\n", fp->f_name);
  151. }
  152.  
  153.  
  154. /*
  155.  * Find the user function with the specified name, and return its index.
  156.  * If the function does not exist, its name is added to the function table
  157.  * and an error will be generated when it is called if it is still undefined.
  158.  */
  159. long
  160. adduserfunc(name)
  161.     char *name;        /* name of function */
  162. {
  163.     long index;        /* index of function */
  164.  
  165.     index = findstr(&funcnames, name);
  166.     if (index >= 0)
  167.         return index;
  168.     if (funccount >= funcavail) {
  169.         functions = (FUNC **) realloc(functions,
  170.             sizeof(FUNC *) * (funcavail + FUNCALLOCSIZE));
  171.         if (functions == NULL)
  172.             error("Failed to reallocate function table");
  173.         funcavail += FUNCALLOCSIZE;
  174.     }
  175.     if (addstr(&funcnames, name) == NULL)
  176.         error("Cannot save function name");
  177.     index = funccount++;
  178.     functions[index] = NULL;
  179.     return index;
  180. }
  181.  
  182.  
  183. /*
  184.  * Clear any optimization that may be done for the next opcode.
  185.  * This is used when defining a label.
  186.  */
  187. void
  188. clearopt()
  189. {
  190.     oldop = OP_NOP;
  191.     debugline = 0;
  192. }
  193.  
  194.  
  195. /*
  196.  * Find a function structure given its index.
  197.  */
  198. FUNC *
  199. findfunc(index)
  200.     long index;
  201. {
  202.     if ((unsigned long) index >= funccount)
  203.         error("Undefined function");
  204.     return functions[index];
  205. }
  206.  
  207.  
  208. /*
  209.  * Return the name of a function given its index.
  210.  */
  211. char *
  212. namefunc(index)
  213.     long index;
  214. {
  215.     return namestr(&funcnames, index);
  216. }
  217.  
  218.  
  219. /*
  220.  * Add an opcode to the current function being compiled.
  221.  * Note: This can change the curfunc global variable when the
  222.  * function needs expanding.
  223.  */
  224. void
  225. addop(op)
  226.     long op;
  227. {
  228.     register FUNC *fp;        /* current function */
  229.     NUMBER *q;
  230.  
  231.     fp = curfunc;
  232.     if ((fp->f_opcodecount + 5) >= maxopcodes) {
  233.         maxopcodes += OPCODEALLOCSIZE;
  234.         fp = (FUNC *) malloc(funcsize(maxopcodes));
  235.         if (fp == NULL)
  236.             error("cannot reallocate function");
  237.         memcpy((char *) fp, (char *) curfunc,
  238.             funcsize(curfunc->f_opcodecount));
  239.         if (curfunc != functemplate)
  240.             free(curfunc);
  241.         curfunc = fp;
  242.     }
  243.     /*
  244.      * Check the current opcode against the previous opcode and try to
  245.      * slightly optimize the code depending on the various combinations.
  246.      */
  247.     if (op == OP_GETVALUE) {
  248.         switch (oldop) {
  249.  
  250.         case OP_NUMBER: case OP_ZERO: case OP_ONE: case OP_IMAGINARY:
  251.         case OP_GETEPSILON: case OP_SETEPSILON: case OP_STRING:
  252.         case OP_UNDEF: case OP_GETCONFIG: case OP_SETCONFIG:
  253.             return;
  254.         case OP_DUPLICATE:
  255.             fp->f_opcodes[fp->f_opcodecount - 1] = OP_DUPVALUE;
  256.             oldop = OP_DUPVALUE;
  257.             return;
  258.         case OP_INDEXADDR:
  259.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_INDEXVALUE;
  260.             oldop = OP_INDEXVALUE;
  261.             return;
  262.         case OP_FIADDR:
  263.             fp->f_opcodes[fp->f_opcodecount - 1] = OP_FIVALUE;
  264.             oldop = OP_FIVALUE;
  265.             return;
  266.         case OP_GLOBALADDR:
  267.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_GLOBALVALUE;
  268.             oldop = OP_GLOBALVALUE;
  269.             return;
  270.         case OP_LOCALADDR:
  271.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_LOCALVALUE;
  272.             oldop = OP_LOCALVALUE;
  273.             return;
  274.         case OP_PARAMADDR:
  275.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_PARAMVALUE;
  276.             oldop = OP_PARAMVALUE;
  277.             return;
  278.         case OP_ELEMADDR:
  279.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_ELEMVALUE;
  280.             oldop = OP_ELEMVALUE;
  281.             return;
  282.         }
  283.     }
  284.     if ((op == OP_NEGATE) && (oldop == OP_NUMBER)) {
  285.         q = constvalue(fp->f_opcodes[fp->f_opcodecount - 1]);
  286.         fp->f_opcodes[fp->f_opcodecount - 1] = addqconstant(qneg(q));
  287.         oldop = OP_NUMBER;
  288.         return;
  289.     }
  290.     if ((op == OP_POWER) && (oldop == OP_NUMBER)) {
  291.         if (qcmpi(constvalue(fp->f_opcodes[fp->f_opcodecount - 1]), 2L) == 0) {
  292.             fp->f_opcodecount--;
  293.             fp->f_opcodes[fp->f_opcodecount - 1] = OP_SQUARE;
  294.             oldop = OP_SQUARE;
  295.             return;
  296.         }
  297.         if (qcmpi(constvalue(fp->f_opcodes[fp->f_opcodecount - 1]), 4L) == 0) {
  298.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_SQUARE;
  299.             fp->f_opcodes[fp->f_opcodecount - 1] = OP_SQUARE;
  300.             oldop = OP_SQUARE;
  301.             return;
  302.         }
  303.     }
  304.     if ((op == OP_POP) && (oldop == OP_ASSIGN)) {    /* optimize */
  305.         fp->f_opcodes[fp->f_opcodecount - 1] = OP_ASSIGNPOP;
  306.         oldop = OP_ASSIGNPOP;
  307.         return;
  308.     }
  309.     /*
  310.      * No optimization possible, so store the opcode.
  311.      */
  312.     fp->f_opcodes[fp->f_opcodecount] = op;
  313.     fp->f_opcodecount++;
  314.     oldop = op;
  315. }
  316.  
  317.  
  318. /*
  319.  * Add an opcode and an index to the current function being compiled.
  320.  */
  321. void
  322. addopindex(op, index)
  323.     long op;
  324.     long index;
  325. {
  326.     NUMBER *q;
  327.  
  328.     switch (op) {
  329.     case OP_NUMBER:
  330.         q = constvalue(index);
  331.         if (qiszero(q)) {
  332.             addop(OP_ZERO);
  333.             return;
  334.         }
  335.         if (qisone(q)) {
  336.             addop(OP_ONE);
  337.             return;
  338.         }
  339.         break;
  340.  
  341.     case OP_DEBUG:
  342.         if ((traceflags & TRACE_NODEBUG) || (index == debugline))
  343.             return;
  344.         debugline = index;
  345.         if (oldop == OP_DEBUG) {
  346.             curfunc->f_opcodes[curfunc->f_opcodecount - 1] = index;
  347.             return;
  348.         }
  349.         break;
  350.     }
  351.     addop(op);
  352.     curfunc->f_opcodes[curfunc->f_opcodecount] = index;
  353.     curfunc->f_opcodecount++;
  354. }
  355.  
  356.  
  357. /*
  358.  * Add an opcode and a character pointer to the function being compiled.
  359.  */
  360. void
  361. addopptr(op, ptr)
  362.     long op;
  363.     char *ptr;
  364. {
  365.     char **ptraddr;
  366.  
  367.     addop(op);
  368.     ptraddr = (char **) &curfunc->f_opcodes[curfunc->f_opcodecount];
  369.     *ptraddr = ptr;
  370.     curfunc->f_opcodecount += PTR_SIZE;
  371. }
  372.  
  373.  
  374. /*
  375.  * Add an opcode and an index and an argument count for a function call.
  376.  */
  377. void
  378. addopfunction(op, index, count)
  379.     long op;
  380.     long index;
  381. {
  382.     long newop;
  383.  
  384.     if ((op == OP_CALL) && ((newop = builtinopcode(index)) != OP_NOP)) {
  385.         if ((newop == OP_SETCONFIG) && (count == 1))
  386.             newop = OP_GETCONFIG;
  387.         if ((newop == OP_SETEPSILON) && (count == 0))
  388.             newop = OP_GETEPSILON;
  389.         if ((newop == OP_ABS) && (count == 1))
  390.             addop(OP_GETEPSILON);
  391.         addop(newop);
  392.         return;
  393.     }
  394.     addop(op);
  395.     curfunc->f_opcodes[curfunc->f_opcodecount++] = index;
  396.     curfunc->f_opcodes[curfunc->f_opcodecount++] = count;
  397. }
  398.  
  399.  
  400. /*
  401.  * Add a jump-type opcode and a label to the function being compiled.
  402.  */
  403. void
  404. addoplabel(op, label)
  405.     long op;
  406.     LABEL *label;        /* label to be added */
  407. {
  408.     addop(op);
  409.     uselabel(label);
  410. }
  411.  
  412. /* END CODE */
  413.