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/
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.
67 maxopcodes
= OPCODEALLOCSIZE
;
68 functemplate
= (FUNC
*) malloc(funcsize(maxopcodes
));
69 if (functemplate
== NULL
) {
70 math_error("Cannot allocate function template");
73 functions
= (FUNC
**) malloc(sizeof(FUNC
*) * FUNCALLOCSIZE
);
74 if (functions
== NULL
) {
75 math_error("Cannot allocate function table");
79 funcavail
= FUNCALLOCSIZE
;
84 * Show the list of user defined functions.
89 FUNC
*fp
; /* current function */
95 if (conf
->resource_debug
& RSCDBG_FUNC_INFO
)
96 math_str("Index\tName \tArgs\tOpcodes\n"
97 "-----\t------ \t---- \t------\n");
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
));
109 math_fmt("%-5d\t%-5ld\n",
110 fp
->f_paramcount
, fp
->f_opcodecount
);
112 math_str("null\t0\n");
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
);
129 math_fmt("\nNumber: %ld\n", count
);
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.
143 * name name of function
144 * newflag TRUE if need new structure
147 beginfunc(char *name
, BOOL newflag
)
149 register FUNC
*fp
; /* current function */
151 newindex
= adduserfunc(name
);
152 maxopcodes
= OPCODEALLOCSIZE
;
155 fp
= (FUNC
*) malloc(funcsize(maxopcodes
));
157 math_error("Cannot allocate temporary function");
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
;
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.
186 register FUNC
*fp
; /* function just finished */
187 size_t size
; /* size of just created function */
190 if (oldop
!= OP_RETURN
) {
198 scanerror(T_NULL
,"Compilation of \"%s\" failed: %ld error(s)",
199 newname
, errorcount
);
202 size
= funcsize(curfunc
->f_opcodecount
);
203 fp
= (FUNC
*) malloc(size
);
205 math_error("Cannot commit function");
208 memcpy((char *) fp
, (char *) curfunc
, size
);
209 if (curfunc
!= functemplate
)
211 if (newname
[0] != '*' && (conf
->traceflags
& TRACE_FNCODES
)) {
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
++) {
224 printf("%s", paramname(index
));
227 if (functions
[newindex
])
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.
245 * name name of function
248 adduserfunc(char *name
)
250 long index
; /* index of function */
252 index
= findstr(&funcnames
, name
);
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");
262 funcavail
+= FUNCALLOCSIZE
;
264 if (addstr(&funcnames
, name
) == NULL
) {
265 math_error("Cannot save function name");
269 functions
[index
] = NULL
;
274 * Remove user defined function
277 rmuserfunc(char *name
)
279 long index
; /* index of function */
281 index
= findstr(&funcnames
, name
);
283 warning("No function named \"%s\" to be undefined", name
);
286 if (functions
[index
] == NULL
) {
287 warning("No defined function \"%s\" to be undefined", name
);
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
313 for (index
= 0; index
< funccount
; index
++) {
314 if (functions
[index
] == fp
)
317 if (index
== funccount
) {
318 math_error("Bad call to freefunc!!!");
322 if (newname
[0] != '*' && (conf
->traceflags
& TRACE_FNCODES
)) {
323 printf("Freeing function \"%s\"\n",namestr(&funcnames
,index
));
325 for (i
= 0; i
< fp
->f_opcodecount
; ) {
327 i
+= dumpop(&fp
->f_opcodes
[i
]);
331 if (fp
!= functemplate
)
342 for (index
= 0; index
< funccount
; index
++) {
343 fp
= functions
[index
];
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
357 getuserfunc(char *name
)
361 index
= findstr(&funcnames
, name
);
362 if (index
>= 0 && functions
[index
] != NULL
)
369 * Clear any optimization that may be done for the next opcode.
370 * This is used when defining a label.
382 * Find a function structure given its index.
387 if (index
>= funccount
) {
388 math_error("Undefined function");
391 return functions
[index
];
396 * Return the name of a function given its 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.
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.
425 register FUNC
*fp
; /* current function */
432 count
= fp
->f_opcodecount
;
436 if ((count
+ 5) >= maxopcodes
) {
437 maxopcodes
+= OPCODEALLOCSIZE
;
438 fp
= (FUNC
*) malloc(funcsize(maxopcodes
));
440 math_error("cannot malloc function");
443 memcpy((char *) fp
, (char *) curfunc
,
444 funcsize(curfunc
->f_opcodecount
));
445 if (curfunc
!= functemplate
)
451 * Check the current opcode against the previous opcode and try to
452 * slightly optimize the code depending on the various combinations.
478 oldop
= OP_GLOBALVALUE
;
481 oldop
= OP_LOCALVALUE
;
484 oldop
= OP_PARAMVALUE
;
487 oldop
= OP_ELEMVALUE
;
494 fp
->f_opcodes
[count
- diff
] = oldop
;
501 fp
->f_opcodes
[count
-1] = OP_ASSIGNPOP
;
502 oldop
= OP_ASSIGNPOP
;
506 q
= constvalue(fp
->f_opcodes
[count
-1]);
510 sfree(findstring((long)fp
->f_opcodes
[count
-1]));
519 fp
->f_opcodecount
-= 1;
527 fp
->f_opcodecount
-= diff
;
530 warning("Constant before comma operator");
535 if (oldop
== OP_NUMBER
) {
536 q
= constvalue(fp
->f_opcodes
[count
-1]);
537 fp
->f_opcodes
[count
-1] = addqconstant(qneg(q
));
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]);
564 if (qisfrac(q2
) || qisneg(q2
))
575 fp
->f_opcodes
[count
- 3] = addqconstant(q
);
576 fp
->f_opcodecount
-= 2;
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) {
585 fp
->f_opcodes
[count
- 2] = OP_SQUARE
;
590 if (qcmpi(q
, 4L) == 0) {
591 fp
->f_opcodes
[count
- 2] = OP_SQUARE
;
592 fp
->f_opcodes
[count
- 1] = OP_SQUARE
;
600 fp
->f_opcodes
[count
- 2] = OP_ZERO
;
602 } else if (qisone(q
)) {
604 fp
->f_opcodes
[count
- 2] = OP_ONE
;
610 * No optimization possible, so store the opcode.
612 fp
->f_opcodes
[fp
->f_opcodecount
] = op
;
620 * Add an opcode and and one integer argument to the current function
624 addopone(long op
, long arg
)
626 if (op
== OP_DEBUG
) {
627 if ((conf
->traceflags
& TRACE_NODEBUG
) || (arg
== debugline
))
630 if (oldop
== OP_DEBUG
) {
631 curfunc
->f_opcodes
[curfunc
->f_opcodecount
- 1] = arg
;
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
646 addoptwo(long op
, long arg1
, long arg2
)
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.
658 addopptr(long op
, char *ptr
)
663 ptraddr
= (char **) &curfunc
->f_opcodes
[curfunc
->f_opcodecount
];
665 curfunc
->f_opcodecount
+= PTR_SIZE
;
670 * Add an opcode and an index and an argument count for a function call.
673 addopfunction(long op
, long index
, int count
)
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
);
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.
697 * label label to be added
700 addoplabel(long op
, LABEL
*label
)