home *** CD-ROM | disk | FTP | other *** search
/ Computerworld 1996 March / Computerworld_1996-03_cd.bin / idg_cd3 / grafika / fraktaly / frasr192 / parserfp.c < prev    next >
C/C++ Source or Header  |  1995-02-15  |  54KB  |  1,446 lines

  1. /* PARSERFP.C  -- Part of FRACTINT fractal drawer.  */
  2.  
  3. /*   By Chuck Ebbert  CompuServe [76306,1226]  */
  4. /*                     internet: 76306.1226@compuserve.com  */
  5.  
  6. /* Fast floating-point parser code.  The functions beginning with  */
  7. /*    "fStk" are in PARSERA.ASM.  PARSER.C calls this code after  */
  8. /*    it has parsed the formula.  */
  9.  
  10. /*   Converts the function pointers/load pointers/store pointers  */
  11. /*       built by parsestr() into an optimized array of function  */
  12. /*       pointer/operand pointer pairs.  */
  13.  
  14. /*   As of 31 Dec 93, also generates executable code in memory.  */
  15. /*       Define the varible COMPILER to generate executable code.  */
  16. /*       COMPILER must also be defined in PARSERA.ASM. */
  17.  
  18.  
  19. /* Revision history:  */
  20.  
  21. /* 15 Feb 1995 CAE  */
  22. /*    added safety tests to pointer conversion code  */
  23. /*    added the capability for functions to require 4 free regs  */
  24.  
  25. /* 8 Feb 1995 CAE  */
  26. /*    Comments changed.  */
  27.  
  28. /* 8 Jan 1995 JCO  */
  29. /*    Function fStkASin added to support new 'asin' function in v19    */
  30. /*    Function fStkASinh added to support new 'asinh' function in v19  */
  31. /*    Function fStkACos added to support new 'acos' function in v19    */
  32. /*    Function fStkACosh added to support new 'acosh' function in v19  */
  33. /*    Function fStkATan added to support new 'atan' function in v19    */
  34. /*    Function fStkATanh added to support new 'atanh' function in v19  */
  35. /*    Function fStkSqrt added to support new 'sqrt' function in v19    */
  36. /*    Function fStkCAbs added to support new 'cabs' function in v19    */
  37. /*    Added support for a third parameter p3    */
  38.  
  39. /* 31 Dec 1993 CAE  */
  40. /*    Fixed optimizer bug discovered while testing compiler.  */
  41.  
  42. /* 29 Dec 1993 CAE  */
  43. /*    Added compiler.  */
  44.  
  45. /* 04 Dec 1993 CAE  */
  46. /*    Added optimizations for LodImagAdd/Sub/Mul.  */
  47.  
  48. /* 06 Nov 1993 CAE  */
  49. /*    Added optimizer support for LodRealPwr and ORClr2 functions.  */
  50. /*    If stack top is a real, a simpler sqr() or mod() fn will be  */
  51. /*          called (fStkSqr3() was added.)  */
  52. /*    The identities x^0=1, x^1=x, and x^-1=recip(x) are now used by the  */
  53. /*          optimizer.  (fStkOne() was added for this.)  */
  54.  
  55. /* 31 Oct 1993 CAE  */
  56. /*    Optimizer converts '2*x' and 'x*2' to 'x+x'. */
  57. /*        "     recognizes LastSqr as a real if not stored to.  */
  58.  
  59. /* 9 Oct 1993 CAE  */
  60. /*    Functions are now converted via table search.                    */
  61. /*    Added "real" stack count variable and debug msgs for stack size. */
  62. /*    Added optimizer extension for commutative multiply.              */
  63. /*    P1, P2 will be treated as consts if they are never stored to.    */
  64. /*    Function fStkStoClr2 now emitted for sto,clr with 2 on stack.    */
  65. /*       "     fStkZero added to support new 'zero' function in v18    */
  66. /*    Added optimization for x^2 -> sqr(x).                            */
  67. /*    Changed "stopmsg" to "DBUGMSG" and made all macros upper case.   */
  68. /*       (debugflag=324 now needed for debug msgs to print.)           */
  69.  
  70. /* 12 July 1993 (for v18.1) by CAE to fix optimizer bug  */
  71.  
  72. /* 22 MAR 1993 (for Fractint v18.0)  */
  73.  
  74. /* ******************************************************************* */
  75. /*                                                                     */
  76. /*  (c) Copyright 1992-1995 Chuck Ebbert.  All rights reserved.        */
  77. /*                                                                     */
  78. /*    This code may be freely distributed and used in non-commercial   */
  79. /*    programs provided the author is credited either during program   */
  80. /*    execution or in the documentation, and this copyright notice     */
  81. /*    is left intact.  Sale of this code, or its use in any commercial */
  82. /*    product requires permission from the author.  Nominal            */
  83. /*    distribution and handling fees may be charged by shareware and   */
  84. /*    freeware distributors.                                           */
  85. /*                                                                     */
  86. /* ******************************************************************* */
  87.  
  88. /* Uncomment the next line to enable debug messages.  */
  89. /* --#define TESTFP 1  */
  90.  
  91. /* Use startup parameter "debugflag=324" to show debug messages after  */
  92. /*    compiling with above #define uncommented.  */
  93.  
  94. /* uncomment this to gen for compiler (IT WORKS!!!)  */
  95. /*#define COMPILER 1 */
  96.  
  97. #include <string.h>
  98. #include <ctype.h>
  99. #include <stdio.h>
  100. #include <stdlib.h>
  101. #include <float.h>
  102. #include <time.h>
  103. #ifndef XFRACT
  104. #include <dos.h>
  105. #endif
  106. #include "fractint.h"
  107. #include "mpmath.h"
  108. #include "prototyp.h"
  109.  
  110. /* global data  */
  111. struct fls far *pfls = (struct fls far *)0;
  112.  
  113. #ifndef XFRACT  /* --  */
  114.  
  115. /* not moved to PROTOTYPE.H because these only communicate within
  116.    PARSER.C and other parser modules */
  117.    
  118. extern union Arg *Arg1, *Arg2;
  119. extern double _1_, _2_;
  120. extern union Arg s[20], far * far *Store, far * far *Load;
  121. extern int StoPtr, LodPtr, OpPtr;
  122. extern unsigned vsp, LastOp;
  123. extern struct ConstArg far *v;
  124. extern int InitLodPtr, InitStoPtr, InitOpPtr, LastInitOp;
  125. extern void (far * far *f)(void);
  126. extern char far compiled_fn_1[];
  127. extern char far compiled_fn_2[];
  128.  
  129. int fFormula(void);
  130.  
  131. typedef void OLD_FN(void);  /* old C functions  */
  132.  
  133. OLD_FN  StkLod, StkClr, StkSto, EndInit;
  134. OLD_FN  dStkAdd, dStkSub, dStkMul, dStkDiv;
  135. OLD_FN  dStkSqr, dStkMod;
  136. OLD_FN  dStkSin, dStkCos, dStkSinh, dStkCosh, dStkCosXX;
  137. OLD_FN  dStkTan, dStkTanh, dStkCoTan, dStkCoTanh;
  138. OLD_FN  dStkLog, dStkExp, dStkPwr;
  139. OLD_FN  dStkLT, dStkLTE;
  140. OLD_FN  dStkFlip, dStkReal, dStkImag;
  141. OLD_FN  dStkConj, dStkNeg, dStkAbs;
  142. OLD_FN  dStkRecip, StkIdent;
  143. OLD_FN  dStkGT, dStkGTE, dStkNE, dStkEQ;
  144. OLD_FN  dStkAND, dStkOR;
  145. OLD_FN  dStkZero;
  146. OLD_FN  dStkSqrt;
  147. OLD_FN  dStkASin, dStkACos, dStkASinh, dStkACosh;
  148. OLD_FN  dStkATanh, dStkATan;
  149. OLD_FN  dStkCAbs;
  150.  
  151. typedef void (near NEW_FN)(void);  /* new 387-only ASM functions  */
  152.  
  153. NEW_FN  fStkPull2;  /* pull up fpu stack from 2 to 4  */
  154. NEW_FN  fStkPush2;  /* push down fpu stack from 8 to 6  */
  155. NEW_FN  fStkPush2a;  /* push down fpu stack from 6 to 4  */
  156. NEW_FN  fStkPush4;  /* push down fpu stack from 8 to 4  */
  157. NEW_FN  fStkLodDup;  /* lod, dup  */
  158. NEW_FN  fStkLodSqr;  /* lod, sqr, dont save magnitude(i.e. lastsqr)  */
  159. NEW_FN  fStkLodSqr2;  /* lod, sqr, save lastsqr  */
  160. NEW_FN  fStkStoDup;  /* store, duplicate  */
  161. NEW_FN  fStkStoSqr;  /* store, sqr, save lastsqr  */
  162. NEW_FN  fStkStoSqr0;  /* store, sqr, dont save lastsqr  */
  163. NEW_FN  fStkLodDbl;  /* load, double  */
  164. NEW_FN  fStkStoDbl;  /* store, double  */
  165. NEW_FN  fStkReal2;  /* fast ver. of real  */
  166. NEW_FN  fStkSqr;  /* sqr, save magnitude in lastsqr  */
  167. NEW_FN  fStkSqr0;  /* sqr, no save magnitude  */
  168. NEW_FN  fStkClr1;  /* clear fpu  */
  169. NEW_FN  fStkClr2;  /* test stack top, clear fpu  */
  170. NEW_FN  fStkStoClr1;  /* store, clr1  */
  171. NEW_FN  fStkAdd, fStkSub;
  172. NEW_FN  fStkSto, fStkSto2;  /* fast ver. of sto  */
  173. NEW_FN  fStkLod, fStkEndInit;
  174. NEW_FN  fStkMod, fStkMod2;  /* faster mod  */
  175. NEW_FN  fStkLodMod2, fStkStoMod2;
  176. NEW_FN  fStkLTE, fStkLodLTEMul, fStkLTE2, fStkLodLTE;
  177. NEW_FN  fStkLodLTE2, fStkLodLTEAnd2;
  178. NEW_FN  fStkLT, fStkLodLTMul, fStkLT2, fStkLodLT;
  179. NEW_FN  fStkLodLT2;
  180. NEW_FN  fStkGTE, fStkLodGTE, fStkLodGTE2;
  181. NEW_FN  fStkGT, fStkGT2, fStkLodGT, fStkLodGT2;
  182. NEW_FN  fStkEQ, fStkLodEQ, fStkNE, fStkLodNE;
  183. NEW_FN  fStkAND, fStkANDClr2, fStkOR, fStkORClr2;
  184. NEW_FN  fStkSin, fStkSinh, fStkCos, fStkCosh, fStkCosXX;
  185. NEW_FN  fStkTan, fStkTanh, fStkCoTan, fStkCoTanh;
  186. NEW_FN  fStkLog, fStkExp, fStkPwr;
  187. NEW_FN  fStkMul, fStkDiv;
  188. NEW_FN  fStkFlip, fStkReal, fStkImag, fStkRealFlip, fStkImagFlip;
  189. NEW_FN  fStkConj, fStkNeg, fStkAbs, fStkRecip;
  190. NEW_FN  fStkLodReal, fStkLodRealC, fStkLodImag;
  191. NEW_FN  fStkLodRealFlip, fStkLodRealAbs;
  192. NEW_FN  fStkLodRealMul, fStkLodRealAdd, fStkLodRealSub, fStkLodRealPwr;
  193. NEW_FN  fStkLodImagMul, fStkLodImagAdd, fStkLodImagSub;  /* CAE 4Dec93  */
  194. NEW_FN  fStkLodImagFlip, fStkLodImagAbs;
  195. NEW_FN  fStkLodConj;
  196. NEW_FN  fStkLodAdd, fStkLodSub, fStkLodSubMod, fStkLodMul;
  197. NEW_FN  fStkPLodAdd, fStkPLodSub;  /* push-lod-add/sub  */
  198. NEW_FN  fStkIdent;
  199. NEW_FN  fStkStoClr2;  /* store, clear stack by popping  */
  200. NEW_FN  fStkZero;  /* to support new parser fn.  */
  201. NEW_FN  fStkDbl;  /* double the stack top  CAE 31OCT93  */
  202. NEW_FN  fStkOne, fStkSqr3;  /* sqr3 is sqr/mag of a real  CAE 09NOV93  */
  203. NEW_FN  fStkSqrt;
  204. NEW_FN  fStkASin, fStkACos, fStkASinh, fStkACosh;
  205. NEW_FN  fStkATanh, fStkATan;
  206. NEW_FN  fStkCAbs;
  207.  
  208. /* check to see if a const is being loaded  */
  209. /* the really awful hack below gets the first char of the name  */
  210. /*    of the variable being accessed  */
  211. /* if first char not alpha, or const p1, p2, or p3 are being accessed  */
  212. /*    then this is a const.  */
  213. #define IS_CONST(x) \
  214.       (!isalpha(**(((char * far *)x ) - 2 ) ) \
  215.       || (x==&PARM1 && p1const ) \
  216.       || (x==&PARM2 && p2const ) \
  217.       || (x==&PARM3 && p3const ) )
  218.  
  219. /* is stack top a real?  */
  220. #define STACK_TOP_IS_REAL \
  221.       ( prevfptr == fStkReal || prevfptr == fStkReal2 \
  222.       || prevfptr == fStkLodReal || prevfptr == fStkLodRealC \
  223.       || prevfptr == fStkLodRealAbs \
  224.       || prevfptr == fStkImag || prevfptr == fStkLodImag )
  225.  
  226. /* remove push operator from stack top  */
  227. #define REMOVE_PUSH --cvtptrx, stkcnt+=2
  228.  
  229. #define CLEAR_STK 127
  230. #define FNPTR(x) pfls[(x)].function  /* function pointer */
  231. #define OPPTR(x) pfls[(x)].operand   /* operand pointer */
  232. #define NO_OPERAND (union Arg near *)0
  233. #define NO_FUNCTION (void (near *)(void))0
  234. #define LASTSQR v[4].a
  235. #define PARM1 v[1].a
  236. #define PARM2 v[2].a
  237. #define PARM3 v[8].a
  238. #define MAX_ARGS 100  /* maximum memory variables  */
  239. #define MAX_STACK 8   /* max # of stack register avail  */
  240.  
  241. #ifdef TESTFP
  242.  
  243. #define DBUGMSG(x,y) if (debugflag==324 ) stopmsg((x), (y) )
  244. #define DBUGMSG1(x,y,p) \
  245.       if (debugflag==324 ){ \
  246.          sprintf(cDbgMsg, (y), (p) ); \
  247.          stopmsg((x), cDbgMsg ); \
  248.       }
  249. #define DBUGMSG2(x,y,p,q) \
  250.       if (debugflag==324 ){ \
  251.          sprintf(cDbgMsg, (y), (p), (q) ); \
  252.          stopmsg((x), cDbgMsg ); \
  253.       }
  254. #define DBUGMSG3(x,y,p,q,r) \
  255.       if (debugflag==324 ){ \
  256.          sprintf(cDbgMsg, (y), (p), (q), (r) ); \
  257.          stopmsg((x), cDbgMsg ); \
  258.       }
  259. #define DBUGMSG4(x,y,p,q,r,s) \
  260.       if (debugflag==324 ){ \
  261.          sprintf(cDbgMsg, (y), (p), (q), (r), (s) ); \
  262.          stopmsg((x), cDbgMsg ); \
  263.       }
  264.  
  265. #else
  266.  
  267. #define DBUGMSG(x,y)
  268. #define DBUGMSG1(x,y,p)
  269. #define DBUGMSG2(x,y,p,q)
  270. #define DBUGMSG3(x,y,p,q,r)
  271. #define DBUGMSG4(x,y,p,q,r,s)
  272.  
  273. #endif /* TESTFP */
  274.  
  275. #define FN_LOD            0
  276. #define FN_CLR            1
  277. #define FN_ADD            2
  278. #define FN_SUB            3
  279. #define FN_MUL            4
  280. #define FN_DIV            5
  281. #define FN_STO            6
  282. #define FN_SQR            7
  283. #define FN_ENDINIT        8
  284. #define FN_MOD            9
  285. #define FN_LTE           10
  286. #define FN_SIN           11
  287. #define FN_COS           12
  288. #define FN_SINH          13
  289. #define FN_COSH          14
  290. #define FN_COSXX         15
  291. #define FN_TAN           16
  292. #define FN_TANH          17
  293. #define FN_COTAN         18
  294. #define FN_COTANH        19
  295. #define FN_LOG           20
  296. #define FN_EXP           21
  297. #define FN_PWR           22
  298. #define FN_LT            23
  299. #define FN_FLIP          24
  300. #define FN_REAL          25
  301. #define FN_IMAG          26
  302. #define FN_CONJ          27
  303. #define FN_NEG           28
  304. #define FN_ABS           29
  305. #define FN_RECIP         30
  306. #define FN_IDENT         31
  307. #define FN_GT            32
  308. #define FN_GTE           33
  309. #define FN_NE            34
  310. #define FN_EQ            35
  311. #define FN_AND           36
  312. #define FN_OR            37
  313. #define FN_ZERO          38
  314. #define FN_SQRT          39
  315. #define FN_ASIN          40
  316. #define FN_ACOS          41
  317. #define FN_ASINH         42
  318. #define FN_ACOSH         43
  319. #define FN_ATANH         44
  320. #define FN_ATAN          45
  321. #define FN_CABS          46
  322.  
  323. /* number of "old" functions in the table.  */
  324. /* these are the ones that the parser outputs  */
  325.  
  326. #define LAST_OLD_FN   FN_CABS
  327. #define NUM_OLD_FNS   LAST_OLD_FN + 1
  328.  
  329. /* total number of functions in the table.  */
  330.  
  331. #define LAST_FN          FN_CABS
  332. #define NUM_FNS          LAST_FN + 1
  333.  
  334. static unsigned char
  335.    realstkcnt,   /* how many scalars are really on stack  */
  336.    stkcnt,       /* # scalars on FPU stack  */
  337.    cvtptrx,      /* subscript of next free entry in pfls  */
  338.    lastsqrused,  /* was lastsqr loaded in the formula?  */
  339.    lastsqrreal,  /* was lastsqr stored explicitly in the formula?  */
  340.    p1const,      /* is p1 a constant?  */
  341.    p2const,      /* ...and p2?  */
  342.    p3const;      /* ...and p3?  */
  343.  
  344. static void (near *prevfptr )(void);  /* previous function pointer  */
  345.  
  346. /* the entries in this table must be in the same order as  */
  347. /*    the #defines above  */
  348. /* this table is searched sequentially  */
  349. struct fn_entry {
  350.  
  351.    char far *fname;  /* function name  */
  352.  
  353.    void (far *infn)(void);  /* 'old' function pointer  */
  354.          /* (infn points to an operator fn in parser.c)  */
  355.  
  356.    void (near *outfn)(void);  /* pointer to equiv. fast fn.  */
  357.  
  358.    char min_regs;  /* min regs needed on stack by this fn.  */
  359.          /* (legal values are 0, 2, 4)  */
  360.  
  361.    char free_regs;  /* free regs required by this fn  */
  362.          /* (legal values are 0, 2, 4)  */
  363.  
  364.    char delta;  /* net change to # of values on the fp stack  */
  365.          /* (legal values are -2, 0, +2)  */
  366.  
  367. } static far afe[NUM_OLD_FNS] = {  /* array of function entries  */
  368.  
  369.    {"Lod",     StkLod,      fStkLod,    0, 2, +2 },          /*  0  */
  370.    {"Clr",     StkClr,      fStkClr1,   0, 0,  CLEAR_STK },  /*  1  */
  371.    {"+",       dStkAdd,     fStkAdd,    4, 0, -2 },          /*  2  */
  372.    {"-",       dStkSub,     fStkSub,    4, 0, -2 },          /*  3  */
  373.    {"*",       dStkMul,     fStkMul,    4, 2, -2 },          /*  4  */
  374.    {"/",       dStkDiv,     fStkDiv,    4, 2, -2 },          /*  5  */
  375.    {"Sto",     StkSto,      fStkSto,    2, 0,  0 },          /*  6  */
  376.    {"Sqr",     dStkSqr,     fStkSqr,    2, 2,  0 },          /*  7  */
  377.    {":",       EndInit,     fStkEndInit,0, 0,  CLEAR_STK },  /*  8  */
  378.    {"Mod",     dStkMod,     fStkMod,    2, 0,  0 },          /*  9  */
  379.    {"<=",      dStkLTE,     fStkLTE,    4, 0, -2 },          /* 10  */
  380.    {"Sin",     dStkSin,     fStkSin,    2, 2,  0 },          /* 11  */
  381.    {"Cos",     dStkCos,     fStkCos,    2, 2,  0 },          /* 12  */
  382.    {"Sinh",    dStkSinh,    fStkSinh,   2, 2,  0 },          /* 13  */
  383.    {"Cosh",    dStkCosh,    fStkCosh,   2, 2,  0 },          /* 14  */
  384.    {"Cosxx",   dStkCosXX,   fStkCosXX,  2, 2,  0 },          /* 15  */
  385.    {"Tan",     dStkTan,     fStkTan,    2, 2,  0 },          /* 16  */
  386.    {"Tanh",    dStkTanh,    fStkTanh,   2, 2,  0 },          /* 17  */
  387.    {"CoTan",   dStkCoTan,   fStkCoTan,  2, 2,  0 },          /* 18  */
  388.    {"CoTanh",  dStkCoTanh,  fStkCoTanh, 2, 2,  0 },          /* 19  */
  389.    {"Log",     dStkLog,     fStkLog,    2, 2,  0 },          /* 20  */
  390.    {"Exp",     dStkExp,     fStkExp,    2, 2,  0 },          /* 21  */
  391.    {"^",       dStkPwr,     fStkPwr,    4, 2, -2 },          /* 22  */
  392.    {"<",       dStkLT,      fStkLT,     4, 0, -2 },          /* 23  */
  393.    {"Flip",    dStkFlip,    fStkFlip,   2, 0,  0 },          /* 24  */
  394.    {"Real",    dStkReal,    fStkReal,   2, 0,  0 },          /* 25  */
  395.    {"Imag",    dStkImag,    fStkImag,   2, 0,  0 },          /* 26  */
  396.    {"Conj",    dStkConj,    fStkConj,   2, 0,  0 },          /* 27  */
  397.    {"Neg",     dStkNeg,     fStkNeg,    2, 0,  0 },          /* 28  */
  398.    {"Abs",     dStkAbs,     fStkAbs,    2, 0,  0 },          /* 29  */
  399.    {"Recip",   dStkRecip,   fStkRecip,  2, 2,  0 },          /* 30  */
  400.    {"Ident",   StkIdent,    fStkIdent,  2, 0,  0 },          /* 31  */
  401.    {">",       dStkGT,      fStkGT,     4, 0, -2 },          /* 32  */
  402.    {">=",      dStkGTE,     fStkGTE,    4, 0, -2 },          /* 33  */
  403.    {"!=",      dStkNE,      fStkNE,     4, 0, -2 },          /* 34  */
  404.    {"==",      dStkEQ,      fStkEQ,     4, 0, -2 },          /* 35  */
  405.    {"&&",      dStkAND,     fStkAND,    4, 0, -2 },          /* 36  */
  406.    {"||",      dStkOR,      fStkOR,     4, 0, -2 },          /* 37  */
  407.    {"Zero",    dStkZero,    fStkZero,   2, 0,  0 },          /* 38  */
  408.    {"Sqrt",    dStkSqrt,    fStkSqrt,   2, 2,  0 },          /* 39  */
  409.    {"ASin",    dStkASin,    fStkASin,   2, 4,  0 },          /* 40  */
  410.    {"ACos",    dStkACos,    fStkACos,   2, 4,  0 },          /* 41  */
  411.    {"ASinh",   dStkASinh,   fStkASinh,  2, 4,  0 },          /* 42  */
  412.    {"ACosh",   dStkACosh,   fStkACosh,  2, 4,  0 },          /* 43  */
  413.    {"ATanh",   dStkATanh,   fStkATanh,  2, 4,  0 },          /* 44  */
  414.    {"ATan",    dStkATan,    fStkATan,   2, 4,  0 },          /* 45  */
  415.    {"CAbs",    dStkCAbs,    fStkCAbs,   2, 0,  0 }           /* 46  */
  416. };
  417.  
  418. #ifdef COMPILER
  419. struct fn_header {
  420.    unsigned int fn_size;  /* size of function code in bytes  */
  421.    char near *pcode;      /* pointer to actual code  */
  422.    char near *incl_addr;  /* addr of included fn (offset from seg base)  */
  423.    char x_fixup;          /* offset of any x fixup (-1 if none)  */
  424.    char y_fixup;          /* "      "  "   y "      "  "   "     */
  425.    char incl_offset;      /* "      "  included fn. "  "   "     */
  426. };
  427. #endif  /* COMPILER  */
  428.  
  429. #ifdef TESTFP
  430. static char cDbgMsg[255];
  431. #endif  /* TESTFP  */
  432.  
  433.  
  434. #ifdef COMPILER
  435.  
  436. static int near fIncl_fn(char far *pcIncl, char far *pcTarget ){
  437.  
  438.    int i, iIncl_len = *(int far *)pcIncl & 0x007f;  /* max 127  */
  439.  
  440.    for (i=0, pcIncl+=2; i<iIncl_len; i++ ){
  441.       *pcTarget++ = *pcIncl++;
  442.    }
  443.  
  444.    return iIncl_len;
  445. }
  446.  
  447. static int near fNormal_fn(struct fn_header far *psIn, char far *pcTarget,
  448.       char near *npcOperand ){
  449.  
  450.    int i;  /* temp loop variable (offset into src fn)  */
  451.    int iBytesCopied;  /* another temp  */
  452.    int iCount = 0;  /* count of bytes copied to target  */
  453.    long lSegment = (long)compiled_fn_1 & 0xFFFF0000L;
  454.    int iCodeSize = psIn->fn_size & 0x007f;  /* max 127 bytes  */
  455.    char far *pcCode;
  456.  
  457.    pcCode = (char far *)((long)lSegment | (int)(psIn->pcode) );
  458.  
  459.    for (i=0; i<iCodeSize; i++){
  460.       if (i == psIn->incl_offset ){
  461.          DBUGMSG(0, "Including a function" );
  462.          if (*pcCode == -1 ){  /* sanity check  */
  463.             iBytesCopied = fIncl_fn(
  464.                   (char far *)(lSegment | (unsigned int)(psIn->incl_addr )),
  465.                   pcTarget );
  466.             pcTarget += iBytesCopied;
  467.             pcCode++;  /* to skip 1-byte placeholder  */
  468.             iCount += iBytesCopied;
  469.          }
  470.          else {
  471.             DBUGMSG(0, "Unexpected error, incl_placeholder != -1" );
  472.          }
  473.       }
  474.       else if (i == psIn->x_fixup || i == psIn->y_fixup ){
  475.          if (i == psIn->x_fixup ){
  476.             DBUGMSG(0, "X fixup" );
  477.             *(char near * far *)pcTarget = npcOperand;
  478.          }
  479.          else {
  480.             DBUGMSG(0, "Y fixup" );
  481.             *(char near * far *)pcTarget = npcOperand + sizeof(double);
  482.          }
  483.          pcTarget+=2, pcCode+=2;  /* two bytes copied from src to target  */
  484.          i++;  /* two bytes were taken from source instead of one  */
  485.          iCount += 2;
  486.       }
  487.       else {
  488.          *pcTarget++ = *pcCode++;
  489.          iCount++;
  490.       }
  491.    }
  492.  
  493.    return iCount;
  494. }
  495.  
  496. static void near fCompile(void){
  497.  
  498.    int i;
  499.    struct fn_header far *pfnh;
  500.    long lSegment = (long)compiled_fn_1 & 0xFFFF0000L;
  501.    char far *pcTarget;
  502.  
  503.    for (i=0,pcTarget=compiled_fn_1; i<cvtptrx; i++ ){
  504.       pfnh = (struct fn_header far *)
  505.              (lSegment | (unsigned int)(pfls[i].function));
  506.       if (pfnh->fn_size & 0x8000 ){
  507.          /* Normal function  */
  508.          pcTarget += fNormal_fn(pfnh, pcTarget, (char near *)pfls[i].operand );
  509.       }
  510.       else {
  511.          pcTarget += fIncl_fn((char far *)pfnh, pcTarget );
  512.       }
  513.       if (pfls[i].function == fStkEndInit ){
  514.          *pcTarget++ = '\xC3';  /* opcode for near return  */
  515.          break;
  516.       }
  517.    }
  518.  
  519.    for (i++,pcTarget=compiled_fn_2; i<cvtptrx; i++ ){
  520.       pfnh = (struct fn_header far *)
  521.              (lSegment | (unsigned int)(pfls[i].function));
  522.       if (pfnh->fn_size & 0x8000 ){
  523.          pcTarget +=
  524.                fNormal_fn(pfnh, pcTarget, (char near *)pfls[i].operand );
  525.       }
  526.       else {
  527.          pcTarget += fIncl_fn((char far *)pfnh, pcTarget );
  528.       }
  529.    }
  530.    *pcTarget++ = '\xC3';  /* near return at end of fn  */
  531.  
  532.    return;
  533. }
  534.  
  535. #endif /* COMPILER  */
  536.  
  537.  
  538. static int CvtFptr(void (near * ffptr)(void), int MinStk, int FreeStk,
  539.       int Delta )
  540. {
  541.    union Arg near *otemp;    /* temp operand ptr  */
  542.    union Arg far *testload;
  543. #ifdef TESTFP
  544.    int prevstkcnt;
  545. #endif
  546.    double dTemp;
  547.  
  548.    int Max_On_Stack = MAX_STACK - FreeStk;  /* max regs allowed on stack  */
  549.    int Num_To_Push; /* number of regs to push  */
  550.  
  551.    /* first do some sanity checks  */ /* CAE 15Feb95  */
  552.    if ( (Delta != -2 && Delta != 0 && Delta != 2 && Delta != CLEAR_STK)
  553.          || (FreeStk != 0 && FreeStk != 2 && FreeStk != 4)
  554.          || (MinStk != 0 && MinStk != 2 && MinStk != 4) ){
  555. awful_error:
  556.       stopmsg (0,"FATAL INTERNAL PARSER ERROR!");
  557.       return 0;  /* put out dire message and revert to old parser  */
  558.    }
  559.  
  560.    /* this if statement inserts a stack push or pull into the token array  */
  561.    /*   it would be much better to do this *after* optimization  */
  562.    if ((int)stkcnt < MinStk ) { /* not enough operands on fpu stack  */
  563.       DBUGMSG2(0, "Inserted pull.  Stack: %2d --> %2d", stkcnt, stkcnt+2 );
  564.       OPPTR(cvtptrx) = NO_OPERAND;
  565.       FNPTR(cvtptrx++) = fStkPull2;  /* so adjust the stack, pull operand  */
  566.       stkcnt += 2;
  567.    }
  568.    else if ((int)stkcnt > Max_On_Stack ) { /* too many operands  */
  569.  
  570.       Num_To_Push = stkcnt - Max_On_Stack;
  571.       if (Num_To_Push == 2 ){
  572.          if (stkcnt == MAX_STACK ){
  573.             /* push stack down from max to max-2  */
  574.             FNPTR(cvtptrx) = fStkPush2;
  575.          }
  576.          else if (stkcnt == MAX_STACK - 2 ){
  577.             /* push stack down from max-2 to max-4  */
  578.             FNPTR(cvtptrx) = fStkPush2a;
  579.          }
  580.          else {
  581.             goto awful_error;
  582.          }
  583.          DBUGMSG2(0,
  584.                "Inserted push.  Stack: %2d --> %2d", stkcnt, stkcnt-2 );
  585.          OPPTR(cvtptrx++) = NO_OPERAND;
  586.          stkcnt -= 2;
  587.       }
  588.       else if (Num_To_Push == 4 ){
  589.          /* push down from max to max-4  */
  590.          FNPTR(cvtptrx) = fStkPush4;
  591.          DBUGMSG2(0,
  592.                "Inserted push.  Stack: %2d --> %2d", stkcnt, stkcnt-4 );
  593.          OPPTR(cvtptrx++) = NO_OPERAND;
  594.          stkcnt -= 4;
  595.       }
  596.       else {
  597.          goto awful_error;
  598.       }
  599.    }
  600.  
  601.    /* set the operand pointer here for store function  */
  602.    if (ffptr == fStkSto ){
  603.       OPPTR(cvtptrx) = (void near *)FP_OFF((Store[StoPtr++]));
  604.    }
  605.    else if (ffptr == fStkLod && debugflag == 322 ){
  606.       /* when disabling optimizer, set load pointer here  */
  607.       OPPTR(cvtptrx) = (void near *)FP_OFF((Load[LodPtr++]));
  608.    }
  609.    else { /* the optimizer will set the pointer for load fn.  */
  610.       OPPTR(cvtptrx) = NO_OPERAND;
  611.    }
  612.  
  613.    if (debugflag == 322 ){
  614.       goto SkipOptimizer;
  615.    } /* --------------------------  begin optimizer  --------------------- */
  616.  
  617.    /* This optimizer grew from a simple if statement into a monster.  */
  618.  
  619.    /* Most of the bugs in the optimizer have been in the code that  */
  620.    /*   juggles the overflow stack.  */
  621.  
  622.    /* For the following:  */
  623.    /*   * == cvtptrx points to this  */
  624.    /*  () == this is about to be added to the array  */
  625.  
  626.    /* ******************************************************************** */
  627.    if (ffptr == fStkLod) { /* about to add Lod to the array  */
  628.  
  629.       if (prevfptr == fStkLod && Load[LodPtr-1] == Load[LodPtr] ) {
  630.          /* previous non-adjust operator was Lod of same operand  */
  631.          /* ? lodx ? (*lodx)  */
  632.          if (FNPTR(--cvtptrx) == fStkPush2 ){ /* prev fn was push  */
  633.             /* ? lod *push (lod)  */
  634.             --cvtptrx;  /* found  *lod push (lod)  */
  635.             if (FNPTR(cvtptrx-1) == fStkPush2){ /* always more ops here  */
  636.                DBUGMSG(0, "push *lod push (lod) -> push4 (*loddup)" );
  637.                FNPTR(cvtptrx-1) = fStkPush4;
  638.             }
  639.             else { /* prev op not push  */
  640.                DBUGMSG(0, "op *lod push (lod) -> op pusha(p=0) (*loddup)" );
  641.                OPPTR(cvtptrx) = NO_OPERAND;  /* use 'alternate' push fn.  */
  642.                FNPTR(cvtptrx++) = fStkPush2a;  /* push w/2 free on stack  */
  643.                /* operand ptr will be set below  */
  644.             }
  645.          }
  646.          else {  /* never  push *lod (lod)  so must be  */
  647.             DBUGMSG(0, "op *lod (lod) -> op (*loddup)" );
  648.          }
  649.          ffptr = fStkLodDup;
  650.       }
  651.       else if (prevfptr == fStkSto2
  652.             && Store[StoPtr-1] == Load[LodPtr] ){
  653.          /* store, load of same value  */
  654.          /* only one operand on stack here when prev oper is Sto2  */
  655.          DBUGMSG(0, "*sto2 (lod) -> (*stodup)" );
  656.          --cvtptrx;
  657.          ffptr = fStkStoDup;
  658.       }
  659.       /* This may cause roundoff problems when later operators  */
  660.       /*  use the rounded value that was stored here, while the next  */
  661.       /*  operator uses the more accurate internal value.  */
  662.       else if (prevfptr == fStkStoClr2
  663.                && Store[StoPtr-1] == Load[LodPtr] ){
  664.          /* store, clear, load same value found  */
  665.          /* only one operand was on stack so this is safe  */
  666.          DBUGMSG (0, "*StoClr2 (Lod) -> (*Sto2)" );
  667.          --cvtptrx;
  668.          ffptr = fStkSto2;  /* use different Sto fn  */
  669.       }
  670.       else {
  671.          testload = Load[LodPtr];
  672.          if (testload == &LASTSQR && lastsqrreal ){
  673.             /* -- LastSqr is a real.  CAE 31OCT93  */
  674.             DBUGMSG(0, "(*lod[lastsqr]) -> (*lodreal)" );
  675.             ffptr = fStkLodReal;
  676.          }
  677.          else if (IS_CONST(testload) && testload->d.y == 0.0 ){
  678.             DBUGMSG(0, "(*lod) -> (*lodrealc)" );
  679.             ffptr = fStkLodRealC;  /* a real const is being loaded  */
  680.          }
  681.       }
  682.       /* set the operand ptr here  */
  683.       OPPTR(cvtptrx) = (void near *)FP_OFF((Load[LodPtr++]));
  684.    }
  685.    /* ******************************************************************** */
  686.    else if (ffptr == fStkAdd ){
  687.  
  688.       if (prevfptr == fStkLodDup ){ /* there is never a push before add  */
  689.          --cvtptrx;  /* found  ? *loddup (add)  */
  690.          if (cvtptrx!=0 && FNPTR(cvtptrx-1) == fStkPush2a ){
  691.             /* because  push lod lod  is impossible so is  push loddup  */
  692.             DBUGMSG(0, "pusha *loddup (add) -> (*loddbl),stk+=2" );
  693.             REMOVE_PUSH;
  694.             OPPTR(cvtptrx) = OPPTR(cvtptrx+1);  /* fix opptr  */
  695.          }
  696.          else if (cvtptrx!=0 && FNPTR(cvtptrx-1) == fStkPush4 ){
  697.             DBUGMSG(0, "push4 *loddup (add) -> push2 (*loddbl),stk+=2" );
  698.             FNPTR(cvtptrx-1) = fStkPush2;
  699.             stkcnt += 2;  /*  CAE added 12 July 1993 to fix bug  */
  700.          }
  701.          else {
  702.             DBUGMSG(0, "op *loddup (add) -> op (*loddbl)" );
  703.          }
  704.          ffptr = fStkLodDbl;
  705.       }
  706.       else if (prevfptr == fStkStoDup ){
  707.          DBUGMSG(0, "stodup (*add) -> (*stodbl)" );
  708.          /* there are always exactly 4 on stack here  */
  709.          --cvtptrx;
  710.          ffptr = fStkStoDbl;
  711.       }
  712.       else if (prevfptr == fStkLod ){ /* have found  lod (*add)  */
  713.          --cvtptrx;    /*  ? *lod (add)  */
  714.          if (FNPTR(cvtptrx-1) == fStkPush2 ){
  715.             DBUGMSG(0, "*push load (add) -> (*plodadd),stk+=2" );
  716.             REMOVE_PUSH;
  717.             OPPTR(cvtptrx) = OPPTR(cvtptrx+1);  /* fix opptrs  */
  718.             ffptr = fStkPLodAdd;
  719.          }
  720.          else {
  721.             DBUGMSG(0, "op *lod (add) -> op (*lodadd)" );
  722.             ffptr = fStkLodAdd;
  723.          }
  724.       }
  725.       else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
  726.          --cvtptrx;  /* found  ? *lodreal (add)  */
  727.          if (FNPTR(cvtptrx-1) == fStkPush2 ){
  728.             DBUGMSG(0, "*push lodreal (add) -> (*lodrealadd),stk+=2" );
  729.             REMOVE_PUSH;
  730.             OPPTR(cvtptrx) = OPPTR(cvtptrx+1);  /* fix opptrs  */
  731.          }
  732.          else {
  733.             DBUGMSG(0, "*lodreal (add) -> (*lodrealadd)" );
  734.          }
  735.          ffptr = fStkLodRealAdd;
  736.       }
  737.       else if (prevfptr == fStkLodImag ){  /* CAE 4DEC93  */
  738.          --cvtptrx;  /* found  ? *lodimag (add)  */
  739.          if (FNPTR(cvtptrx-1) == fStkPush2 ){
  740.             DBUGMSG(0, "*push lodimag (add) -> (*lodimagadd),stk+=2" );
  741.             REMOVE_PUSH;
  742.             OPPTR(cvtptrx) = OPPTR(cvtptrx+1);  /* fix opptrs  */
  743.          }
  744.          else {
  745.             DBUGMSG(0, "*lodimag (add) -> (*lodimagadd)" );
  746.          }
  747.          ffptr = fStkLodImagAdd;
  748.       }
  749.    }
  750.    /* ******************************************************************** */
  751.    else if (ffptr == fStkSub ){
  752.  
  753.       if (prevfptr == fStkLod ){
  754.          /* found  lod (*sub)  */
  755.          --cvtptrx;  /*  *lod (sub)  */
  756.          /* there is never a sequence (lod push sub )  */
  757.          if (FNPTR(cvtptrx-1) == fStkPush2 ){
  758.             DBUGMSG(0, "*push lod (sub) -> (*plodsub),stk+=2" );
  759.             REMOVE_PUSH;
  760.             OPPTR(cvtptrx) = OPPTR(cvtptrx+1);  /* fix opptrs  */
  761.             ffptr = fStkPLodSub;
  762.          }
  763.          else {
  764.             DBUGMSG(0, "*lod (sub) -> (*lodsub)" );
  765.             ffptr = fStkLodSub;
  766.          }
  767.       }
  768.       else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
  769.          --cvtptrx;  /*  ? *lodreal (sub)  */
  770.          if (FNPTR(cvtptrx-1) == fStkPush2 ){
  771.             DBUGMSG(0, "*push lodreal (sub) -> (*lodrealsub),stk+=2" );
  772.             REMOVE_PUSH;
  773.             OPPTR(cvtptrx) = OPPTR(cvtptrx+1);  /* fix opptrs  */
  774.          }
  775.          else {
  776.             DBUGMSG(0, "*lodreal (sub) -> (*lodrealsub)" );
  777.          }
  778.          ffptr = fStkLodRealSub;
  779.       }
  780.       else if (prevfptr == fStkLodImag ){  /* CAE 4DEC93  */
  781.          --cvtptrx;  /*  ? *lodimag (sub)  */
  782.          if (FNPTR(cvtptrx-1) == fStkPush2 ){
  783.             DBUGMSG(0, "*push lodimag (sub) -> (*lodimagsub),stk+=2" );
  784.             REMOVE_PUSH;
  785.             OPPTR(cvtptrx) = OPPTR(cvtptrx+1);  /* fix opptrs  */
  786.          }
  787.          else {
  788.             DBUGMSG(0, "*lodimag (sub) -> (*lodimagsub)" );
  789.          }
  790.          ffptr = fStkLodImagSub;
  791.       }
  792.    }
  793.    /* ******************************************************************** */
  794.    else if (ffptr == fStkMul ){
  795.  
  796.       if (prevfptr == fStkLodDup ){
  797.          /* found  loddup ? (*mul)  */
  798.          if (FNPTR(--cvtptrx) == fStkPush2 ){
  799.             DBUGMSG(0, "loddup *push (mul) -> (*lodsqr),stk+=2" );
  800.             REMOVE_PUSH;
  801.          }
  802.          else {
  803.             DBUGMSG(0, "*loddup (mul) -> (*lodsqr)" );
  804.          }
  805.          ffptr = fStkLodSqr;
  806.       }
  807.       else if (prevfptr == fStkStoDup ){ /* no pushes here, 4 on stk.  */
  808.          DBUGMSG(0, "stodup (mul) -> (*stosqr0)" );
  809.          --cvtptrx;
  810.          ffptr = fStkStoSqr0;  /* dont save lastsqr here ever  */
  811.       }
  812.       else if (prevfptr == fStkLod ){
  813.          --cvtptrx;  /*  lod *? (mul)  */
  814.          if (FNPTR(cvtptrx) == fStkPush2 ){ /*  lod *push (mul)  */
  815.             --cvtptrx;  /* ? *lod push (mul)  */
  816.             if(FNPTR(cvtptrx-1) == fStkPush2 ){
  817.                DBUGMSG(0, "push *lod push (mul) -> push4 (*lodmul)" );
  818.                FNPTR(cvtptrx-1) = fStkPush4;
  819.             }
  820.             else {
  821.                DBUGMSG(0, "op *lod push (mul) -> op pusha (*lodmul)" );
  822.                OPPTR(cvtptrx+1) = OPPTR(cvtptrx);  /* fix operand ptr  */
  823.                FNPTR(cvtptrx) = fStkPush2a;
  824.                OPPTR(cvtptrx) = NO_OPERAND;
  825.                cvtptrx++;
  826.             }
  827.          }
  828.          else {
  829.             DBUGMSG(0, "*lod (mul) -> (*lodmul)" );
  830.          }
  831.          ffptr = fStkLodMul;
  832.  
  833.          /**********************  begin extension  ***  CAE 9 Oct 93  ****/
  834.          /*  change loadreal a, lodmul b --> lod b, lodrealmul a  */
  835.  
  836.          FNPTR(cvtptrx) = NO_FUNCTION;  /* mark the pending fn as null  */
  837.          if (FNPTR(cvtptrx-1) == fStkPush4
  838.                || FNPTR(cvtptrx-1) == fStkPush2a ){
  839.             --cvtptrx;  /* look back past this push  */
  840.          }
  841.  
  842.          if (FNPTR(cvtptrx-1) == fStkLodRealC
  843.                && Load[LodPtr-2]->d.x == _2_ ){
  844.             /* -- Convert '2*a' into 'a+a'.                CAE 31OCT93  */
  845.             if (FNPTR(cvtptrx) == NO_FUNCTION ){
  846.                DBUGMSG(0, "lodreal[2] (*lodmul[b])"
  847.                      " -> (*loddbl[b])" );
  848.                OPPTR(cvtptrx-1) = OPPTR(cvtptrx);
  849.             }
  850.             else if (FNPTR(cvtptrx) == fStkPush2a ){
  851.                DBUGMSG(0, "lodreal[2] *pusha (lodmul[b])"
  852.                      " -> loddbl[b],stk+=2" );
  853.                OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1);
  854.                stkcnt += 2;
  855.             }
  856.             else if (FNPTR(cvtptrx) == fStkPush4 ){
  857.                DBUGMSG(0, "lodreal[2] *push4 (lodmul[b])"
  858.                      " -> loddbl[b],stk+=4" );
  859.                OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1);
  860.                stkcnt += 4;
  861.             }
  862.             FNPTR(--cvtptrx) = NO_FUNCTION;  /* so no increment later  */
  863.             ffptr = fStkLodDbl;
  864.          }
  865.          else if (FNPTR(cvtptrx-1) == fStkLodReal
  866.                || FNPTR(cvtptrx-1) == fStkLodRealC ){
  867.             /* lodreal *?push?? (*?lodmul)  */
  868.             otemp = OPPTR(cvtptrx-1);  /* save previous fn's operand  */
  869.             FNPTR(cvtptrx-1) = fStkLod;  /* prev fn = lod  */
  870.             /* Moved setting of prev lodptr to below         CAE 31DEC93  */
  871.             /* This was a bug causing a bad loadptr to be set here  */
  872.             /* 3 lines marked 'prev lodptr=this' below replace this line  */
  873.             if (FNPTR(cvtptrx) == NO_FUNCTION ){
  874.                DBUGMSG(0, "lodreal[a] (*lodmul[b])"
  875.                     " -> lod[b] (*lodrealmul[a])" );
  876.                OPPTR(cvtptrx-1) = OPPTR(cvtptrx);  /* prev lodptr=this  */
  877.             }
  878.             else if (FNPTR(cvtptrx) == fStkPush2a ){
  879.                DBUGMSG(0, "lodreal[a] *pusha (lodmul[b])"
  880.                      " -> lod[b] (*lodrealmul[a]),stk+=2" );
  881.                /* set this fn ptr to null so cvtptrx won't be incr later  */
  882.                FNPTR(cvtptrx) = NO_FUNCTION;
  883.                OPPTR(cvtptrx-1) = OPPTR(cvtptrx+1);  /* prev lodptr=this  */
  884.                stkcnt += 2;
  885.             }
  886.             else if (FNPTR(cvtptrx) == fStkPush4 ){
  887.                DBUGMSG(0, "lodreal[a] *push4 (lodmul[b])"
  888.                      " -> lod[b] push2 (*lodrealmul[a]),stk+=2" );
  889.                FNPTR(cvtptrx++) = fStkPush2;
  890.                OPPTR(cvtptrx-2) = OPPTR(cvtptrx);  /* prev lodptr=this  */
  891.                /* we know cvtptrx points to a null function now  */
  892.                stkcnt += 2;
  893.             }
  894.             OPPTR(cvtptrx) = otemp;  /* switch the operands  */
  895.             ffptr = fStkLodRealMul;  /* next fn is now lodrealmul  */
  896.          }
  897.  
  898.          if (FNPTR(cvtptrx) != NO_FUNCTION ){
  899.             cvtptrx++;  /* adjust cvtptrx back to normal if needed  */
  900.          }
  901.          /* **********************  end extension  *********************** */
  902.       }
  903.       else if (prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
  904.  
  905.          --cvtptrx;  /* found  lodreal *? (mul)  */
  906.          if (FNPTR(cvtptrx) == fStkPush2 ){
  907.             DBUGMSG(0, "lodreal *push2 (mul) -> (*lodrealmul),stk+=2" );
  908.             REMOVE_PUSH;
  909.          }
  910.          else {
  911.             DBUGMSG(0, "*lodreal (mul) -> (*lodrealmul)" );
  912.          }
  913.          ffptr = fStkLodRealMul;
  914.  
  915.          /**********************  begin extension  ***  CAE 31OCT93  ****/
  916.          if (prevfptr == fStkLodRealC  /* use prevfptr here  */
  917.                && Load[LodPtr-1]->d.x == _2_ ){
  918.             if (FNPTR(cvtptrx) == fStkPush2 ){
  919.                DBUGMSG(0, "push (*lodrealmul[2]) -> (*dbl),stk+=2" );
  920.                REMOVE_PUSH;
  921.             }
  922.             else {
  923.                DBUGMSG(0, "*lodrealmul[2] -> (*dbl)" );
  924.             }
  925.             OPPTR(cvtptrx) = NO_OPERAND;
  926.             ffptr = fStkDbl;
  927.  
  928.             if (FNPTR(cvtptrx-1) == fStkLod ){
  929.                DBUGMSG(0, "lod (*dbl) -> (*loddbl)" );
  930.                --cvtptrx;
  931.                ffptr = fStkLodDbl;
  932.             }
  933.             else if (FNPTR(cvtptrx-1) == fStkSto2 ){
  934.                DBUGMSG(0, "sto2 (*dbl) -> (*stodbl)" );
  935.                --cvtptrx;
  936.                ffptr = fStkStoDbl;
  937.             }
  938.          }
  939.          /************************  end extension  ***  CAE 31OCT93  ****/
  940.       }
  941.       else if (prevfptr == fStkLodImag ){  /* CAE 4DEC93  */
  942.  
  943.          --cvtptrx;  /* found  lodimag *? (mul)  */
  944.          if (FNPTR(cvtptrx) == fStkPush2 ){
  945.             DBUGMSG(0, "lodimag *push2 (mul) -> (*lodimagmul),stk+=2" );
  946.             REMOVE_PUSH;
  947.          }
  948.          else {
  949.             DBUGMSG(0, "*lodimag (mul) -> (*lodimagmul)" );
  950.          }
  951.          ffptr = fStkLodImagMul;
  952.       }
  953.       else if (prevfptr == fStkLodLT && FNPTR(cvtptrx-1) != fStkPull2 ){
  954.          /* this shortcut fails if  Lod LT Pull Mul  found  */
  955.          DBUGMSG(0, "LodLT (*Mul) -> (*LodLTMul)" );
  956.          --cvtptrx;  /* never  lod LT Push Mul  here  */
  957.          ffptr = fStkLodLTMul;
  958.       }
  959.       else if (prevfptr == fStkLodLTE && FNPTR(cvtptrx-1) != fStkPull2 ){
  960.          DBUGMSG(0, "LodLTE (*mul) -> (*LodLTEmul)" );
  961.          --cvtptrx;
  962.          ffptr = fStkLodLTEMul;
  963.       }
  964.    }
  965.    /* ******************************************************************** */
  966.    else if (ffptr == fStkClr1 && prevfptr == fStkSto ){
  967.  
  968.       --cvtptrx;
  969.       if (stkcnt == 2 ){
  970.          DBUGMSG(0, "sto (*clr1) -> (*stoclr2)" );
  971.          ffptr = fStkStoClr2;
  972.       }
  973.       else {
  974.          DBUGMSG(0, "sto (*clr1) -> (*stoclr1)" );
  975.          ffptr = fStkStoClr1;
  976.       }
  977.    }
  978.    /* ******************************************************************** */
  979.    else if (ffptr == fStkDiv ){
  980.  
  981.       if (prevfptr == fStkLodRealC && vsp < MAX_ARGS - 1 ){
  982.          /* have found a divide by a real constant  */
  983.          /*  and there is space to create a new one  */
  984.          /* lodrealc ? (*div)  */
  985.          if (FNPTR(--cvtptrx) == fStkPush2 ){
  986.             DBUGMSG(0, "lodrealc *push (div) -> (*lodrealmul),stk+=2" );
  987.             REMOVE_PUSH;
  988.          }
  989.          else {
  990.             DBUGMSG(0, "*lodrealc (div) -> (*lodrealmul)" );
  991.          }
  992.          v[vsp].s = (void near *)0;  /* this constant has no name  */
  993.          v[vsp].len = 0;
  994.          v[vsp].a.d.x = _1_ / Load[LodPtr-1]->d.x;
  995.          v[vsp].a.d.y = 0.0;
  996.          {
  997.             void far *p = &v[vsp++].a;
  998.             OPPTR(cvtptrx) = (void near *)FP_OFF(p);  /* isn't C fun!  */
  999.          }
  1000.          ffptr = fStkLodRealMul;
  1001.       }
  1002.    }
  1003.    /* ******************************************************************** */
  1004.    else if (ffptr == fStkReal ){
  1005.  
  1006.       if (prevfptr == fStkLod ){
  1007.          DBUGMSG(0, "lod (*real) -> (*lodreal)" );
  1008.          --cvtptrx;
  1009.          ffptr = fStkLodReal;
  1010.       }
  1011.       else if (stkcnt < MAX_STACK ){
  1012.          DBUGMSG(0, "(*real) -> (*real2)" );
  1013.          ffptr = fStkReal2;
  1014.       }
  1015.    }
  1016.    /* ******************************************************************** */
  1017.    else if (ffptr == fStkImag && prevfptr == fStkLod ){
  1018.  
  1019.       DBUGMSG(0, "lod (*imag) -> lodimag" );
  1020.       --cvtptrx;
  1021.       ffptr = fStkLodImag;
  1022.    }
  1023.    /* ******************************************************************** */
  1024.    else if (ffptr == fStkConj && prevfptr == fStkLod ){
  1025.  
  1026.       DBUGMSG(0, "lod (*conj) -> (*lodconj)" );
  1027.       --cvtptrx;
  1028.       ffptr = fStkLodConj;
  1029.    }
  1030.    /* ******************************************************************** */
  1031.    else if (ffptr == fStkMod && stkcnt < MAX_STACK ){
  1032.  
  1033.       DBUGMSG(0, "(*mod) -> (*mod2)" );
  1034.       ffptr = fStkMod2;  /* use faster version if room on stack  */
  1035.       if (prevfptr == fStkLod ){
  1036.          DBUGMSG(0, "lod (*mod2) -> (*lodmod2)" );
  1037.          --cvtptrx;
  1038.          ffptr = fStkLodMod2;
  1039.       }
  1040.       else if (prevfptr == fStkSto || prevfptr == fStkSto2 ){
  1041.          DBUGMSG(0, "sto (*mod2) -> (*stomod2)" );
  1042.          --cvtptrx;
  1043.          ffptr = fStkStoMod2;
  1044.       }
  1045.       else if (prevfptr == fStkLodSub ){
  1046.          DBUGMSG(0, "lodsub (*mod2) -> (*lodsubmod)" );
  1047.          --cvtptrx;
  1048.          ffptr = fStkLodSubMod;
  1049.       }
  1050.       else if (STACK_TOP_IS_REAL){  /* CAE 06NOV93  */
  1051.          DBUGMSG(0, "(*mod2[st real]) -> (*sqr3)" );
  1052.          ffptr = fStkSqr3;
  1053.       }
  1054.    }
  1055.    /* ******************************************************************** */
  1056.    else if (ffptr == fStkFlip ){
  1057.  
  1058.       if (prevfptr == fStkReal || prevfptr == fStkReal2 ){
  1059.          DBUGMSG(0, "real (*flip) -> (*realflip)" );
  1060.          --cvtptrx;
  1061.          ffptr = fStkRealFlip;
  1062.       }
  1063.       else if (prevfptr == fStkImag ){
  1064.          DBUGMSG(0, "imag (*flip) -> (*imagflip)" );
  1065.          --cvtptrx;
  1066.          ffptr = fStkImagFlip;
  1067.       }
  1068.       else if (prevfptr == fStkLodReal ){
  1069.          DBUGMSG(0, "lodreal (*flip) -> (*lodrealflip)" );
  1070.          --cvtptrx;
  1071.          ffptr = fStkLodRealFlip;
  1072.       }
  1073.       else if (prevfptr == fStkLodImag ){
  1074.          DBUGMSG(0, "lodimag (*flip) -> (*lodimagflip)" );
  1075.          --cvtptrx;
  1076.          ffptr = fStkLodImagFlip;
  1077.       }
  1078.    }
  1079.    /* ******************************************************************** */
  1080.    else if (ffptr == fStkAbs ){
  1081.  
  1082.       if (prevfptr == fStkLodReal ){
  1083.          DBUGMSG(0, "lodreal (*abs) -> (*lodrealabs)" );
  1084.          --cvtptrx;
  1085.          ffptr = fStkLodRealAbs;
  1086.       }
  1087.       else if (prevfptr == fStkLodImag ){
  1088.          DBUGMSG(0, "lodimag (*abs) -> (*lodimagabs)" );
  1089.          --cvtptrx;
  1090.          ffptr = fStkLodImagAbs;
  1091.       }
  1092.    }
  1093.    /* ******************************************************************** */
  1094.    else if (ffptr == fStkSqr ){
  1095.  
  1096.       if (prevfptr == fStkLod && FNPTR(cvtptrx-1) != fStkPush2 ){
  1097.          DBUGMSG(0, "lod (*sqr) -> (*lodsqr)" );
  1098.          --cvtptrx;
  1099.          ffptr = fStkLodSqr;  /* assume no need to save lastsqr  */
  1100.          if (lastsqrused){
  1101.             DBUGMSG(0, "(*lodsqr) -> (*lodsqr2)" );
  1102.             ffptr = fStkLodSqr2;  /* lastsqr is being used  */
  1103.          }
  1104.       }
  1105.       else if (prevfptr == fStkSto2 ){
  1106.          DBUGMSG(0, "sto2 (*sqr) -> (*stosqr0)" );
  1107.          --cvtptrx;
  1108.          ffptr = fStkStoSqr0;  /* assume no need to save lastsqr  */
  1109.          if (lastsqrused) {
  1110.             DBUGMSG(0, "(*stosqr0) -> (*stosqr)" );
  1111.             ffptr = fStkStoSqr;  /* save lastsqr  */
  1112.          }
  1113.       }
  1114.       else {
  1115.          if (!lastsqrused) {
  1116.             DBUGMSG(0, "(*sqr) -> (*sqr0)" );
  1117.             ffptr = fStkSqr0;  /* don't save lastsqr  */
  1118.             if (STACK_TOP_IS_REAL){  /* CAE 06NOV93  */
  1119.                DBUGMSG(0, "(*sqr0[st real]) -> (*sqr3)" );
  1120.                ffptr = fStkSqr3;
  1121.             }
  1122.          }
  1123.       }
  1124.    }
  1125.    /* ******************************************************************** */
  1126.    else if (ffptr == fStkPwr ){
  1127.  
  1128.       if (prevfptr == fStkLodRealC ){
  1129.          dTemp = Load[LodPtr-1]->d.x;
  1130.          if (dTemp == _2_ || dTemp == _1_ || dTemp == -1.0 || dTemp == 0.0 ){
  1131.             /* change ^[-1,0,1,or 2] to recip,one,ident,sqr  CAE 06NOV93  */
  1132.             if (FNPTR(cvtptrx-1) == fStkPush2 ){
  1133.                DBUGMSG(0, "LodRealC[-1,0,1,2] Push (*Pwr)"
  1134.                      " -> (*[recip,1,ident,Sqr0]), stk+=2" );
  1135.                REMOVE_PUSH;  /* lod[?] (push) *pwr */
  1136.             }
  1137.             else {
  1138.                DBUGMSG(0, "LodRealC[-1,0,1,2] (*Pwr)"
  1139.                      " -> (*[recip,1,ident,sqr0])" );
  1140.             }
  1141.             --cvtptrx;
  1142.             OPPTR(cvtptrx) = NO_OPERAND;
  1143.             if (dTemp == _2_ ){
  1144.                DBUGMSG(0, "[]=Sqr0" );
  1145.                ffptr = fStkSqr0;  /* no need to compute lastsqr here  */
  1146.                if (FNPTR(cvtptrx-1) == fStkLod ){
  1147.                   DBUGMSG(0, "Lod (*Sqr0) -> (*LodSqr)" );
  1148.                   --cvtptrx;
  1149.                   ffptr = fStkLodSqr;  /* dont save lastsqr  */
  1150.                }
  1151.                else if (FNPTR(cvtptrx-1) == fStkSto2 ){
  1152.                   DBUGMSG(0, "Sto2 (*Sqr0) -> (*StoSqr0)" );
  1153.                   --cvtptrx;
  1154.                   ffptr = fStkStoSqr0;  /* dont save lastsqr  */
  1155.                }
  1156.             }
  1157.             else if (dTemp == _1_ ){
  1158.                DBUGMSG(0, "[]=Ident" );
  1159.                ffptr = fStkIdent;
  1160.             }
  1161.             else if (dTemp == 0.0 ){
  1162.                DBUGMSG(0, "[]=One" );
  1163.                ffptr = fStkOne;
  1164.             }
  1165.             else if (dTemp == -1.0 ){
  1166.                DBUGMSG(0, "[]=Recip" );
  1167.                ffptr = fStkRecip;
  1168.             }
  1169.          }
  1170.          else if (FNPTR(cvtptrx-1) == prevfptr ){
  1171.             --cvtptrx;
  1172.             ffptr = fStkLodRealPwr;  /* see comments below  */
  1173.          }
  1174.       }
  1175.       else if (prevfptr == fStkLodReal && FNPTR(cvtptrx-1) == prevfptr ){
  1176.          /* CAE 6NOV93  */
  1177.          /* don't handle pushes here, lodrealpwr needs 4 free  */
  1178.          DBUGMSG(0, "LodReal (*Pwr) -> (*LodRealPwr)" );
  1179.          --cvtptrx;
  1180.          ffptr = fStkLodRealPwr;
  1181.       }
  1182.    }
  1183.    /* ******************************************************************** */
  1184.    else if (ffptr == fStkLTE ){
  1185.  
  1186.       if (prevfptr == fStkLod
  1187.             || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
  1188.          DBUGMSG(0, "Lod (*LTE) -> (*LodLTE)" );
  1189.          --cvtptrx;
  1190.          ffptr = fStkLodLTE;
  1191.       }
  1192.    }
  1193.    /* ******************************************************************** */
  1194.    else if (ffptr == fStkLT ){
  1195.  
  1196.       if (prevfptr == fStkLod || prevfptr == fStkLodReal
  1197.             || prevfptr == fStkLodRealC ){
  1198.          DBUGMSG(0, "Lod (*LT) -> (*LodLT)" );
  1199.          --cvtptrx;
  1200.          ffptr = fStkLodLT;
  1201.       }
  1202.    }
  1203.    /* ******************************************************************** */
  1204.    else if (ffptr == fStkGT ){
  1205.  
  1206.       if (prevfptr == fStkLod
  1207.             || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
  1208.          DBUGMSG(0, "Lod (*GT) -> (*LodGT)" );
  1209.          --cvtptrx;
  1210.          ffptr = fStkLodGT;
  1211.       }
  1212.    }
  1213.    /* ******************************************************************** */
  1214.    else if (ffptr == fStkGTE ){
  1215.  
  1216.       if (prevfptr == fStkLod
  1217.             || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
  1218.          DBUGMSG(0, "Lod (*GTE) -> (*LodGTE)" );
  1219.          --cvtptrx;
  1220.          ffptr = fStkLodGTE;
  1221.       }
  1222.    }
  1223.    /* ******************************************************************** */
  1224.    else if (ffptr == fStkNE ){
  1225.  
  1226.       if (prevfptr == fStkLod
  1227.             || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
  1228.          DBUGMSG(0, "Lod (*NE) -> (*LodNE)" );
  1229.          --cvtptrx;
  1230.          ffptr = fStkLodNE;
  1231.       }
  1232.    }
  1233.    /* ******************************************************************** */
  1234.    else if (ffptr == fStkEQ ){
  1235.  
  1236.       if (prevfptr == fStkLod
  1237.             || prevfptr == fStkLodReal || prevfptr == fStkLodRealC ){
  1238.          DBUGMSG(0, "Lod (*EQ) -> (*LodEQ)" );
  1239.          --cvtptrx;
  1240.          ffptr = fStkLodEQ;
  1241.       }
  1242.    }
  1243.    /* ******************************************************************** */
  1244. SkipOptimizer:  /* -------------  end of optimizer ----------------------- */
  1245.  
  1246.    FNPTR(cvtptrx++) = prevfptr = ffptr;
  1247. #ifdef TESTFP
  1248.    prevstkcnt = stkcnt;
  1249. #endif   
  1250.    if (Delta == CLEAR_STK ){
  1251.       realstkcnt = stkcnt = 0;
  1252.    }
  1253.    else {
  1254.       stkcnt = (unsigned char)(stkcnt + Delta);
  1255.       realstkcnt = (unsigned char)(realstkcnt + Delta);
  1256.    }
  1257.  
  1258.    DBUGMSG3(0, "Stack:  %2d --> %2d,  Real stack:  %2d",
  1259.          prevstkcnt, stkcnt, realstkcnt );
  1260.  
  1261.    return 1;  /* return 1 for success  */
  1262. }
  1263.  
  1264. extern int fform_per_pixel(void);    /* these fns are in parsera.asm  */
  1265. extern int BadFormula(void);
  1266. extern void (far Img_Setup )(void);
  1267.  
  1268. int CvtStk() {    /* convert the array of ptrs  */
  1269.    extern char FormName[];
  1270.    void (far *ftst)(void);
  1271.    void (near *ntst)(void);
  1272.    union Arg far *testoperand;
  1273.    struct fn_entry far *pfe;
  1274.    int fnfound;
  1275.  
  1276.    lastsqrreal = 1;  /* assume lastsqr is real (not stored explicitly)  */
  1277.    p1const = p2const = p3const = (unsigned char)1;  /* . . . p1, p2, p3 const  */
  1278.    lastsqrused = 0;  /* ... and LastSqr is not used  */
  1279.  
  1280.    /* now see if the above assumptions are true */
  1281.    for (OpPtr = LodPtr = StoPtr = 0; OpPtr < (int)LastOp; OpPtr++ ){
  1282.       ftst = f[OpPtr];
  1283.       if (ftst == StkLod ){
  1284.          if (Load[LodPtr++] == &LASTSQR ){
  1285.             lastsqrused = 1;
  1286.          }
  1287.       }
  1288.       else if (ftst == StkSto ){
  1289.          testoperand = Store[StoPtr++];
  1290.          if (testoperand == &PARM1 ){
  1291.             p1const = 0;
  1292.          }
  1293.          else if (testoperand == &PARM2 ){
  1294.             p2const = 0;
  1295.          }
  1296.          else if (testoperand == &PARM3 ){
  1297.             p3const = 0;
  1298.          }
  1299.          else if (testoperand == &LASTSQR ){
  1300.             lastsqrreal = 0;
  1301.          }
  1302.       }
  1303.    }
  1304.  
  1305.    if (!p1const) {
  1306.       DBUGMSG(0, "p1 not constant" );
  1307.    }
  1308.    if (!p2const) {
  1309.       DBUGMSG(0, "p2 not constant" );
  1310.    }
  1311.    if (!p3const) {
  1312.       DBUGMSG(0, "p3 not constant" );
  1313.    }
  1314.    if (lastsqrused) {
  1315.       DBUGMSG(0, "LastSqr loaded" );
  1316.       if (!lastsqrreal) {
  1317.          DBUGMSG(0, "LastSqr stored" );
  1318.       }
  1319.    }
  1320.  
  1321.    if (f[LastOp-1] != StkClr ){
  1322.       DBUGMSG(0, "Missing clr added at end" );
  1323.       /* should be safe to modify this  */
  1324.       f[LastOp++] = StkClr;
  1325.    }
  1326.  
  1327.    prevfptr = (void (near *)(void))0;
  1328.    realstkcnt = stkcnt = cvtptrx = 0;
  1329.  
  1330.    for (OpPtr = LodPtr = StoPtr = 0; OpPtr < (int)LastOp; OpPtr++) {
  1331.       ftst = f[OpPtr];
  1332.       fnfound = 0;
  1333.       for (pfe = &afe[0]; pfe <= &afe[LAST_OLD_FN]; pfe++ ){
  1334.          if (ftst == pfe->infn ){
  1335.             fnfound = 1;
  1336.             ntst = pfe->outfn;
  1337.             if (ntst == fStkClr1 && OpPtr == (int)(LastOp-1) ){
  1338.                ntst = fStkClr2;  /* convert the last clear to a clr2  */
  1339.                DBUGMSG(0, "Last fn (CLR) --> (is really CLR2)" );
  1340.             }
  1341.             if (ntst == fStkIdent && debugflag != 322 ){
  1342.                /* ident will be skipped here  */
  1343.                /* this is really part of the optimizer  */
  1344.                DBUGMSG(0, "IDENT was skipped" );
  1345.             }
  1346.             else {
  1347.                DBUGMSG4(0, "fn=%Fs, minstk=%1i, freestk=%1i, delta=%3i",
  1348.                      pfe->fname,
  1349.                      (int)(pfe->min_regs),
  1350.                      (int)(pfe->free_regs),
  1351.                      (int)(pfe->delta) );
  1352.                if (!CvtFptr(ntst,
  1353.                       pfe->min_regs,
  1354.                       pfe->free_regs,
  1355.                       pfe->delta) ){
  1356.                    return 1;
  1357.                }
  1358.             }
  1359.          }
  1360.       }
  1361.       if (!fnfound ){
  1362.          /* return success so old code will be used  */
  1363.          /* stopmsg(0, "Fast 387 parser failed, reverting to slower code." );*/
  1364.          return 1;  /* this should only happen if random numbers are used  */
  1365.       }
  1366.    } /* end for  */
  1367.  
  1368.    if (debugflag == 322 ){
  1369.       goto skipfinalopt;
  1370.    } /* ------------------------------ final optimizations ---------- */
  1371.  
  1372.    /* cvtptrx -> one past last operator (always clr2)  */
  1373.    --cvtptrx;  /* now it points to the last operator  */
  1374.    ntst = FNPTR(cvtptrx-1);
  1375.    /* ntst is the next-to-last operator  */
  1376.  
  1377.    if (ntst == fStkLT ){
  1378.       DBUGMSG(0, "LT Clr2 -> LT2" );
  1379.       FNPTR(cvtptrx-1) = fStkLT2;
  1380.    }
  1381.    else if (ntst == fStkLodLT ){
  1382.       DBUGMSG(0, "LodLT Clr2 -> LodLT2" );
  1383.       FNPTR(cvtptrx-1) = fStkLodLT2;
  1384.    }
  1385.    else if (ntst == fStkLTE ){
  1386.       DBUGMSG(0, "LTE Clr2 -> LTE2" );
  1387.       FNPTR(cvtptrx-1) = fStkLTE2;
  1388.    }
  1389.    else if (ntst == fStkLodLTE ){
  1390.       DBUGMSG(0, "LodLTE Clr2 -> LodLTE2" );
  1391.       FNPTR(cvtptrx-1) = fStkLodLTE2;
  1392.    }
  1393.    else if (ntst == fStkGT ){
  1394.       DBUGMSG(0, "GT Clr2 -> GT2" );
  1395.       FNPTR(cvtptrx-1) = fStkGT2;
  1396.    }
  1397.    else if (ntst == fStkLodGT ){
  1398.       DBUGMSG(0, "LodGT Clr2 -> LodGT2" );
  1399.       FNPTR(cvtptrx-1) = fStkLodGT2;
  1400.    }
  1401.    else if (ntst == fStkLodGTE ){
  1402.       DBUGMSG(0, "LodGTE Clr2 -> LodGTE2" );
  1403.       FNPTR(cvtptrx-1) = fStkLodGTE2;
  1404.    }
  1405.    else if (ntst == fStkAND ){
  1406.       DBUGMSG(0, "AND Clr2 -> ANDClr2" );
  1407.       FNPTR(cvtptrx-1) = fStkANDClr2;
  1408.       ntst = FNPTR(cvtptrx-2);
  1409.       if (ntst == fStkLodLTE ){
  1410.          DBUGMSG(0, "LodLTE ANDClr2 -> LodLTEAnd2" );
  1411.          --cvtptrx;
  1412.          FNPTR(cvtptrx-1) = fStkLodLTEAnd2;
  1413.       }
  1414.    }
  1415.    else if (ntst == fStkOR ){  /* CAE 06NOV93  */
  1416.       DBUGMSG(0, "OR Clr2 -> ORClr2" );
  1417.       FNPTR(cvtptrx-1) = fStkORClr2;
  1418.    }
  1419.    else {
  1420.       ++cvtptrx;  /* adjust this back since no optimization was found  */
  1421.    }
  1422.  
  1423. skipfinalopt:  /* -------------- end of final optimizations ------------ */
  1424.  
  1425.    LastOp = cvtptrx;  /* save the new operator count  */
  1426.    LASTSQR.d.y = 0.0;  /* do this once per image  */
  1427.  
  1428.    /* now change the pointers  */
  1429.    if (FormName[0] != 0 ){ /* but only if parse succeeded  */
  1430.       curfractalspecific->per_pixel = fform_per_pixel;
  1431.       curfractalspecific->orbitcalc = fFormula;
  1432.    }
  1433.    else {
  1434.       curfractalspecific->per_pixel = BadFormula;
  1435.       curfractalspecific->orbitcalc = BadFormula;
  1436.    }
  1437.  
  1438. #ifdef COMPILER
  1439.    fCompile();
  1440. #endif
  1441.    Img_Setup();  /* call assembler setup code  */
  1442.    return 1;
  1443. }
  1444.  
  1445. #endif /* XFRACT  */
  1446.