home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Computerworld 1996 March
/
Computerworld_1996-03_cd.bin
/
idg_cd3
/
grafika
/
fraktaly
/
frasr192
/
parserfp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-15
|
54KB
|
1,446 lines
/* PARSERFP.C -- Part of FRACTINT fractal drawer. */
/* By Chuck Ebbert CompuServe [76306,1226] */
/* internet: 76306.1226@compuserve.com */
/* Fast floating-point parser code. The functions beginning with */
/* "fStk" are in PARSERA.ASM. PARSER.C calls this code after */
/* it has parsed the formula. */
/* Converts the function pointers/load pointers/store pointers */
/* built by parsestr() into an optimized array of function */
/* pointer/operand pointer pairs. */
/* As of 31 Dec 93, also generates executable code in memory. */
/* Define the varible COMPILER to generate executable code. */
/* COMPILER must also be defined in PARSERA.ASM. */
/* Revision history: */
/* 15 Feb 1995 CAE */
/* added safety tests to pointer conversion code */
/* added the capability for functions to require 4 free regs */
/* 8 Feb 1995 CAE */
/* Comments changed. */
/* 8 Jan 1995 JCO */
/* Function fStkASin added to support new 'asin' function in v19 */
/* Function fStkASinh added to support new 'asinh' function in v19 */
/* Function fStkACos added to support new 'acos' function in v19 */
/* Function fStkACosh added to support new 'acosh' function in v19 */
/* Function fStkATan added to support new 'atan' function in v19 */
/* Function fStkATanh added to support new 'atanh' function in v19 */
/* Function fStkSqrt added to support new 'sqrt' function in v19 */
/* Function fStkCAbs added to support new 'cabs' function in v19 */
/* Added support for a third parameter p3 */
/* 31 Dec 1993 CAE */
/* Fixed optimizer bug discovered while testing compiler. */
/* 29 Dec 1993 CAE */
/* Added compiler. */
/* 04 Dec 1993 CAE */
/* Added optimizations for LodImagAdd/Sub/Mul. */
/* 06 Nov 1993 CAE */
/* Added optimizer support for LodRealPwr and ORClr2 functions. */
/* If stack top is a real, a simpler sqr() or mod() fn will be */
/* called (fStkSqr3() was added.) */
/* The identities x^0=1, x^1=x, and x^-1=recip(x) are now used by the */
/* optimizer. (fStkOne() was added for this.) */
/* 31 Oct 1993 CAE */
/* Optimizer converts '2*x' and 'x*2' to 'x+x'. */
/* " recognizes LastSqr as a real if not stored to. */
/* 9 Oct 1993 CAE */
/* Functions are now converted via table search. */
/* Added "real" stack count variable and debug msgs for stack size. */
/* Added optimizer extension for commutative multiply. */
/* P1, P2 will be treated as consts if they are never stored to. */
/* Function fStkStoClr2 now emitted for sto,clr with 2 on stack. */
/* " fStkZero added to support new 'zero' function in v18 */
/* Added optimization for x^2 -> sqr(x). */
/* Changed "stopmsg" to "DBUGMSG" and made all macros upper case. */
/* (debugflag=324 now needed for debug msgs to print.) */
/* 12 July 1993 (for v18.1) by CAE to fix optimizer bug */
/* 22 MAR 1993 (for Fractint v18.0) */
/* ******************************************************************* */
/* */
/* (c) Copyright 1992-1995 Chuck Ebbert. All rights reserved. */
/* */
/* This code may be freely distributed and used in non-commercial */
/* programs provided the author is credited either during program */
/* execution or in the documentation, and this copyright notice */
/* is left intact. Sale of this code, or its use in any commercial */
/* product requires permission from the author. Nominal */
/* distribution and handling fees may be charged by shareware and */
/* freeware distributors. */
/* */
/* ******************************************************************* */
/* Uncomment the next line to enable debug messages. */
/* --#define TESTFP 1 */
/* Use startup parameter "debugflag=324" to show debug messages after */
/* compiling with above #define uncommented. */
/* uncomment this to gen for compiler (IT WORKS!!!) */
/*#define COMPILER 1 */
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <time.h>
#ifndef XFRACT
#include <dos.h>
#endif
#include "fractint.h"
#include "mpmath.h"
#include "prototyp.h"
/* global data */
struct fls far *pfls = (struct fls far *)0;
#ifndef XFRACT /* -- */
/* not moved to PROTOTYPE.H because these only communicate within
PARSER.C and other parser modules */
extern union Arg *Arg1, *Arg2;
extern double _1_, _2_;
extern union Arg s[20], far * far *Store, far * far *Load;
extern int StoPtr, LodPtr, OpPtr;
extern unsigned vsp, LastOp;
extern struct ConstArg far *v;
extern int InitLodPtr, InitStoPtr, InitOpPtr, LastInitOp;
extern void (far * far *f)(void);
extern char far compiled_fn_1[];
extern char far compiled_fn_2[];
int fFormula(void);
typedef void OLD_FN(void); /* old C functions */
OLD_FN StkLod, StkClr, StkSto, EndInit;
OLD_FN dStkAdd, dStkSub, dStkMul, dStkDiv;
OLD_FN dStkSqr, dStkMod;
OLD_FN dStkSin, dStkCos, dStkSinh, dStkCosh, dStkCosXX;
OLD_FN dStkTan, dStkTanh, dStkCoTan, dStkCoTanh;
OLD_FN dStkLog, dStkExp, dStkPwr;
OLD_FN dStkLT, dStkLTE;
OLD_FN dStkFlip, dStkReal, dStkImag;
OLD_FN dStkConj, dStkNeg, dStkAbs;
OLD_FN dStkRecip, StkIdent;
OLD_FN dStkGT, dStkGTE, dStkNE, dStkEQ;
OLD_FN dStkAND, dStkOR;
OLD_FN dStkZero;
OLD_FN dStkSqrt;
OLD_FN dStkASin, dStkACos, dStkASinh, dStkACosh;
OLD_FN dStkATanh, dStkATan;
OLD_FN dStkCAbs;
typedef void (near NEW_FN)(void); /* new 387-only ASM functions */
NEW_FN fStkPull2; /* pull up fpu stack from 2 to 4 */
NEW_FN fStkPush2; /* push down fpu stack from 8 to 6 */
NEW_FN fStkPush2a; /* push down fpu stack from 6 to 4 */
NEW_FN fStkPush4; /* push down fpu stack from 8 to 4 */
NEW_FN fStkLodDup; /* lod, dup */
NEW_FN fStkLodSqr; /* lod, sqr, dont save magnitude(i.e. lastsqr) */
NEW_FN fStkLodSqr2; /* lod, sqr, save lastsqr */
NEW_FN fStkStoDup; /* store, duplicate */
NEW_FN fStkStoSqr; /* store, sqr, save lastsqr */
NEW_FN fStkStoSqr0; /* store, sqr, dont save lastsqr */
NEW_FN fStkLodDbl; /* load, double */
NEW_FN fStkStoDbl; /* store, double */
NEW_FN fStkReal2; /* fast ver. of real */
NEW_FN fStkSqr; /* sqr, save magnitude in lastsqr */
NEW_FN fStkSqr0; /* sqr, no save magnitude */
NEW_FN fStkClr1; /* clear fpu */
NEW_FN fStkClr2; /* test stack top, clear fpu */
NEW_FN fStkStoClr1; /* store, clr1 */
NEW_FN fStkAdd, fStkSub;
NEW_FN fStkSto, fStkSto2; /* fast ver. of sto */
NEW_FN fStkLod, fStkEndInit;
NEW_FN fStkMod, fStkMod2; /* faster mod */
NEW_FN fStkLodMod2, fStkStoMod2;
NEW_FN fStkLTE, fStkLodLTEMul, fStkLTE2, fStkLodLTE;
NEW_FN fStkLodLTE2, fStkLodLTEAnd2;
NEW_FN fStkLT, fStkLodLTMul, fStkLT2, fStkLodLT;
NEW_FN fStkLodLT2;
NEW_FN fStkGTE, fStkLodGTE, fStkLodGTE2;
NEW_FN fStkGT, fStkGT2, fStkLodGT, fStkLodGT2;
NEW_FN fStkEQ, fStkLodEQ, fStkNE, fStkLodNE;
NEW_FN fStkAND, fStkANDClr2, fStkOR, fStkORClr2;
NEW_FN fStkSin, fStkSinh, fStkCos, fStkCosh, fStkCosXX;
NEW_FN fStkTan, fStkTanh, fStkCoTan, fStkCoTanh;
NEW_FN fStkLog, fStkExp, fStkPwr;
NEW_FN fStkMul, fStkDiv;
NEW_FN fStkFlip, fStkReal, fStkImag, fStkRealFlip, fStkImagFlip;
NEW_FN fStkConj, fStkNeg, fStkAbs, fStkRecip;
NEW_FN fStkLodReal, fStkLodRealC, fStkLodImag;
NEW_FN fStkLodRealFlip, fStkLodRealAbs;
NEW_FN fStkLodRealMul, fStkLodRealAdd, fStkLodRealSub, fStkLodRealPwr;
NEW_FN fStkLodImagMul, fStkLodImagAdd, fStkLodImagSub; /* CAE 4Dec93 */
NEW_FN fStkLodImagFlip, fStkLodImagAbs;
NEW_FN fStkLodConj;
NEW_FN fStkLodAdd, fStkLodSub, fStkLodSubMod, fStkLodMul;
NEW_FN fStkPLodAdd, fStkPLodSub; /* push-lod-add/sub */
NEW_FN fStkIdent;
NEW_FN fStkStoClr2; /* store, clear stack by popping */
NEW_FN fStkZero; /* to support new parser fn. */
NEW_FN fStkDbl; /* double the stack top CAE 31OCT93 */
NEW_FN fStkOne, fStkSqr3; /* sqr3 is sqr/mag of a real CAE 09NOV93 */
NEW_FN fStkSqrt;
NEW_FN fStkASin, fStkACos, fStkASinh, fStkACosh;
NEW_FN fStkATanh, fStkATan;
NEW_FN fStkCAbs;
/* check to see if a const is being loaded */
/* the really awful hack below gets the first char of the name */
/* of the variable being accessed */
/* if first char not alpha, or const p1, p2, or p3 are being accessed */
/* then this is a const. */
#define IS_CONST(x) \
(!isalpha(**(((char * far *)x ) - 2 ) ) \
|| (x==&PARM1 && p1const ) \
|| (x==&PARM2 && p2const ) \
|| (x==&PARM3 && p3const ) )
/* is stack top a real? */
#define STACK_TOP_IS_REAL \
( prevfptr == fStkReal || prevfptr == fStkReal2 \
|| prevfptr == fStkLodReal || prevfptr == fStkLodRealC \
|| prevfptr == fStkLodRealAbs \
|| prevfptr == fStkImag || prevfptr == fStkLodImag )
/* remove push operator from stack top */
#define REMOVE_PUSH --cvtptrx, stkcnt+=2
#define CLEAR_STK 127
#define FNPTR(x) pfls[(x)].function /* function pointer */
#define OPPTR(x) pfls[(x)].operand /* operand pointer */
#define NO_OPERAND (union Arg near *)0
#define NO_FUNCTION (void (near *)(void))0
#define LASTSQR v[4].a
#define PARM1 v[1].a
#define PARM2 v[2].a
#define PARM3 v[8].a
#define MAX_ARGS 100 /* maximum memory variables */
#define MAX_STACK 8 /* max # of stack register avail */
#ifdef TESTFP
#define DBUGMSG(x,y) if (debugflag==324 ) stopmsg((x), (y) )
#define DBUGMSG1(x,y,p) \
if (debugflag==324 ){ \
sprintf(cDbgMsg, (y), (p) ); \
stopmsg((x), cDbgMsg ); \
}
#define DBUGMSG2(x,y,p,q) \
if (debugflag==324 ){ \
sprintf(cDbgMsg, (y), (p), (q) ); \
stopmsg((x), cDbgMsg ); \
}
#define DBUGMSG3(x,y,p,q,r) \
if (debugflag==324 ){ \
sprintf(cDbgMsg, (y), (p), (q), (r) ); \
stopmsg((x), cDbgMsg ); \
}
#define DBUGMSG4(x,y,p,q,r,s) \
if (debugflag==324 ){ \
sprintf(cDbgMsg, (y), (p), (q), (r), (s) ); \
stopmsg((x), cDbgMsg ); \
}
#else
#define DBUGMSG(x,y)
#define DBUGMSG1(x,y,p)
#define DBUGMSG2(x,y,p,q)
#define DBUGMSG3(x,y,p,q,r)
#define DBUGMSG4(x,y,p,q,r,s)
#endif /* TESTFP */
#define FN_LOD 0
#define FN_CLR 1
#define FN_ADD 2
#define FN_SUB 3
#define FN_MUL 4
#define FN_DIV 5
#define FN_STO 6
#define FN_SQR 7
#define FN_ENDINIT 8
#define FN_MOD 9
#define FN_LTE 10
#define FN_SIN 11
#define FN_COS 12
#define FN_SINH 13
#define FN_COSH 14
#define FN_COSXX 15
#define FN_TAN 16
#define FN_TANH 17
#define FN_COTAN 18
#define FN_COTANH 19
#define FN_LOG 20
#define FN_EXP 21
#define FN_PWR 22
#define FN_LT 23
#define FN_FLIP 24
#define FN_REAL 25
#define FN_IMAG 26
#define FN_CONJ 27
#define FN_NEG 28
#define FN_ABS 29
#define FN_RECIP 30
#define FN_IDENT 31
#define FN_GT 32
#define FN_GTE 33
#define FN_NE 34
#define FN_EQ 35
#define FN_AND 36
#define FN_OR 37
#define FN_ZERO 38
#define FN_SQRT 39
#define FN_ASIN 40
#define FN_ACOS 41
#define FN_ASINH 42
#define FN_ACOSH 43
#define FN_ATANH 44
#define FN_ATAN 45
#define FN_CABS 46
/* number of "old" functions in the table. */
/* these are the ones that the parser outputs */
#define LAST_OLD_FN FN_CABS
#define NUM_OLD_FNS LAST_OLD_FN + 1
/* total number of functions in the table. */
#define LAST_FN FN_CABS
#define NUM_FNS LAST_FN + 1
static unsigned char
realstkcnt, /* how many scalars are really on stack */
stkcnt, /* # scalars on FPU stack */
cvtptrx, /* subscript of next free entry in pfls */
lastsqrused, /* was lastsqr loaded in the formula? */
lastsqrreal, /* was lastsqr stored explicitly in the formula? */
p1const, /* is p1 a constant? */
p2const, /* ...and p2? */
p3const; /* ...and p3? */
static void (near *prevfptr )(void); /* previous function pointer */
/* the entries in this table must be in the same order as */
/* the #defines above */
/* this table is searched sequentially */
struct fn_entry {
char far *fname; /* function name */
void (far *infn)(void); /* 'old' function pointer */
/* (infn points to an operator fn in parser.c) */
void (near *outfn)(void); /* pointer to equiv. fast fn. */
char min_regs; /* min regs needed on stack by this fn. */
/* (legal values are 0, 2, 4) */
char free_regs; /* free regs required by this fn */
/* (legal values are 0, 2, 4) */
char delta; /* net change to # of values on the fp stack */
/* (legal values are -2, 0, +2) */
} static far afe[NUM_OLD_FNS] = { /* array of function entries */
{"Lod", StkLod, fStkLod, 0, 2, +2 }, /* 0 */
{"Clr", StkClr, fStkClr1, 0, 0, CLEAR_STK }, /* 1 */
{"+", dStkAdd, fStkAdd, 4, 0, -2 }, /* 2 */
{"-", dStkSub, fStkSub, 4, 0, -2 }, /* 3 */
{"*", dStkMul, fStkMul, 4, 2, -2 }, /* 4 */
{"/", dStkDiv, fStkDiv, 4, 2, -2 }, /* 5 */
{"Sto", StkSto, fStkSto, 2, 0, 0 }, /* 6 */
{"Sqr", dStkSqr, fStkSqr, 2, 2, 0 }, /* 7 */
{":", EndInit, fStkEndInit,0, 0, CLEAR_STK }, /* 8 */
{"Mod", dStkMod, fStkMod, 2, 0, 0 }, /* 9 */
{"<=", dStkLTE, fStkLTE, 4, 0, -2 }, /* 10 */
{"Sin", dStkSin, fStkSin, 2, 2, 0 }, /* 11 */
{"Cos", dStkCos, fStkCos, 2, 2, 0 }, /* 12 */
{"Sinh", dStkSinh, fStkSinh, 2, 2, 0 }, /* 13 */
{"Cosh", dStkCosh, fStkCosh, 2, 2, 0 }, /* 14 */
{"Cosxx", dStkCosXX, fStkCosXX, 2, 2, 0 }, /* 15 */
{"Tan", dStkTan, fStkTan, 2, 2, 0 }, /* 16 */
{"Tanh", dStkTanh, fStkTanh, 2, 2, 0 }, /* 17 */
{"CoTan", dStkCoTan, fStkCoTan, 2, 2, 0 }, /* 18 */
{"CoTanh", dStkCoTanh, fStkCoTanh, 2, 2, 0 }, /* 19 */
{"Log", dStkLog, fStkLog, 2, 2, 0 }, /* 20 */
{"Exp", dStkExp, fStkExp, 2, 2, 0 }, /* 21 */
{"^", dStkPwr, fStkPwr, 4, 2, -2 }, /* 22 */
{"<", dStkLT, fStkLT, 4, 0, -2 }, /* 23 */
{"Flip", dStkFlip, fStkFlip, 2, 0, 0 }, /* 24 */
{"Real", dStkReal, fStkReal, 2, 0, 0 }, /* 25 */
{"Imag", dStkImag, fStkImag, 2, 0, 0 }, /* 26 */
{"Conj", dStkConj, fStkConj, 2, 0, 0 }, /* 27 */
{"Neg", dStkNeg, fStkNeg, 2, 0, 0 }, /* 28 */
{"Abs", dStkAbs, fStkAbs, 2, 0, 0 }, /* 29 */
{"Recip", dStkRecip, fStkRecip, 2, 2, 0 }, /* 30 */
{"Ident", StkIdent, fStkIdent, 2, 0, 0 }, /* 31 */
{">", dStkGT, fStkGT, 4, 0, -2 }, /* 32 */
{">=", dStkGTE, fStkGTE, 4, 0, -2 }, /* 33 */
{"!=", dStkNE, fStkNE, 4, 0, -2 }, /* 34 */
{"==", dStkEQ, fStkEQ, 4, 0, -2 }, /* 35 */
{"&&", dStkAND, fStkAND, 4, 0, -2 }, /* 36 */
{"||", dStkOR, fStkOR, 4, 0, -2 }, /* 37 */
{"Zero", dStkZero, fStkZero, 2, 0, 0 }, /* 38 */
{"Sqrt", dStkSqrt, fStkSqrt, 2, 2, 0 }, /* 39 */
{"ASin", dStkASin, fStkASin, 2, 4, 0 }, /* 40 */
{"ACos", dStkACos, fStkACos, 2, 4, 0 }, /* 41 */
{"ASinh", dStkASinh, fStkASinh, 2, 4, 0 }, /* 42 */
{"ACosh", dStkACosh, fStkACosh, 2, 4, 0 }, /* 43 */
{"ATanh", dStkATanh, fStkATanh, 2, 4, 0 }, /* 44 */
{"ATan", dStkATan, fStkATan, 2, 4, 0 }, /* 45 */
{"CAbs", dStkCAbs, fStkCAbs, 2, 0, 0 } /* 46 */
};
#ifdef COMPILER
struct fn_header {
unsigned int fn_size; /* size of function code in bytes */
char near *pcode; /* pointer to actual code */
char near *incl_addr; /* addr of included fn (offset from seg base) */
char x_fixup; /* offset of any x fixup (-1 if none) */
char y_fixup; /* " " " y " " " " */
char incl_offset; /* " " included fn. " " " */
};
#endif /* COMPILER */
#ifdef TESTFP
static char cDbgMsg[255];
#endif /* TESTFP */
#ifdef COMPILER
static int near fIncl_fn(char far *pcIncl, char far *pcTarget ){
int i, iIncl_len = *(int far *)pcIncl & 0x007f; /* max 127 */
for (i=0, pcIncl+=2; i<iIncl_len; i++ ){
*pcTarget++ = *pcIncl++;
}
return iIncl_len;
}
static int near fNormal_fn(struct fn_header far *psIn, char far *pcTarget,
char near *npcOperand ){
int i; /* temp loop variable (offset into src fn) */
int iBytesCopied; /* another temp */
int iCount = 0; /* count of bytes copied to target */
long lSegment = (long)compiled_fn_1 & 0xFFFF0000L;
int iCodeSize = psIn->fn_size & 0x007f; /* max 127 bytes */
char far *pcCode;
pcCode = (char far *)((long)lSegment | (int)(psIn->pcode) );
for (i=0; i<iCodeSize; i++){
if (i == psIn->incl_offset ){
DBUGMSG(0, "Including a function" );
if (*pcCode == -1 ){ /* sanity check */
iBytesCopied = fIncl_fn(
(char far *)(lSegment | (unsigned int)(psIn->incl_addr )),
pcTarget );
pcTarget += iBytesCopied;
pcCode++; /* to skip 1-byte placeholder */
iCount += iBytesCopied;
}
else {
DBUGMSG(0, "Unexpected error, incl_placeholder != -1" );
}
}
else if (i == psIn->x_fixup || i == psIn->y_fixup ){
if (i == psIn->x_fixup ){
DBUGMSG(0, "X fixup" );
*(char near * far *)pcTarget = npcOperand;
}
else {
DBUGMSG(0, "Y fixup" );
*(char near * far *)pcTarget = npcOperand + sizeof(double);
}
pcTarget+=2, pcCode+=2; /* two bytes copied from src to target */
i++; /* two bytes were taken from source instead of one */
iCount += 2;
}
else {
*pcTarget++ = *pcCode++;
iCount++;
}
}
return iCount;
}
static void near fCompile(void){
int i;
struct fn_header far *pfnh;
long lSegment = (long)compiled_fn_1 & 0xFFFF0000L;
char far *pcTarget;
for (i=0,pcTarget=compiled_fn_1; i<cvtptrx; i++ ){
pfnh = (struct fn_header far *)
(lSegment | (unsigned int)(pfls[i].function));
if (pfnh->fn_size & 0x8000 ){
/* Normal function */
pcTarget += fNormal_fn(pfnh, pcTarget, (char near *)pfls[i].operand );
}
else {
pcTarget += fIncl_fn((char far *)pfnh, pcTarget );
}
if (pfls[i].function == fStkEndInit ){
*pcTarget++ = '\xC3'; /* opcode for near return */
break;
}
}
for (i++,pcTarget=compiled_fn_2; i<cvtptrx; i++ ){
pfnh = (struct fn_header far *)
(lSegment | (unsigned int)(pfls[i].function));
if (pfnh->fn_size & 0x8000 ){
pcTarget +=
fNormal_fn(pfnh, pcTarget, (char near *)pfls[i].operand );
}
else {
pcTarget += fIncl_fn((char far *)pfnh, pcTarget );
}
}
*pcTarget++ = '\xC3'; /* near return at end of fn */
return;
}
#endif /* COMPILER */
static int CvtFptr(void (near * ffptr)(void), int MinStk, int FreeStk,
int Delta )
{
union Arg near *otemp; /* temp operand ptr */
union Arg far *testload;
#ifdef TESTFP
int prevstkcnt;
#endif
double dTemp;
int Max_On_Stack = MAX_STACK - FreeStk; /* max regs allowed on stack */
int Num_To_Push; /* number of regs to push */
/* first do some sanity checks */ /* CAE 15Feb95 */
if ( (Delta != -2 && Delta != 0 && Delta != 2 && Delta != CLEAR_STK)
|| (FreeStk != 0 && FreeStk != 2 && FreeStk != 4)
|| (MinStk != 0 && MinStk != 2 && MinStk != 4) ){
awful_error:
stopmsg (0,"FATAL INTERNAL PARSER ERROR!");
return 0; /* put out dire message and revert to old parser */
}
/* this if statement inserts a stack push or pull into the token array */
/* it would be much better to do this *after* optimization */
if ((int)stkcnt < MinStk ) { /* not enough operands on fpu stack */
DBUGMSG2(0, "Inserted pull. Stack: %2d --> %2d", stkcnt, stkcnt+2 );
OPPTR(cvtptrx) = NO_OPERAND;
FNPTR(cvtptrx++) = fStkPull2; /* so adjust the stack, pull operand */
stkcnt += 2;
}
else if ((int)stkcnt > Max_On_Stack ) { /* too many operands */
Num_To_Push = stkcnt - Max_On_Stack;
if (Num_To_Push == 2 ){
if (stkcnt == MAX_STACK ){
/* push stack down from max to max-2 */
FNPTR(cvtptrx) = fStkPush2;
}
else if (stkcnt == MAX_STACK - 2 ){
/* push stack down from max-2 to max-4 */
FNPTR(cvtptrx) = fStkPush2a;
}
else {
goto awful_error;
}
DBUGMSG2(0,
"Inserted push. Stack: %2d --> %2d", stkcnt, stkcnt-2 );
OPPTR(cvtptrx++) = NO_OPERAND;
stkcnt -= 2;
}
else if (Num_To_Push == 4 ){
/* push down from max to max-4 */
FNPTR(cvtptrx) = fStkPush4;
DBUGMSG2(0,
"Inserted push. Stack: %2d --> %2d", stkcnt, stkcnt-4 );
OPPTR(cvtptrx++) = NO_OPERAND;
stkcnt -= 4;
}
else {
goto awful_error;
}
}
/* set the operand pointer here for store function */
if (ffptr == fStkSto ){
OPPTR(cvtptrx) = (void near *)FP_OFF((Store[StoPtr++]));
}
else if (ffptr == fStkLod && debugflag == 322 ){
/* when disabling optimizer, set load pointer here */
OPPTR(cvtptrx) = (void near *)FP_OFF((Load[LodPtr++]));
}
else { /* the optimizer will set the pointer for load fn. */
OPPTR(cvtptrx) = NO_OPERAND;
}
if (debugflag == 322 ){
goto SkipOptimizer;
} /* -------------------------- begin optimizer --------------------- */
/* This optimizer grew from a simple if statement into a monster. */
/* Most of the bugs in the optimizer have been in the code that */
/* juggles the overflow stack. */
/* For the following: */
/* * == cvtptrx points to this */
/* () == this is about to be added to the array */
/* ******************************************************************** */
if (ffptr == fStkLod) { /* about to add Lod to the array */
if (prevfptr == fStkLod && Load[LodPtr-1] == Load[LodPtr] ) {
/* previous non-adjust operator was Lod of same operand */
/* ? lodx ? (*lodx) */
if (FNPTR(--cvtptrx) == fStkPush2 ){ /* prev fn was push */
/* ? lod *push (lod) */
--cvtptrx; /* found *lod push (lod) */
if (FNPTR(cvtptrx-1) == fStkPush2){ /* always more ops here */
DBUGMSG(0, "push *lod push (lod) -> push4 (*loddup)" );
FNPTR(cvtptrx-1) = fStkPush4;
}
else { /* prev op not push */
DBUGMSG(0, "op *lod push (lod) -> op pusha(p=0) (*loddup)" );
OPPTR(cvtptrx) = NO_OPERAND; /* use 'alternate' push fn. */
FNPTR(cvtptrx++) = fStkPush2a; /* push w/2 free on stack */
/* operand ptr will be set below */
}
}
else { /* never push *lod (lod) so must be */
DBUGMSG(0, "op *lod (lod) -> op (*loddup)" );
}
ffptr = fStkLodDup;
}
else if (prevfptr == fStkSto2
&& Store[StoPtr-1] == Load[LodPtr] ){
/* store, load of same value */
/* only one operand on stack here when prev oper is Sto2 */
DBUGMSG(0, "*sto2 (lod) -> (*stodup)" );
--cvtptrx;
ffptr = fStkStoDup;
}
/* This may cause roundoff problems when later operators */
/* use the rounded value that was stored here, while the next */
/* operator uses the more accurate internal value. */
else if (prevfptr == fStkStoClr2
&& Store[StoPtr-1] == Load[LodPtr] ){
/* store, clear, load same value found */
/* only one operand was on stack so this is safe */
DBUGMSG (0, "*StoClr2 (Lod) -> (*Sto2)" );
--cvtptrx;
ffptr = fStkSto2; /* use different Sto fn */
}
else {
testload = Load[LodPtr];
if (testload == &LASTSQR && lastsqrreal ){
/* -- LastSqr is a real. CAE 31OCT93 */
DBUGMSG(0, "(*lod[lastsqr]) -> (*lodreal)" );
ffptr = fStkLodReal;
}
else if (IS_CONST(testload) && testload->d.y == 0.0 ){
DBUGMSG(0, "(*lod) -> (*lodrealc)" );
ffptr = fStkLodRealC; /* a real const is being loaded */
}
}
/* set the operand ptr here */
OPPTR(cvtptrx) = (void near *)FP_OFF((Load[LodPtr++]));
}
/* ******************************************************************** */
else if (ffptr == fStkAdd ){
if (prevfptr == fStkLodDup ){ /* there is never a push before add */
--cvtptrx; /* found ? *loddup (add) */
if (cvtptrx!=0 && FNPTR(cvtptrx-1) == fStkPush2a ){
/* because push lod lod is impossible so is push loddup */
DBUGMSG(0, "pusha *loddup (add) -> (*loddbl),stk+=2" );
REMOVE_PUSH;
OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptr */
}
else if (cvtptrx!=0 && FNPTR(cvtptrx-1) == fStkPush4 ){
DBUGMSG(0, "push4 *loddup (add) -> push2 (*loddbl),stk+=2" );
FNPTR(cvtptrx-1) = fStkPush2;
stkcnt += 2; /* CAE added 12 July 1993 to fix bug */
}
else {
DBUGMSG(0, "op *loddup (add) -> op (*loddbl)" );
}
ffptr = fStkLodDbl;
}
else if (prevfptr == fStkStoDup ){
DBUGMSG(0, "stodup (*add) -> (*stodbl)" );
/* there are always exactly 4 on stack here */
--cvtptrx;
ffptr = fStkStoDbl;
}
else if (prevfptr == fStkLod ){ /* have found lod (*add) */
--cvtptrx; /* ? *lod (add) */
if (FNPTR(cvtptrx-1) == fStkPush2 ){
DBUGMSG(0, "*push load (add) -> (*plodadd),stk+=2" );
REMOVE_PUSH;
OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */
ffptr = fStkPLodAdd;
}
else {
DBUGMSG(0, "op *lod (add) -> op (*lodadd)" );
ffptr = fStkLodAdd;
}
}
else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
--cvtptrx; /* found ? *lodreal (add) */
if (FNPTR(cvtptrx-1) == fStkPush2 ){
DBUGMSG(0, "*push lodreal (add) -> (*lodrealadd),stk+=2" );
REMOVE_PUSH;
OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */
}
else {
DBUGMSG(0, "*lodreal (add) -> (*lodrealadd)" );
}
ffptr = fStkLodRealAdd;
}
else if (prevfptr == fStkLodImag ){ /* CAE 4DEC93 */
--cvtptrx; /* found ? *lodimag (add) */
if (FNPTR(cvtptrx-1) == fStkPush2 ){
DBUGMSG(0, "*push lodimag (add) -> (*lodimagadd),stk+=2" );
REMOVE_PUSH;
OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */
}
else {
DBUGMSG(0, "*lodimag (add) -> (*lodimagadd)" );
}
ffptr = fStkLodImagAdd;
}
}
/* ******************************************************************** */
else if (ffptr == fStkSub ){
if (prevfptr == fStkLod ){
/* found lod (*sub) */
--cvtptrx; /* *lod (sub) */
/* there is never a sequence (lod push sub ) */
if (FNPTR(cvtptrx-1) == fStkPush2 ){
DBUGMSG(0, "*push lod (sub) -> (*plodsub),stk+=2" );
REMOVE_PUSH;
OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */
ffptr = fStkPLodSub;
}
else {
DBUGMSG(0, "*lod (sub) -> (*lodsub)" );
ffptr = fStkLodSub;
}
}
else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
--cvtptrx; /* ? *lodreal (sub) */
if (FNPTR(cvtptrx-1) == fStkPush2 ){
DBUGMSG(0, "*push lodreal (sub) -> (*lodrealsub),stk+=2" );
REMOVE_PUSH;
OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */
}
else {
DBUGMSG(0, "*lodreal (sub) -> (*lodrealsub)" );
}
ffptr = fStkLodRealSub;
}
else if (prevfptr == fStkLodImag ){ /* CAE 4DEC93 */
--cvtptrx; /* ? *lodimag (sub) */
if (FNPTR(cvtptrx-1) == fStkPush2 ){
DBUGMSG(0, "*push lodimag (sub) -> (*lodimagsub),stk+=2" );
REMOVE_PUSH;
OPPTR(cvtptrx) = OPPTR(cvtptrx+1); /* fix opptrs */
}
else {
DBUGMSG(0, "*lodimag (sub) -> (*lodimagsub)" );
}
ffptr = fStkLodImagSub;
}
}
/* ******************************************************************** */
else if (ffptr == fStkMul ){
if (prevfptr == fStkLodDup ){
/* found loddup ? (*mul) */
if (FNPTR(--cvtptrx) == fStkPush2 ){
DBUGMSG(0, "loddup *push (mul) -> (*lodsqr),stk+=2" );
REMOVE_PUSH;
}
else {
DBUGMSG(0, "*loddup (mul) -> (*lodsqr)" );
}
ffptr = fStkLodSqr;
}
else if (prevfptr == fStkStoDup ){ /* no pushes here, 4 on stk. */
DBUGMSG(0, "stodup (mul) -> (*stosqr0)" );
--cvtptrx;
ffptr = fStkStoSqr0; /* dont save lastsqr here ever */
}
else if (prevfptr == fStkLod ){
--cvtptrx; /* lod *? (mul) */
if (FNPTR(cvtptrx) == fStkPush2 ){ /* lod *push (mul) */
--cvtptrx; /* ? *lod push (mul) */
if(FNPTR(cvtptrx-1) == fStkPush2 ){
DBUGMSG(0, "push *lod push (mul) -> push4 (*lodmul)" );
FNPTR(cvtptrx-1) = fStkPush4;
}
else {
DBUGMSG(0, "op *lod push (mul) -> op pusha (*lodmul)" );
OPPTR(cvtptrx+1) = OPPTR(cvtptrx); /* fix operand ptr */
FNPTR(cvtptrx) = fStkPush2a;
OPPTR(cvtptrx) = NO_OPERAND;
cvtptrx++;
}
}
else {
DBUGMSG(0, "*lod (mul) -> (*lodmul)" );
}
ffptr = fStkLodMul;
/********************** begin extension *** CAE 9 Oct 93 ****/
/* change loadreal a, lodmul b --> lod b, lodrealmul a */
FNPTR(cvtptrx) = NO_FUNCTION; /* mark the pending fn as null */
if (FNPTR(cvtptrx-1) == fStkPush4
|| FNPTR(cvtptrx-1) == fStkPush2a ){
--cvtptrx; /* look back past this push */
}
if (FNPTR(cvtptrx-1) == fStkLodRealC
&& Load[LodPtr-2]->d.x == _2_ ){
/* -- Convert '2*a' into 'a+a'. CAE 31OCT93 */
if (FNPTR(cvtptrx) == NO_FUNCTION ){
DBUGMSG(0, "lodreal[2] (*lodmul[b])"
" -> (*loddbl[b])" );
OPPTR(cvtptrx-1) = OPPTR(cvtptrx);
}
else if (FNPTR(cvtptrx) == fStkPush2a ){
DBUGMSG(0, "lodreal[2] *pusha (lodmul[b])"
" -> loddbl[b],stk+=2" );
OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1);
stkcnt += 2;
}
else if (FNPTR(cvtptrx) == fStkPush4 ){
DBUGMSG(0, "lodreal[2] *push4 (lodmul[b])"
" -> loddbl[b],stk+=4" );
OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1);
stkcnt += 4;
}
FNPTR(--cvtptrx) = NO_FUNCTION; /* so no increment later */
ffptr = fStkLodDbl;
}
else if (FNPTR(cvtptrx-1) == fStkLodReal
|| FNPTR(cvtptrx-1) == fStkLodRealC ){
/* lodreal *?push?? (*?lodmul) */
otemp = OPPTR(cvtptrx-1); /* save previous fn's operand */
FNPTR(cvtptrx-1) = fStkLod; /* prev fn = lod */
/* Moved setting of prev lodptr to below CAE 31DEC93 */
/* This was a bug causing a bad loadptr to be set here */
/* 3 lines marked 'prev lodptr=this' below replace this line */
if (FNPTR(cvtptrx) == NO_FUNCTION ){
DBUGMSG(0, "lodreal[a] (*lodmul[b])"
" -> lod[b] (*lodrealmul[a])" );
OPPTR(cvtptrx-1) = OPPTR(cvtptrx); /* prev lodptr=this */
}
else if (FNPTR(cvtptrx) == fStkPush2a ){
DBUGMSG(0, "lodreal[a] *pusha (lodmul[b])"
" -> lod[b] (*lodrealmul[a]),stk+=2" );
/* set this fn ptr to null so cvtptrx won't be incr later */
FNPTR(cvtptrx) = NO_FUNCTION;
OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1); /* prev lodptr=this */
stkcnt += 2;
}
else if (FNPTR(cvtptrx) == fStkPush4 ){
DBUGMSG(0, "lodreal[a] *push4 (lodmul[b])"
" -> lod[b] push2 (*lodrealmul[a]),stk+=2" );
FNPTR(cvtptrx++) = fStkPush2;
OPPTR(cvtptrx-2) = OPPTR(cvtptrx); /* prev lodptr=this */
/* we know cvtptrx points to a null function now */
stkcnt += 2;
}
OPPTR(cvtptrx) = otemp; /* switch the operands */
ffptr = fStkLodRealMul; /* next fn is now lodrealmul */
}
if (FNPTR(cvtptrx) != NO_FUNCTION ){
cvtptrx++; /* adjust cvtptrx back to normal if needed */
}
/* ********************** end extension *********************** */
}
else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
--cvtptrx; /* found lodreal *? (mul) */
if (FNPTR(cvtptrx) == fStkPush2 ){
DBUGMSG(0, "lodreal *push2 (mul) -> (*lodrealmul),stk+=2" );
REMOVE_PUSH;
}
else {
DBUGMSG(0, "*lodreal (mul) -> (*lodrealmul)" );
}
ffptr = fStkLodRealMul;
/********************** begin extension *** CAE 31OCT93 ****/
if (prevfptr == fStkLodRealC /* use prevfptr here */
&& Load[LodPtr-1]->d.x == _2_ ){
if (FNPTR(cvtptrx) == fStkPush2 ){
DBUGMSG(0, "push (*lodrealmul[2]) -> (*dbl),stk+=2" );
REMOVE_PUSH;
}
else {
DBUGMSG(0, "*lodrealmul[2] -> (*dbl)" );
}
OPPTR(cvtptrx) = NO_OPERAND;
ffptr = fStkDbl;
if (FNPTR(cvtptrx-1) == fStkLod ){
DBUGMSG(0, "lod (*dbl) -> (*loddbl)" );
--cvtptrx;
ffptr = fStkLodDbl;
}
else if (FNPTR(cvtptrx-1) == fStkSto2 ){
DBUGMSG(0, "sto2 (*dbl) -> (*stodbl)" );
--cvtptrx;
ffptr = fStkStoDbl;
}
}
/************************ end extension *** CAE 31OCT93 ****/
}
else if (prevfptr == fStkLodImag ){ /* CAE 4DEC93 */
--cvtptrx; /* found lodimag *? (mul) */
if (FNPTR(cvtptrx) == fStkPush2 ){
DBUGMSG(0, "lodimag *push2 (mul) -> (*lodimagmul),stk+=2" );
REMOVE_PUSH;
}
else {
DBUGMSG(0, "*lodimag (mul) -> (*lodimagmul)" );
}
ffptr = fStkLodImagMul;
}
else if (prevfptr == fStkLodLT && FNPTR(cvtptrx-1) != fStkPull2 ){
/* this shortcut fails if Lod LT Pull Mul found */
DBUGMSG(0, "LodLT (*Mul) -> (*LodLTMul)" );
--cvtptrx; /* never lod LT Push Mul here */
ffptr = fStkLodLTMul;
}
else if (prevfptr == fStkLodLTE && FNPTR(cvtptrx-1) != fStkPull2 ){
DBUGMSG(0, "LodLTE (*mul) -> (*LodLTEmul)" );
--cvtptrx;
ffptr = fStkLodLTEMul;
}
}
/* ******************************************************************** */
else if (ffptr == fStkClr1 && prevfptr == fStkSto ){
--cvtptrx;
if (stkcnt == 2 ){
DBUGMSG(0, "sto (*clr1) -> (*stoclr2)" );
ffptr = fStkStoClr2;
}
else {
DBUGMSG(0, "sto (*clr1) -> (*stoclr1)" );
ffptr = fStkStoClr1;
}
}
/* ******************************************************************** */
else if (ffptr == fStkDiv ){
if (prevfptr == fStkLodRealC && vsp < MAX_ARGS - 1 ){
/* have found a divide by a real constant */
/* and there is space to create a new one */
/* lodrealc ? (*div) */
if (FNPTR(--cvtptrx) == fStkPush2 ){
DBUGMSG(0, "lodrealc *push (div) -> (*lodrealmul),stk+=2" );
REMOVE_PUSH;
}
else {
DBUGMSG(0, "*lodrealc (div) -> (*lodrealmul)" );
}
v[vsp].s = (void near *)0; /* this constant has no name */
v[vsp].len = 0;
v[vsp].a.d.x = _1_ / Load[LodPtr-1]->d.x;
v[vsp].a.d.y = 0.0;
{
void far *p = &v[vsp++].a;
OPPTR(cvtptrx) = (void near *)FP_OFF(p); /* isn't C fun! */
}
ffptr = fStkLodRealMul;
}
}
/* ******************************************************************** */
else if (ffptr == fStkReal ){
if (prevfptr == fStkLod ){
DBUGMSG(0, "lod (*real) -> (*lodreal)" );
--cvtptrx;
ffptr = fStkLodReal;
}
else if (stkcnt < MAX_STACK ){
DBUGMSG(0, "(*real) -> (*real2)" );
ffptr = fStkReal2;
}
}
/* ******************************************************************** */
else if (ffptr == fStkImag && prevfptr == fStkLod ){
DBUGMSG(0, "lod (*imag) -> lodimag" );
--cvtptrx;
ffptr = fStkLodImag;
}
/* ******************************************************************** */
else if (ffptr == fStkConj && prevfptr == fStkLod ){
DBUGMSG(0, "lod (*conj) -> (*lodconj)" );
--cvtptrx;
ffptr = fStkLodConj;
}
/* ******************************************************************** */
else if (ffptr == fStkMod && stkcnt < MAX_STACK ){
DBUGMSG(0, "(*mod) -> (*mod2)" );
ffptr = fStkMod2; /* use faster version if room on stack */
if (prevfptr == fStkLod ){
DBUGMSG(0, "lod (*mod2) -> (*lodmod2)" );
--cvtptrx;
ffptr = fStkLodMod2;
}
else if (prevfptr == fStkSto || prevfptr == fStkSto2 ){
DBUGMSG(0, "sto (*mod2) -> (*stomod2)" );
--cvtptrx;
ffptr = fStkStoMod2;
}
else if (prevfptr == fStkLodSub ){
DBUGMSG(0, "lodsub (*mod2) -> (*lodsubmod)" );
--cvtptrx;
ffptr = fStkLodSubMod;
}
else if (STACK_TOP_IS_REAL){ /* CAE 06NOV93 */
DBUGMSG(0, "(*mod2[st real]) -> (*sqr3)" );
ffptr = fStkSqr3;
}
}
/* ******************************************************************** */
else if (ffptr == fStkFlip ){
if (prevfptr == fStkReal || prevfptr == fStkReal2 ){
DBUGMSG(0, "real (*flip) -> (*realflip)" );
--cvtptrx;
ffptr = fStkRealFlip;
}
else if (prevfptr == fStkImag ){
DBUGMSG(0, "imag (*flip) -> (*imagflip)" );
--cvtptrx;
ffptr = fStkImagFlip;
}
else if (prevfptr == fStkLodReal ){
DBUGMSG(0, "lodreal (*flip) -> (*lodrealflip)" );
--cvtptrx;
ffptr = fStkLodRealFlip;
}
else if (prevfptr == fStkLodImag ){
DBUGMSG(0, "lodimag (*flip) -> (*lodimagflip)" );
--cvtptrx;
ffptr = fStkLodImagFlip;
}
}
/* ******************************************************************** */
else if (ffptr == fStkAbs ){
if (prevfptr == fStkLodReal ){
DBUGMSG(0, "lodreal (*abs) -> (*lodrealabs)" );
--cvtptrx;
ffptr = fStkLodRealAbs;
}
else if (prevfptr == fStkLodImag ){
DBUGMSG(0, "lodimag (*abs) -> (*lodimagabs)" );
--cvtptrx;
ffptr = fStkLodImagAbs;
}
}
/* ******************************************************************** */
else if (ffptr == fStkSqr ){
if (prevfptr == fStkLod && FNPTR(cvtptrx-1) != fStkPush2 ){
DBUGMSG(0, "lod (*sqr) -> (*lodsqr)" );
--cvtptrx;
ffptr = fStkLodSqr; /* assume no need to save lastsqr */
if (lastsqrused){
DBUGMSG(0, "(*lodsqr) -> (*lodsqr2)" );
ffptr = fStkLodSqr2; /* lastsqr is being used */
}
}
else if (prevfptr == fStkSto2 ){
DBUGMSG(0, "sto2 (*sqr) -> (*stosqr0)" );
--cvtptrx;
ffptr = fStkStoSqr0; /* assume no need to save lastsqr */
if (lastsqrused) {
DBUGMSG(0, "(*stosqr0) -> (*stosqr)" );
ffptr = fStkStoSqr; /* save lastsqr */
}
}
else {
if (!lastsqrused) {
DBUGMSG(0, "(*sqr) -> (*sqr0)" );
ffptr = fStkSqr0; /* don't save lastsqr */
if (STACK_TOP_IS_REAL){ /* CAE 06NOV93 */
DBUGMSG(0, "(*sqr0[st real]) -> (*sqr3)" );
ffptr = fStkSqr3;
}
}
}
}
/* ******************************************************************** */
else if (ffptr == fStkPwr ){
if (prevfptr == fStkLodRealC ){
dTemp = Load[LodPtr-1]->d.x;
if (dTemp == _2_ || dTemp == _1_ || dTemp == -1.0 || dTemp == 0.0 ){
/* change ^[-1,0,1,or 2] to recip,one,ident,sqr CAE 06NOV93 */
if (FNPTR(cvtptrx-1) == fStkPush2 ){
DBUGMSG(0, "LodRealC[-1,0,1,2] Push (*Pwr)"
" -> (*[recip,1,ident,Sqr0]), stk+=2" );
REMOVE_PUSH; /* lod[?] (push) *pwr */
}
else {
DBUGMSG(0, "LodRealC[-1,0,1,2] (*Pwr)"
" -> (*[recip,1,ident,sqr0])" );
}
--cvtptrx;
OPPTR(cvtptrx) = NO_OPERAND;
if (dTemp == _2_ ){
DBUGMSG(0, "[]=Sqr0" );
ffptr = fStkSqr0; /* no need to compute lastsqr here */
if (FNPTR(cvtptrx-1) == fStkLod ){
DBUGMSG(0, "Lod (*Sqr0) -> (*LodSqr)" );
--cvtptrx;
ffptr = fStkLodSqr; /* dont save lastsqr */
}
else if (FNPTR(cvtptrx-1) == fStkSto2 ){
DBUGMSG(0, "Sto2 (*Sqr0) -> (*StoSqr0)" );
--cvtptrx;
ffptr = fStkStoSqr0; /* dont save lastsqr */
}
}
else if (dTemp == _1_ ){
DBUGMSG(0, "[]=Ident" );
ffptr = fStkIdent;
}
else if (dTemp == 0.0 ){
DBUGMSG(0, "[]=One" );
ffptr = fStkOne;
}
else if (dTemp == -1.0 ){
DBUGMSG(0, "[]=Recip" );
ffptr = fStkRecip;
}
}
else if (FNPTR(cvtptrx-1) == prevfptr ){
--cvtptrx;
ffptr = fStkLodRealPwr; /* see comments below */
}
}
else if (prevfptr == fStkLodReal && FNPTR(cvtptrx-1) == prevfptr ){
/* CAE 6NOV93 */
/* don't handle pushes here, lodrealpwr needs 4 free */
DBUGMSG(0, "LodReal (*Pwr) -> (*LodRealPwr)" );
--cvtptrx;
ffptr = fStkLodRealPwr;
}
}
/* ******************************************************************** */
else if (ffptr == fStkLTE ){
if (prevfptr == fStkLod
|| prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
DBUGMSG(0, "Lod (*LTE) -> (*LodLTE)" );
--cvtptrx;
ffptr = fStkLodLTE;
}
}
/* ******************************************************************** */
else if (ffptr == fStkLT ){
if (prevfptr == fStkLod || prevfptr == fStkLodReal
|| prevfptr == fStkLodRealC ){
DBUGMSG(0, "Lod (*LT) -> (*LodLT)" );
--cvtptrx;
ffptr = fStkLodLT;
}
}
/* ******************************************************************** */
else if (ffptr == fStkGT ){
if (prevfptr == fStkLod
|| prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
DBUGMSG(0, "Lod (*GT) -> (*LodGT)" );
--cvtptrx;
ffptr = fStkLodGT;
}
}
/* ******************************************************************** */
else if (ffptr == fStkGTE ){
if (prevfptr == fStkLod
|| prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
DBUGMSG(0, "Lod (*GTE) -> (*LodGTE)" );
--cvtptrx;
ffptr = fStkLodGTE;
}
}
/* ******************************************************************** */
else if (ffptr == fStkNE ){
if (prevfptr == fStkLod
|| prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
DBUGMSG(0, "Lod (*NE) -> (*LodNE)" );
--cvtptrx;
ffptr = fStkLodNE;
}
}
/* ******************************************************************** */
else if (ffptr == fStkEQ ){
if (prevfptr == fStkLod
|| prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
DBUGMSG(0, "Lod (*EQ) -> (*LodEQ)" );
--cvtptrx;
ffptr = fStkLodEQ;
}
}
/* ******************************************************************** */
SkipOptimizer: /* ------------- end of optimizer ----------------------- */
FNPTR(cvtptrx++) = prevfptr = ffptr;
#ifdef TESTFP
prevstkcnt = stkcnt;
#endif
if (Delta == CLEAR_STK ){
realstkcnt = stkcnt = 0;
}
else {
stkcnt = (unsigned char)(stkcnt + Delta);
realstkcnt = (unsigned char)(realstkcnt + Delta);
}
DBUGMSG3(0, "Stack: %2d --> %2d, Real stack: %2d",
prevstkcnt, stkcnt, realstkcnt );
return 1; /* return 1 for success */
}
extern int fform_per_pixel(void); /* these fns are in parsera.asm */
extern int BadFormula(void);
extern void (far Img_Setup )(void);
int CvtStk() { /* convert the array of ptrs */
extern char FormName[];
void (far *ftst)(void);
void (near *ntst)(void);
union Arg far *testoperand;
struct fn_entry far *pfe;
int fnfound;
lastsqrreal = 1; /* assume lastsqr is real (not stored explicitly) */
p1const = p2const = p3const = (unsigned char)1; /* . . . p1, p2, p3 const */
lastsqrused = 0; /* ... and LastSqr is not used */
/* now see if the above assumptions are true */
for (OpPtr = LodPtr = StoPtr = 0; OpPtr < (int)LastOp; OpPtr++ ){
ftst = f[OpPtr];
if (ftst == StkLod ){
if (Load[LodPtr++] == &LASTSQR ){
lastsqrused = 1;
}
}
else if (ftst == StkSto ){
testoperand = Store[StoPtr++];
if (testoperand == &PARM1 ){
p1const = 0;
}
else if (testoperand == &PARM2 ){
p2const = 0;
}
else if (testoperand == &PARM3 ){
p3const = 0;
}
else if (testoperand == &LASTSQR ){
lastsqrreal = 0;
}
}
}
if (!p1const) {
DBUGMSG(0, "p1 not constant" );
}
if (!p2const) {
DBUGMSG(0, "p2 not constant" );
}
if (!p3const) {
DBUGMSG(0, "p3 not constant" );
}
if (lastsqrused) {
DBUGMSG(0, "LastSqr loaded" );
if (!lastsqrreal) {
DBUGMSG(0, "LastSqr stored" );
}
}
if (f[LastOp-1] != StkClr ){
DBUGMSG(0, "Missing clr added at end" );
/* should be safe to modify this */
f[LastOp++] = StkClr;
}
prevfptr = (void (near *)(void))0;
realstkcnt = stkcnt = cvtptrx = 0;
for (OpPtr = LodPtr = StoPtr = 0; OpPtr < (int)LastOp; OpPtr++) {
ftst = f[OpPtr];
fnfound = 0;
for (pfe = &afe[0]; pfe <= &afe[LAST_OLD_FN]; pfe++ ){
if (ftst == pfe->infn ){
fnfound = 1;
ntst = pfe->outfn;
if (ntst == fStkClr1 && OpPtr == (int)(LastOp-1) ){
ntst = fStkClr2; /* convert the last clear to a clr2 */
DBUGMSG(0, "Last fn (CLR) --> (is really CLR2)" );
}
if (ntst == fStkIdent && debugflag != 322 ){
/* ident will be skipped here */
/* this is really part of the optimizer */
DBUGMSG(0, "IDENT was skipped" );
}
else {
DBUGMSG4(0, "fn=%Fs, minstk=%1i, freestk=%1i, delta=%3i",
pfe->fname,
(int)(pfe->min_regs),
(int)(pfe->free_regs),
(int)(pfe->delta) );
if (!CvtFptr(ntst,
pfe->min_regs,
pfe->free_regs,
pfe->delta) ){
return 1;
}
}
}
}
if (!fnfound ){
/* return success so old code will be used */
/* stopmsg(0, "Fast 387 parser failed, reverting to slower code." );*/
return 1; /* this should only happen if random numbers are used */
}
} /* end for */
if (debugflag == 322 ){
goto skipfinalopt;
} /* ------------------------------ final optimizations ---------- */
/* cvtptrx -> one past last operator (always clr2) */
--cvtptrx; /* now it points to the last operator */
ntst = FNPTR(cvtptrx-1);
/* ntst is the next-to-last operator */
if (ntst == fStkLT ){
DBUGMSG(0, "LT Clr2 -> LT2" );
FNPTR(cvtptrx-1) = fStkLT2;
}
else if (ntst == fStkLodLT ){
DBUGMSG(0, "LodLT Clr2 -> LodLT2" );
FNPTR(cvtptrx-1) = fStkLodLT2;
}
else if (ntst == fStkLTE ){
DBUGMSG(0, "LTE Clr2 -> LTE2" );
FNPTR(cvtptrx-1) = fStkLTE2;
}
else if (ntst == fStkLodLTE ){
DBUGMSG(0, "LodLTE Clr2 -> LodLTE2" );
FNPTR(cvtptrx-1) = fStkLodLTE2;
}
else if (ntst == fStkGT ){
DBUGMSG(0, "GT Clr2 -> GT2" );
FNPTR(cvtptrx-1) = fStkGT2;
}
else if (ntst == fStkLodGT ){
DBUGMSG(0, "LodGT Clr2 -> LodGT2" );
FNPTR(cvtptrx-1) = fStkLodGT2;
}
else if (ntst == fStkLodGTE ){
DBUGMSG(0, "LodGTE Clr2 -> LodGTE2" );
FNPTR(cvtptrx-1) = fStkLodGTE2;
}
else if (ntst == fStkAND ){
DBUGMSG(0, "AND Clr2 -> ANDClr2" );
FNPTR(cvtptrx-1) = fStkANDClr2;
ntst = FNPTR(cvtptrx-2);
if (ntst == fStkLodLTE ){
DBUGMSG(0, "LodLTE ANDClr2 -> LodLTEAnd2" );
--cvtptrx;
FNPTR(cvtptrx-1) = fStkLodLTEAnd2;
}
}
else if (ntst == fStkOR ){ /* CAE 06NOV93 */
DBUGMSG(0, "OR Clr2 -> ORClr2" );
FNPTR(cvtptrx-1) = fStkORClr2;
}
else {
++cvtptrx; /* adjust this back since no optimization was found */
}
skipfinalopt: /* -------------- end of final optimizations ------------ */
LastOp = cvtptrx; /* save the new operator count */
LASTSQR.d.y = 0.0; /* do this once per image */
/* now change the pointers */
if (FormName[0] != 0 ){ /* but only if parse succeeded */
curfractalspecific->per_pixel = fform_per_pixel;
curfractalspecific->orbitcalc = fFormula;
}
else {
curfractalspecific->per_pixel = BadFormula;
curfractalspecific->orbitcalc = BadFormula;
}
#ifdef COMPILER
fCompile();
#endif
Img_Setup(); /* call assembler setup code */
return 1;
}
#endif /* XFRACT */