Esempio n. 1
0
/*
 * Read in a literal real number and add it to the table of constant numbers,
 * creating a new entry if necessary.  The incoming number is a string
 * value which must have a correct format.
 * Returns the index of the number in the constant table.
 *
 * given:
 *	str		string representation of number
 */
long
addnumber(char *str)
{
	NUMBER *q;

	q = str2q(str);
	return addqconstant(q);
}
Esempio n. 2
0
/*
 * 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, *q1, *q2;
    unsigned long count;
    BOOL cut;
    int diff;

    fp = curfunc;
    count = fp->f_opcodecount;
    cut = TRUE;
    diff = 2;
    q = NULL;
    if ((count + 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.
     */
    switch (op) {
    case 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:
            diff = 1;
            oldop = OP_DUPVALUE;
            break;
        case OP_FIADDR:
            diff = 1;
            oldop = OP_FIVALUE;
            break;
        case OP_GLOBALADDR:
            diff = 1 + PTR_SIZE;
            oldop = OP_GLOBALVALUE;
            break;
        case OP_LOCALADDR:
            oldop = OP_LOCALVALUE;
            break;
        case OP_PARAMADDR:
            oldop = OP_PARAMVALUE;
            break;
        case OP_ELEMADDR:
            oldop = OP_ELEMVALUE;
            break;
        default:
            cut = FALSE;

        }
        if (cut) {
            fp->f_opcodes[count - diff] = oldop;
            return;
        }
        break;
    case OP_POP:
        switch (oldop) {
        case OP_ASSIGN:
            fp->f_opcodes[count-1] = OP_ASSIGNPOP;
            oldop = OP_ASSIGNPOP;
            return;
        case OP_NUMBER:
        case OP_IMAGINARY:
            q = constvalue(fp->f_opcodes[count-1]);
            qfree(q);
            break;
        case OP_STRING:
            sfree(findstring((long)fp->f_opcodes[count-1]));
            break;
        case OP_LOCALADDR:
        case OP_PARAMADDR:
            break;
        case OP_GLOBALADDR:
            diff = 1 + PTR_SIZE;
            break;
        case OP_UNDEF:
            fp->f_opcodecount -= 1;
            oldop = OP_NOP;
            oldoldop = OP_NOP;
            return;
        default:
            cut = FALSE;
        }
        if (cut) {
            fp->f_opcodecount -= diff;
            oldop = OP_NOP;
            oldoldop = OP_NOP;
            fprintf(stderr,
                    "Line %ld: unused value ignored\n",
                    linenumber());
            return;
        }
        break;
    case OP_NEGATE:
        if (oldop == OP_NUMBER) {
            q = constvalue(fp->f_opcodes[count-1]);
            fp->f_opcodes[count-1] = addqconstant(qneg(q));
            qfree(q);
            return;
        }
    }
    if (oldop == OP_NUMBER) {
        if (oldoldop == OP_NUMBER) {
            q1 = constvalue(fp->f_opcodes[count - 3]);
            q2 = constvalue(fp->f_opcodes[count - 1]);
            switch (op) {
            case OP_DIV:
                if (qiszero(q2)) {
                    cut = FALSE;
                    break;
                }
                q = qqdiv(q1,q2);
                break;
            case OP_MUL:
                q = qmul(q1,q2);
                break;
            case OP_ADD:
                q = qqadd(q1,q2);
                break;
            case OP_SUB:
                q = qsub(q1,q2);
                break;
            case OP_POWER:
                if (qisfrac(q2) || qisneg(q2))
                    cut = FALSE;
                else
                    q = qpowi(q1,q2);
                break;
            default:
                cut = FALSE;
            }
            if (cut) {
                qfree(q1);
                qfree(q2);
                fp->f_opcodes[count - 3] = addqconstant(q);
                fp->f_opcodecount -= 2;
                oldoldop = OP_NOP;
                return;
            }
        } else if (op != OP_NUMBER) {
            q = constvalue(fp->f_opcodes[count - 1]);
            if (op == OP_POWER) {
                if (qcmpi(q, 2L) == 0) {
                    fp->f_opcodecount--;
                    fp->f_opcodes[count - 2] = OP_SQUARE;
                    qfree(q);
                    oldop = OP_SQUARE;
                    return;
                }
                if (qcmpi(q, 4L) == 0) {
                    fp->f_opcodes[count - 2] = OP_SQUARE;
                    fp->f_opcodes[count - 1] = OP_SQUARE;
                    qfree(q);
                    oldop = OP_SQUARE;
                    return;
                }
            }
            if (qiszero(q)) {
                qfree(q);
                fp->f_opcodes[count - 2] = OP_ZERO;
                fp->f_opcodecount--;
            } else if (qisone(q)) {
                qfree(q);
                fp->f_opcodes[count - 2] = OP_ONE;
                fp->f_opcodecount--;
            }
        }
    }
    /*
     * No optimization possible, so store the opcode.
     */
    fp->f_opcodes[fp->f_opcodecount] = op;
    fp->f_opcodecount++;
    oldoldop = oldop;
    oldop = op;
}