modified: SpatialOmicsCoord.py
[GalaxyCodeBases.git] / c_cpp / etc / calc / addop.c
bloba34e4340af815fbe4c8150d79bcfc1f19b68dc48
1 /*
2 * addop - add opcodes to a function being compiled
4 * Copyright (C) 1999-2007 David I. Bell and Ernest Bowen
6 * Primary author: David I. Bell
8 * Calc is open software; you can redistribute it and/or modify it under
9 * the terms of the version 2.1 of the GNU Lesser General Public License
10 * as published by the Free Software Foundation.
12 * Calc is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
15 * Public License for more details.
17 * A copy of version 2.1 of the GNU Lesser General Public License is
18 * distributed with calc under the filename COPYING-LGPL. You should have
19 * received a copy with calc; if not, write to Free Software Foundation, Inc.
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * @(#) $Revision: 30.1 $
23 * @(#) $Id: addop.c,v 30.1 2007/03/16 11:09:46 chongo Exp $
24 * @(#) $Source: /usr/local/src/bin/calc/RCS/addop.c,v $
26 * Under source code control: 1990/02/15 01:48:10
27 * File existed as early as: before 1990
29 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
33 #include <stdio.h>
34 #include "calc.h"
35 #include "opcodes.h"
36 #include "str.h"
37 #include "func.h"
38 #include "token.h"
39 #include "label.h"
40 #include "symbol.h"
43 #define FUNCALLOCSIZE 20 /* reallocate size for functions */
44 #define OPCODEALLOCSIZE 100 /* reallocate size for opcodes in functions */
47 STATIC unsigned long maxopcodes;/* number of opcodes available */
48 STATIC long newindex; /* index of new function */
49 STATIC char *newname; /* name of new function */
50 STATIC long oldop; /* previous opcode */
51 STATIC long oldoldop; /* opcode before previous opcode */
52 STATIC long debugline; /* line number of latest debug opcode */
53 STATIC long funccount; /* number of functions */
54 STATIC long funcavail; /* available number of functions */
55 STATIC FUNC *functemplate; /* function definition template */
56 STATIC FUNC **functions; /* table of functions */
57 STATIC STRINGHEAD funcnames; /* function names */
61 * Initialize the table of user defined functions.
63 void
64 initfunctions(void)
66 initstr(&funcnames);
67 maxopcodes = OPCODEALLOCSIZE;
68 functemplate = (FUNC *) malloc(funcsize(maxopcodes));
69 if (functemplate == NULL) {
70 math_error("Cannot allocate function template");
71 /*NOTREACHED*/
73 functions = (FUNC **) malloc(sizeof(FUNC *) * FUNCALLOCSIZE);
74 if (functions == NULL) {
75 math_error("Cannot allocate function table");
76 /*NOTREACHED*/
78 funccount = 0;
79 funcavail = FUNCALLOCSIZE;
84 * Show the list of user defined functions.
86 void
87 showfunctions(void)
89 FUNC *fp; /* current function */
90 long count;
91 long index;
93 count = 0;
94 if (funccount > 0) {
95 if (conf->resource_debug & RSCDBG_FUNC_INFO)
96 math_str("Index\tName \tArgs\tOpcodes\n"
97 "-----\t------ \t---- \t------\n");
98 else
99 math_str("Name\tArguments\n"
100 "----\t---------\n");
101 for (index = 0; index < funccount; index++) {
102 fp = functions[index];
103 if (conf->resource_debug & RSCDBG_FUNC_INFO) {
105 math_fmt("%5ld\t%-12s\t", index,
106 namestr(&funcnames,index));
107 if (fp) {
108 count++;
109 math_fmt("%-5d\t%-5ld\n",
110 fp->f_paramcount, fp->f_opcodecount);
111 } else {
112 math_str("null\t0\n");
114 } else {
115 if (fp == NULL)
116 continue;
117 count++;
118 math_fmt("%-12s\t%-2d\n", namestr(&funcnames,
119 index), fp->f_paramcount);
123 if (conf->resource_debug & RSCDBG_FUNC_INFO) {
124 math_fmt("\nNumber non-null: %ld\n", count);
125 math_fmt("Number null: %ld\n", funccount - count);
126 math_fmt("Total number: %ld\n", funccount);
127 } else {
128 if (count > 0)
129 math_fmt("\nNumber: %ld\n", count);
130 else
131 math_str("No user functions defined\n");
137 * Initialize a function for definition.
138 * Newflag is TRUE if we should allocate a new function structure,
139 * instead of the usual overwriting of the template function structure.
140 * The new structure is returned in the global curfunc variable.
142 * given:
143 * name name of function
144 * newflag TRUE if need new structure
146 void
147 beginfunc(char *name, BOOL newflag)
149 register FUNC *fp; /* current function */
151 newindex = adduserfunc(name);
152 maxopcodes = OPCODEALLOCSIZE;
153 fp = functemplate;
154 if (newflag) {
155 fp = (FUNC *) malloc(funcsize(maxopcodes));
156 if (fp == NULL) {
157 math_error("Cannot allocate temporary function");
158 /*NOTREACHED*/
161 fp->f_next = NULL;
162 fp->f_localcount = 0;
163 fp->f_opcodecount = 0;
164 fp->f_savedvalue.v_type = V_NULL;
165 fp->f_savedvalue.v_subtype = V_NOSUBTYPE;
166 newname = namestr(&funcnames, newindex);
167 fp->f_name = newname;
168 curfunc = fp;
169 initlocals();
170 initlabels();
171 oldop = OP_NOP;
172 oldoldop = OP_NOP;
173 debugline = 0;
174 errorcount = 0;
179 * Commit the just defined function for use.
180 * This replaces any existing definition for the function.
181 * This should only be called for normal user-defined functions.
183 void
184 endfunc(void)
186 register FUNC *fp; /* function just finished */
187 size_t size; /* size of just created function */
188 unsigned long index;
190 if (oldop != OP_RETURN) {
191 addop(OP_UNDEF);
192 addop(OP_RETURN);
195 checklabels();
197 if (errorcount) {
198 scanerror(T_NULL,"Compilation of \"%s\" failed: %ld error(s)",
199 newname, errorcount);
200 return;
202 size = funcsize(curfunc->f_opcodecount);
203 fp = (FUNC *) malloc(size);
204 if (fp == NULL) {
205 math_error("Cannot commit function");
206 /*NOTREACHED*/
208 memcpy((char *) fp, (char *) curfunc, size);
209 if (curfunc != functemplate)
210 free(curfunc);
211 if (newname[0] != '*' && (conf->traceflags & TRACE_FNCODES)) {
212 dumpnames = TRUE;
213 for (size = 0; size < fp->f_opcodecount; ) {
214 printf("%ld: ", (unsigned long)size);
215 size += dumpop(&fp->f_opcodes[size]);
218 if ((inputisterminal() && conf->resource_debug & RSCDBG_STDIN_FUNC) ||
219 (!inputisterminal() && conf->resource_debug & RSCDBG_FILE_FUNC)) {
220 printf("%s(", newname);
221 for (index = 0; index < fp->f_paramcount; index++) {
222 if (index)
223 putchar(',');
224 printf("%s", paramname(index));
226 printf(") ");
227 if (functions[newindex])
228 printf("re");
229 printf("defined\n");
231 if (functions[newindex]) {
232 freenumbers(functions[newindex]);
233 free(functions[newindex]);
235 functions[newindex] = fp;
240 * Find the user function with the specified name, and return its index.
241 * If the function does not exist, its name is added to the function table
242 * and an error will be generated when it is called if it is still undefined.
244 * given:
245 * name name of function
247 long
248 adduserfunc(char *name)
250 long index; /* index of function */
252 index = findstr(&funcnames, name);
253 if (index >= 0)
254 return index;
255 if (funccount >= funcavail) {
256 functions = (FUNC **) realloc(functions,
257 sizeof(FUNC *) * (funcavail + FUNCALLOCSIZE));
258 if (functions == NULL) {
259 math_error("Failed to reallocate function table");
260 /*NOTREACHED*/
262 funcavail += FUNCALLOCSIZE;
264 if (addstr(&funcnames, name) == NULL) {
265 math_error("Cannot save function name");
266 /*NOTREACHED*/
268 index = funccount++;
269 functions[index] = NULL;
270 return index;
274 * Remove user defined function
276 void
277 rmuserfunc(char *name)
279 long index; /* index of function */
281 index = findstr(&funcnames, name);
282 if (index < 0) {
283 warning("No function named \"%s\" to be undefined", name);
284 return;
286 if (functions[index] == NULL) {
287 warning("No defined function \"%s\" to be undefined", name);
288 return;
290 freenumbers(functions[index]);
291 free(functions[index]);
292 if ((inputisterminal() && conf->resource_debug & RSCDBG_STDIN_FUNC) ||
293 (!inputisterminal() && conf->resource_debug & RSCDBG_FILE_FUNC))
294 printf("%s() undefined\n", name);
295 functions[index] = NULL;
300 * Free memory used to store function and its constants
302 void
303 freefunc(FUNC *fp)
305 long index;
306 unsigned long i;
308 if (fp == NULL)
309 return;
310 if (fp == curfunc) {
311 index = newindex;
312 } else {
313 for (index = 0; index < funccount; index++) {
314 if (functions[index] == fp)
315 break;
317 if (index == funccount) {
318 math_error("Bad call to freefunc!!!");
319 /*NOTREACHED*/
322 if (newname[0] != '*' && (conf->traceflags & TRACE_FNCODES)) {
323 printf("Freeing function \"%s\"\n",namestr(&funcnames,index));
324 dumpnames = FALSE;
325 for (i = 0; i < fp->f_opcodecount; ) {
326 printf("%ld: ", i);
327 i += dumpop(&fp->f_opcodes[i]);
330 freenumbers(fp);
331 if (fp != functemplate)
332 free(fp);
336 void
337 rmalluserfunc(void)
339 FUNC *fp;
340 long index;
342 for (index = 0; index < funccount; index++) {
343 fp = functions[index];
344 if (fp) {
345 freefunc(fp);
346 functions[index] = NULL;
353 * get index of defined user function with specified name, or -1 if there
354 * is none or if it has been undefined
356 long
357 getuserfunc(char *name)
359 long index;
361 index = findstr(&funcnames, name);
362 if (index >= 0 && functions[index] != NULL)
363 return index;
364 return -1L;
369 * Clear any optimization that may be done for the next opcode.
370 * This is used when defining a label.
372 void
373 clearopt(void)
375 oldop = OP_NOP;
376 oldoldop = OP_NOP;
377 debugline = 0;
382 * Find a function structure given its index.
384 FUNC *
385 findfunc(long index)
387 if (index >= funccount) {
388 math_error("Undefined function");
389 /*NOTREACHED*/
391 return functions[index];
396 * Return the name of a function given its index.
398 char *
399 namefunc(long index)
401 return namestr(&funcnames, index);
406 * Let a matrix indexing operation know that it will be treated as a write
407 * reference instead of just as a read reference.
409 void
410 writeindexop(void)
412 if (oldop == OP_INDEXADDR)
413 curfunc->f_opcodes[curfunc->f_opcodecount - 1] = TRUE;
418 * Add an opcode to the current function being compiled.
419 * Note: This can change the curfunc global variable when the
420 * function needs expanding.
422 void
423 addop(long op)
425 register FUNC *fp; /* current function */
426 NUMBER *q, *q1, *q2;
427 unsigned long count;
428 BOOL cut;
429 int diff;
431 fp = curfunc;
432 count = fp->f_opcodecount;
433 cut = TRUE;
434 diff = 2;
435 q = NULL;
436 if ((count + 5) >= maxopcodes) {
437 maxopcodes += OPCODEALLOCSIZE;
438 fp = (FUNC *) malloc(funcsize(maxopcodes));
439 if (fp == NULL) {
440 math_error("cannot malloc function");
441 /*NOTREACHED*/
443 memcpy((char *) fp, (char *) curfunc,
444 funcsize(curfunc->f_opcodecount));
445 if (curfunc != functemplate)
446 free(curfunc);
447 curfunc = fp;
451 * Check the current opcode against the previous opcode and try to
452 * slightly optimize the code depending on the various combinations.
454 switch (op) {
455 case OP_GETVALUE:
456 switch (oldop) {
457 case OP_NUMBER:
458 case OP_ZERO:
459 case OP_ONE:
460 case OP_IMAGINARY:
461 case OP_GETEPSILON:
462 case OP_SETEPSILON:
463 case OP_STRING:
464 case OP_UNDEF:
465 case OP_GETCONFIG:
466 case OP_SETCONFIG:
467 return;
468 case OP_DUPLICATE:
469 diff = 1;
470 oldop = OP_DUPVALUE;
471 break;
472 case OP_FIADDR:
473 diff = 1;
474 oldop = OP_FIVALUE;
475 break;
476 case OP_GLOBALADDR:
477 diff = 1 + PTR_SIZE;
478 oldop = OP_GLOBALVALUE;
479 break;
480 case OP_LOCALADDR:
481 oldop = OP_LOCALVALUE;
482 break;
483 case OP_PARAMADDR:
484 oldop = OP_PARAMVALUE;
485 break;
486 case OP_ELEMADDR:
487 oldop = OP_ELEMVALUE;
488 break;
489 default:
490 cut = FALSE;
493 if (cut) {
494 fp->f_opcodes[count - diff] = oldop;
495 return;
497 break;
498 case OP_POP:
499 switch (oldop) {
500 case OP_ASSIGN:
501 fp->f_opcodes[count-1] = OP_ASSIGNPOP;
502 oldop = OP_ASSIGNPOP;
503 return;
504 case OP_NUMBER:
505 case OP_IMAGINARY:
506 q = constvalue(fp->f_opcodes[count-1]);
507 qfree(q);
508 break;
509 case OP_STRING:
510 sfree(findstring((long)fp->f_opcodes[count-1]));
511 break;
512 case OP_LOCALADDR:
513 case OP_PARAMADDR:
514 break;
515 case OP_GLOBALADDR:
516 diff = 1 + PTR_SIZE;
517 break;
518 case OP_UNDEF:
519 fp->f_opcodecount -= 1;
520 oldop = OP_NOP;
521 oldoldop = OP_NOP;
522 return;
523 default:
524 cut = FALSE;
526 if (cut) {
527 fp->f_opcodecount -= diff;
528 oldop = OP_NOP;
529 oldoldop = OP_NOP;
530 warning("Constant before comma operator");
531 return;
533 break;
534 case OP_NEGATE:
535 if (oldop == OP_NUMBER) {
536 q = constvalue(fp->f_opcodes[count-1]);
537 fp->f_opcodes[count-1] = addqconstant(qneg(q));
538 qfree(q);
539 return;
542 if (oldop == OP_NUMBER) {
543 if (oldoldop == OP_NUMBER) {
544 q1 = constvalue(fp->f_opcodes[count - 3]);
545 q2 = constvalue(fp->f_opcodes[count - 1]);
546 switch (op) {
547 case OP_DIV:
548 if (qiszero(q2)) {
549 cut = FALSE;
550 break;
552 q = qqdiv(q1,q2);
553 break;
554 case OP_MUL:
555 q = qmul(q1,q2);
556 break;
557 case OP_ADD:
558 q = qqadd(q1,q2);
559 break;
560 case OP_SUB:
561 q = qsub(q1,q2);
562 break;
563 case OP_POWER:
564 if (qisfrac(q2) || qisneg(q2))
565 cut = FALSE;
566 else
567 q = qpowi(q1,q2);
568 break;
569 default:
570 cut = FALSE;
572 if (cut) {
573 qfree(q1);
574 qfree(q2);
575 fp->f_opcodes[count - 3] = addqconstant(q);
576 fp->f_opcodecount -= 2;
577 oldoldop = OP_NOP;
578 return;
580 } else if (op != OP_NUMBER) {
581 q = constvalue(fp->f_opcodes[count - 1]);
582 if (op == OP_POWER) {
583 if (qcmpi(q, 2L) == 0) {
584 fp->f_opcodecount--;
585 fp->f_opcodes[count - 2] = OP_SQUARE;
586 qfree(q);
587 oldop = OP_SQUARE;
588 return;
590 if (qcmpi(q, 4L) == 0) {
591 fp->f_opcodes[count - 2] = OP_SQUARE;
592 fp->f_opcodes[count - 1] = OP_SQUARE;
593 qfree(q);
594 oldop = OP_SQUARE;
595 return;
598 if (qiszero(q)) {
599 qfree(q);
600 fp->f_opcodes[count - 2] = OP_ZERO;
601 fp->f_opcodecount--;
602 } else if (qisone(q)) {
603 qfree(q);
604 fp->f_opcodes[count - 2] = OP_ONE;
605 fp->f_opcodecount--;
610 * No optimization possible, so store the opcode.
612 fp->f_opcodes[fp->f_opcodecount] = op;
613 fp->f_opcodecount++;
614 oldoldop = oldop;
615 oldop = op;
620 * Add an opcode and and one integer argument to the current function
621 * being compiled.
623 void
624 addopone(long op, long arg)
626 if (op == OP_DEBUG) {
627 if ((conf->traceflags & TRACE_NODEBUG) || (arg == debugline))
628 return;
629 debugline = arg;
630 if (oldop == OP_DEBUG) {
631 curfunc->f_opcodes[curfunc->f_opcodecount - 1] = arg;
632 return;
635 addop(op);
636 curfunc->f_opcodes[curfunc->f_opcodecount] = arg;
637 curfunc->f_opcodecount++;
642 * Add an opcode and and two integer arguments to the current function
643 * being compiled.
645 void
646 addoptwo(long op, long arg1, long arg2)
648 addop(op);
649 curfunc->f_opcodes[curfunc->f_opcodecount++] = arg1;
650 curfunc->f_opcodes[curfunc->f_opcodecount++] = arg2;
655 * Add an opcode and a character pointer to the function being compiled.
657 void
658 addopptr(long op, char *ptr)
660 char **ptraddr;
662 addop(op);
663 ptraddr = (char **) &curfunc->f_opcodes[curfunc->f_opcodecount];
664 *ptraddr = ptr;
665 curfunc->f_opcodecount += PTR_SIZE;
670 * Add an opcode and an index and an argument count for a function call.
672 void
673 addopfunction(long op, long index, int count)
675 long newop;
677 if ((op == OP_CALL) && ((newop = builtinopcode(index)) != OP_NOP)) {
678 if ((newop == OP_SETCONFIG) && (count == 1))
679 newop = OP_GETCONFIG;
680 if ((newop == OP_SETEPSILON) && (count == 0))
681 newop = OP_GETEPSILON;
682 if ((newop == OP_ABS) && (count == 1))
683 addop(OP_GETEPSILON);
684 addop(newop);
685 return;
687 addop(op);
688 curfunc->f_opcodes[curfunc->f_opcodecount++] = index;
689 curfunc->f_opcodes[curfunc->f_opcodecount++] = count;
694 * Add a jump-type opcode and a label to the function being compiled.
696 * given:
697 * label label to be added
699 void
700 addoplabel(long op, LABEL *label)
702 addop(op);
703 uselabel(label);