/* expr.c  94.07.03
 * Copyright 1983-1993   Albert Davis
 * Behavioral modeling functions moved from dev.c to clean it up.
 * I plan to redo all of the behavioral modeling stuff.
 */
#include "ecah.h"
#include "argparse.h"
#include "branch.h"
#include "error.h"
#include "expr.h"
#include "options.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	void	parseexpr(branch_t*,const char*,int*);
static	void	getkey(int*,int*,const char*,int*);
	void	printexpr(const branch_t*,int);
/*--------------------------------------------------------------------------*/
extern const char e_om[];
/*--------------------------------------------------------------------------*/
/* parseexpr: parse ureca style expressions, etc.???  (needs work)
 */
void parseexpr(branch_t *brh, const char *cmd, int *cnt)
{
 double numbers[EXPRSIZE];	/* there are two dynamic arrays		    */
 int keys[EXPRSIZE];		/* one for the keys			    */
 int numcount;			/* other for arguments (doubles)	    */
 int keycount;			/* keys are first.			    */

 brh->val = ctof(cmd,cnt);
 for (;;){
    int dummy;
    if (argparse(cmd,cnt,REPEAT,
	/*"IC",		aDOUBLE,	&brh->ic,*/
	"METHOD",	aENUM,		&dummy,		YES,
	"GEAR",		aENUM,		&brh->method_u,	mGEAR,
	"TRAPezoidal",	aENUM,		&brh->method_u,	mTRAPEZOID,
	"STIFF",	aENUM,		&brh->method_u,	mSTIFF,
	"")){
	;
    }else{
       /* no syntax check.  expression follows. */
       break;
    }
 }

				/* Initially, they are unknown size, so	    */
 numcount = keycount = 0;	/* use local fixed allocation.  Then copy   */
 for (;;){			/* in appropriate size to malloc space,	    */
    int key;			/* with links to parent branch struct.	    */
    int args;
    int arg;
    int paren = 0;
    getkey(&key, &args, cmd, cnt);
    if (!key)
       break;
    if ((keycount + 1 >= EXPRSIZE) || (numcount + args > EXPRSIZE))
       error(bERROR, "expression too long\n");
    keys[keycount++] = key;
    if (args == aVARIABLE){			/* variable # of args	    */
       double *argcount;			/* 1st arg is count	    */
       paren += skiplparen(cmd,cnt);
       argcount = &(numbers[numcount++]);
       *argcount = 1.;
       while (isfloat(cmd[*cnt])){
	   numbers[numcount++] = ctof(cmd,cnt);
	   (*argcount)++;
       }
       paren -= skiprparen(cmd,cnt);
    }else if (args == aASSIGN){
       skipequal(cmd,cnt);
       numbers[numcount++] = ctof(cmd,cnt);
    }else if (args > 0){
       paren += skiplparen(cmd,cnt);
       for (arg = 1;  arg <= args;  arg++)
	   numbers[numcount++] = ctof(cmd,cnt);
       paren -= skiprparen(cmd,cnt);
    }else{
       /* no args, do nothing */
    }
    if (paren != 0)
       syntax_msg(cmd,cnt,bWARNING);
 }

 if (keycount != 0){		/* allocate mem to save this stuff,	    */
    struct expr *x;		/* then copy.				    */
    size_t ssize;

    brh->x = (generic_t*)calloc(1,sizeof(struct expr));
    if (!brh->x)
       error(bERROR, e_om, "partslist (expression)");
    x = (struct expr*)brh->x;
    x->ssize = sizeof(struct expr);

    keys[keycount++] = eEND;

    ssize = sizeof(generic_t) + keycount*sizeof(int);
    x->x = (generic_t*)calloc(1, ssize);
    if (!x->x)
       error(bERROR, e_om, "partslist (expression)");
    x->x->ssize = ssize;
    x->keys = (struct ints*)x->x;

    ssize = sizeof(generic_t) + numcount*sizeof(double);
    x->x->x = (generic_t*)calloc(1, ssize);
    if (!x->x->x)
       error(bERROR, e_om, "partslist (expression)");
    x->x->x->ssize = ssize;
    x->args = (struct dbls*)x->x->x;

    x->x->x->x = (generic_t*)NULL;

    (void)memcpy((void*)x->keys->args,(void*)keys,   keycount*sizeof(int));
    (void)memcpy((void*)x->args->args,(void*)numbers,numcount*sizeof(double));
 }else{
    brh->x = (generic_t*)NULL;
 }
}
/*--------------------------------------------------------------------------*/
/* getkey: scan for a keyword. Return its key and desired arg count.
 * returns key == eNO if no match.
 */
static void getkey(int *key, int *args, const char *cmd, int *cnt)
{
 setmatch(cmd,cnt);
      if (rematch("AC"		)) { *key = eAC; 	*args = aAC; }
 else if (rematch("DC"		)) { *key = eDC; 	*args = aDC; }
 else if (rematch("DCTran"	)) { *key = eDCTRAN;	*args = aDCTRAN; }
 else if (rematch("Frequency"	)) { *key = eFREQUENCY;	*args = aFREQUENCY; }
 else if (rematch("PEriod"	)) { *key = ePERIOD;	*args = aPERIOD; }
 else if (rematch("Ramp"	)) { *key = eRAMP;	*args = aRAMP; }
 else if (rematch("TIme"	)) { *key = eTIME;	*args = aTIME; }
 else if (rematch("TRansient"	)) { *key = eTRAN;	*args = aTRAN; }

 else if (rematch("BAndwidth"	)) { *key = eBANDWIDTH;	*args = aBANDWIDTH; }
 else if (rematch("COMplex"	)) { *key = eCOMPLEX;	*args = aCOMPLEX; }
 else if (rematch("CORNERDown"	)) { *key = eCORNERDOWN;*args = aCORNERDOWN; }
 else if (rematch("CORNERUp"	)) { *key = eCORNERUP;	*args = aCORNERUP; }
 else if (rematch("DElay"	)) { *key = eDELAY;	*args = aDELAY; }
 else if (rematch("EXP"		)) { *key = eEXP;	*args = aEXP; }
 else if (rematch("EXPTerm"	)) { *key = eEXPTERM;	*args = aEXPTERM; }
 else if (rematch("Generator"	)) { *key = eGENERATOR;	*args = aGENERATOR; }
 else if (rematch("Max"		)) { *key = eMAX;	*args = aMAX; }
 else if (rematch("NEtfunction" )) { *key = eNETFUNC;	*args = aNETFUNC; }
 else if (rematch("NOtch"	)) { *key = eNOTCH;	*args = aNOTCH; }
 else if (isfloat(cmd[*cnt]	)) { *key = eNUMERIC;	*args = aNUMERIC; }
 else if (rematch("Offset"	)) { *key = eOFFSET;	*args = aOFFSET; }
 else if (rematch("POLAr"	)) { *key = ePOLAR;	*args = aPOLAR; }
 else if (rematch("POLYTerm"	)) { *key = ePOLYTERM;	*args = aPOLYTERM; }
 else if (rematch("PUlse"	)) { *key = ePULSE;	*args = aPULSE; }
 else if (rematch("PWl"		)) { *key = ePWL;	*args = aPWL;}
 else if (rematch("SFfm"	)) { *key = eSFFM;	*args = aSFFM; }
 else if (rematch("SIn"		)) { *key = eSIN;	*args = aSIN; }
 else if (rematch("Tanh"	)) { *key = eTANH;	*args = aTANH; }

 else if (rematch("IC"		)) { *key = eIC; 	*args = aIC; }
 else if (rematch("II"		)) { *key = eII; 	*args = aII; }
 else if (rematch("IV"		)) { *key = eIV; 	*args = aIV; }
 else if (rematch("TEmpco"	)) { *key = eTEMPCO;	*args = aTEMPCO; }
 else 	{ syntax_check(cmd,cnt,bWARNING);  *key = eNO;	*args = 0; }
}
/*--------------------------------------------------------------------------*/
void printexpr(const branch_t *brh, int where)
{
 if (!brh->x  ||  brh->val != 0.){
    mprintf(where, "%s", ftos(brh->val, "", 7, 0));
 }
 if (brh->method_u == mTRAPEZOID) mprintf(where, " method=trapezoid ");
 else if (brh->method_u == mGEAR) mprintf(where, " method=gear ");
 else if (brh->method_u == mSTIFF) mprintf(where, " stiff ");

 if (brh->x){
    struct expr *x;
    double *arg;
    int *key;
    const char *fname;
    int terms;

    x = (struct expr*)brh->x;
    arg = x->args->args;
    for (key = x->keys->args;  *key;  key++){
       switch (*key){
	 case eAC:	  fname = "ac";	   	terms = aAC;		break;
	 case eDC:	  fname = "dc";	   	terms = aDC;		break;
	 case eDCTRAN:    fname = "dctran";	terms = aDCTRAN;	break;
	 case eFREQUENCY: fname = "freq";	terms = aFREQUENCY;	break;
	 case ePERIOD:    fname = "period";	terms = aPERIOD;	break;
	 case eRAMP:	  fname = "ramp";	terms = aRAMP;		break;
	 case eTIME:	  fname = "time";	terms = aTIME;		break;
	 case eTRAN:	  fname = "tran";	terms = aTRAN;		break;

	 case eBANDWIDTH: fname = "bandwidth";  terms = aBANDWIDTH;	break;
	 case eCOMPLEX:   fname = "complex";	terms = aCOMPLEX;	break;
	 case eCORNERDOWN:fname = "cornerdown"; terms = aCORNERDOWN;	break;
	 case eCORNERUP:  fname = "cornerup";	terms = aCORNERUP;	break;
	 case eDELAY:     fname = "delay";	terms = aDELAY;		break;
	 case eEXP:	  fname = "exp";	terms = aEXP;		break;
	 case eEXPTERM:   fname = "expterm";	terms = aEXPTERM;	break;
	 case eGENERATOR: fname = "generator";  terms = aGENERATOR;	break;
	 case eMAX:	  fname = "max";	terms = aMAX;		break;
	 case eNOTCH:     fname = "notch";	terms = aNOTCH;		break;
	 case eNETFUNC:   fname = "netfunction";terms = aNETFUNC;	break;
	 case eNUMERIC:   fname = "";	   	terms = aNUMERIC;	break;
	 case eOFFSET:    fname = "offset";	terms = aOFFSET;	break;
	 case ePOLAR:     fname = "polar";	terms = aPOLAR;		break;
	 case ePOLYTERM:  fname = "polyterm";   terms = aPOLYTERM;	break;
	 case ePULSE:     fname = "pulse";	terms = aPULSE;		break;
	 case ePWL:	  fname = "pwl";	terms = aPWL;		break;
	 case eSFFM:	  fname = "sffm";	terms = aSFFM;		break;
	 case eSIN:	  fname = "sin";	terms = aSIN;		break;
	 case eTANH:	  fname = "tanh";	terms = aTANH;		break;

	 case eIC:	  fname = "ic";	   	terms = aIC;		break;
	 case eII:	  fname = "ii";	   	terms = aII;		break;
	 case eIV:	  fname = "iv";	   	terms = aIV;		break;
	 case eTEMPCO:    fname = "tempco";	terms = aTEMPCO;	break;
	 default:	  fname = "\n+ ERROR";  terms = 0;		break;
       }
       mprintf(where, " %s", fname);
       if (*key == eNUMERIC){
	  mprintf(where,"%s ",ftos(*(arg++), "", 7, 0));
       }else if (terms == aVARIABLE){
          int i;
	  terms = (int)(*(arg++)) - 1;
	  mprintf(where, "(", fname);
	  for (i = 1;   i <= terms;   i++){
	     mprintf(where,"%s ",ftos(*(arg++), "", 7, 0));
	  }
	  mprintf(where, ") ");
       }else if (terms == aASSIGN){
	  mprintf(where, "=", fname);
	  mprintf(where,"%s ",ftos(*(arg++), "", 7, 0));
       }else if (terms > 0){
          int i;
	  mprintf(where, "(", fname);
	  for (i = 1;   i <= terms;   i++){
	     mprintf(where,"%s ",ftos(*(arg++), "", 7, 0));
	  }
	  mprintf(where, ") ");
       }
    }
 }
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
