mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
Release calc version 2.10.2t30
This commit is contained in:
448
addop.c
Normal file
448
addop.c
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright (c) 1995 David I. Bell
|
||||
* Permission is granted to use, distribute, or modify this source,
|
||||
* provided that this copyright notice remains intact.
|
||||
*
|
||||
* Add opcodes to a function being compiled.
|
||||
*/
|
||||
|
||||
#include "calc.h"
|
||||
#include "opcodes.h"
|
||||
#include "string.h"
|
||||
#include "func.h"
|
||||
#include "token.h"
|
||||
#include "label.h"
|
||||
#include "symbol.h"
|
||||
|
||||
|
||||
#define FUNCALLOCSIZE 20 /* reallocate size for functions */
|
||||
#define OPCODEALLOCSIZE 100 /* reallocate size for opcodes in functions */
|
||||
|
||||
|
||||
static long maxopcodes; /* number of opcodes available */
|
||||
static long newindex; /* index of new function */
|
||||
static long oldop; /* previous opcode */
|
||||
static long debugline; /* line number of latest debug opcode */
|
||||
static long funccount; /* number of functions */
|
||||
static long funcavail; /* available number of functions */
|
||||
static FUNC *functemplate; /* function definition template */
|
||||
static FUNC **functions; /* table of functions */
|
||||
static STRINGHEAD funcnames; /* function names */
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the table of user defined functions.
|
||||
*/
|
||||
void
|
||||
initfunctions(void)
|
||||
{
|
||||
initstr(&funcnames);
|
||||
maxopcodes = OPCODEALLOCSIZE;
|
||||
functemplate = (FUNC *) malloc(funcsize(maxopcodes));
|
||||
if (functemplate == NULL) {
|
||||
math_error("Cannot allocate function template");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
functions = (FUNC **) malloc(sizeof(FUNC *) * FUNCALLOCSIZE);
|
||||
if (functions == NULL) {
|
||||
math_error("Cannot allocate function table");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
funccount = 0;
|
||||
funcavail = FUNCALLOCSIZE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Show the list of user defined functions.
|
||||
*/
|
||||
void
|
||||
showfunctions(void)
|
||||
{
|
||||
FUNC **fpp; /* pointer into function table */
|
||||
FUNC *fp; /* current function */
|
||||
|
||||
if (funccount == 0) {
|
||||
printf("No user functions defined.\n");
|
||||
return;
|
||||
}
|
||||
printf("Name Arguments\n");
|
||||
printf("---- ---------\n");
|
||||
for (fpp = &functions[funccount - 1]; fpp >= functions; fpp--) {
|
||||
fp = *fpp;
|
||||
if (fp == NULL)
|
||||
continue;
|
||||
printf("%-12s %-2d\n", fp->f_name, fp->f_paramcount);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize a function for definition.
|
||||
* Newflag is TRUE if we should allocate a new function structure,
|
||||
* instead of the usual overwriting of the template function structure.
|
||||
* The new structure is returned in the global curfunc variable.
|
||||
*
|
||||
* given:
|
||||
* name name of function
|
||||
* newflag TRUE if need new structure
|
||||
*/
|
||||
void
|
||||
beginfunc(char *name, BOOL newflag)
|
||||
{
|
||||
register FUNC *fp; /* current function */
|
||||
|
||||
newindex = adduserfunc(name);
|
||||
maxopcodes = OPCODEALLOCSIZE;
|
||||
fp = functemplate;
|
||||
if (newflag) {
|
||||
fp = (FUNC *) malloc(funcsize(maxopcodes));
|
||||
if (fp == NULL) {
|
||||
math_error("Cannot allocate temporary function");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
fp->f_next = NULL;
|
||||
fp->f_localcount = 0;
|
||||
fp->f_opcodecount = 0;
|
||||
fp->f_savedvalue.v_type = V_NULL;
|
||||
fp->f_name = namestr(&funcnames, newindex);
|
||||
curfunc = fp;
|
||||
initlocals();
|
||||
initlabels();
|
||||
oldop = OP_NOP;
|
||||
debugline = 0;
|
||||
errorcount = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Commit the just defined function for use.
|
||||
* This replaces any existing definition for the function.
|
||||
* This should only be called for normal user-defined functions.
|
||||
*/
|
||||
void
|
||||
endfunc(void)
|
||||
{
|
||||
register FUNC *fp; /* function just finished */
|
||||
unsigned long size; /* size of just created function */
|
||||
|
||||
checklabels();
|
||||
if (errorcount) {
|
||||
printf("\"%s\": %ld error%s\n", curfunc->f_name, errorcount,
|
||||
((errorcount == 1) ? "" : "s"));
|
||||
return;
|
||||
}
|
||||
size = funcsize(curfunc->f_opcodecount);
|
||||
fp = (FUNC *) malloc(size);
|
||||
if (fp == NULL) {
|
||||
math_error("Cannot commit function");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
memcpy((char *) fp, (char *) curfunc, size);
|
||||
if (curfunc != functemplate)
|
||||
free(curfunc);
|
||||
if (conf->traceflags & TRACE_FNCODES) {
|
||||
dumpnames = TRUE;
|
||||
for (size = 0; size < fp->f_opcodecount; ) {
|
||||
printf("%ld: ", (long)size);
|
||||
size += dumpop(&fp->f_opcodes[size]);
|
||||
}
|
||||
}
|
||||
if (functions[newindex]) {
|
||||
free(functions[newindex]);
|
||||
fprintf(stderr, "**** %s() has been redefined\n", fp->f_name);
|
||||
}
|
||||
functions[newindex] = fp;
|
||||
objuncache();
|
||||
if (inputisterminal())
|
||||
printf("\"%s\" defined\n", fp->f_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find the user function with the specified name, and return its index.
|
||||
* If the function does not exist, its name is added to the function table
|
||||
* and an error will be generated when it is called if it is still undefined.
|
||||
*
|
||||
* given:
|
||||
* name name of function
|
||||
*/
|
||||
long
|
||||
adduserfunc(char *name)
|
||||
{
|
||||
long index; /* index of function */
|
||||
|
||||
index = findstr(&funcnames, name);
|
||||
if (index >= 0)
|
||||
return index;
|
||||
if (funccount >= funcavail) {
|
||||
functions = (FUNC **) realloc(functions,
|
||||
sizeof(FUNC *) * (funcavail + FUNCALLOCSIZE));
|
||||
if (functions == NULL) {
|
||||
math_error("Failed to reallocate function table");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
funcavail += FUNCALLOCSIZE;
|
||||
}
|
||||
if (addstr(&funcnames, name) == NULL) {
|
||||
math_error("Cannot save function name");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
index = funccount++;
|
||||
functions[index] = NULL;
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Clear any optimization that may be done for the next opcode.
|
||||
* This is used when defining a label.
|
||||
*/
|
||||
void
|
||||
clearopt(void)
|
||||
{
|
||||
oldop = OP_NOP;
|
||||
debugline = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find a function structure given its index.
|
||||
*/
|
||||
FUNC *
|
||||
findfunc(long index)
|
||||
{
|
||||
if ((unsigned long) index >= funccount) {
|
||||
math_error("Undefined function");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
return functions[index];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the name of a function given its index.
|
||||
*/
|
||||
char *
|
||||
namefunc(long index)
|
||||
{
|
||||
return namestr(&funcnames, index);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Let a matrix indexing operation know that it will be treated as a write
|
||||
* reference instead of just as a read reference.
|
||||
*/
|
||||
void
|
||||
writeindexop(void)
|
||||
{
|
||||
if (oldop == OP_INDEXADDR)
|
||||
curfunc->f_opcodes[curfunc->f_opcodecount - 1] = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add an opcode to the current function being compiled.
|
||||
* Note: This can change the curfunc global variable when the
|
||||
* function needs expanding.
|
||||
*/
|
||||
void
|
||||
addop(long op)
|
||||
{
|
||||
register FUNC *fp; /* current function */
|
||||
NUMBER *q;
|
||||
|
||||
fp = curfunc;
|
||||
if ((fp->f_opcodecount + 5) >= maxopcodes) {
|
||||
maxopcodes += OPCODEALLOCSIZE;
|
||||
fp = (FUNC *) malloc(funcsize(maxopcodes));
|
||||
if (fp == NULL) {
|
||||
math_error("cannot malloc function");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
memcpy((char *) fp, (char *) curfunc,
|
||||
funcsize(curfunc->f_opcodecount));
|
||||
if (curfunc != functemplate)
|
||||
free(curfunc);
|
||||
curfunc = fp;
|
||||
}
|
||||
/*
|
||||
* Check the current opcode against the previous opcode and try to
|
||||
* slightly optimize the code depending on the various combinations.
|
||||
*/
|
||||
if (op == OP_GETVALUE) {
|
||||
switch (oldop) {
|
||||
|
||||
case OP_NUMBER: case OP_ZERO: case OP_ONE: case OP_IMAGINARY:
|
||||
case OP_GETEPSILON: case OP_SETEPSILON: case OP_STRING:
|
||||
case OP_UNDEF: case OP_GETCONFIG: case OP_SETCONFIG:
|
||||
return;
|
||||
case OP_DUPLICATE:
|
||||
fp->f_opcodes[fp->f_opcodecount - 1] = OP_DUPVALUE;
|
||||
oldop = OP_DUPVALUE;
|
||||
return;
|
||||
case OP_FIADDR:
|
||||
fp->f_opcodes[fp->f_opcodecount - 1] = OP_FIVALUE;
|
||||
oldop = OP_FIVALUE;
|
||||
return;
|
||||
case OP_GLOBALADDR:
|
||||
fp->f_opcodes[fp->f_opcodecount - 2] = OP_GLOBALVALUE;
|
||||
oldop = OP_GLOBALVALUE;
|
||||
return;
|
||||
case OP_LOCALADDR:
|
||||
fp->f_opcodes[fp->f_opcodecount - 2] = OP_LOCALVALUE;
|
||||
oldop = OP_LOCALVALUE;
|
||||
return;
|
||||
case OP_PARAMADDR:
|
||||
fp->f_opcodes[fp->f_opcodecount - 2] = OP_PARAMVALUE;
|
||||
oldop = OP_PARAMVALUE;
|
||||
return;
|
||||
case OP_ELEMADDR:
|
||||
fp->f_opcodes[fp->f_opcodecount - 2] = OP_ELEMVALUE;
|
||||
oldop = OP_ELEMVALUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((op == OP_NEGATE) && (oldop == OP_NUMBER)) {
|
||||
q = constvalue(fp->f_opcodes[fp->f_opcodecount - 1]);
|
||||
fp->f_opcodes[fp->f_opcodecount - 1] = addqconstant(qneg(q));
|
||||
oldop = OP_NUMBER;
|
||||
return;
|
||||
}
|
||||
if ((op == OP_POWER) && (oldop == OP_NUMBER)) {
|
||||
if (qcmpi(constvalue(fp->f_opcodes[fp->f_opcodecount - 1]), 2L) == 0) {
|
||||
fp->f_opcodecount--;
|
||||
fp->f_opcodes[fp->f_opcodecount - 1] = OP_SQUARE;
|
||||
oldop = OP_SQUARE;
|
||||
return;
|
||||
}
|
||||
if (qcmpi(constvalue(fp->f_opcodes[fp->f_opcodecount - 1]), 4L) == 0) {
|
||||
fp->f_opcodes[fp->f_opcodecount - 2] = OP_SQUARE;
|
||||
fp->f_opcodes[fp->f_opcodecount - 1] = OP_SQUARE;
|
||||
oldop = OP_SQUARE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((op == OP_POP) && (oldop == OP_ASSIGN)) { /* optimize */
|
||||
fp->f_opcodes[fp->f_opcodecount - 1] = OP_ASSIGNPOP;
|
||||
oldop = OP_ASSIGNPOP;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* No optimization possible, so store the opcode.
|
||||
*/
|
||||
fp->f_opcodes[fp->f_opcodecount] = op;
|
||||
fp->f_opcodecount++;
|
||||
oldop = op;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add an opcode and and one integer argument to the current function
|
||||
* being compiled.
|
||||
*/
|
||||
void
|
||||
addopone(long op, long arg)
|
||||
{
|
||||
NUMBER *q;
|
||||
|
||||
switch (op) {
|
||||
case OP_NUMBER:
|
||||
q = constvalue(arg);
|
||||
if (q == NULL)
|
||||
break;
|
||||
if (qiszero(q)) {
|
||||
addop(OP_ZERO);
|
||||
return;
|
||||
}
|
||||
if (qisone(q)) {
|
||||
addop(OP_ONE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_DEBUG:
|
||||
if ((conf->traceflags & TRACE_NODEBUG) || (arg == debugline))
|
||||
return;
|
||||
debugline = arg;
|
||||
if (oldop == OP_DEBUG) {
|
||||
curfunc->f_opcodes[curfunc->f_opcodecount - 1] = arg;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
addop(op);
|
||||
curfunc->f_opcodes[curfunc->f_opcodecount] = arg;
|
||||
curfunc->f_opcodecount++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add an opcode and and two integer arguments to the current function
|
||||
* being compiled.
|
||||
*/
|
||||
void
|
||||
addoptwo(long op, long arg1, long arg2)
|
||||
{
|
||||
addop(op);
|
||||
curfunc->f_opcodes[curfunc->f_opcodecount++] = arg1;
|
||||
curfunc->f_opcodes[curfunc->f_opcodecount++] = arg2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add an opcode and a character pointer to the function being compiled.
|
||||
*/
|
||||
void
|
||||
addopptr(long op, char *ptr)
|
||||
{
|
||||
char **ptraddr;
|
||||
|
||||
addop(op);
|
||||
ptraddr = (char **) &curfunc->f_opcodes[curfunc->f_opcodecount];
|
||||
*ptraddr = ptr;
|
||||
curfunc->f_opcodecount += PTR_SIZE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add an opcode and an index and an argument count for a function call.
|
||||
*/
|
||||
void
|
||||
addopfunction(long op, long index, int count)
|
||||
{
|
||||
long newop;
|
||||
|
||||
if ((op == OP_CALL) && ((newop = builtinopcode(index)) != OP_NOP)) {
|
||||
if ((newop == OP_SETCONFIG) && (count == 1))
|
||||
newop = OP_GETCONFIG;
|
||||
if ((newop == OP_SETEPSILON) && (count == 0))
|
||||
newop = OP_GETEPSILON;
|
||||
if ((newop == OP_ABS) && (count == 1))
|
||||
addop(OP_GETEPSILON);
|
||||
addop(newop);
|
||||
return;
|
||||
}
|
||||
addop(op);
|
||||
curfunc->f_opcodes[curfunc->f_opcodecount++] = index;
|
||||
curfunc->f_opcodes[curfunc->f_opcodecount++] = count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add a jump-type opcode and a label to the function being compiled.
|
||||
*
|
||||
* given:
|
||||
* label label to be added
|
||||
*/
|
||||
void
|
||||
addoplabel(long op, LABEL *label)
|
||||
{
|
||||
addop(op);
|
||||
uselabel(label);
|
||||
}
|
||||
|
||||
/* END CODE */
|
Reference in New Issue
Block a user