/* symtab.c,v 1.2 1995/04/08 19:53:04 explorer Exp */

/*
 * Copyright (C) 1989, 1991, Craig E. Kolb, Rod G. Bogart
 * All rights reserved.
 *
 * This software may be freely copied, modified, and redistributed
 * provided that this copyright notice is preserved on all copies.
 *
 * You may not distribute this software, in whole or in part, as part of
 * any commercial product without the express consent of the authors.
 *
 * There is no warranty or other guarantee of fitness of this software
 * for any purpose.  It is provided solely "as is".
 *
 */

#include "rayshade.h"
#include "symtab.h"
#include "builtin.h"
#ifdef AMIGA
#ifndef __GNUC__
extern double hypot(double, double);
#endif
#endif

static struct SymtabPredefinedEntry SymtabPredefined[] = {
  {"pi", 3.141592, NULL, FLOAT_EXPR, FALSE, 0},
  {"dtor", 0.017453, NULL, FLOAT_EXPR, FALSE, 0},
  {"rtod", 57.29578, NULL, FLOAT_EXPR, FALSE, 0},
  {"cos", 0.0, (Float(*) ()) cos, BUILTIN_EXPR, FALSE, 1},
  {"sin", 0.0, (Float(*) ()) sin, BUILTIN_EXPR, FALSE, 1},
  {"tan", 0.0, (Float(*) ()) tan, BUILTIN_EXPR, FALSE, 1},
  {"sqrt", 0.0, (Float(*) ()) sqrt, BUILTIN_EXPR, FALSE, 1},
  {"acos", 0.0, (Float(*) ()) acos, BUILTIN_EXPR, FALSE, 1},
  {"asin", 0.0, (Float(*) ()) asin, BUILTIN_EXPR, FALSE, 1},
  {"atan", 0.0, (Float(*) ()) atan, BUILTIN_EXPR, FALSE, 1},
  {"hypot", 0.0, (Float(*) ()) hypot, BUILTIN_EXPR, FALSE, 2},
  {"time", 0.0, NULL, FLOAT_EXPR, TRUE, 0},
  {"frame", 0.0, NULL, FLOAT_EXPR, TRUE, 0},
  {"linear", 0.0, LinearTime, BUILTIN_EXPR, TRUE, 4},
  {"linear", 0.0, LinearMode, FLOAT_EXPR, TRUE, 0},
  {"accel", 0.0, AccelMode, FLOAT_EXPR, TRUE, 0},
  {"decel", 0.0, DecelMode, FLOAT_EXPR, TRUE, 0},
  {"accdec", 0.0, AccelDecelMode, FLOAT_EXPR, TRUE, 0},
  {"jump", 0.0, JumpMode, FLOAT_EXPR, TRUE, 0},
  {NULL, 0.0, NULL, 0, 0}
};

SymtabEntry *Symtab = (SymtabEntry *) NULL;

void
SymtabInit()
{
  int i;

  for (i = 0; SymtabPredefined[i].name; i++) {
    switch (SymtabPredefined[i].type) {
    case BUILTIN_EXPR:
      SymtabAddEntry(SymtabPredefined[i].name,
		     SymtabPredefined[i].type,
		     NULL,
		     SymtabPredefined[i].fp,
		     SymtabPredefined[i].timevary,
		     SymtabPredefined[i].params);
      break;

    case FLOAT_EXPR:
      if (SymtabPredefined[i].fp == NULL) {
	SymtabAddEntry(SymtabPredefined[i].name,
			SymtabPredefined[i].type,
			ExprFloatCreate(SymtabPredefined[i].f,
			SymtabPredefined[i].timevary),
			NULL,
			SymtabPredefined[i].timevary,
			0);
      } else {
	/* Modes for animated variables */
	SymtabAddEntry(SymtabPredefined[i].name,
			SymtabPredefined[i].type,
			ExprFunctionCreate(SymtabPredefined[i].fp, 1,
						&TimeExpr, TRUE),
			NULL,
			SymtabPredefined[i].timevary,
			0);
      }
      break;

    default:
      RLerror(RL_WARN, "Type %d not implemented!!!\n",
		SymtabPredefined[i].type);
    }

  }
  TimeExpr = ExprFloatSymtabFind("time");
  FrameExpr = ExprFloatSymtabFind("frame");
  DefaultMode = ExprFloatSymtabFind("linear");
}

void
SymtabAddEntry(name, type, expr, fp, timevary, params)
  char *name;
  Expr *expr;
  FloatFuncPtr fp;
  int type, timevary, params;
{
  SymtabEntry *res;

  /* If symbol with same name and same type already exists, complain */
  if (SymtabFind(name, type) != (SymtabEntry *)NULL)
    RLerror(RL_ABORT, "Symbol %s redefined.\n", name);

  res = (SymtabEntry *) Malloc(sizeof(SymtabEntry));
  res->name = strsave(name);
  res->type = type;
  res->timevary = timevary;
  switch (type) {
  case FLOAT_EXPR:
    res->value.expr = expr;
    expr->symtab = TRUE;
    break;
  case BUILTIN_EXPR:
    res->value.fp = fp;
    break;
  default:
    RLerror(RL_WARN, "Type %d not implemented!!!", type);
  }
  res->params = params;
  res->next = Symtab;
  Symtab = res;
}

SymtabEntry *
SymtabFind(name, type)
  char	*name;
  int	type;
{
  SymtabEntry *res;

  for (res = Symtab; res != NULL; res = res->next) {
    if (streq(res->name, name) && res->type == type)
      return res;
  }
  /* error */
  return NULL;
}

Expr *
ExprFloatSymtabFind(name)
  char *name;
{
  SymtabEntry *res;

  if ((res = SymtabFind(name, FLOAT_EXPR)) == NULL) 
    RLerror(RL_PANIC, "Symbol %s not defined or not a float expression!\n",
		name);

  return res->value.expr;
}


SymtabEntry *
SymtabBuiltinFind(name)
  char *name;
{
  SymtabEntry *res;

  if ((res = SymtabFind(name, BUILTIN_EXPR)) == NULL) 
    RLerror(RL_PANIC, "Symbol %s not defined or not a builtin function!\n",
		name);

  return res;
}
