Logo Search packages:      
Sourcecode: ksh version File versions

exeval.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1989-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * expression library evaluator
 */

#include "exlib.h"
#include "exop.h"

#include <tm.h>

static Extype_t   eval(Expr_t*, Exnode_t*, void*);

#define TOTNAME         4
#define MAXNAME         16
#define FRAME           64

static char*
lexname(int op, int subop)
{
      register char*    b;

      static int  n;
      static char buf[TOTNAME][MAXNAME];

      if (op > MINTOKEN && op < MAXTOKEN)
            return (char*)exop[op - MINTOKEN];
      if (++n >= TOTNAME)
            n = 0;
      b = buf[n];
      if (op == '=')
      {
            if (subop > MINTOKEN && subop < MAXTOKEN)
                  sfsprintf(b, MAXNAME, "%s=", exop[subop - MINTOKEN]);
            else if (subop > ' ' && subop <= '~')
                  sfsprintf(b, MAXNAME, "%c=", subop);
            else
                  sfsprintf(b, MAXNAME, "(%d)=", subop);
      }
      else if (subop < 0)
            sfsprintf(b, MAXNAME, "(EXTERNAL:%d)", op);
      else if (op > ' ' && op <= '~')
            sfsprintf(b, MAXNAME, "%c", op);
      else
            sfsprintf(b, MAXNAME, "(%d)", op);
      return b;
}

/*
 * return dynamic (associative array) variable value
 * assoc will point to the associative array bucket
 */

static Extype_t
getdyn(Expr_t* ex, register Exnode_t* expr, void* env, Exassoc_t** assoc)
{
      Exassoc_t*  b;
      Extype_t    v;

      if (expr->data.variable.index)
      {
            char  buf[9];

            v = eval(ex, expr->data.variable.index, env);
            if (expr->data.variable.index->type != STRING)
            {
                  sfsprintf(buf, sizeof(buf), "%I*x", sizeof(v.integer), v.integer);
                  v.string = buf;
            }
            if (!(b = (Exassoc_t*)dtmatch((Dt_t*)expr->data.variable.symbol->local.pointer, v.string)))
            {
                  if (!(b = newof(0, Exassoc_t, 1, strlen(v.string))))
                        exnospace();
                  strcpy(b->name, v.string);
                  dtinsert((Dt_t*)expr->data.variable.symbol->local.pointer, b);
            }
            *assoc = b;
            if (b)
            {
                  if (expr->data.variable.symbol->type == STRING && !b->value.string)
                        b->value = exzero(expr->data.variable.symbol->type);
                  return b->value;
            }
            v = exzero(expr->data.variable.symbol->type);
            return v;
      }
      *assoc = 0;
      return expr->data.variable.symbol->value->data.constant.value;
}

typedef struct
{
      Sffmt_t           fmt;
      Expr_t*           expr;
      void*       env;
      Print_t*    args;
      Extype_t    value;
      Exnode_t*   actuals;
      Sfio_t*           tmp;
} Fmt_t;

/*
 * printf %! extension function
 */

static int
prformat(Sfio_t* sp, void* vp, Sffmt_t* dp)
{
      register Fmt_t*         fmt = (Fmt_t*)dp;
      register Exnode_t*      node;
      register char*          s;
      register char*          txt;
      int               n;
      int               from;
      int               to;
      time_t                  tm;

      dp->flags |= SFFMT_VALUE;
      if (fmt->args)
      {
            if (node = (dp->fmt == '*') ? fmt->args->param[dp->size] : fmt->args->arg)
                  fmt->value = exeval(fmt->expr, node, fmt->env);
            else
                  fmt->value.integer = 0;
            to = fmt->args->arg->type;
      }
      else if (!(fmt->actuals = fmt->actuals->data.operand.right))
            exerror("printf: not enough arguments");
      else
      {
            node = fmt->actuals->data.operand.left;
            from = node->type;
            switch (dp->fmt)
            {
            case 'f':
            case 'g':
                  to = FLOATING;
                  break;
            case 's':
                  to = STRING;
                  break;
            default:
                  switch (from)
                  {
                  case INTEGER:
                  case UNSIGNED:
                        to = from;
                        break;
                  default:
                        to = INTEGER;
                        break;
                  }
                  break;
            }
            if (to == from)
                  fmt->value = exeval(fmt->expr, node, fmt->env);
            else
            {
                  node = excast(fmt->expr, node, to, NiL, 0);
                  fmt->value = exeval(fmt->expr, node, fmt->env);
                  node->data.operand.left = 0;
                  exfree(fmt->expr, node);
                  if (to == STRING)
                  {
                        if (fmt->value.string)
                        {
                              n = strlen(fmt->value.string);
                              if (s = fmtbuf(n + 1))
                                    memcpy(s, fmt->value.string, n + 1);
                              vmfree(fmt->expr->vm, fmt->value.string);
                              fmt->value.string = s;
                        }
                        if (!fmt->value.string)
                              fmt->value.string = "";
                  }
            }
      }
      switch (to)
      {
      case STRING:
            *((char**)vp) = fmt->value.string;
            fmt->fmt.size = -1;
            break;
      case FLOATING:
            *((double*)vp) = fmt->value.floating;
            fmt->fmt.size = sizeof(double);
            break;
      default:
            *((Sflong_t*)vp) = fmt->value.integer;
            dp->size = sizeof(Sflong_t);
            break;
      }
      if (dp->n_str > 0)
      {
            if (!fmt->tmp || !(fmt->tmp = sfstropen()))
                  txt = exnospace();
            else
            {
                  sfprintf(fmt->tmp, "%.*s", dp->n_str, dp->t_str);
                  txt = exstash(fmt->tmp, NiL);
            }
      }
      else
            txt = 0;
      switch (dp->fmt)
      {
      case 'q':
      case 'Q':
            s = *((char**)vp);
            *((char**)vp) = fmtquote(s, "$'", "'", strlen(s), 0);
            dp->fmt = 's';
            dp->size = -1;
            break;
      case 'S':
            dp->flags &= ~SFFMT_LONG;
            s = *((char**)vp);
            if (txt)
            {
                  if (streq(txt, "identifier"))
                  {
                        if (*s && !isalpha(*s))
                              *s++ = '_';
                        for (; *s; s++)
                              if (!isalnum(*s))
                                    *s = '_';
                  }
                  else if (streq(txt, "invert"))
                  {
                        for (; *s; s++)
                              if (isupper(*s))
                                    *s = tolower(*s);
                              else if (islower(*s))
                                    *s = toupper(*s);
                  }
                  else if (streq(txt, "lower"))
                  {
                        for (; *s; s++)
                              if (isupper(*s))
                                    *s = tolower(*s);
                  }
                  else if (streq(txt, "upper"))
                  {
                        for (; *s; s++)
                              if (islower(*s))
                                    *s = toupper(*s);
                  }
                  else if (streq(txt, "variable"))
                  {
                        for (; *s; s++)
                              if (!isalnum(*s) && *s != '_')
                                    *s = '.';
                  }
            }
            dp->fmt = 's';
            dp->size = -1;
            break;
      case 't':
      case 'T':
            if ((tm = *((Sflong_t*)vp)) == -1)
                  tm = time(NiL);
            *((char**)vp) = fmttime(txt ? txt : "%?%K", tm);
            dp->fmt = 's';
            dp->size = -1;
            break;
      }
      return 0;
}

/*
 * do printf
 */

static int
print(Expr_t* ex, Exnode_t* expr, void* env, Sfio_t* sp)
{
      register Print_t* x;
      Extype_t          v;
      Fmt_t             fmt;

      if (!sp)
      {
            v = eval(ex, expr->data.print.descriptor, env);
            if (v.integer < 0 || v.integer >= elementsof(ex->file) || !(sp = ex->file[v.integer]) && !(sp = ex->file[v.integer] = sfnew(NiL, NiL, SF_UNBOUND, v.integer, SF_READ|SF_WRITE)))
            {
                  exerror("printf: %d: invalid descriptor", v.integer);
                  return 0;
            }
      }
      memset(&fmt, 0, sizeof(fmt));
      fmt.fmt.version = SFIO_VERSION;
      fmt.fmt.extf = prformat;
      fmt.expr = ex;
      fmt.env = env;
      x = expr->data.print.args;
      if (x->format)
            do
            {
                  if (x->arg)
                  {
                        fmt.fmt.form = x->format;
                        fmt.args = x;
                        sfprintf(sp, "%!", &fmt);
                  }
                  else
                        sfputr(sp, x->format, -1);
            } while (x = x->next);
      else
      {
            v = eval(ex, x->arg->data.operand.left, env);
            fmt.fmt.form = v.string;
            fmt.actuals = x->arg;
            sfprintf(sp, "%!", &fmt);
            if (fmt.actuals->data.operand.right)
                  exerror("printf: \"%s\": too many arguments", fmt.fmt.form);
      }
      if (fmt.tmp)
            sfstrclose(fmt.tmp);
      return 1;
}

/*
 * scanf %! extension function
 */

static int
scformat(Sfio_t* sp, void* vp, Sffmt_t* dp)
{
      register Fmt_t*         fmt = (Fmt_t*)dp;
      register Exnode_t*      node;

      if (!fmt->actuals)
      {
            exerror("scanf: not enough arguments");
            return -1;
      }
      node = fmt->actuals->data.operand.left;
      switch (dp->fmt)
      {
      case 'f':
      case 'g':
            if (node->type != FLOATING)
            {
                  exerror("scanf: %s: floating variable address argument expected", node->data.variable.symbol->name);
                  return -1;
            }
            fmt->fmt.size = sizeof(double);
            *((void**)vp) = &node->data.variable.symbol->value->data.constant.value;
            break;
      case 's':
            if (node->type != STRING)
            {
                  exerror("scanf: %s: string variable address argument expected", node->data.variable.symbol->name);
                  return -1;
            }
            if (node->data.variable.symbol->value->data.constant.value.string == expr.nullstring)
                  node->data.variable.symbol->value->data.constant.value.string = 0;
            fmt->fmt.size = 1024;
            *((void**)vp) = node->data.variable.symbol->value->data.constant.value.string = vmnewof(fmt->expr->vm, node->data.variable.symbol->value->data.constant.value.string, char, fmt->fmt.size, 0);
            break;
      default:
            if (node->type != INTEGER && node->type != UNSIGNED)
            {
                  exerror("scanf: %s: integer variable address argument expected", node->data.variable.symbol->name);
                  return -1;
            }
            dp->size = sizeof(Sflong_t);
            *((void**)vp) = &node->data.variable.symbol->value->data.constant.value;
            break;
      }
      fmt->actuals = fmt->actuals->data.operand.right;
      dp->flags |= SFFMT_VALUE;
      return 0;
}

/*
 * do scanf
 */

static int
scan(Expr_t* ex, Exnode_t* expr, void* env, Sfio_t* sp)
{
      Extype_t          v;
      Extype_t          u;
      Fmt_t             fmt;
      int               n;

      if (!sp)
      {
            if (expr->data.scan.descriptor)
            {
                  v = eval(ex, expr->data.scan.descriptor, env);
                  if (expr->data.scan.descriptor->type == STRING)
                        goto get;
            }
            else
                  v.integer = 0;
            if (v.integer < 0 || v.integer >= elementsof(ex->file) || !(sp = ex->file[v.integer]) && !(sp = ex->file[v.integer] = sfnew(NiL, NiL, SF_UNBOUND, v.integer, SF_READ|SF_WRITE)))
            {
                  exerror("scanf: %d: invalid descriptor", v.integer);
                  return 0;
            }
      }
 get:
      memset(&fmt, 0, sizeof(fmt));
      fmt.fmt.version = SFIO_VERSION;
      fmt.fmt.extf = scformat;
      fmt.expr = ex;
      fmt.env = env;
      u = eval(ex, expr->data.scan.format, env);
      fmt.fmt.form = u.string;
      fmt.actuals = expr->data.scan.args;
      n = sp ? sfscanf(sp, "%!", &fmt) : sfsscanf(v.string, "%!", &fmt);
      if (fmt.actuals && !*fmt.fmt.form)
            exerror("scanf: %s: too many arguments", fmt.actuals->data.operand.left->data.variable.symbol->name);
      return n;
}

/*
 * string add
 */

static char*
str_add(Expr_t* ex, register char* l, register char* r)
{
      sfprintf(ex->tmp, "%s%s", l, r);
      return exstash(ex->tmp, ex->ve);
}

/*
 * string ior
 */

static char*
str_ior(Expr_t* ex, register char* l, register char* r)
{
      register int      c;
      register char*    s = l;

      while (c = *s++)
            if (!strchr(s, c))
                  sfputc(ex->tmp, c);
      while (c = *r++)
            if (!strchr(l, c) && !strchr(r, c))
                  sfputc(ex->tmp, c);
      return exstash(ex->tmp, ex->ve);
}

/*
 * string and
 */

static char*
str_and(Expr_t* ex, register char* l, register char* r)
{
      register int      c;

      while (c = *l++)
            if (strchr(r, c) && !strchr(l, c))
                  sfputc(ex->tmp, c);
      return exstash(ex->tmp, ex->ve);
}

/*
 * string xor
 */

static char*
str_xor(Expr_t* ex, register char* l, register char* r)
{
      register int      c;
      register char*    s = l;

      while (c = *s++)
            if (!strchr(r, c) && !strchr(s, c))
                  sfputc(ex->tmp, c);
      while (c = *r++)
            if (!strchr(l, c) && !strchr(r, c))
                  sfputc(ex->tmp, c);
      return exstash(ex->tmp, ex->ve);
}

/*
 * string mod
 */

static char*
str_mod(Expr_t* ex, register char* l, register char* r)
{
      register int      c;

      while (c = *l++)
            if (!strchr(r, c) && !strchr(l, c))
                  sfputc(ex->tmp, c);
      return exstash(ex->tmp, ex->ve);
}

/*
 * string mpy
 */

static char*
str_mpy(Expr_t* ex, register char* l, register char* r)
{
      register int      lc;
      register int      rc;

      while ((lc = *l++) && (rc = *r++))
            sfputc(ex->tmp, lc == rc ? lc : ' ');
      return exstash(ex->tmp, ex->ve);
}

/*
 * internal exeval
 */

static Extype_t
eval(Expr_t* ex, register Exnode_t* expr, void* env)
{
      register Exnode_t*      x;
      register Exnode_t*      a;
      register Extype_t**     t;
      register int            n;
      Extype_t          v;
      Extype_t          r;
      Extype_t          i;
      char*             e;
      Exnode_t          tmp;
      Exassoc_t*        assoc;
      Extype_t          args[FRAME];
      Extype_t          save[FRAME];

      if (!expr || ex->loopcount)
      {
            v.integer = 1;
            return v;
      }
      x = expr->data.operand.left;
      switch (expr->op)
      {
      case BREAK:
      case CONTINUE:
            v = eval(ex, x, env);
            ex->loopcount = v.integer;
            ex->loopop = expr->op;
            return v;
      case CONSTANT:
            return expr->data.constant.value;
      case DEC:
            n = -1;
      add:
            if (x->op == DYNAMIC)
                  r = getdyn(ex, x, env, &assoc);
            else
            {
                  if (x->data.variable.index)
                        i = eval(ex, x->data.variable.index, env);
                  else
                        i.integer = EX_SCALAR;
                  r = (*ex->disc->getf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)i.integer, ex->disc);
            }
            v = r;
            switch (x->type)
            {
            case FLOATING:
                  v.floating += n;
                  break;
            case INTEGER:
            case UNSIGNED:
                  v.integer += n;
                  break;
            default:
                  goto huh;
            }
      set:
            if (x->op == DYNAMIC)
            {
                  if (x->type == STRING)
                  {
                        v.string = vmstrdup(ex->vm, v.string);
                        if (e = assoc ? assoc->value.string : x->data.variable.symbol->value->data.constant.value.string)
                              vmfree(ex->vm, e);
                  }
                  if (assoc)
                        assoc->value = v;
                  else
                        x->data.variable.symbol->value->data.constant.value = v;
            }
            else
            {
                  if (x->data.variable.index)
                        i = eval(ex, x->data.variable.index, env);
                  else
                        i.integer = EX_SCALAR;
                  if ((*ex->disc->setf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)i.integer, v, ex->disc) < 0)
                        exerror("%s: cannot set value", x->data.variable.symbol->name);
            }
            if (expr->subop == PRE)
                  r = v;
            return r;
      case DYNAMIC:
            return getdyn(ex, expr, env, &assoc);
      case EXIT:
            v = eval(ex, x, env);
            exit((int)v.integer);
            /*NOTREACHED*/
            v.integer = -1;
            return v;
      case IF:
            v = eval(ex, x, env);
            if (v.integer)
                  eval(ex, expr->data.operand.right->data.operand.left, env);
            else
                  eval(ex, expr->data.operand.right->data.operand.right, env);
            v.integer = 1;
            return v;
      case FOR:
      case WHILE:
            expr = expr->data.operand.right;
            for (;;)
            {
                  r = eval(ex, x, env);
                  if (!r.integer)
                  {
                        v.integer = 1;
                        return v;
                  }
                  if (expr->data.operand.right)
                  {
                        eval(ex, expr->data.operand.right, env);
                        if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
                        {
                              v.integer = 0;
                              return v;
                        }
                  }
                  if (expr->data.operand.left)
                        eval(ex, expr->data.operand.left, env);
            }
            /*NOTREACHED*/
      case SWITCH:
            v = eval(ex, x, env);
            i.integer = x->type;
            r.integer = 0;
            x = expr->data.operand.right;
            a = x->data.select.statement;
            n = 0;
            while (x = x->data.select.next)
            {
                  if (!(t = x->data.select.constant))
                        n = 1;
                  else
                        for (; *t; t++)
                        {
                              switch ((int)i.integer)
                              {
                              case INTEGER:
                              case UNSIGNED:
                                    if ((*t)->integer == v.integer)
                                          break;
                                    continue;
                              case STRING:
                                    if ((ex->disc->version >= 19981111L && ex->disc->matchf) ? (*ex->disc->matchf)(ex, x, (*t)->string, expr->data.operand.left, v.string, env, ex->disc) : strmatch((*t)->string, v.string))
                                          break;
                                    continue;
                              case FLOATING:
                                    if ((*t)->floating == v.floating)
                                          break;
                                    continue;
                              }
                              n = 1;
                              break;
                        }
                  if (n)
                  {
                        if (!x->data.select.statement)
                        {
                              r.integer = 1;
                              break;
                        }
                        r = eval(ex, x->data.select.statement, env);
                        if (ex->loopcount > 0)
                        {
                              ex->loopcount--;
                              break;
                        }
                  }
            }
            if (!n && a)
            {
                  r = eval(ex, a, env);
                  if (ex->loopcount > 0)
                        ex->loopcount--;
            }
            return r;
      case ITERATE:
            v.integer = 0;
            if (expr->data.generate.array->op == DYNAMIC)
            {
                  n = expr->data.generate.index->type == STRING;
                  for (assoc = (Exassoc_t*)dtfirst((Dt_t*)expr->data.generate.array->data.variable.symbol->local.pointer); assoc; assoc = (Exassoc_t*)dtnext((Dt_t*)expr->data.generate.array->data.variable.symbol->local.pointer, assoc))
                  {
                        v.integer++;
                        if (n)
                              expr->data.generate.index->value->data.constant.value.string = assoc->name;
                        else
                              expr->data.generate.index->value->data.constant.value.integer = strtol(assoc->name, NiL, 0);
                        eval(ex, expr->data.generate.statement, env);
                        if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
                        {
                              v.integer = 0;
                              break;
                        }
                  }
            }
            else
            {
                  r = (*ex->disc->getf)(ex, expr, expr->data.generate.array->data.variable.symbol, expr->data.generate.array->data.variable.reference, env, 0, ex->disc);
                  for (v.integer = 0; v.integer < r.integer; v.integer++)
                  {
                        expr->data.generate.index->value->data.constant.value.integer = v.integer;
                        eval(ex, expr->data.generate.statement, env);
                        if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE))
                        {
                              v.integer = 0;
                              break;
                        }
                  }
            }
            return v;
      case CALL:
            x = expr->data.call.args;
            for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && x; a = a->data.operand.right)
            {
                  if (n < elementsof(args))
                  {
                        save[n] = a->data.operand.left->data.variable.symbol->value->data.constant.value;
                        args[n++] = eval(ex, x->data.operand.left, env);
                  }
                  else
                        a->data.operand.left->data.variable.symbol->value->data.constant.value = eval(ex, x->data.operand.left, env);
                  x = x->data.operand.right;
            }
            for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && n < elementsof(save); a = a->data.operand.right)
                  a->data.operand.left->data.variable.symbol->value->data.constant.value = args[n++];
            if (x)
                  exerror("too many actual args");
            else if (a)
                  exerror("not enough actual args");
            v = exeval(ex, expr->data.call.procedure->value->data.procedure.body, env);
            for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && n < elementsof(save); a = a->data.operand.right)
                  a->data.operand.left->data.variable.symbol->value->data.constant.value = save[n++];
            return v;
      case FUNCTION:
            n = 0;
            for (x = expr->data.operand.right; x && n < elementsof(args); x = x->data.operand.right)
                  args[n++] = eval(ex, x->data.operand.left, env);
            return (*ex->disc->getf)(ex, expr->data.operand.left, expr->data.operand.left->data.variable.symbol, expr->data.operand.left->data.variable.reference, args, EX_CALL, ex->disc);
      case ID:
            if (expr->data.variable.index)
                  i = eval(ex, expr->data.variable.index, env);
            else
                  i.integer = EX_SCALAR;
            return (*ex->disc->getf)(ex, expr, expr->data.variable.symbol, expr->data.variable.reference, env, (int)i.integer, ex->disc);
      case INC:
            n = 1;
            goto add;
      case PRINTF:
            v.integer = print(ex, expr, env, NiL);
            return v;
      case QUERY:
            print(ex, expr, env, sfstderr);
            v.integer = !astquery(2, "");
            return v;
      case RETURN:
            ex->loopret = eval(ex, x, env);
            ex->loopcount = 32767;
            ex->loopop = expr->op;
            return ex->loopret;
      case SCANF:
      case SSCANF:
            v.integer = scan(ex, expr, env, NiL);
            return v;
      case SPRINTF:
            print(ex, expr, env, ex->tmp);
            v.string = exstash(ex->tmp, ex->ve);
            return v;
      case '=':
            v = eval(ex, expr->data.operand.right, env);
            if (expr->subop != '=')
            {
                  r = v;
                  if (x->op == DYNAMIC)
                        v = getdyn(ex, x, env, &assoc);
                  else
                  {
                        if (x->data.variable.index)
                              v = eval(ex, x->data.variable.index, env);
                        else
                              v.integer = EX_SCALAR;
                        v = (*ex->disc->getf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)v.integer, ex->disc);
                  }
                  switch (x->type)
                  {
                  case FLOATING:
                        switch (expr->subop)
                        {
                        case '+':
                              v.floating += r.floating;
                              break;
                        case '-':
                              v.floating -= r.floating;
                              break;
                        case '*':
                              v.floating *= r.floating;
                              break;
                        case '/':
                              if (r.floating == 0.0)
                                    exerror("floating divide by 0");
                              else
                                    v.floating /= r.floating;
                              break;
                        case '%':
                              if ((r.integer = r.floating) == 0)
                                    exerror("floating 0 modulus");
                              else
                                    v.floating = ((Sflong_t)v.floating) % r.integer;
                              break;
                        case '&':
                              v.floating = ((Sflong_t)v.floating) & ((Sflong_t)r.floating);
                              break;
                        case '|':
                              v.floating = ((Sflong_t)v.floating) | ((Sflong_t)r.floating);
                              break;
                        case '^':
                              v.floating = ((Sflong_t)v.floating) ^ ((Sflong_t)r.floating);
                              break;
                        case LS:
                              v.floating = ((Sflong_t)v.floating) << ((Sflong_t)r.floating);
                              break;
                        case RS:
#if _WIN32
                              v.floating = (Sflong_t)(((Sfulong_t)v.floating) >> ((Sflong_t)r.floating));
#else
                              v.floating = ((Sfulong_t)v.floating) >> ((Sflong_t)r.floating);
#endif
                              break;
                        default:
                              goto huh;
                        }
                        break;
                  case INTEGER:
                  case UNSIGNED:
                        switch (expr->subop)
                        {
                        case '+':
                              v.integer += r.integer;
                              break;
                        case '-':
                              v.integer -= r.integer;
                              break;
                        case '*':
                              v.integer *= r.integer;
                              break;
                        case '/':
                              if (r.integer == 0)
                                    exerror("integer divide by 0");
                              else
                                    v.integer /= r.integer;
                              break;
                        case '%':
                              if (r.integer == 0)
                                    exerror("integer 0 modulus");
                              else
                                    v.integer %= r.integer;
                              break;
                        case '&':
                              v.integer &= r.integer;
                              break;
                        case '|':
                              v.integer |= r.integer;
                              break;
                        case '^':
                              v.integer ^= r.integer;
                              break;
                        case LS:
                              v.integer <<= r.integer;
                              break;
                        case RS:
                              v.integer = (Sfulong_t)v.integer >> r.integer;
                              break;
                        default:
                              goto huh;
                        }
                        break;
                  case STRING:
                        switch (expr->subop)
                        {
                        case '+':
                              v.string = str_add(ex, v.string, r.string);
                              break;
                        case '|':
                              v.string = str_ior(ex, v.string, r.string);
                              break;
                        case '&':
                              v.string = str_and(ex, v.string, r.string);
                              break;
                        case '^':
                              v.string = str_xor(ex, v.string, r.string);
                              break;
                        case '%':
                              v.string = str_mod(ex, v.string, r.string);
                              break;
                        case '*':
                              v.string = str_mpy(ex, v.string, r.string);
                              break;
                        default:
                              goto huh;
                        }
                        break;
                  default:
                        goto huh;
                  }
            }
            else if (x->op == DYNAMIC)
                  getdyn(ex, x, env, &assoc);
            else
                  assoc = 0;
            r = v;
            goto set;
      case ';':
      case ',':
            v = eval(ex, x, env);
            while ((expr = expr->data.operand.right) && (expr->op == ';' || expr->op == ','))
            {
                  v = eval(ex, expr->data.operand.left, env);
                  if (ex->loopcount)
                        return v;
            }
            return expr ? eval(ex, expr, env) : v;
      case '?':
            v = eval(ex, x, env);
            return v.integer ? eval(ex, expr->data.operand.right->data.operand.left, env) : eval(ex, expr->data.operand.right->data.operand.right, env);
      case AND:
            v = eval(ex, x, env);
            return v.integer ? eval(ex, expr->data.operand.right, env) : v;
      case OR:
            v = eval(ex, x, env);
            return v.integer ? v : eval(ex, expr->data.operand.right, env);
      }
      v = eval(ex, x, env);
      if (x = expr->data.operand.right)
            r = eval(ex, x, env);
      switch (expr->data.operand.left->type)
      {
      case FLOATING:
            switch (expr->op)
            {
            case F2I:
                  v.integer = v.floating;
                  return v;
            case F2S:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if (expr->data.operand.left->op != DYNAMIC && expr->data.operand.left->op != ID)
                  {
                        sfprintf(ex->tmp, "%g", v.floating);
                        tmp.data.constant.value.string = exstash(ex->tmp, ex->ve);
                  }
                  else if ((*ex->disc->convertf)(ex, &tmp, STRING, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                        exerror("%s: cannot convert value to string", expr->data.operand.left->data.variable.symbol->name);
                  tmp.type = STRING;
                  return tmp.data.constant.value;
            case F2X:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if ((*ex->disc->convertf)(ex, &tmp, expr->type, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                        exerror("%s: cannot convert floating value to external", tmp.data.variable.symbol->name);
                  tmp.type = expr->type;
                  return tmp.data.constant.value;
            case '!':
                  v.floating = !((Sflong_t)v.floating);
                  return v;
            case '~':
                  v.floating = ~((Sflong_t)v.floating);
                  return v;
            case '-':
                  if (x)
                        v.floating -= r.floating;
                  else
                        v.floating = -v.floating;
                  return v;
            case '+':
                  v.floating += r.floating;
                  return v;
            case '&':
                  v.floating = (Sflong_t)v.floating & (Sflong_t)r.floating;
                  return v;
            case '|':
                  v.floating = (Sflong_t)v.floating | (Sflong_t)r.floating;
                  return v;
            case '^':
                  v.floating = (Sflong_t)v.floating ^ (Sflong_t)r.floating;
                  return v;
            case '*':
                  v.floating *= r.floating;
                  return v;
            case '/':
                  if (r.floating == 0.0)
                        exerror("floating divide by 0");
                  else
                        v.floating /= r.floating;
                  return v;
            case '%':
                  if ((r.integer = r.floating) == 0)
                        exerror("floating 0 modulus");
                  else
                        v.floating = (Sflong_t)v.floating % r.integer;
                  return v;
            case '<':
                  v.integer = v.floating < r.floating;
                  return v;
            case LE:
                  v.integer = v.floating <= r.floating;
                  return v;
            case EQ:
                  v.integer = v.floating == r.floating;
                  return v;
            case NE:
                  v.integer = v.floating != r.floating;
                  return v;
            case GE:
                  v.integer = v.floating >= r.floating;
                  return v;
            case '>':
                  v.integer = v.floating > r.floating;
                  return v;
            case LS:
                  v.floating = (Sflong_t)v.floating << (Sflong_t)r.floating;
                  return v;
            case RS:
                  v.integer = ((Sfulong_t)v.floating) >> (Sflong_t)r.floating;
                  return v;
            }
            break;
      default:
            switch (expr->op)
            {
            case X2F:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if ((*ex->disc->convertf)(ex, &tmp, FLOATING, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                        exerror("%s: cannot convert value to floating", expr->data.operand.left->data.variable.symbol->name);
                  tmp.type = FLOATING;
                  return tmp.data.constant.value;
            case X2I:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if ((*ex->disc->convertf)(ex, &tmp, INTEGER, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                        exerror("%s: cannot convert value to integer", expr->data.operand.left->data.variable.symbol->name);
                  tmp.type = INTEGER;
                  return tmp.data.constant.value;
            case X2S:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if ((*ex->disc->convertf)(ex, &tmp, STRING, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                        exerror("%s: cannot convert value to string", expr->data.operand.left->data.variable.symbol->name);
                  tmp.type = STRING;
                  return tmp.data.constant.value;
            }
            goto integer;
      case UNSIGNED:
            switch (expr->op)
            {
            case '<':
                  v.integer = (Sfulong_t)v.integer < (Sfulong_t)r.integer;
                  return v;
            case LE:
                  v.integer = (Sfulong_t)v.integer <= (Sfulong_t)r.integer;
                  return v;
            case GE:
                  v.integer = (Sfulong_t)v.integer >= (Sfulong_t)r.integer;
                  return v;
            case '>':
                  v.integer = (Sfulong_t)v.integer > (Sfulong_t)r.integer;
                  return v;
            }
            /*FALLTHROUGH*/
      case INTEGER:
      integer:
            switch (expr->op)
            {
            case I2F:
#if _WIN32
                  v.floating = v.integer;
#else
                  if (expr->type == UNSIGNED)
                        v.floating = (Sfulong_t)v.integer;
                  else
                        v.floating = v.integer;
#endif
                  return v;
            case I2S:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if (expr->data.operand.left->op != DYNAMIC && expr->data.operand.left->op != ID)
                  {
                        if (expr->data.operand.left->type == UNSIGNED)
                              sfprintf(ex->tmp, "%I*u", sizeof(v.integer), v.integer);
                        else
                              sfprintf(ex->tmp, "%I*d", sizeof(v.integer), v.integer);
                        tmp.data.constant.value.string = exstash(ex->tmp, ex->ve);
                  }
                  else if ((*ex->disc->convertf)(ex, &tmp, STRING, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                        exerror("%s: cannot convert value to string", expr->data.operand.left->data.variable.symbol->name);
                  tmp.type = STRING;
                  return tmp.data.constant.value;
            case I2X:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if ((*ex->disc->convertf)(ex, &tmp, expr->type, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                        exerror("%s: cannot convert integer value to external", tmp.data.variable.symbol->name);
                  tmp.type = expr->type;
                  return tmp.data.constant.value;
            case '!':
                  v.integer = !v.integer;
                  return v;
            case '~':
                  v.integer = ~v.integer;
                  return v;
            case '-':
                  if (x)
                        v.integer -= r.integer;
                  else
                        v.integer = -v.integer;
                  return v;
            case '+':
                  v.integer += r.integer;
                  return v;
            case '&':
                  v.integer &= r.integer;
                  return v;
            case '|':
                  v.integer |= r.integer;
                  return v;
            case '^':
                  v.integer ^= r.integer;
                  return v;
            case '*':
                  v.integer *= r.integer;
                  return v;
            case '/':
                  if (r.integer == 0)
                        exerror("integer divide by 0");
                  else
                        v.integer /= r.integer;
                  return v;
            case '%':
                  if (r.integer == 0)
                        exerror("integer 0 modulus");
                  else
                        v.integer %= r.integer;
                  return v;
            case EQ:
                  v.integer = v.integer == r.integer;
                  return v;
            case NE:
                  v.integer = v.integer != r.integer;
                  return v;
            case LS:
                  v.integer = v.integer << r.integer;
                  return v;
            case RS:
                  v.integer = ((Sfulong_t)v.integer) >> r.integer;
                  return v;
            case '<':
                  v.integer = v.integer < r.integer;
                  return v;
            case LE:
                  v.integer = v.integer <= r.integer;
                  return v;
            case GE:
                  v.integer = v.integer >= r.integer;
                  return v;
            case '>':
                  v.integer = v.integer > r.integer;
                  return v;
            }
            break;
      case STRING:
            switch (expr->op)
            {
            case S2B:
                  v.integer = *v.string != 0;
                  return v;
            case S2F:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if ((*ex->disc->convertf)(ex, &tmp, FLOATING, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                  {
                        tmp.data.constant.value.floating = strtod(v.string, &e);
                        if (*e)
                              tmp.data.constant.value.floating = *v.string != 0;
                  }
                  tmp.type = FLOATING;
                  return tmp.data.constant.value;
            case S2I:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if ((*ex->disc->convertf)(ex, &tmp, INTEGER, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                  {
                        tmp.data.constant.value.integer = strtoll(v.string, &e, 0);
                        if (*e)
                              tmp.data.constant.value.integer = *v.string != 0;
                  }
                  tmp.type = INTEGER;
                  return tmp.data.constant.value;
            case S2X:
                  tmp = *expr->data.operand.left;
                  tmp.data.constant.value = v;
                  if ((*ex->disc->convertf)(ex, &tmp, expr->type, expr->data.operand.right ? expr->data.operand.right->data.variable.symbol : (Exid_t*)0, 0, ex->disc))
                        exerror("%s: cannot convert string value to external", tmp.data.variable.symbol->name);
                  tmp.type = expr->type;
                  return tmp.data.constant.value;
            case EQ:
            case NE:
                  v.integer = ((v.string && r.string) ? ((ex->disc->version >= 19981111L && ex->disc->matchf) ? (*ex->disc->matchf)(ex, expr->data.operand.left, v.string, expr->data.operand.right, r.string, env, ex->disc) : strmatch(v.string, r.string)) : (v.string == r.string)) == (expr->op == EQ);
                  return v;
            case '+':
                  v.string = str_add(ex, v.string, r.string);
                  return v;
            case '|':
                  v.string = str_ior(ex, v.string, r.string);
                  return v;
            case '&':
                  v.string = str_and(ex, v.string, r.string);
                  return v;
            case '^':
                  v.string = str_xor(ex, v.string, r.string);
                  return v;
            case '%':
                  v.string = str_mod(ex, v.string, r.string);
                  return v;
            case '*':
                  v.string = str_mpy(ex, v.string, r.string);
                  return v;
            }
            v.integer = strcoll(v.string, r.string);
            switch (expr->op)
            {
            case '<':
                  v.integer = v.integer < 0;
                  return v;
            case LE:
                  v.integer = v.integer <= 0;
                  return v;
            case GE:
                  v.integer = v.integer >= 0;
                  return v;
            case '>':
                  v.integer = v.integer > 0;
                  return v;
            }
            goto huh;
      }
 huh:
      if (expr->binary)
            exerror("operator %s %s %s not implemented", lexname(expr->data.operand.left->type, -1), lexname(expr->op, expr->subop), expr->data.operand.right ? lexname(expr->data.operand.right->type, -1) : "UNARY");
      else
            exerror("operator %s %s not implemented", lexname(expr->op, expr->subop), lexname(expr->data.operand.left->type, -1));
      return exzero(expr->type);
}

/*
 * evaluate expression expr
 */

Extype_t
exeval(Expr_t* ex, Exnode_t* expr, void* env)
{
      Extype_t    v;

      vmclear(ex->ve);
      if (expr->compiled.integer)
      {
            switch (expr->type)
            {
            case FLOATING:
                  v.floating = (*expr->compiled.floating)(ex->disc->data);
                  break;
            case STRING:
                  v.string = (*expr->compiled.string)(ex->disc->data);
                  break;
            default:
                  v.integer = (*expr->compiled.integer)(ex->disc->data);
                  break;
            }
      }
      else
      {
            v = eval(ex, expr, env);
            if (ex->loopcount > 0)
            {
                  ex->loopcount = 0;
                  if (ex->loopop == RETURN)
                        return ex->loopret;
            }
      }
      return v;
}

Generated by  Doxygen 1.6.0   Back to index