diff --git a/src/ChangeLog b/src/ChangeLog
index de000c9bf87a2745d56bc3676b45faba540eceab..1574e91eab0599e9bb4364efc1bf1671cd669bd8 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+Sun Feb 25 22:42:48 1996  Fredrik Hubinette  <hubbe@tymin.signum.se>
+
+	* operator functions implemented
+	* typeof() added
+
 Sat Feb 24 04:12:52 1996  Fredrik Hubinette  <hubbe@tymin.signum.se>
 
 	* program.c, array.c, object.c, gc.c: 
diff --git a/src/Makefile.in b/src/Makefile.in
index fbfd057af6a905fd05479c34eee0d9c5e3d2bed8..41e2f32f64fb0cd51a571ad52bdbf19c8cc58c48 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -172,6 +172,12 @@ depend: language.c
 	gcc -MM $(PREFLAGS) *.c $(SRCDIR)/*.c | $(FIXDEP) $(SRCDIR)/Makefile.in
 	for a in $(MODULES) ; do ( cd $$a ; ${MAKE} $(MAKE_FLAGS) depend ) ; done
 
+docs:
+	mkdir docs
+
+html_docs: docs
+	$(RUNULPC) $(TMP_BINDIR)/htmlify_docs $(TMP_DOCDIR) docs
+
 #
 # uLPC internal targets
 #
diff --git a/src/builtin_efuns.c b/src/builtin_efuns.c
index 992553c9cfacea3a9bf5fdcd11ea3ddc30c6df1e..81cc0404a1ba94a70ec418fb91bff22e213d0e6d 100644
--- a/src/builtin_efuns.c
+++ b/src/builtin_efuns.c
@@ -579,7 +579,14 @@ void f_sizeof(INT32 args)
     tmp=sp[-1].u.list->ind->size;
     free_list(sp[-1].u.list);
     break;
-    
+
+  case T_OBJECT:
+    if(!sp[-1].u.object->prog)
+      error("sizeof() on destructed object.\n");
+    tmp=sp[-1].u.object->prog->num_identifier_indexes;
+    free_object(sp[-1].u.object);
+    break;
+
   default:
     error("Bad argument 1 to sizeof().\n");
     return; /* make apcc happy */
@@ -1263,7 +1270,7 @@ void init_builtin_efuns()
   add_efun("reverse",f_reverse,"function(int:int)|function(string:string)|function(array:array)",0);
   add_efun("rusage", f_rusage, "function(:int *)",OPT_EXTERNAL_DEPEND);
   add_efun("search",f_search,"function(string,string,void|int:int)|function(array,mixed,void|int:int)|function(mapping,mixed:mixed)",0);
-  add_efun("sizeof", f_sizeof, "function(string|list|array|mapping:int)",0);
+  add_efun("sizeof", f_sizeof, "function(string|list|array|mapping|object:int)",0);
   add_efun("sleep", f_sleep, "function(int:void)",OPT_SIDE_EFFECT);
   add_efun("stringp", f_stringp, "function(mixed:int)",0);
 
diff --git a/src/language.y b/src/language.y
index 528e4714a8898c35089169963a155dbf8f1d2089..0c4ef11bf4e56087691861b69e349aa994453d88 100644
--- a/src/language.y
+++ b/src/language.y
@@ -113,6 +113,7 @@
 %token F_STRING_ID
 %token F_SUBSCRIPT
 %token F_SUB_EQ
+%token F_TYPEOF
 %token F_VAL_LVAL
 %token F_VARARGS 
 %token F_VOID_ID
@@ -223,7 +224,7 @@ void fix_comp_stack(int sp)
 %type <n> for do cond optional_else_part while statements
 %type <n> local_name_list class catch_arg
 %type <n> unused2 foreach unused switch case return expr_list default
-%type <n> continue break block_or_semi
+%type <n> continue break block_or_semi typeof
 %%
 
 all: program;
@@ -920,6 +921,7 @@ expr4: string
      | F_FLOAT { $$=mkfloatnode($1); }
      | catch
      | gauge
+     | typeof
      | sscanf
      | lambda
      | class
@@ -1029,8 +1031,15 @@ gauge: F_GAUGE '(' unused ')'
 				   mkintnode(GAUGE_RUSAGE_INDEX)))),0);
   } ;
 
+typeof: F_TYPEOF '(' expr0 ')'
+      {
+	node *tmp;
+	tmp=mknode(F_ARG_LIST,$3,0);
+        $$=mkstrnode(describe_type($3->type));
+        free_node(tmp);
+      } ;
 
-catch_arg: '(' unused ')'  { $$=$2; }
+catch_arg: '(' comma_expr ')'  { $$=$2; }
          | block
          ; 
 
diff --git a/src/lex.c b/src/lex.c
index a1ad1fdb7ee2da8b70fa58f1930f601856fb1b86..9738a418ce8b344dd06d6c714a717b5db3855392 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -124,6 +124,7 @@ struct keyword reserved_words[] =
 { "static",	F_STATIC, },
 { "string",	F_STRING_ID, },
 { "switch",	F_SWITCH, },
+{ "typeof",	F_TYPEOF, },
 { "varargs",	F_VARARGS, },
 { "void",	F_VOID_ID, },
 { "while",	F_WHILE, },
@@ -1532,8 +1533,6 @@ static int do_lex2(int literal, YYSTYPE *yylval)
       case '|': tmp="`|"; break;
       case '^': tmp="`^"; break;
       case '~': tmp="`~"; break;
-      case '(':
-	if(GOBBLE(')')) { tmp="`()"; break; }
 
       default:
 	yyerror("Illegal ` identifier.");
diff --git a/src/lpc_types.c b/src/lpc_types.c
index 4cf28ef1201393cba59d9545c3e23d1b90d276d6..e2186c79741998ca054d12d1790eea4140138152 100644
--- a/src/lpc_types.c
+++ b/src/lpc_types.c
@@ -18,6 +18,8 @@
 #include "macros.h"
 #include "error.h"
 
+static void internal_parse_type(char **s);
+
 /*
  * basic types are represented by just their value in a string
  * basic type are string, int, float, object and program
@@ -80,10 +82,12 @@ static int type_length(char *t)
 
   case T_MAPPING:
   case T_OR:
+  case T_AND:
     t+=type_length(t);
 
   case T_ARRAY:
   case T_LIST:
+  case T_NOT:
     t+=type_length(t);
 
   case T_INT:
@@ -99,7 +103,7 @@ static int type_length(char *t)
   return t-q;
 }
 
-static void internal_parse_type(char **s)
+static void internal_parse_typeA(char **s)
 {
   char buf[80];
   unsigned int len;
@@ -169,8 +173,8 @@ static void internal_parse_type(char **s)
       type_stack_reverse();
       if(**s != ')') error("Missing ')' in function type.\n");
       ++*s;
-      type_stack_reverse();
-    }else{
+      type_stack_reverse(); 
+   }else{
       push_type(T_MIXED);
       push_type(T_MIXED);
       push_type(T_MANY);
@@ -227,19 +231,81 @@ static void internal_parse_type(char **s)
     error("Couldn't parse type. (%s)\n",buf);
 
   while(isspace(**s)) ++*s;
+}
+
+
+static void internal_parse_typeB(char **s)
+{
+  while(isspace(**s)) ++*s;
+  switch(**s)
+  {
+  case '!':
+    ++*s;
+    internal_parse_typeB(s);
+    push_type(T_NOT);
+    break;
+
+  case '(':
+    ++*s;
+    internal_parse_typeB(s);
+    while(isspace(**s)) ++*s;
+    if(**s != ')') error("Expecting ')'.\n");
+    break;
+    
+  default:
+
+    internal_parse_typeA(s);
+  }
+}
+
+static void internal_parse_typeCC(char **s)
+{
+  internal_parse_typeB(s);
+
+  while(isspace(**s)) ++*s;
+  
   while(**s == '*')
   {
     ++*s;
-    push_type(T_ARRAY);
     while(isspace(**s)) ++*s;
+    push_type(T_ARRAY);
   }
+}
+
+static void internal_parse_typeC(char **s)
+{
+  type_stack_mark();
+
+  type_stack_mark();
+  internal_parse_typeCC(s);
+  type_stack_reverse();
 
+  while(isspace(**s)) ++*s;
+  
+  if(**s == '&')
+  {
+    ++*s;
+    type_stack_mark();
+    internal_parse_typeC(s);
+    type_stack_reverse();
+    type_stack_reverse();
+    push_type(T_AND);
+  }else{
+    type_stack_reverse();
+  }
+}
+
+static void internal_parse_type(char **s)
+{
+  internal_parse_typeC(s);
+
+  while(isspace(**s)) ++*s;
+  
   while(**s == '|')
   {
     ++*s;
-    internal_parse_type(s);
+    internal_parse_typeC(s);
     push_type(T_OR);
-    while(isspace(**s)) ++*s;
   }
 }
 
@@ -280,6 +346,8 @@ void stupid_describe_type(char *a,INT32 len)
     case T_UNKNOWN: printf("unknown"); break;
     case T_MANY: printf("many"); break;
     case T_OR: printf("or"); break;
+    case T_AND: printf("and"); break;
+    case T_NOT: printf("not"); break;
     case T_VOID: printf("void"); break;
     case T_MIXED: printf("mixed"); break;
 
@@ -299,33 +367,14 @@ char *low_describe_type(char *t)
 {
   switch(EXTRACT_UCHAR(t++))
   {
-  case T_VOID:
-    my_strcat("void");
-    break;
-
-  case T_MIXED:
-    my_strcat("mixed");
-    break;
-
-  case T_UNKNOWN:
-    my_strcat("unknown");
-    break;
-
-  case T_INT:
-    my_strcat("int");
-    break;
-
-  case T_FLOAT:
-    my_strcat("float");
-    break;
-
-  case T_PROGRAM:
-    my_strcat("program");
-    break;
-
-  case T_OBJECT:
-    my_strcat("object");
-    break;
+  case T_VOID: my_strcat("void"); break;
+  case T_MIXED: my_strcat("mixed"); break;
+  case T_UNKNOWN: my_strcat("unknown"); break;
+  case T_INT: my_strcat("int"); break;
+  case T_FLOAT: my_strcat("float"); break;
+  case T_PROGRAM: my_strcat("program"); break;
+  case T_OBJECT: my_strcat("object"); break;
+  case T_STRING: my_strcat("string"); break;
 
   case T_FUNCTION:
   {
@@ -335,36 +384,49 @@ char *low_describe_type(char *t)
     while(EXTRACT_UCHAR(t) != T_MANY)
     {
       if(s++) my_strcat(", ");
-      low_describe_type(t);
-      t+=type_length(t);
+      t=low_describe_type(t);
     }
     t++;
-    if(EXTRACT_UCHAR(t) != T_VOID)
+    if(EXTRACT_UCHAR(t) == T_VOID)
     {
+      t++;
+    }else{
       if(s++) my_strcat(", ");
-      low_describe_type(t);
+      t=low_describe_type(t);
       my_strcat(" ...");
     }
-    t+=type_length(t);
     my_strcat(" : ");
-    low_describe_type(t);
+    t=low_describe_type(t);
     my_strcat(")");
     break;
   }
 
-  case T_STRING:
-    my_strcat("string");
-    break;
-
   case T_ARRAY:
-    t=low_describe_type(t);
-    my_strcat("*");
+    if(EXTRACT_UCHAR(t)==T_MIXED)
+    {
+      my_strcat("array");
+      t++;
+    }else{
+      t=low_describe_type(t);
+      my_strcat("*");
+    }
     break;
 
   case T_LIST:
-    my_strcat("list (");
+    my_strcat("list");
+    if(EXTRACT_UCHAR(t)!=T_MIXED)
+    {
+      my_strcat("(");
+      t=low_describe_type(t);
+      my_strcat(")");
+    }else{
+      t++;
+    }
+    break;
+
+  case T_NOT:
+    my_strcat("!");
     t=low_describe_type(t);
-    my_strcat(")");
     break;
 
   case T_OR:
@@ -372,28 +434,53 @@ char *low_describe_type(char *t)
     my_strcat(" | ");
     t=low_describe_type(t);
     break;
-    
-  case T_MAPPING:
-    my_strcat("mapping (");
+
+  case T_AND:
     t=low_describe_type(t);
-    my_strcat(":");
+    my_strcat(" & ");
     t=low_describe_type(t);
-    my_strcat(")");
+    break;
+    
+  case T_MAPPING:
+    my_strcat("mapping");
+    if(EXTRACT_UCHAR(t)==T_MIXED && EXTRACT_UCHAR(t+1)==T_MIXED)
+    {
+      t+=2;
+    }else{
+      my_strcat("(");
+      t=low_describe_type(t);
+      my_strcat(":");
+      t=low_describe_type(t);
+      my_strcat(")");
+    }
     break;
   }
   return t;
 }
 
-TYPE_T compile_type_to_runtime_type(struct lpc_string *s)
+struct lpc_string *describe_type(struct lpc_string *type)
 {
-  char *t;
-  t=s->str;
-  
+  if(!type) return make_shared_string("mixed");
+  init_buf();
+  low_describe_type(type->str);
+  return free_buf();
+}
+
+static TYPE_T low_compile_type_to_runtime_type(char *t)
+{
+  TYPE_T tmp;
   switch(EXTRACT_UCHAR(t))
   {
   case T_OR:
+    t++;
+    tmp=low_compile_type_to_runtime_type(t);
+    if(tmp == low_compile_type_to_runtime_type(t+type_length(t)))
+      return tmp;
+
   case T_MANY:
   case T_UNKNOWN:
+  case T_AND:
+  case T_NOT:
     return T_MIXED;
 
   default:
@@ -401,36 +488,70 @@ TYPE_T compile_type_to_runtime_type(struct lpc_string *s)
   }
 }
 
+TYPE_T compile_type_to_runtime_type(struct lpc_string *s)
+{
+  return low_compile_type_to_runtime_type(s->str);
+}
+
+#define A_EXACT 1
+#define B_EXACT 2
+
 /*
  * match two type strings, return zero if they don't match, and return
  * the part of 'a' that _did_ match if it did.
  */
-static char *low_match_types(char *a,char *b)
+static char *low_match_types(char *a,char *b, int flags)
 {
   char *ret;
   if(a == b) return a;
 
-  if(EXTRACT_UCHAR(a) == T_OR)
+  switch(EXTRACT_UCHAR(a))
   {
+  case T_AND:
     a++;
-    ret=low_match_types(a,b);
+    ret=low_match_types(a,b,flags);
+    if(!ret) return 0;
+    a+=type_length(a);
+    return low_match_types(a,b,flags);
+
+  case T_OR:
+    a++;
+    ret=low_match_types(a,b,flags);
     if(ret) return ret;
     a+=type_length(a);
-    return low_match_types(a,b);
+    return low_match_types(a,b,flags);
+
+  case T_NOT:
+    if(low_match_types(a+1,b,flags | B_EXACT))
+      return 0;
+    return a;
   }
 
-  if(EXTRACT_UCHAR(b) == T_OR)
+  switch(EXTRACT_UCHAR(b))
   {
+  case T_AND:
     b++;
-    ret=low_match_types(a,b);
+    ret=low_match_types(a,b,flags);
+    if(!ret) return 0;
+    b+=type_length(b);
+    return low_match_types(a,b,flags);
+
+  case T_OR:
+    b++;
+    ret=low_match_types(a,b,flags);
     if(ret) return ret;
     b+=type_length(b);
-    return low_match_types(a,b);
+    return low_match_types(a,b,flags);
+
+  case T_NOT:
+    if(low_match_types(a,b+1, flags | A_EXACT))
+      return 0;
+    return a;
   }
 
   /* 'mixed' matches anything */
-  if(EXTRACT_UCHAR(a) == T_MIXED) return a;
-  if(EXTRACT_UCHAR(b) == T_MIXED) return a;
+  if(EXTRACT_UCHAR(a) == T_MIXED && !(flags & A_EXACT)) return a;
+  if(EXTRACT_UCHAR(b) == T_MIXED && !(flags & B_EXACT)) return a;
   if(EXTRACT_UCHAR(a) != EXTRACT_UCHAR(b)) return 0;
 
   ret=a;
@@ -458,7 +579,7 @@ static char *low_match_types(char *a,char *b)
 	b+=type_length(b);
       }
 
-      if(!low_match_types(a_tmp, b_tmp)) return 0;
+      if(!low_match_types(a_tmp, b_tmp, flags)) return 0;
     }
     /* check the 'many' type */
     a++;
@@ -468,20 +589,20 @@ static char *low_match_types(char *a,char *b)
       a+=type_length(a);
       b+=type_length(b);
     }else{
-      if(!low_match_types(a,b)) return 0;
+      if(!low_match_types(a,b,flags)) return 0;
     }
     /* check the returntype */
-    if(!low_match_types(a,b)) return 0;
+    if(!low_match_types(a,b,flags)) return 0;
     break;
 
   case T_MAPPING:
-    if(!low_match_types(++a,++b)) return 0;
-    if(!low_match_types(a+type_length(a),b+type_length(b))) return 0;
+    if(!low_match_types(++a,++b,flags)) return 0;
+    if(!low_match_types(a+type_length(a),b+type_length(b),flags)) return 0;
     break;
 
   case T_LIST:
   case T_ARRAY:
-    if(!low_match_types(++a,++b)) return 0;
+    if(!low_match_types(++a,++b,flags)) return 0;
 
   case T_INT:
   case T_FLOAT:
@@ -503,19 +624,25 @@ static char *low_match_types(char *a,char *b)
  */
 static int low_get_return_type(char *a,char *b)
 {
-  if(EXTRACT_UCHAR(a) == T_OR)
+  int tmp;
+  switch(EXTRACT_UCHAR(a))
   {
-    int tmp;
+  case T_OR:
     a++;
     tmp=low_get_return_type(a,b);
     tmp+=low_get_return_type(a+type_length(a),b);
     if(tmp==2) push_type(T_OR);
     return tmp>0;
-  }
 
-  if(EXTRACT_UCHAR(a) == T_ARRAY)
-  {
-    int tmp;
+  case T_AND:
+    a++;
+    type_stack_mark();
+    tmp=low_get_return_type(a,b);
+    type_stack_pop_to_mark();
+    if(!tmp) return 0;
+    return low_get_return_type(a+type_length(a),b);
+
+  case T_ARRAY:
     a++;
     tmp=low_get_return_type(a,b);
     if(!tmp) return 0;
@@ -523,7 +650,7 @@ static int low_get_return_type(char *a,char *b)
     return 1;
   }
 
-  a=low_match_types(a,b);
+  a=low_match_types(a,b,0);
   if(a)
   {
     switch(EXTRACT_UCHAR(a))
@@ -547,7 +674,7 @@ static int low_get_return_type(char *a,char *b)
 
 int match_types(struct lpc_string *a,struct lpc_string *b)
 {
-  return 0!=low_match_types(a->str, b->str);
+  return 0!=low_match_types(a->str, b->str,0);
 }
 
 
@@ -585,6 +712,12 @@ void pop_type_stack()
     fatal("Type stack underflow\n");
 }
 
+void type_stack_pop_to_mark()
+{
+  pop_stack_mark();
+  type_stackp=*mark_stackp;
+}
+
 void type_stack_reverse()
 {
   unsigned char *a,*b,tmp;
@@ -651,6 +784,8 @@ static struct lpc_string *low_index_type(char *t)
     return pop_type();
   }
 
+  case T_AND:
+    return low_index_type(t+type_length(t));
 
   case T_STRING: /* always int */
   case T_LIST: /* always int */
@@ -680,17 +815,24 @@ static int low_check_indexing(char *type, char *index_type)
   case T_OR:
     return low_check_indexing(type,index_type) ||
       low_check_indexing(type+type_length(type),index_type);
-    
+
+  case T_AND:
+    return low_check_indexing(type,index_type) &&
+      low_check_indexing(type+type_length(type),index_type);
+
+  case T_NOT:
+    return !low_check_indexing(type,index_type);
+
   case T_STRING:
   case T_ARRAY:
-    return !!low_match_types(int_type_string->str, index_type);
+    return !!low_match_types(int_type_string->str, index_type,0);
 
   case T_OBJECT:
-    return !!low_match_types(string_type_string->str, index_type);
+    return !!low_match_types(string_type_string->str, index_type,0);
 
   case T_LIST:
   case T_MAPPING:
-    return !!low_match_types(type,index_type);
+    return !!low_match_types(type,index_type,0);
 
   case T_MIXED:
     return 1;
@@ -741,7 +883,6 @@ struct lpc_string *check_call(struct lpc_string *args,
   }
 }
 
-
 void check_array_type(struct array *a)
 {
   push_type(T_MIXED);
diff --git a/src/lpc_types.h b/src/lpc_types.h
index 01ef1497344b7dba569e2d9435d7a4eb53a86ed1..1e898a8f14c0fd7595025f5eba7322ac226d689d 100644
--- a/src/lpc_types.h
+++ b/src/lpc_types.h
@@ -23,13 +23,16 @@ extern struct lpc_string *any_type_string;
 void init_types();
 struct lpc_string *parse_type(char *s);
 void stupid_describe_type(char *a,INT32 len);
+void simple_describe_type(struct lpc_string *s);
 char *low_describe_type(char *t);
+struct lpc_string *describe_type(struct lpc_string *type);
 TYPE_T compile_type_to_runtime_type(struct lpc_string *s);
 int match_types(struct lpc_string *a,struct lpc_string *b);
 void reset_type_stack();
 void type_stack_mark();
 void pop_stack_mark();
 void pop_type_stack();
+void type_stack_pop_to_mark();
 void type_stack_reverse();
 void push_type(unsigned char tmp);
 void push_unfinished_type(char *s);
diff --git a/src/object.c b/src/object.c
index 9d6e0ff0876f9a54d9937de3d1cb016c4baa737b..86174658e9593168b002d1de02bcc8480135464f 100644
--- a/src/object.c
+++ b/src/object.c
@@ -657,13 +657,13 @@ void gc_check_object(struct object *o)
     
     i=ID_FROM_INT(o->prog, e);
 
-    if(i->run_time_type & IDENTIFIER_FUNCTION) continue;
+    if(i->flags & IDENTIFIER_FUNCTION) continue;
 
     if(i->run_time_type == T_MIXED)
     {
       gc_check_svalues((struct svalue *)LOW_GET_GLOBAL(o,e,i),1);
     }else{
-      gc_check_short_svalue((struct svalue *)LOW_GET_GLOBAL(o,e,i),
+      gc_check_short_svalue((union anything *)LOW_GET_GLOBAL(o,e,i),
 			    i->run_time_type);
     }
   }
diff --git a/src/operators.c b/src/operators.c
index ca9bdbce4003a011ab2dc94356a7f212eb32b324..3a21b0d51f0052e715aa4497294e5d5e42dff2aa 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -169,6 +169,24 @@ void f_add(INT32 args)
     break;
   }
 
+  case BIT_FLOAT | BIT_INT:
+  {
+    FLOAT_TYPE sum;
+    sum=0.0;
+    for(e=-args; e<0; e++)
+    {
+      if(sp[e].type==T_FLOAT)
+      {
+	sum+=sp[e].u.float_number;
+      }else{
+	sum+=(FLOAT_TYPE)sp[e].u.integer;
+      }
+    }
+    sp-=args-1;
+    sp[-1].u.float_number=sum;
+    break;
+  }
+
   case BIT_ARRAY:
   {
     struct array *a;
@@ -231,7 +249,8 @@ static node *optimize_binary(node *n)
       fatal("Couldn't find argument!\n");
 #endif
 
-    if((*second_arg)->type == (*first_arg)->type)
+    if((*second_arg)->type == (*first_arg)->type &&
+       compile_type_to_runtime_type((*second_arg)->type) != T_MIXED)
     {
       if((*first_arg)->token == F_APPLY &&
 	 CAR(*first_arg)->token == F_CONSTANT &&
@@ -295,10 +314,26 @@ static int generate_comparison(node *n)
   return 0;
 }
 
+static int float_promote()
+{
+  if(sp[-2].type==T_INT)
+  {
+    sp[-2].u.float_number=(FLOAT_TYPE)sp[-2].u.integer;
+    sp[-2].type=T_FLOAT;
+  }
+
+  if(sp[-1].type==T_INT)
+  {
+    sp[-1].u.float_number=(FLOAT_TYPE)sp[-1].u.integer;
+    sp[-1].type=T_FLOAT;
+  }
+
+  return sp[-2].type == sp[-1].type;
+}
 
 void o_subtract()
 {
-  if (sp[-2].type != sp[-1].type )
+  if (sp[-2].type != sp[-1].type && !float_promote())
     error("Subtract on different types.\n");
 
   switch(sp[-1].type)
@@ -659,15 +694,14 @@ static int generate_rsh(node *n)
   return 0;
 }
 
+
+#define TWO_TYPES(X,Y) (((X)<<8)|(Y))
 void o_multiply()
 {
-  switch(sp[-2].type)
+  switch(TWO_TYPES(sp[-2].type,sp[-1].type))
   {
-  case T_ARRAY:
-    if(sp[-1].type!=T_STRING)
+  case TWO_TYPES(T_ARRAY,T_STRING):
     {
-      error("Bad argument 2 to multiply.\n");
-    }else{
       struct lpc_string *ret;
       sp--;
       ret=implode(sp[-1].u.array,sp[0].u.string);
@@ -678,20 +712,30 @@ void o_multiply()
       return;
     }
 
-  case T_FLOAT:
-    if(sp[-1].type!=T_FLOAT) error("Bad argument 2 to multiply.\n");
+  case TWO_TYPES(T_FLOAT,T_FLOAT):
     sp--;
     sp[-1].u.float_number *= sp[0].u.float_number;
     return;
 
-  case T_INT:
-    if(sp[-1].type!=T_INT) error("Bad argument 2 to multiply.\n");
+  case TWO_TYPES(T_FLOAT,T_INT):
+    sp--;
+    sp[-1].u.float_number *= (FLOAT_TYPE)sp[0].u.integer;
+    return;
+
+  case TWO_TYPES(T_INT,T_FLOAT):
+    sp--;
+    sp[-1].u.float_number= 
+      (FLOAT_TYPE) sp[-1].u.integer * (FLOAT_TYPE)sp[0].u.float_number;
+    sp[-1].type=T_FLOAT;
+    return;
+
+  case TWO_TYPES(T_INT,T_INT):
     sp--;
     sp[-1].u.integer *= sp[0].u.integer;
     return;
 
   default:
-    error("Bad argument 1 to multiply.\n");
+    error("Bad arguments to multiply.\n");
   }
 }
 
@@ -726,7 +770,7 @@ static int generate_multiply(node *n)
 
 void o_divide()
 {
-  if(sp[-2].type!=sp[-1].type)
+  if(sp[-2].type!=sp[-1].type && !float_promote())
     error("Division on different types.\n");
 
   switch(sp[-2].type)
@@ -782,7 +826,7 @@ static int generate_divide(node *n)
 
 void o_mod()
 {
-  if(sp[-2].type != sp[-1].type)
+  if(sp[-2].type != sp[-1].type && !float_promote())
     error("Modulo on different types.\n");
 
   switch(sp[-1].type)
@@ -956,14 +1000,14 @@ void init_operators()
 {
   add_efun2("`==",f_eq,"function(mixed,mixed:int)",0,0,generate_comparison);
   add_efun2("`!=",f_ne,"function(mixed,mixed:int)",0,0,generate_comparison);
-  add_efun2("`<", f_lt,"function(int,int:int)|function(float,float:int)|function(string,string:int)",0,0,generate_comparison);
-  add_efun2("`<=",f_le,"function(int,int:int)|function(float,float:int)|function(string,string:int)",0,0,generate_comparison);
-  add_efun2("`>", f_gt,"function(int,int:int)|function(float,float:int)|function(string,string:int)",0,0,generate_comparison);
-  add_efun2("`>=",f_ge,"function(int,int:int)|function(float,float:int)|function(string,string:int)",0,0,generate_comparison);
+  add_efun2("`<", f_lt,"function(int|float,int|float:int)|function(string,string:int)",0,0,generate_comparison);
+  add_efun2("`<=",f_le,"function(int|float,int|float:int)|function(string,string:int)",0,0,generate_comparison);
+  add_efun2("`>", f_gt,"function(int|float,int|float:int)|function(string,string:int)",0,0,generate_comparison);
+  add_efun2("`>=",f_ge,"function(int|float,int|float:int)|function(string,string:int)",0,0,generate_comparison);
 
-  add_efun2("`+",f_add,"function(int ...:int)|function(float ...:float)|function(string,string|int|float ...:string)|function(string,string|int|float ...:string)|function(int|float,string,string|int|float:string)|function(array ...:array)|function(mapping ...:mapping)|function(list...:list)",0,optimize_binary,generate_sum);
+  add_efun2("`+",f_add,"function(int...:int)|!function(int...:mixed)&function(int|float...:float)|!function(int|float...:mixed)&function(string|int|float...:string)|function(array...:array)|function(mapping...:mapping)|function(list...:list)",0,optimize_binary,generate_sum);
 
-  add_efun2("`-",f_minus,"function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(list,list:list)|function(float,float:float)|function(int,int:int)|function(string,string:string)",0,0,generate_minus);
+  add_efun2("`-",f_minus,"function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(list,list:list)|function(float|int,float:float)|function(float,int:float)|function(int,int:int)|function(string,string:string)",0,0,generate_minus);
 
   add_efun2("`&",f_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",0,optimize_binary,generate_and);
 
@@ -974,13 +1018,12 @@ void init_operators()
   add_efun2("`<<",f_lsh,"function(int,int:int)",0,0,generate_lsh);
   add_efun2("`>>",f_rsh,"function(int,int:int)",0,0,generate_rsh);
 
-  add_efun2("`*",f_multiply,"function(int...:int)|function(float...:float)|function(string*,string:string)",0,optimize_binary,generate_multiply);
+  add_efun2("`*",f_multiply,"function(int...:int)|!function(int...:mixed)&function(float|int...:float)|function(string*,string:string)",0,optimize_binary,generate_multiply);
 
-  add_efun2("`/",f_divide,"function(int,int:int)|function(float,float:float)|function(string,string:string*)",0,0,generate_divide);
+  add_efun2("`/",f_divide,"function(int,int:int)|function(float|int,float:float)|function(float,int:float)|function(string,string:string*)",0,0,generate_divide);
 
   add_efun2("`%",f_mod,"function(int,int:int)|function(float,float:float)",0,0,generate_mod);
 
   add_efun2("`!",f_not,"function(mixed:int)",0,0,generate_not);
   add_efun2("`~",f_compl,"function(int:int)",0,0,generate_compl);
-  
 }
diff --git a/src/svalue.c b/src/svalue.c
index 612ab00302229ed296953c159a555c9ca85971f7..6793c90527bf8e231fe64010267aa287e77d3ff1 100644
--- a/src/svalue.c
+++ b/src/svalue.c
@@ -366,7 +366,6 @@ int is_eq(struct svalue *a, struct svalue *b)
   }
 }
 
-
 int low_is_equal(struct svalue *a,
 		 struct svalue *b,
 		 struct processing *p)
@@ -443,8 +442,7 @@ int is_equal(struct svalue *a,struct svalue *b)
   return low_is_equal(a,b,0);
 }
 
-
-int is_gt(const struct svalue *a,const struct svalue *b)
+int is_lt(const struct svalue *a,const struct svalue *b)
 {
   check_type(a->type);
   check_type(b->type);
@@ -453,39 +451,18 @@ int is_gt(const struct svalue *a,const struct svalue *b)
 
   if (a->type != b->type)
   {
-    error("Cannot compare different types.\n");
-  }
-  switch(a->type)
-  {
-  default:
-    error("Bad argument 1 to '>'.\n");
-
-  case T_INT:
-    return a->u.integer > b->u.integer;
-
-  case T_STRING:
-    return my_strcmp(a->u.string, b->u.string) > 0;
+    if(a->type == T_FLOAT && b->type==T_INT)
+      return a->u.float_number < (FLOAT_TYPE)b->u.integer;
 
-  case T_FLOAT:
-    return a->u.float_number > b->u.float_number;
-  }
-}
-
-int is_lt(const struct svalue *a,const struct svalue *b)
-{
-  check_type(a->type);
-  check_type(b->type);
-  check_refs(a);
-  check_refs(b);
+    if(a->type == T_INT && b->type==T_FLOAT)
+      return (FLOAT_TYPE)a->u.integer < b->u.float_number;
 
-  if (a->type != b->type)
-  {
     error("Cannot compare different types.\n");
   }
   switch(a->type)
   {
   default:
-    error("Bad arg 1 to '<'.\n");
+    error("Bad type to comparison.\n");
 
   case T_INT:
     return a->u.integer < b->u.integer;
diff --git a/src/svalue.h b/src/svalue.h
index 9e536ff2f14ca6db4848639f5ff48241ef7cb008..80bf0c88f6fdc01752e7d2e0005359878dce2ae5 100644
--- a/src/svalue.h
+++ b/src/svalue.h
@@ -55,6 +55,8 @@ struct svalue
 #define T_FLOAT 7
 #define T_INT 8
 
+#define T_NOT 247
+#define T_AND 248
 #define T_UNKNOWN 249
 #define T_MANY 250
 #define T_OR 251
@@ -87,6 +89,7 @@ struct svalue
 #define NUMBER_UNDEFINED 1
 #define NUMBER_DESTRUCTED 2
 
+#define is_gt(a,b) is_lt(b,a)
 #define IS_ZERO(X) ((X)->type==T_INT && (X)->u.integer==0)
 
 #define check_destructed(S) \
@@ -163,7 +166,6 @@ int low_short_is_equal(const union anything *a,
 		       TYPE_T type,
 		       struct processing *p);
 int is_equal(struct svalue *a,struct svalue *b);
-int is_gt(const struct svalue *a,const struct svalue *b);
 int is_lt(const struct svalue *a,const struct svalue *b);
 void describe_svalue(struct svalue *s,int indent,struct processing *p);
 void clear_svalues(struct svalue *s, INT32 num);
@@ -173,6 +175,8 @@ void copy_svalues_recursively_no_free(struct svalue *to,
 				      struct processing *p);
 void check_short_svalue(union anything *u,TYPE_T type);
 void check_svalue(struct svalue *s);
+void gc_check_svalues(struct svalue *s, int num);
+void gc_check_short_svalue(union anything *u, TYPE_T type);
 /* Prototypes end here */
 
 #endif