diff --git a/lib/simulate.lpc b/lib/simulate.lpc
index f2d317a52ebaa3b0bfd89f4f31144b510b6a7423..80b96aac1be9381bcd90e4ce9385cd6a14e0d1c1 100644
--- a/lib/simulate.lpc
+++ b/lib/simulate.lpc
@@ -288,7 +288,7 @@ varargs mixed *sort_array(array foo,function cmp,mixed ... args)
 
   if(sizeof(foo)<2) return copy_value(foo);
 
-  if(!cmp) cmp=lambda(mixed a,mixed b) { return a > b; };
+  if(!cmp) cmp=`>;
 
   a=sort_array(foo[0..sizeof(foo)/2-1],cmp,@args);
   b=sort_array(foo[sizeof(foo)/2..sizeof(foo)],cmp,@args);
@@ -342,6 +342,7 @@ list mklist(mixed *a)
 void create()
 {
   add_efun("PI",3.1415926535897932384626433832795080);
+  add_efun("sum",`+);
   add_efun("capitalize",capitalize);
   add_efun("code_value",code_value);
   add_efun("exec","exec");
@@ -365,7 +366,7 @@ void create()
   add_efun("strstr",search);
   add_efun("sum_arrays",sum_arrays);
   add_efun("this_function",this_function);
-  add_efun("version",lambda() { return "uLPC v1.0E-11"; });
+  add_efun("version",lambda() { return "uLPC v1.0E-10"; });
   add_efun("write_file",write_file);
   add_efun("get_function",get_function);
   add_efun("regexp",regexp);
diff --git a/src/add_efun.c b/src/add_efun.c
index 86ce35af757739e48f461dcab760586326207fef..7c35fa8cf2ca8a271c10f01e4f3215617e40826b 100644
--- a/src/add_efun.c
+++ b/src/add_efun.c
@@ -53,7 +53,12 @@ void low_add_efun(struct lpc_string *name, struct svalue *fun)
 }
 
 
-struct callable *make_callable(c_fun fun,char *name, char *type, INT16 flags)
+struct callable *make_callable(c_fun fun,
+			       char *name,
+			       char *type,
+			       INT16 flags,
+			       optimize_fun optimize,
+			       docode_fun docode)
 {
   struct callable *f;
   f=ALLOC_STRUCT(callable);
@@ -62,6 +67,8 @@ struct callable *make_callable(c_fun fun,char *name, char *type, INT16 flags)
   f->name=make_shared_string(name);
   f->type=parse_type(type);
   f->flags=flags;
+  f->docode=docode;
+  f->optimize=optimize;
   return f;
 }
 
@@ -72,7 +79,12 @@ void really_free_callable(struct callable *fun)
   free((char *)fun);
 }
 
-void add_efun(char *name, c_fun fun, char *type, INT16 flags)
+void add_efun2(char *name,
+	       c_fun fun,
+	       char *type,
+	       INT16 flags,
+	       optimize_fun optimize,
+	       docode_fun docode)
 {
   struct svalue s;
   struct lpc_string *n;
@@ -80,12 +92,17 @@ void add_efun(char *name, c_fun fun, char *type, INT16 flags)
   n=make_shared_string(name);
   s.type=T_FUNCTION;
   s.subtype=-1;
-  s.u.efun=make_callable(fun, name, type, flags);
+  s.u.efun=make_callable(fun, name, type, flags, optimize, docode);
   low_add_efun(n, &s);
   free_svalue(&s);
   free_string(n);
 }
 
+void add_efun(char *name, c_fun fun, char *type, INT16 flags)
+{
+  add_efun2(name,fun,type,flags,0,0);
+}
+
 static void push_efun_entry(struct hash_entry *h)
 {
   struct efun *f;
diff --git a/src/add_efun.h b/src/add_efun.h
index f27b34a2c26e2c50f498e90f7a7ae251e7918b0d..2400328411ee9449f7a42355df66cce6c57c4fa6 100644
--- a/src/add_efun.h
+++ b/src/add_efun.h
@@ -17,6 +17,8 @@ struct efun
 };
 
 typedef void (*c_fun)(INT32);
+typedef int (*docode_fun)(node *n);
+typedef void (*optimize_fun)(node *n);
 
 struct callable
 {
@@ -25,13 +27,26 @@ struct callable
   struct lpc_string *type;
   struct lpc_string *name;
   INT16 flags;
+  optimize_fun optimize;
+  docode_fun docode;
 };
 
 /* Prototypes begin here */
 struct efun *lookup_efun(struct lpc_string *name);
 void low_add_efun(struct lpc_string *name, struct svalue *fun);
-struct callable *make_callable(c_fun fun,char *name, char *type, INT16 flags);
+struct callable *make_callable(c_fun fun,
+			       char *name,
+			       char *type,
+			       INT16 flags,
+			       optimize_fun optimize,
+			       docode_fun docode);
 void really_free_callable(struct callable *fun);
+void add_efun2(char *name,
+	       c_fun fun,
+	       char *type,
+	       INT16 flags,
+	       optimize_fun optimize,
+	       docode_fun docode);
 void add_efun(char *name, c_fun fun, char *type, INT16 flags);
 void push_all_efuns_on_stack();
 void cleanup_added_efuns();
diff --git a/src/builtin_efuns.c b/src/builtin_efuns.c
index 28120bf6e97b1c5bbc78a19c1efe34fa3cc92246..aa094a6853eb609b693ce2cdb0eb4256d8416039 100644
--- a/src/builtin_efuns.c
+++ b/src/builtin_efuns.c
@@ -1234,6 +1234,8 @@ TYPEP(f_floatp, "floatp", T_FLOAT)
 
 void init_builtin_efuns()
 {
+  init_operators();
+
   add_efun("add_efun",f_add_efun,"function(string,void|mixed:void)",OPT_SIDE_EFFECT);
   add_efun("aggregate",f_aggregate,"function(mixed ...:mixed *)",OPT_TRY_OPTIMIZE);
   add_efun("aggregate_list",f_aggregate_list,"function(mixed ...:list)",OPT_TRY_OPTIMIZE);
@@ -1286,7 +1288,7 @@ void init_builtin_efuns()
   add_efun("sizeof", f_sizeof, "function(string|list|array|mapping:int)",0);
   add_efun("sleep", f_sleep, "function(int:void)",OPT_SIDE_EFFECT);
   add_efun("stringp", f_stringp, "function(mixed:int)",0);
-  add_efun("sum",f_sum,"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);
+
   add_efun("this_object", f_this_object, "function(:object)",OPT_EXTERNAL_DEPEND);
   add_efun("throw",f_throw,"function(mixed:void)",0);
   add_efun("time",f_time,"function(void|int:int)",OPT_EXTERNAL_DEPEND);
diff --git a/src/docode.c b/src/docode.c
index 4421a16df0152421765eb630f62509ad121a7251..3eab7112dde70b57ecc162e3d8faf52295b0f619 100644
--- a/src/docode.c
+++ b/src/docode.c
@@ -389,7 +389,7 @@ static int do_docode2(node *n,int flags);
 
 #define DO_CODE_BLOCK(N) do_pop(do_docode(N,DO_NOT_COPY | DO_POP))
 
-static int do_docode(node *n,INT16 flags)
+int do_docode(node *n,INT16 flags)
 {
   int i;
   int save_current_line=current_line;
@@ -535,6 +535,9 @@ static int do_docode2(node *n,int flags)
 
     if(tmp2 < tmp1) tmp1=tmp2;
 
+    if(tmp1 == -1)
+      fatal("Unknown number of args in ? :\n");
+
     tmp2=do_jump_when_zero(CAR(n),-1);
 
     tmp3=do_docode(CADR(n), flags);
@@ -873,26 +876,46 @@ static int do_docode2(node *n,int flags)
     return 1;
 
   case F_APPLY:
-    ins_f_byte(F_MARK);
     if(CAR(n)->token == F_CONSTANT)
     {
-      do_docode(CDR(n),0);
-      if(CAR(n)->u.sval.type == T_FUNCTION && 
-	 CAR(n)->u.sval.subtype != -1 &&
-	 CAR(n)->u.sval.u.object == &fake_object)
+      if(CAR(n)->u.sval.type == T_FUNCTION)
       {
-	ins_f_byte_with_numerical_arg(F_CALL_LFUN, CAR(n)->u.sval.subtype);
-      }else{
-	tmp1=store_constant(& CAR(n)->u.sval,
-			    !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND));
-	ins_f_byte(F_MAX_OPCODE + tmp1);
-	if(n->type == void_type_string) return 0;
+	if(CAR(n)->u.sval.subtype == -1) /* driver fun? */
+	{
+	  if(!CAR(n)->u.sval.u.efun->docode || 
+	     !CAR(n)->u.sval.u.efun->docode(n))
+	  {
+	    ins_f_byte(F_MARK);
+	    do_docode(CDR(n),0);
+	    tmp1=store_constant(& CAR(n)->u.sval,
+				!(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND));
+	    ins_f_byte(F_MAX_OPCODE + tmp1);
+	  }
+	  if(n->type == void_type_string) return 0;
+	  return 1;
+	}else{
+	  if(CAR(n)->u.sval.u.object == &fake_object)
+	  {
+	    ins_f_byte(F_MARK);
+	    do_docode(CDR(n),0);
+	    ins_f_byte_with_numerical_arg(F_CALL_LFUN, CAR(n)->u.sval.subtype);
+	    return 1;
+	  }
+       	}
       }
+
+      ins_f_byte(F_MARK);
+      do_docode(CDR(n),0);
+      tmp1=store_constant(& CAR(n)->u.sval,
+			  !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND));
+      ins_f_byte(F_MAX_OPCODE + tmp1);
+      
       return 1;
     }
     else if(CAR(n)->token == F_IDENTIFIER &&
 	    ID_FROM_INT(& fake_program, CAR(n)->u.number)->flags & IDENTIFIER_FUNCTION)
     {
+      ins_f_byte(F_MARK);
       do_docode(CDR(n),0);
       ins_f_byte_with_numerical_arg(F_CALL_LFUN, CAR(n)->u.number);
       return 1;
@@ -902,6 +925,7 @@ static int do_docode2(node *n,int flags)
       struct lpc_string *tmp;
       struct efun *fun;
 
+      ins_f_byte(F_MARK);
       tmp=make_shared_string("call_function");
       if(!tmp) yyerror("No call_function efun.");
       fun=lookup_efun(tmp);
diff --git a/src/docode.h b/src/docode.h
index 78bf2f8230cc107c200ce8fb5e096f7fa476f7ba..8f87b05b8d3acf2e28f39b1ff45364cbcc71939f 100644
--- a/src/docode.h
+++ b/src/docode.h
@@ -6,6 +6,10 @@
 #ifndef DOCODE_H
 #define DOCODE_H
 
+#define DO_LVALUE 1
+#define DO_NOT_COPY 2
+#define DO_POP 4
+
 extern int store_linenumbers;
 extern int comp_stackp;
 extern INT32 comp_stack[COMPILER_STACK_SIZE];
@@ -14,12 +18,14 @@ extern INT32 comp_stack[COMPILER_STACK_SIZE];
 void ins_byte(unsigned char b,int area);
 void ins_signed_byte(char b,int area);
 void ins_short(INT16 l,int area);
-void ins_long(long l,int area);
+void ins_long(INT32 l,int area);
 void ins_f_byte(unsigned int b);
 void push_address();
-void push_explicit(int address);
-int pop_address();
+void push_explicit(INT32 address);
+INT32 pop_address();
 struct jump;
+struct jump_list;
+int do_docode(node *n,INT16 flags);
 int docode(node *n);
 void do_code_block(node *n);
 /* Prototypes end here */
diff --git a/src/interpret.c b/src/interpret.c
index ce61e6db18369afc3424593b7008308c7ddab89d..117e643c83981cd708223deb820f1755a5fa65a8 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -797,14 +797,14 @@ static void eval_instruction(unsigned char *pc)
       COMPARISMENT(F_LT, is_lt(sp-2,sp-1));
       COMPARISMENT(F_LE,!is_gt(sp-2,sp-1));
 
-      CASE(F_ADD);      f_sum(2);     break;
-      CASE(F_SUBTRACT); f_subtract(); break;
-      CASE(F_AND);      f_and();      break;
-      CASE(F_OR);       f_or();       break;
-      CASE(F_XOR);      f_xor();      break;
-      CASE(F_MULTIPLY); f_multiply(); break;
-      CASE(F_DIVIDE);   f_divide();   break;
-      CASE(F_MOD);      f_mod();      break;
+      CASE(F_ADD);      f_add(2);     break;
+      CASE(F_SUBTRACT); o_subtract(); break;
+      CASE(F_AND);      o_and();      break;
+      CASE(F_OR);       o_or();       break;
+      CASE(F_XOR);      o_xor();      break;
+      CASE(F_MULTIPLY); o_multiply(); break;
+      CASE(F_DIVIDE);   o_divide();   break;
+      CASE(F_MOD);      o_mod();      break;
 
       CASE(F_PUSH_ARRAY);
       if(sp[-1].type!=T_ARRAY) error("Bad argument to @\n");
@@ -819,7 +819,7 @@ static void eval_instruction(unsigned char *pc)
 
       CASE(F_CAST); f_cast(); break;
 
-      CASE(F_RANGE); f_range(); break;
+      CASE(F_RANGE); o_range(); break;
       CASE(F_COPY_VALUE);
       copy_svalues_recursively_no_free(sp,sp-1,1,0);
       sp++;
diff --git a/src/language.y b/src/language.y
index 46739d6791214206fd05cc476215adeb0909cb67..fc5266f752b1943e5f17793573a8145276b60e2c 100644
--- a/src/language.y
+++ b/src/language.y
@@ -879,22 +879,22 @@ assoc_pair:  expr0 ':' expr1
 expr1: expr2
      | expr1 F_LOR expr1  { $$=mknode(F_LOR,$1,$3); }
      | expr1 F_LAND expr1 { $$=mknode(F_LAND,$1,$3); }
-     | expr1 '|' expr1    { $$=mknode(F_OR,$1,$3); }
-     | expr1 '^' expr1    { $$=mknode(F_XOR,$1,$3); }
-     | expr1 '&' expr1    { $$=mknode(F_AND,$1,$3); }
-     | expr1 F_EQ expr1   { $$=mknode(F_EQ,$1,$3); }
-     | expr1 F_NE expr1   { $$=mknode(F_NE,$1,$3); }
-     | expr1 '>' expr1    { $$=mknode(F_GT,$1,$3); }
-     | expr1 F_GE expr1   { $$=mknode(F_GE,$1,$3); }
-     | expr1 '<' expr1    { $$=mknode(F_LT,$1,$3); }
-     | expr1 F_LE expr1   { $$=mknode(F_LE,$1,$3); }
-     | expr1 F_LSH expr1  { $$=mknode(F_LSH,$1,$3); }
-     | expr1 F_RSH expr1  { $$=mknode(F_RSH,$1,$3); }
-     | expr1 '+' expr1    { $$=mknode(F_ADD,$1,$3); }
-     | expr1 '-' expr1    { $$=mknode(F_SUBTRACT,$1,$3); }
-     | expr1 '*' expr1    { $$=mknode(F_MULTIPLY,$1,$3); }
-     | expr1 '%' expr1    { $$=mknode(F_MOD,$1,$3); }
-     | expr1 '/' expr1    { $$=mknode(F_DIVIDE,$1,$3); }
+     | expr1 '|' expr1    { $$=mkopernode("`|",$1,$3); }
+     | expr1 '^' expr1    { $$=mkopernode("`^",$1,$3); }
+     | expr1 '&' expr1    { $$=mkopernode("`&",$1,$3); }
+     | expr1 F_EQ expr1   { $$=mkopernode("`==",$1,$3); }
+     | expr1 F_NE expr1   { $$=mkopernode("`!=",$1,$3); }
+     | expr1 '>' expr1    { $$=mkopernode("`>",$1,$3); }
+     | expr1 F_GE expr1   { $$=mkopernode("`>=",$1,$3); }
+     | expr1 '<' expr1    { $$=mkopernode("`<",$1,$3); }
+     | expr1 F_LE expr1   { $$=mkopernode("`<=",$1,$3); }
+     | expr1 F_LSH expr1  { $$=mkopernode("`<<",$1,$3); }
+     | expr1 F_RSH expr1  { $$=mkopernode("`>>",$1,$3); }
+     | expr1 '+' expr1    { $$=mkopernode("`+",$1,$3); }
+     | expr1 '-' expr1    { $$=mkopernode("`-",$1,$3); }
+     | expr1 '*' expr1    { $$=mkopernode("`*",$1,$3); }
+     | expr1 '%' expr1    { $$=mkopernode("`%",$1,$3); }
+     | expr1 '/' expr1    { $$=mkopernode("`/",$1,$3); }
      ;
 
 expr2: expr3
@@ -906,8 +906,8 @@ expr2: expr3
      | F_INC expr4       { $$=mknode(F_INC,$2,0); }
      | F_DEC expr4       { $$=mknode(F_DEC,$2,0); }
      | F_NOT expr2        { $$=mknode(F_NOT,$2,0); }
-     | '~' expr2          { $$=mknode(F_COMPL,$2,0); }
-     | '-' expr2          { $$=mknode(F_NEGATE,$2,0); }
+     | '~' expr2          { $$=mkopernode("`~",$2,0); }
+     | '-' expr2          { $$=mkopernode("`-",$2,0); }
      ;
 
 expr3: expr4
diff --git a/src/las.c b/src/las.c
index 8d3d7f8a9b5bc6c2334c95c2dc975df12e1d86e5..9f3165bdcfd1a4927a7c644d66ad3effa277c3ee 100644
--- a/src/las.c
+++ b/src/las.c
@@ -67,12 +67,17 @@ int cdr_is_node(node *n)
 
 INT32 count_args(node *n)
 {
+  int a,b;
   if(!n) return 0;
   switch(n->token)
   {
   case F_VAL_LVAL:
   case F_ARG_LIST:
-    return count_args(CAR(n)) + count_args(CDR(n));
+    a=count_args(CAR(n));
+    if(a==-1) return -1;
+    b=count_args(CDR(n));
+    if(b==-1) return -1;
+    return a+b;
 
   case F_CAST:
     if(n->type == void_type_string)
@@ -98,6 +103,7 @@ INT32 count_args(node *n)
     int tmp1,tmp2;
     tmp1=count_args(CDAR(n));
     tmp2=count_args(CDAR(n));
+    if(tmp1==-1 || tmp2==-2) return -1;
     if(tmp1 < tmp2) return tmp1;
     return tmp2;
   }
@@ -267,6 +273,14 @@ node *mkefuncallnode(char *function, node *args)
   return mkapplynode(mksvaluenode(&fun->function), args);
 }
 
+node *mkopernode(char *oper_id, node *arg1, node *arg2)
+{
+  if(arg1 && arg2)
+    arg1=mknode(F_ARG_LIST,arg1,arg2);
+
+  return mkefuncallnode(oper_id, arg1);
+}
+
 node *mklocalnode(int var)
 {
   node *res = mkemptynode();
diff --git a/src/las.h b/src/las.h
index 2b73993e158ab69f76b0cae22ba855e86c95633c..3d99b7328a42511fa5c8c5a0f8a6f55213e87edb 100644
--- a/src/las.h
+++ b/src/las.h
@@ -85,6 +85,7 @@ node *mkintnode(int nr);
 node *mkfloatnode(FLOAT_TYPE foo);
 node *mkapplynode(node *func,node *args);
 node *mkefuncallnode(char *function, node *args);
+node *mkopernode(char *oper_id, node *arg1, node *arg2);
 node *mklocalnode(int var);
 node *mkidentifiernode(int i);
 node *mkcastnode(struct lpc_string *type,node *n);
diff --git a/src/lex.c b/src/lex.c
index 16f024b5782e8a82218bed1e2f792c8fe9cbfa81..173b4655d5421270b31a15b3b25c2a491fbc92d4 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -808,12 +808,12 @@ static void do_define()
       if(e==argc)
       {
 	push_string(s2);
-	if(sp[-2].type==T_STRING) f_add();
+	if(sp[-2].type==T_STRING) f_add(2);
       }
       if(c=='\n' || c==MY_EOF)
       {
 	push_string(make_shared_string(" "));
-	if(sp[-2].type==T_STRING) f_add();
+	if(sp[-2].type==T_STRING) f_add(2);
 	break;
       }
       t=!!isidchar(c);
@@ -1507,6 +1507,61 @@ static int do_lex2(int literal, YYSTYPE *yylval)
     case '{':
     case ';':
     case '}': return c;
+
+    case '`':
+    {
+      char *tmp;
+      switch(GETC())
+      {
+      case '+': tmp="`+"; break;
+      case '-': tmp="`-"; break;
+      case '/': tmp="`/"; break;
+      case '%': tmp="`%"; break;
+      case '*': tmp="`*"; break;
+      case '&': tmp="`&"; break;
+      case '|': tmp="`|"; break;
+      case '^': tmp="`^"; break;
+      case '~': tmp="`~"; break;
+      case '(':
+	if(GOBBLE(')')) { tmp="`()"; break; }
+
+      default:
+	yyerror("Illegal ` identifier.");
+	tmp="";
+	break;
+
+      case '<':
+	if(GOBBLE('<')) { tmp="`<<"; break; }
+	if(GOBBLE('=')) { tmp="`<="; break; }
+	tmp="`<";
+	break;
+
+      case '>':
+	if(GOBBLE('>')) { tmp="`>>"; break; }
+	if(GOBBLE('=')) { tmp="`>="; break; }
+	tmp="`>";
+	break;
+
+      case '!':
+	if(GOBBLE('=')) { tmp="`!="; break; }
+	tmp="`!";
+	break;
+
+      case '=':
+	if(GOBBLE('=')) { tmp="`=="; break; }
+	tmp="`=";
+	break;
+      }
+
+      if(literal)
+      {
+	yylval->str=buf;
+      }else{
+	yylval->string=make_shared_string(tmp);
+      }
+      return F_IDENTIFIER;
+    }
+
   
     default:
       if(isidchar(c))
@@ -1679,9 +1734,9 @@ static void calcB()
 {
   switch(lookahead)
   {
-    case '-': low_lex(); calcB(); f_negate(); break;
-    case F_NOT: low_lex(); calcB(); f_not(); break;
-    case '~': low_lex(); calcB(); f_compl(); break;
+    case '-': low_lex(); calcB(); o_negate(); break;
+    case F_NOT: low_lex(); calcB(); o_not(); break;
+    case '~': low_lex(); calcB(); o_compl(); break;
     default: calcC();
   }
 }
@@ -1693,9 +1748,9 @@ static void calcA()
   {
     switch(lookahead)
     {
-      case '/': low_lex(); calcB(); f_divide(); continue;
-      case '*': low_lex(); calcB(); f_multiply(); continue;
-      case '%': low_lex(); calcB(); f_mod(); continue;
+      case '/': low_lex(); calcB(); o_divide(); continue;
+      case '*': low_lex(); calcB(); o_multiply(); continue;
+      case '%': low_lex(); calcB(); o_mod(); continue;
     }
     break;
   }
@@ -1709,8 +1764,8 @@ static void calc9()
   {
     switch(lookahead)
     {
-      case '+': low_lex(); calcA(); f_add(); continue;
-      case '-': low_lex(); calcA(); f_subtract(); continue;
+      case '+': low_lex(); calcA(); f_add(2); continue;
+      case '-': low_lex(); calcA(); o_subtract(); continue;
     }
     break;
   }
@@ -1724,8 +1779,8 @@ static void calc8()
   {
     switch(lookahead)
     {
-      case F_LSH: low_lex(); calc9(); f_lsh(); continue;
-      case F_RSH: low_lex(); calc9(); f_rsh(); continue;
+      case F_LSH: low_lex(); calc9(); o_lsh(); continue;
+      case F_RSH: low_lex(); calc9(); o_rsh(); continue;
     }
     break;
   }
@@ -1739,10 +1794,10 @@ static void calc7b()
   {
     switch(lookahead)
     {
-      case '<': low_lex(); calc8(); f_lt(); continue;
-      case '>': low_lex(); calc8(); f_gt(); continue;
-      case F_GE: low_lex(); calc8(); f_ge(); continue;
-      case F_LE: low_lex(); calc8(); f_le(); continue;
+      case '<': low_lex(); calc8(); f_lt(2); continue;
+      case '>': low_lex(); calc8(); f_gt(2); continue;
+      case F_GE: low_lex(); calc8(); f_ge(2); continue;
+      case F_LE: low_lex(); calc8(); f_le(2); continue;
     }
     break;
   }
@@ -1756,8 +1811,8 @@ static void calc7()
   {
     switch(lookahead)
     {
-      case F_EQ: low_lex(); calc7b(); f_eq(); continue;
-      case F_NE: low_lex(); calc7b(); f_ne(); continue;
+      case F_EQ: low_lex(); calc7b(); f_eq(2); continue;
+      case F_NE: low_lex(); calc7b(); f_ne(2); continue;
     }
     break;
   }
@@ -1771,7 +1826,7 @@ static void calc6()
   {
     low_lex();
     calc7();
-    f_and();
+    o_and();
   }
 }
 
@@ -1783,7 +1838,7 @@ static void calc5()
   {
     low_lex();
     calc6();
-    f_xor();
+    o_xor();
   }
 }
 
@@ -1795,7 +1850,7 @@ static void calc4()
   {
     low_lex();
     calc5();
-    f_or();
+    o_or();
   }
 }
 
diff --git a/src/modules/files/efuns.c b/src/modules/files/efuns.c
index b2172ad6c46cb9c7fcfcef448b50f3cfa35f9d78..28cf14afc282707d0759570bf5157b9cd7eab455 100644
--- a/src/modules/files/efuns.c
+++ b/src/modules/files/efuns.c
@@ -301,7 +301,7 @@ void f_exece(INT32 args)
       push_string(a->string);
       a->string->refs++;
 
-      f_sum(3);
+      f_add(3);
 
       env[e]=sp[-1].u.string->str;
     }
diff --git a/src/operators.c b/src/operators.c
index 9b18904820fe0128210ac8d8ace88ab00cf4d78b..ae7a11c3dae29f2b9ae71a5ef9ef4ab25cc5f3f9 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -16,25 +16,33 @@
 #include "language.h"
 #include "memory.h"
 #include "error.h"
-
-#define COMPARISON(ID,EXPR) \
-void ID() \
-{ \
-  int i=EXPR; \
+#include "docode.h"
+#include "add_efun.h"
+
+#define COMPARISON(ID,NAME,EXPR) \
+void ID(INT32 args) \
+{\
+  int i; \
+  if(args > 2) \
+    pop_n_elems(args-2); \
+  else if(args < 2) \
+    error("Too few arguments to %s\n",NAME); \
+  i=EXPR; \
   pop_n_elems(2); \
   sp->type=T_INT; \
   sp->u.integer=i; \
   sp++; \
-} 
+}
+
+COMPARISON(f_eq,"`==", is_eq(sp-2,sp-1))
+COMPARISON(f_ne,"`!=",!is_eq(sp-2,sp-1))
+COMPARISON(f_lt,"`<" , is_lt(sp-2,sp-1))
+COMPARISON(f_le,"`<=",!is_gt(sp-2,sp-1))
+COMPARISON(f_gt,"`>" , is_gt(sp-2,sp-1))
+COMPARISON(f_ge,"`>=",!is_lt(sp-2,sp-1))
 
-COMPARISON(f_eq, is_eq(sp-2,sp-1))
-COMPARISON(f_ne,!is_eq(sp-2,sp-1))
-COMPARISON(f_lt, is_lt(sp-2,sp-1))
-COMPARISON(f_le,!is_gt(sp-2,sp-1))
-COMPARISON(f_gt, is_gt(sp-2,sp-1))
-COMPARISON(f_ge,!is_lt(sp-2,sp-1))
 
-void f_sum(INT32 args)
+void f_add(INT32 args)
 {
   INT32 e,size;
   TYPE_FIELD types;
@@ -192,9 +200,51 @@ void f_sum(INT32 args)
   }
 }
 
-void f_add() { f_sum(2); }
+static int generate_sum(node *n)
+{
+  switch(count_args(CDR(n)))
+  {
+  case 1:
+    do_docode(CDR(n),0);
+    return 1;
+
+  case 2:
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_ADD);
+    return 1;
+
+  default:
+    return 0;
+  }
+}
+
+static int generate_comparison(node *n)
+{
+  if(count_args(CDR(n))==2)
+  {
+    do_docode(CDR(n),DO_NOT_COPY);
+
+    if(CAR(n)->u.sval.u.efun->function == f_eq)
+      ins_f_byte(F_EQ);
+    else if(CAR(n)->u.sval.u.efun->function == f_ne)
+      ins_f_byte(F_NE);
+    else if(CAR(n)->u.sval.u.efun->function == f_lt)
+      ins_f_byte(F_LT);
+    else if(CAR(n)->u.sval.u.efun->function == f_le)
+      ins_f_byte(F_LE);
+    else if(CAR(n)->u.sval.u.efun->function == f_gt)
+      ins_f_byte(F_GT);
+    else if(CAR(n)->u.sval.u.efun->function == f_ge)
+      ins_f_byte(F_GE);
+    else
+      fatal("Couldn't generate comparison!\n");
+    return 1;
+  }
+  return 0;
+}
+
 
-void f_subtract()
+void o_subtract()
 {
   if (sp[-2].type != sp[-1].type )
     error("Subtract on different types.\n");
@@ -259,7 +309,35 @@ void f_subtract()
   }
 }
 
-void f_and()
+void f_minus(INT32 args)
+{
+  switch(args)
+  {
+  case 0: error("Too few arguments to `-\n");
+  case 1: o_negate(); break;
+  case 2: o_subtract(); break;
+  default: error("Too many arguments to `-\n");
+  }
+}
+
+static int generate_minus(node *n)
+{
+  switch(count_args(CDR(n)))
+  {
+  case 1:
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_NEGATE);
+    return 1;
+
+  case 2:
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_SUBTRACT);
+    return 1;
+  }
+  return 0;
+}
+
+void o_and()
 {
   if(sp[-1].type != sp[-2].type)
     error("Bitwise and on different types.\n");
@@ -302,7 +380,36 @@ void f_and()
   }
 }
 
-void f_or()
+void f_and(INT32 args)
+{
+  switch(args)
+  {
+  case 0: error("Too few arguments to `&\n");
+  case 1: return;
+  case 2: o_and(); return;
+  default: while(--args > 0) o_and();
+  }
+}
+
+static int generate_and(node *n)
+{
+  switch(count_args(CDR(n)))
+  {
+  case 1:
+    do_docode(CDR(n),0);
+    return 1;
+
+  case 2:
+    do_docode(CDR(n),0);
+    ins_f_byte(F_AND);
+    return 1;
+
+  default:
+    return 0;
+  }
+}
+
+void o_or()
 {
   if(sp[-1].type != sp[-2].type)
     error("Bitwise or on different types.\n");
@@ -346,7 +453,37 @@ void f_or()
   }
 }
 
-void f_xor()
+void f_or(INT32 args)
+{
+  switch(args)
+  {
+  case 0: error("Too few arguments to `|\n");
+  case 1: return;
+  case 2: o_or(); return;
+  default: while(--args > 0) o_or();
+  }
+}
+
+static int generate_or(node *n)
+{
+  switch(count_args(CDR(n)))
+  {
+  case 1:
+    do_docode(CDR(n),0);
+    return 1;
+
+  case 2:
+    do_docode(CDR(n),0);
+    ins_f_byte(F_OR);
+    return 1;
+
+  default:
+    return 0;
+  }
+}
+
+
+void o_xor()
 {
   if(sp[-1].type != sp[-2].type)
     error("Bitwise xor on different types.\n");
@@ -389,7 +526,36 @@ void f_xor()
   }
 }
 
-void f_lsh()
+void f_xor(INT32 args)
+{
+  switch(args)
+  {
+  case 0: error("Too few arguments to `^\n");
+  case 1: return;
+  case 2: o_xor(); return;
+  default: while(--args > 0) o_xor();
+  }
+}
+
+static int generate_xor(node *n)
+{
+  switch(count_args(CDR(n)))
+  {
+  case 1:
+    do_docode(CDR(n),0);
+    return 1;
+
+  case 2:
+    do_docode(CDR(n),0);
+    ins_f_byte(F_XOR);
+    return 1;
+
+  default:
+    return 0;
+  }
+}
+
+void o_lsh()
 {
   if(sp[-2].type != T_INT) error("Bad argument 1 to <<\n");
   if(sp[-1].type != T_INT) error("Bad argument 2 to <<\n");
@@ -397,7 +563,25 @@ void f_lsh()
   sp[-1].u.integer <<= sp[0].u.integer;
 }
 
-void f_rsh()
+void f_lsh(INT32 args)
+{
+  if(args != 2)
+    error("Bad number of args to `<<\n");
+  o_lsh();
+}
+
+static int generate_lsh(node *n)
+{
+  if(count_args(CDR(n))==2)
+  {
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_LSH);
+    return 1;
+  }
+  return 0;
+}
+
+void o_rsh()
 {
   if(sp[-2].type != T_INT) error("Bad argument 1 to >>\n"); 
   if(sp[-1].type != T_INT) error("Bad argument 2 to >>\n");
@@ -405,7 +589,25 @@ void f_rsh()
   sp[-1].u.integer >>= sp[0].u.integer;
 }
 
-void f_multiply()
+void f_rsh(INT32 args)
+{
+  if(args != 2)
+    error("Bad number of args to `>>\n");
+  o_rsh();
+}
+
+static int generate_rsh(node *n)
+{
+  if(count_args(CDR(n))==2)
+  {
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_RSH);
+    return 1;
+  }
+  return 0;
+}
+
+void o_multiply()
 {
   switch(sp[-2].type)
   {
@@ -441,7 +643,36 @@ void f_multiply()
   }
 }
 
-void f_divide()
+void f_multiply(INT32 args)
+{
+  switch(args)
+  {
+  case 0: error("Too few arguments to `*\n");
+  case 1: return;
+  case 2: o_multiply(); return;
+  case 3: while(--args > 0) o_multiply(); 
+  }
+}
+
+static int generate_multiply(node *n)
+{
+  switch(count_args(CDR(n)))
+  {
+  case 1:
+    do_docode(CDR(n),0);
+    return 1;
+
+  case 2:
+    do_docode(CDR(n),0);
+    ins_f_byte(F_MULTIPLY);
+    return 1;
+
+  default:
+    return 0;
+  }
+}
+
+void o_divide()
 {
   if(sp[-2].type!=sp[-1].type)
     error("Division on different types.\n");
@@ -479,7 +710,25 @@ void f_divide()
   }
 }
 
-void f_mod()
+void f_divide(INT32 args)
+{
+  if(args != 2)
+    error("Bad number of args to `/\n");
+  o_divide();
+}
+
+static int generate_divide(node *n)
+{
+  if(count_args(CDR(n))==2)
+  {
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_DIVIDE);
+    return 1;
+  }
+  return 0;
+}
+
+void o_mod()
 {
   if(sp[-2].type != sp[-1].type)
     error("Modulo on different types.\n");
@@ -508,7 +757,25 @@ void f_mod()
   }
 }
 
-void f_not()
+void f_mod(INT32 args)
+{
+  if(args != 2)
+    error("Bad number of args to `%%\n");
+  o_mod();
+}
+
+static int generate_mod(node *n)
+{
+  if(count_args(CDR(n))==2)
+  {
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_MOD);
+    return 1;
+  }
+  return 0;
+}
+
+void o_not()
 {
   if(sp[-1].type==T_INT)
   {
@@ -521,13 +788,47 @@ void f_not()
   }
 }
 
-void f_compl()
+void f_not(INT32 args)
+{
+  if(args != 1) error("Bad number of args to `!\n");
+  o_not();
+}
+
+static int generate_not(node *n)
+{
+  if(count_args(CDR(n))==1)
+  {
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_NOT);
+    return 1;
+  }
+  return 0;
+}
+
+void o_compl()
 {
   if (sp[-1].type != T_INT) error("Bad argument to ~\n");
   sp[-1].u.integer = ~ sp[-1].u.integer;
 }
 
-void f_negate()
+void f_compl(INT32 args)
+{
+  if(args != 1) error("Bad number of args to `~\n");
+  o_compl();
+}
+
+static int generate_compl(node *n)
+{
+  if(count_args(CDR(n))==1)
+  {
+    do_docode(CDR(n),DO_NOT_COPY);
+    ins_f_byte(F_COMPL);
+    return 1;
+  }
+  return 0;
+}
+
+void o_negate()
 {
   switch(sp[-1].type)
   {
@@ -544,8 +845,7 @@ void f_negate()
   }
 }
 
-
-void f_range()
+void o_range()
 {
   INT32 from,to;
   if(sp[-2].type != T_INT)
@@ -599,3 +899,38 @@ void f_range()
     error("[ .. ] can only be done on strings and arrays.\n");
   }
 }
+
+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_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,0,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_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",0,0,generate_and);
+
+  add_efun2("`|",f_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",0,0,generate_or);
+
+  add_efun2("`^",f_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",0,0,generate_xor);
+
+  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,0,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_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/operators.h b/src/operators.h
index a93a17f2b03a6457fbbeffa681f7c75f843ebbed..5870c4e35c9fd604b596936d80d9987bd13893d5 100644
--- a/src/operators.h
+++ b/src/operators.h
@@ -6,31 +6,41 @@
 #ifndef OPERATORS_H
 #define OPERATORS_H
 
-#define COMPARISON(ID,X) void ID(void);
+#define COMPARISON(ID,NAME,X) void ID(INT32 num_arg);
 
 /* Prototypes begin here */
-COMPARISON(f_eq, is_eq(sp-2,sp-1))
-COMPARISON(f_ne,!is_eq(sp-2,sp-1))
-COMPARISON(f_lt, is_lt(sp-2,sp-1))
-COMPARISON(f_le,!is_gt(sp-2,sp-1))
-COMPARISON(f_gt, is_gt(sp-2,sp-1))
-COMPARISON(f_ge,!is_lt(sp-2,sp-1))
-void f_sum(INT32 args);
-void f_add();
-void f_subtract();
-void f_and();
-void f_or();
-void f_xor();
-void f_lsh();
-void f_rsh();
-void f_multiply();
-void f_divide();
-void f_mod();
-void f_not();
-void f_compl();
-void f_negate();
-void f_is_equal(int args,struct svalue *argp);
-void f_range();
+COMPARISON(f_eq,"`==", is_eq(sp-2,sp-1))
+COMPARISON(f_ne,"`!=",!is_eq(sp-2,sp-1))
+COMPARISON(f_lt,"`<" , is_lt(sp-2,sp-1))
+COMPARISON(f_le,"`<=",!is_gt(sp-2,sp-1))
+COMPARISON(f_gt,"`>" , is_gt(sp-2,sp-1))
+COMPARISON(f_ge,"`>=",!is_lt(sp-2,sp-1))
+void f_add(INT32 args);
+void o_subtract();
+void f_minus(INT32 args);
+void o_and();
+void f_and(INT32 args);
+void o_or();
+void f_or(INT32 args);
+void o_xor();
+void f_xor(INT32 args);
+void o_lsh();
+void f_lsh(INT32 args);
+void o_rsh();
+void f_rsh(INT32 args);
+void o_multiply();
+void f_multiply(INT32 args);
+void o_divide();
+void f_divide(INT32 args);
+void o_mod();
+void f_mod(INT32 args);
+void o_not();
+void f_not(INT32 args);
+void o_compl();
+void f_compl(INT32 args);
+void o_negate();
+void o_range();
+void init_operators();
 /* Prototypes end here */
 
 #undef COMPARISON