earlybrowserreborn - Rev 1

Subversion Repositories:
Rev:
#include <Mrm/MrmAppl.h>                        /* Motif Toolkit and MRM */
#include "midasoperand.h"
#include <string.h>

extern Widget ActiveWidget;
MidasOperand MidasGetIngotValue();
MidasOperand MidasCallFunction();
XtPointer MidasFindIngot();

static char *UnaryOperatorCharacters = "+-";
static char *BinaryOperatorCharacters = "+-*/><!=&|";

static MidasOperator BinaryOperators[] = {
                                {"==", 6,  MString,  MString, MBoolean},
                                {"!=", 6,  MString,  MString, MBoolean},
                                {"<=", 7,  MNumber,  MNumber, MBoolean},
                                {">=", 7,  MNumber,  MNumber, MBoolean},
                                {"&&", 1, MBoolean, MBoolean, MBoolean},
                                {"||", 1, MBoolean, MBoolean, MBoolean},
                                {"//", 9,     MInt,     MInt,     MInt},
                                {"++",10,  MString,  MString,  MString},
                                {"<" , 7,  MNumber,  MNumber, MBoolean},
                                {">" , 7,  MNumber,  MNumber, MBoolean},
                                {"+" , 8,  MNumber,  MNumber,  MNumber},
                                {"-" , 8,  MNumber,  MNumber,  MNumber},
                                {"*" , 9,  MNumber,  MNumber,  MNumber},
                                {"/" , 9,  MNumber,  MNumber,  MNumber}};

static char *SBool[2] = {"False" , "True"};

MidasOperand MidasApplyOperation(Op1,Op2,Op)
  MidasOperand  Op1;
  MidasOperand  Op2;
  MidasOperator *Op;
{
  MidasOperand Result;
  Boolean Float = FALSE;
  char *v1,*v2,*v;
  float f;

  Result.Dynamic = FALSE;

  if (strcmp(Op1.Type,Op->Op1)) MidasConvertOperand(&Op1,Op->Op1);    
  if (strcmp(Op2.Type,Op->Op2)) MidasConvertOperand(&Op2,Op->Op2);

  if (strcmp(Op->Op1,MNumber) == 0)
    {
      if      (strcmp(Op1.Type,MFloat) == 0) Float = TRUE;
      else if (strcmp(Op2.Type,MFloat) == 0) Float = TRUE;

      if (Float && strcmp(Op1.Type,MFloat)) MidasConvertOperand(&Op1,MFloat);    
      if (Float && strcmp(Op2.Type,MFloat)) MidasConvertOperand(&Op2,MFloat);
    }

  v1 = (char *) Op1.Value.P;
  v2 = (char *) Op2.Value.P;

  if      (strcmp(Op->Symbol,"==") == 0) v = (char *) (strcmp(v1,v2) == 0);
  else if (strcmp(Op->Symbol,"!=") == 0) v = (char *) (strcmp(v1,v2) != 0);
  else if (strcmp(Op->Symbol,"&&") == 0) v = v1 ? v2 : (char *) FALSE;
  else if (strcmp(Op->Symbol,"||") == 0) v = v1 ? (char *) TRUE :  v2;
  else if (strcmp(Op->Symbol,"++") == 0)
    {
      v = XtMalloc(strlen(v1)+strlen(v2)+1);
      strcpy(v,v1);
      strcat(v,v2);
      Result.Dynamic = TRUE;
    }
  else if (strcmp(Op->Symbol,"//") == 0)
    {
      if (!v2) MidasError("Integer division by zero");
      v = (char *) (((int) v1) / ((int) v2));
    }
  else if (Float)
    {
      float f1 = Op1.Value.F;
      float f2 = Op2.Value.F;
 
      if      (strcmp(Op->Symbol,">=") == 0) f =  f1 >=  f2;
      else if (strcmp(Op->Symbol,"<=") == 0) f =  f1 <=  f2;
      else if (strcmp(Op->Symbol,">" ) == 0) f =  f1 >   f2;
      else if (strcmp(Op->Symbol,"<" ) == 0) f =  f1 <   f2;
      else if (strcmp(Op->Symbol,"-")  == 0) f =  f1 -   f2;
      else if (strcmp(Op->Symbol,"+")  == 0) f =  f1 +   f2;
      else if (strcmp(Op->Symbol,"*")  == 0) f =  f1 *   f2;
      else if (strcmp(Op->Symbol,"/")  == 0)
        {
          if (f2 == 0) MidasError("Division by zero");
          f = f1 / f2;
        }
      else MidasError("Midas Internal Error: MidasApplyOperation");
    }
  else
    {
      if      (strcmp(Op->Symbol,">=") == 0) v = (char *) (((int) v1) >= ((int) v2));
      else if (strcmp(Op->Symbol,"<=") == 0) v = (char *) (((int) v1) <= ((int) v2));
      else if (strcmp(Op->Symbol,">" ) == 0) v = (char *) (((int) v1) >  ((int) v2));
      else if (strcmp(Op->Symbol,"<" ) == 0) v = (char *) (((int) v1) <  ((int) v2));
      else if (strcmp(Op->Symbol,"-")  == 0) v = (char *) (((int) v1) -  ((int) v2));
      else if (strcmp(Op->Symbol,"+")  == 0) v = (char *) (((int) v1) +  ((int) v2));
      else if (strcmp(Op->Symbol,"*")  == 0) v = (char *) (((int) v1) *  ((int) v2));
      else if (strcmp(Op->Symbol,"/")  == 0)
        {
          float r;
          if (!v2) MidasError("Division by zero");
          if (((int) v1) % ((int) v2) == 0) v = (char *) (((int)  v1) / ((int)  v2));
          else
            {
               float f1 = Op1.Value.F;
               float f2 = Op2.Value.F;
               f = f1 / f2;
              Float = TRUE;
            }
        }
      else MidasError("Midas Internal Error: MidasApplyOperation");
    }

  if (Op1.Dynamic) XtFree((char *)Op1.Value.P);
  if (Op2.Dynamic) XtFree((char *)Op2.Value.P);

  if (Float) Result.Value.F = f;
  else       Result.Value.P = v;

  if (strcmp(Op->Result,MNumber) == 0) Result.Type = Float ? MFloat : MInt;
  else Result.Type = Op->Result;

  return Result;
}
static MidasOperand MidasEvaluateFunction(in,outlen)
char *in;
int *outlen;
{
  MidasOperand Temp;
  char *q = in;

  Temp = MidasCallFunction(&q);
  *outlen = q - in + 1;
  return Temp;
}
MidasOperand MidasEvaluateExpression(in)
char *in;
{
   MidasStack Stack[10];
   MidasStack *SP = &Stack[0];
   MidasOperator Dummy, EndOfLine, *CurrentOperator;  
   char Unary = '\0';

#ifdef debug
   printf("Evaluating: %s\n",in);
#endif

   Dummy.Precedence = -1;
   EndOfLine.Precedence = 0;
   EndOfLine.Symbol = "";
   SP->Op = &Dummy;

   for (;;)
     {
       int l1;
       if (*in != '\0' && strchr(UnaryOperatorCharacters,*in) != 0) Unary = *in++;
/*
       Tokens in expressions may be:

          a) sub-expressions (in parentheses)
          b) Function invokations
          c) Quoted strings
          d) Ingots
          e) Unquoted strings

       First deal with Sub-expressions
*/

       if (*in == '(')
         {
           int n = 1, q = 0;
           char *p = in + 1;
           for (; *p != '\0'; p++)
             {
               if (*p == '"') q = !q;
               else if (!q && *p == '(') n++;
               else if (!q && *p == ')') if (--n == 0) break;
             }    
           if (q != 0) MidasError("Mismatched quotes in expression: %s",in);
           if (n != 0) MidasError("Parenthesis error in expression: %s",in);
           *p = '\0';
           in++;
           SP->Operand = MidasEvaluateExpression(in);
           l1 = p - in + 1;
         }
/*
       Now deal with quoted strings
*/

       else if (*in == '"')
         {
           int q = 1;
           char *p = in + 1;
           for (; *p != '\0'; p++) if (*p == '"') { q = 0;  break; }
           if (q != 0) MidasError("Mismatched quotes in expression: %s",in);
           *p = '\0';
           in++;
           SP->Operand.Type = MString;
           SP->Operand.Dynamic = FALSE;
           SP->Operand.Value.P = (XtPointer) in;
           l1 = p - in + 1;
         }
       else
/*
       Could be a function invokation
*/

         {
           char *l2 = strchr(in,'(');
           l1 = strcspn(in,BinaryOperatorCharacters);
           if (l2 != NULL && l2 < in+l1)
             {
               SP->Operand = MidasEvaluateFunction(in,&l1);
             }
           else
             {
/*
       Or it could be an ingot            
*/

               XtPointer Ingot;              
               char temp = *(in + l1);
               *(in + l1) = '\0';

               Ingot = MidasFindIngot(ActiveWidget,in);
               if (Ingot != 0) SP->Operand = MidasGetIngotValue(Ingot);
               else
                 {
                   SP->Operand.Type    = MString;
                   SP->Operand.Dynamic = FALSE;
                   SP->Operand.Value.P = (XtPointer) in;
                 }
               *(in + l1) = temp;
             }
         }      
/*
     Now deal with any pending unary operator
*/

       if (Unary == '-')
         {
           MidasConvertOperand(&SP->Operand,MInt);
           SP->Operand.Value.I = -(int) SP->Operand.Value.I;
         }

       if (*(in+l1) == '\0') CurrentOperator = &EndOfLine;
       else
         {
           int op;
           for (op = 0;  op < XtNumber(BinaryOperators);  op++)
             if (strncmp(in+l1,BinaryOperators[op].Symbol,
                         strlen(BinaryOperators[op].Symbol)) == 0) break;
 
           if (op == XtNumber(BinaryOperators))
             MidasError("Unrecognised operator %s in expression",in+l1);
           CurrentOperator = &BinaryOperators[op];
         }

       *(in+l1) = '\0';
       in += l1 + strlen(CurrentOperator->Symbol);

       for (; CurrentOperator->Precedence <= SP->Op->Precedence; )
         {
           (SP-1)->Operand = MidasApplyOperation((SP-1)->Operand,SP->Operand,SP->Op);
           SP--;
         }

       if (strcmp(CurrentOperator->Symbol,"&&") == 0)
         {
           if (strcmp(SP->Operand.Type,MBoolean)) MidasConvertOperand(&SP->Operand,MBoolean);
           if (SP->Operand.Value.I == FALSE) break;
         }
       else if (strcmp(CurrentOperator->Symbol,"||") == 0)
         {
           if (strcmp(SP->Operand.Type,MBoolean)) MidasConvertOperand(&SP->Operand,MBoolean);
           if (SP->Operand.Value.I == TRUE) break;
         }

       if (CurrentOperator == &EndOfLine) break;
       (++SP)->Op = CurrentOperator;
    }      
#ifdef debug
  printf ("Result is %s = ",SP->Operand.Type);
  if (strcmp(SP->Operand.Type,MString) == 0) printf("%s\n",SP->Operand.Value.I);
  else                                       printf("%d\n",SP->Operand.Value.I);
#endif

  return SP->Operand;
}
void MidasForceEvaluateExpression(in,out)
char **in;
char **out;
{
  MidasOperand Result;
  char temp, *p = *in+1, *pp, *buffer;
  int q = 0, m = 0;

  for (; *p != '\0' && *p != '\n'; p++)
    {
      if (*p == '"')
        {
          if (m == 0 && !q) break;
          else q = !q;
        }
      else if (!q && *p == '(') m++;
      else if (!q && *p == ')') m--;
      else if (!q && m == 0 && *p == ' ') break;
    }
   
  temp = *p;
  *p = '\0';
  buffer = XtNewString(*in+1);
  *p = temp;

  Result = MidasEvaluateExpression(buffer);
  if (strcmp(Result.Type,MString) != 0) MidasConvertOperand(&Result,MString);
     
  for (pp = Result.Value.P; *pp != '\0';) *(*out)++ = *pp++;
  if (Result.Dynamic) XtFree((char *)Result.Value.P);

  XtFree(buffer);
  *in = p - 1;
}
int MidasConvertToInteger(Operand)
MidasOperand Operand;
{
  if (strcmp(Operand.Type,MInt)) MidasConvertOperand(&Operand,MInt);
  return Operand.Value.I;
}
char *MidasConvertToString(Operand)
MidasOperand Operand;
{
  if (strcmp(Operand.Type,MString)) MidasConvertOperand(&Operand,MString);
  return XtNewString(Operand.Value.P);
}
char *MidasConvertToBoolean(Operand)
MidasOperand Operand;
{
  if (strcmp(Operand.Type,MBoolean)) MidasConvertOperand(&Operand,MString);
  return Operand.Value.P;
}
MidasOperand MidasConvertFromString(string)
char *string;
{
  MidasOperand Temp;
  Temp.Type = MString;
  Temp.Dynamic = TRUE;
  Temp.Value.P = XtNewString(string);
  return Temp;
}
MidasOperand MidasConvertFromInteger(i)
int i;
{
  MidasOperand Temp;
  Temp.Type = MInt;
  Temp.Dynamic = FALSE;
  Temp.Value.I = i;
  return Temp;
}
MidasOperand MidasConvertFromBoolean(b)
int b;
{
  MidasOperand Temp;
  Temp.Type = MBoolean;
  Temp.Dynamic = FALSE;
  Temp.Value.I = (b != 0);
  return Temp;

}