diff --git a/src/acconfig.h b/src/acconfig.h
index a1de6a690a1437629e06334d7ad1e1afc835bb36..a5bc2a68a08e0cf00f332a4d56ec891cce4bcb82 100644
--- a/src/acconfig.h
+++ b/src/acconfig.h
@@ -150,6 +150,9 @@
 #undef _SGI_SPROC_THREADS
 #undef _SGI_MP_SOURCE
 
+/* Define this if you have Windows NT threads */
+#undef NT_THREADS
+
 /* Define this if your pthreads have pthread_condattr_default */
 #undef HAVE_PTHREAD_CONDATTR_DEFAULT
 
diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 49e348a9f5cabf88cf6e3165fe8554422e512204..5bacfdb4a2996998e613af91409e5d9e91a96465 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: builtin_functions.c,v 1.58 1997/11/17 03:23:14 hubbe Exp $");
+RCSID("$Id: builtin_functions.c,v 1.59 1998/01/13 22:56:39 hubbe Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "pike_macros.h"
@@ -261,27 +261,6 @@ void f_search(INT32 args)
   }
 }
 
-void f_call_function(INT32 args)
-{
-  INT32 expected_stack=sp-args+2-evaluator_stack;
-
-  strict_apply_svalue(sp-args, args - 1);
-  if(sp < expected_stack + evaluator_stack)
-  {
-#ifdef DEBUG
-    if(sp+1 != expected_stack + evaluator_stack)
-      fatal("Stack underflow!\n");
-#endif
-
-    pop_stack();
-    push_int(0);
-  }else{
-    free_svalue(sp-2);
-    sp[-2]=sp[-1];
-    sp--;
-  }
-}
-
 void f_backtrace(INT32 args)
 {
   INT32 frames;
@@ -372,20 +351,6 @@ void f_add_constant(INT32 args)
   pop_n_elems(args);
 }
 
-void f_compile_file(INT32 args)
-{
-  struct program *p;
-  if(args<1)
-    error("Too few arguments to compile_file.\n");
-
-  if(sp[-args].type!=T_STRING)
-    error("Bad argument 1 to compile_file.\n");
-
-  p=compile_file(sp[-args].u.string);
-  pop_n_elems(args);
-  push_program(p);
-}
-
 static char *combine_path(char *cwd,char *file)
 {
   /* cwd is supposed to be combined already */
@@ -874,24 +839,36 @@ void f_next_object(INT32 args)
 
 void f_object_program(INT32 args)
 {
-  struct program *p;
   if(args < 1)
     error("Too few argumenets to object_program()\n");
 
   if(sp[-args].type == T_OBJECT)
-    p=sp[-args].u.object->prog;
-  else
-    p=0;
-
-  pop_n_elems(args);
-
-  if(!p)
   {
-    push_int(0);
-  }else{
-    p->refs++;
-    push_program(p);
+    struct object *o=sp[-args].u.object;
+    struct program *p;
+    if((p=o->prog))
+    {
+      if(o->parent && o->parent->prog)
+      {
+	INT32 id=o->parent_identifier;
+	o=o->parent;
+	o->refs++;
+	pop_n_elems(args);
+	push_object(o);
+	sp[-1].subtype=id;
+	sp[-1].type=T_FUNCTION;
+	return;
+      }else{
+	p->refs++;
+	pop_n_elems(args);
+	push_program(p);
+	return;
+      }
+    }
   }
+
+  pop_n_elems(args);
+  push_int(0);
 }
 
 void f_reverse(INT32 args)
@@ -1103,26 +1080,17 @@ void f_replace(INT32 args)
   }
 }
 
-void f_compile_string(INT32 args)
+void f_compile(INT32 args)
 {
   
   struct program *p;
   if(args < 1)
-    error("Too few arguments to compile_string()\n");
+    error("Too few arguments to compile()\n");
 
   if(sp[-args].type != T_STRING)
-    error("Bad argument 1 to compile_string()\n");
-
-  if(args < 2)
-  {
-    push_string(make_shared_string("-"));
-    args++;
-  }
-
-  if(sp[1-args].type != T_STRING)
-    error("Bad argument 2 to compile_string()\n");
+    error("Bad argument 1 to compile()\n");
 
-  p=compile_string(sp[-args].u.string,sp[1-args].u.string);
+  p=compile(sp[-args].u.string);
   pop_n_elems(args);
   push_program(p);
 }
@@ -1239,7 +1207,32 @@ void ID(INT32 args) \
   push_int(t); \
 }
 
-TYPEP(f_programp, "programp", T_PROGRAM)
+
+void f_programp(INT32 args)
+{
+  if(args<1)
+    error("Too few arguments to programp()\n");
+  switch(sp[-args].type)
+  {
+  case T_PROGRAM:
+    pop_n_elems(args);
+    push_int(1);
+    return;
+
+  case T_FUNCTION:
+    if(program_from_function(sp-args))
+    {
+      pop_n_elems(args);
+      push_int(1);
+      return;
+    }
+
+  default:
+    pop_n_elems(args);
+    push_int(0);
+  }
+}
+
 TYPEP(f_intp, "intpp", T_INT)
 TYPEP(f_mappingp, "mappingp", T_MAPPING)
 TYPEP(f_arrayp, "arrayp", T_ARRAY)
@@ -1825,12 +1818,10 @@ void init_builtin_efuns(void)
   add_efun("allocate", f_allocate, "function(int, string|void:mixed *)", 0);
   add_efun("arrayp",  f_arrayp,  "function(mixed:int)",0);
   add_efun("backtrace",f_backtrace,"function(:array(array(function|int|string)))",OPT_EXTERNAL_DEPEND);
-  add_efun("call_function",f_call_function,"function(mixed,mixed ...:mixed)",OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND);
 
   add_efun("column",f_column,"function(array,mixed:array)",0);
   add_efun("combine_path",f_combine_path,"function(string,string:string)",0);
-  add_efun("compile_file",f_compile_file,"function(string:program)",OPT_EXTERNAL_DEPEND);
-  add_efun("compile_string",f_compile_string,"function(string,string|void:program)",OPT_EXTERNAL_DEPEND);
+  add_efun("compile",f_compile,"function(string:program)",OPT_EXTERNAL_DEPEND);
   add_efun("copy_value",f_copy_value,"function(mixed:mixed)",0);
   add_efun("crypt",f_crypt,"function(string:string)|function(string,string:int)",OPT_EXTERNAL_DEPEND);
   add_efun("ctime",f_ctime,"function(int:string)",OPT_TRY_OPTIMIZE);
diff --git a/src/builtin_functions.h b/src/builtin_functions.h
index 3dbb24c7b67d62b8f2cf431ca5e297263dbbb985..f7385358f6721f3855f309fbc091a9afba6eee2b 100644
--- a/src/builtin_functions.h
+++ b/src/builtin_functions.h
@@ -26,7 +26,6 @@ void f_search(INT32 args);
 void f_call_function(INT32 args);
 void f_backtrace(INT32 args);
 void f_add_constant(INT32 args);
-void f_compile_file(INT32 args);
 void f_combine_path(INT32 args);
 void f_function_object(INT32 args);
 void f_function_name(INT32 args);
@@ -40,7 +39,6 @@ struct callback *add_exit_callback(callback_func call,
 				   void *arg,
 				   callback_func free_func);
 void f_exit(INT32 args);
-void f_query_host_name(INT32 args);
 void f_time(INT32 args);
 void f_crypt(INT32 args);
 void f_destruct(INT32 args);
@@ -51,13 +49,13 @@ void f_object_program(INT32 args);
 void f_reverse(INT32 args);
 struct tupel;
 void f_replace(INT32 args);
-void f_compile_string(INT32 args);
+void f_compile(INT32 args);
 void f_mkmapping(INT32 args);
 void f_objectp(INT32 args);
 void f_functionp(INT32 args);
 void f_sleep(INT32 args);
 void f_gc(INT32 args);
-TYPEP(f_programp, "programp", T_PROGRAM)
+void f_programp(INT32 args);
 TYPEP(f_intp, "intpp", T_INT)
 TYPEP(f_mappingp, "mappingp", T_MAPPING)
 TYPEP(f_arrayp, "arrayp", T_ARRAY)
@@ -68,12 +66,21 @@ void f_sort(INT32 args);
 void f_rows(INT32 args);
 void f_column(INT32 args);
 void f__verify_internals(INT32 args);
+void f__debug(INT32 args);
 void f_localtime(INT32 args);
 void f_glob(INT32 args);
 struct callback *add_memory_usage_callback(callback_func call,
-					   void *arg,
-					   callback_func free_func);
+					  void *arg,
+					  callback_func free_func);
 void f__memory_usage(INT32 args);
+void f__next(INT32 args);
+void f__prev(INT32 args);
+void f__refs(INT32 args);
+void f_replace_master(INT32 args);
+void f_master(INT32 args);
+void f_gethrvtime(INT32 args);
+void f_gethrtime(INT32 args);
+void f_object_variablep(INT32 args);
 void init_builtin_efuns(void);
 /* Prototypes end here */
 
diff --git a/src/compilation.h b/src/compilation.h
index 6c614ed7fecbf76ff2adc8dc149654a8f480b07b..4be9a7a69013b7af80d03762370a0c15e2aa5028 100644
--- a/src/compilation.h
+++ b/src/compilation.h
@@ -14,7 +14,6 @@
  * defining PUSH pushes the selected state(s) on the stack(s)
  * defining POP pops the selected state(s) from the stack(s)
  *
- * define FILE_STATE to select the file state
  * define PROGRAM_STATE to select the program state
  */
 
@@ -75,35 +74,19 @@
   ZMEMBER(struct pike_string *,X)
 #endif
 
-#ifdef PROGRAM_STATE
   SNAME(program_state,previous_program_state)
   ZMEMBER(INT32,last_line)
   STRMEMBER(last_file,"last_file")
-  ZMEMBER(struct program,fake_program)
+  ZMEMBER(struct program *,new_program)
+  ZMEMBER(struct program *,malloc_size_program)
   ZMEMBER(node *,init_node)
   ZMEMBER(INT32,last_pc)
   ZMEMBER(int,num_parse_error)
-  ZMEMBER(struct locals *,local_variables)
-  ZMEMBER(dynamic_buffer,inherit_names)
+  ZMEMBER(struct compiler_frame *,compiler_frame)
   ZMEMBER(dynamic_buffer,used_modules)
-  ZMEMBER2(dynamic_buffer,areas,[NUM_AREAS])
   IMEMBER(int,comp_stackp)
+  IMEMBER(int,compiler_pass)
   SEND
-#endif
-
-#ifdef FILE_STATE
-  SNAME(file_state,previous_file_state)
-  ZMEMBER(INT32,old_line)
-  ZMEMBER(INT32,current_line)
-  ZMEMBER(INT32,nexpands)
-  ZMEMBER(int,pragma_all_inline)
-  ZMEMBER(struct inputstate *,istate)
-  ZMEMBER(struct hash_table *,defines)
-  ZMEMBER(struct program_state *,previous_program_state)
-  STRMEMBER(current_file,"current_file")
-  SEND
-#endif
-
 
 #undef PCODE
 #undef STRMEMBER
@@ -113,3 +96,8 @@
 #undef ZMEMBER2
 #undef SNAME
 #undef SEND
+
+#undef STRUCT
+#undef PUSH
+#undef POP
+#undef DECLARE
diff --git a/src/configure.in b/src/configure.in
index 8be1d18e9dbe611fbc97846cbfd974cc9c18b3a1..bb3241c011630c05b2ec73efbca83903062f3765 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1,4 +1,4 @@
-AC_REVISION("$Id: configure.in,v 1.148 1998/01/10 21:19:08 hubbe Exp $")
+AC_REVISION("$Id: configure.in,v 1.149 1998/01/13 22:56:40 hubbe Exp $")
 AC_INIT(interpret.c)
 AC_CONFIG_HEADER(machine.h)
 
@@ -692,6 +692,16 @@ fi
 if test x$with_threads = xyes ; then
   OLDLIBS="$LIBS"
 
+if test "x$pike_cv_sys_os" = "xWindows_NT" ; then
+  # NT has threads...
+
+  AC_DEFINE(_REENTRANT)
+  AC_DEFINE(_THREAD_SAFE)
+  AC_DEFINE(_UNIX_THREADS)
+  AC_DEFINE(NT_THREADS)
+
+else
+
   AC_MSG_CHECKING(unix threads)
   case "x$pike_cv_sys_os" in
     *)
@@ -872,6 +882,7 @@ int main()
       # fi
     fi
   fi
+fi  # NT
 else
   # Without threads
   :
diff --git a/src/cpp.c b/src/cpp.c
index 55a84216ff08b2a4ce9e4ddb7b9b84c98b09f61e..c745da50288c4d2cd29554d146a327690d8b9dff 100644
--- a/src/cpp.c
+++ b/src/cpp.c
@@ -1781,7 +1781,7 @@ static void check_constant(struct cpp *this,
     if(!isidchar(data[dlen]))
       break;
 
-  push_string(binary_findstring(data, dlen));
+  push_string(make_shared_binary_string(data, dlen));
   if((sv=low_mapping_string_lookup(get_builtin_constants(),
 				   sp[-1].u.string)))
   {
diff --git a/src/docode.c b/src/docode.c
index 6db4d0f002b9306e047d431523b0f309acc1003d..4110312c1cad4b1dc525c8f3938e87593a0eb15d 100644
--- a/src/docode.c
+++ b/src/docode.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: docode.c,v 1.23 1997/09/22 01:01:15 hubbe Exp $");
+RCSID("$Id: docode.c,v 1.24 1998/01/13 22:56:42 hubbe Exp $");
 #include "las.h"
 #include "program.h"
 #include "language.h"
@@ -15,7 +15,7 @@ RCSID("$Id: docode.c,v 1.23 1997/09/22 01:01:15 hubbe Exp $");
 #include "array.h"
 #include "pike_macros.h"
 #include "error.h"
-#include "pike_memory.h"
+#include "memory.h"
 #include "svalue.h"
 #include "main.h"
 #include "lex.h"
@@ -32,47 +32,14 @@ static INT32 current_switch_default;
 static INT32 current_switch_values_on_stack;
 static INT32 *current_switch_jumptable =0;
 
-void ins_byte(unsigned char b,int area)
-{
-  add_to_mem_block(area, (char *)&b, 1);
-}
-
-void ins_signed_byte(char b,int area)
-{
-  add_to_mem_block(area, (char *)&b, 1);
-}
-
-void ins_short(INT16 l,int area)
-{
-  add_to_mem_block(area, (char *)&l, sizeof(INT16));
-}
-
-/*
- * Store an INT32.
- */
-void ins_int(INT32 l,int area)
-{
-  add_to_mem_block(area, (char *)&l+0, sizeof(INT32));
-}
-
 void upd_int(int offset, INT32 tmp)
 {
-#ifdef HANDLES_UNALIGNED_MEMORY_ACCESS
-  *((int *)(areas[A_PROGRAM].s.str+offset))=tmp;
-#else
-  MEMCPY(areas[A_PROGRAM].s.str+offset, (char *)&tmp,sizeof(tmp));
-#endif
+  MEMCPY(new_program->program+offset, (char *)&tmp,sizeof(tmp));
 }
 
 INT32 read_int(int offset)
 {
-  INT32 tmp;
-#ifdef HANDLES_UNALIGNED_MEMORY_ACCESS
-  tmp=*((int *)(areas[A_PROGRAM].s.str+offset));
-#else
-  MEMCPY((char *)&tmp, areas[A_PROGRAM].s.str+offset,sizeof(tmp));
-#endif
-  return tmp;
+  return EXTRACT_INT(new_program->program+offset);
 }
 
 int store_linenumbers=1;
@@ -148,12 +115,12 @@ void do_pop(int x)
 int do_docode(node *n,INT16 flags)
 {
   int i;
-  int save_current_line=current_line;
+  int save_current_line=lex.current_line;
   if(!n) return 0;
-  current_line=n->line_number;
+  lex.current_line=n->line_number;
   i=do_docode2(n, flags);
 
-  current_line=save_current_line;
+  lex.current_line=save_current_line;
   return i;
 }
 
@@ -174,8 +141,8 @@ static void code_expression(node *n, int flags, char *err)
   case 2:
     fatal("Internal compiler error (%s), line %ld, file %s\n",
 	  err,
-	  (long)current_line,
-	  current_file?current_file->str:"Unknown");
+	  (long)lex.current_line,
+	  lex.current_file?lex.current_file->str:"Unknown");
   }
 }
 
@@ -279,8 +246,7 @@ static int do_docode2(node *n,int flags)
     default:
       yyerror("Illegal lvalue.");
       emit(F_NUMBER,0);
-      emit(F_NUMBER,0);
-      return 2;
+      return 1;
 
     case F_LVALUE_LIST:
     case F_LOCAL:
@@ -289,12 +255,30 @@ static int do_docode2(node *n,int flags)
     case F_INDEX:
     case F_ARROW:
     case F_ARG_LIST:
+    case F_EXTERNAL:
       break;
     }
   }
 
   switch(n->token)
   {
+  case F_EXTERNAL:
+    emit(F_LDA, n->u.integer.a);
+    if(flags & DO_LVALUE)
+    {
+      emit(F_EXTERNAL_LVALUE, n->u.integer.b);
+      return 2;
+    }else{
+      emit(F_EXTERNAL, n->u.integer.b);
+      return 1;
+    }
+    break;
+
+  case F_UNDEFINED:
+    yyerror("Undefined identifier");
+    emit(F_NUMBER,0);
+    return 1;
+
   case F_PUSH_ARRAY:
     code_expression(CAR(n), 0, "`@");
     emit2(F_PUSH_ARRAY);
@@ -368,7 +352,7 @@ static int do_docode2(node *n,int flags)
     tmp1=do_docode(CAR(n),DO_LVALUE);
 #ifdef DEBUG
     if(tmp1 != 2)
-      fatal("HELP! FATAL INTERNAL COMPILER ERROR\n");
+      fatal("HELP! FATAL INTERNAL COMPILER ERROR (7)\n");
 #endif
 
     if(match_types(CAR(n)->type,array_type_string) ||
@@ -441,7 +425,7 @@ static int do_docode2(node *n,int flags)
       switch(CDR(n)->token)
       {
       case F_LOCAL:
-	if(CDR(n)->u.number >= local_variables->max_number_of_locals)
+	if(CDR(n)->u.number >= compiler_frame->max_number_of_locals)
 	  yyerror("Illegal to use local variable here.");
 
 	code_expression(CAR(n), 0, "RHS");
@@ -450,7 +434,7 @@ static int do_docode2(node *n,int flags)
 	break;
 
       case F_IDENTIFIER:
-	if(!IDENTIFIER_IS_VARIABLE( ID_FROM_INT(& fake_program, CDR(n)->u.number)->identifier_flags))
+	if(!IDENTIFIER_IS_VARIABLE( ID_FROM_INT(new_program, CDR(n)->u.number)->identifier_flags))
 	{
 	  yyerror("Cannot assign functions or constants.\n");
 	}else{
@@ -501,7 +485,7 @@ static int do_docode2(node *n,int flags)
   case F_RANGE:
     tmp1=do_docode(CAR(n),DO_NOT_COPY);
     if(do_docode(CDR(n),DO_NOT_COPY)!=2)
-      fatal("Compiler internal error (at %ld).\n",(long)current_line);
+      fatal("Compiler internal error (at %ld).\n",(long)lex.current_line);
     emit2(n->token);
     return tmp1;
 
@@ -510,7 +494,7 @@ static int do_docode2(node *n,int flags)
     tmp1=do_docode(CAR(n),DO_LVALUE);
 #ifdef DEBUG
     if(tmp1 != 2)
-      fatal("HELP! FATAL INTERNAL COMPILER ERROR (again)\n");
+      fatal("HELP! FATAL INTERNAL COMPILER ERROR (1)\n");
 #endif
 
     if(flags & DO_POP)
@@ -527,7 +511,7 @@ static int do_docode2(node *n,int flags)
     tmp1=do_docode(CAR(n),DO_LVALUE);
 #ifdef DEBUG
     if(tmp1 != 2)
-      fatal("HELP! FATAL INTERNAL COMPILER ERROR (yet again)\n");
+      fatal("HELP! FATAL INTERNAL COMPILER ERROR (2)\n");
 #endif
     if(flags & DO_POP)
     {
@@ -703,7 +687,7 @@ static int do_docode2(node *n,int flags)
       return 1;
     }
     else if(CAR(n)->token == F_IDENTIFIER &&
-	    IDENTIFIER_IS_FUNCTION(ID_FROM_INT(& fake_program, CAR(n)->u.number)->identifier_flags))
+	    IDENTIFIER_IS_FUNCTION(ID_FROM_INT(new_program, CAR(n)->u.number)->identifier_flags))
     {
       emit2(F_MARK);
       do_docode(CDR(n),0);
@@ -722,14 +706,15 @@ static int do_docode2(node *n,int flags)
 
       tmp=findstring("call_function");
       if(!tmp) yyerror("No call_function efun.");
-      if(!find_module_identifier(tmp))
+      foo=find_module_identifier(tmp);
+      if(!foo || !foo->token==F_CONSTANT)
       {
 	yyerror("No call_function efun.");
       }else{
-	tmp1=store_constant(sp-1, 1);
-	pop_stack();
+	tmp1=store_constant(& foo->u.sval, 1);
 	emit(F_APPLY, tmp1);
       }
+      free_node(foo);
       return 1;
     }
 
@@ -790,12 +775,12 @@ static int do_docode2(node *n,int flags)
     current_switch_jumptable[current_switch_case++]=-1;
 
     DO_CODE_BLOCK(CDR(n));
-
+    
 #ifdef DEBUG
     if(sp-save_sp != cases)
       fatal("Count cases is wrong!\n");
 #endif
-    
+
     f_aggregate(cases);
     order=get_switch_order(sp[-1].u.array);
 
@@ -1065,7 +1050,7 @@ static int do_docode2(node *n,int flags)
     }
 
   case F_LOCAL:
-    if(n->u.number >= local_variables->max_number_of_locals)
+    if(n->u.number >= compiler_frame->max_number_of_locals)
       yyerror("Illegal to use local variable here.");
     if(flags & DO_LVALUE)
     {
@@ -1077,7 +1062,7 @@ static int do_docode2(node *n,int flags)
     }
 
   case F_IDENTIFIER:
-    if(IDENTIFIER_IS_FUNCTION(ID_FROM_INT(& fake_program, n->u.number)->identifier_flags))
+    if(IDENTIFIER_IS_FUNCTION(ID_FROM_INT(new_program, n->u.number)->identifier_flags))
     {
       if(flags & DO_LVALUE)
       {
diff --git a/src/docode.h b/src/docode.h
index 0fa3162fe513b21c110c70bd0833a885785cb74f..ba04a4bf8ffe8ff78f1dce8c03ba8e9833bb3379 100644
--- a/src/docode.h
+++ b/src/docode.h
@@ -21,20 +21,20 @@ extern int store_linenumbers;
 extern int comp_stackp;
 extern INT32 comp_stack[COMPILER_STACK_SIZE];
 
-#define emit(X,Y) insert_opcode((X),(Y),current_line, current_file)
-#define emit2(X) insert_opcode2((X),current_line, current_file)
+#define emit(X,Y) insert_opcode((X),(Y),lex.current_line, lex.current_file)
+#define emit2(X) insert_opcode2((X),lex.current_line, lex.current_file)
 
 /* Prototypes begin here */
-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_int(INT32 l,int area);
 void upd_int(int offset, INT32 tmp);
 INT32 read_int(int offset);
 void push_address(void);
 void push_explicit(INT32 address);
 INT32 pop_address(void);
+int alloc_label(void);
+int do_jump(int token,INT32 lbl);
+void do_pop(int x);
 int do_docode(node *n,INT16 flags);
+void do_cond_jump(node *n, int label, int iftrue, int flags);
 void do_code_block(node *n);
 int docode(node *n);
 /* Prototypes end here */
diff --git a/src/gc.c b/src/gc.c
index 9a7f6f56514979a5d434040dadb80311b4a2e13a..941e9fe7c141105a671099bf298573770f7d7953 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -276,7 +276,7 @@ void describe_something(void *a, int t)
 	break;
       }
 
-      for(pos=0;pos<(long)p->program_size && pos<100;pos++)
+      for(pos=0;pos<(long)p->num_program && pos<100;pos++)
       {
 	tmp=get_line(p->program+pos, p, &line);
 	if(tmp && line)
diff --git a/src/interpret.c b/src/interpret.c
index 5b66151e4ad00c88ce09d2e74e3e1809086e4779..73837899a2dc929e4a45c82e12cf0bac1a6bc769 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: interpret.c,v 1.56 1997/12/22 17:35:23 hubbe Exp $");
+RCSID("$Id: interpret.c,v 1.57 1998/01/13 22:56:43 hubbe Exp $");
 #include "interpret.h"
 #include "object.h"
 #include "program.h"
@@ -180,7 +180,7 @@ void check_mark_stack(INT32 size)
 }
 
 
-static void eval_instruction(unsigned char *pc);
+static int eval_instruction(unsigned char *pc);
 
 
 /*
@@ -476,9 +476,9 @@ void dump_backlog(void)
 
 static int o_catch(unsigned char *pc);
 
-static void eval_instruction(unsigned char *pc)
+static int eval_instruction(unsigned char *pc)
 {
-  unsigned INT32 instr, prefix=0;
+  unsigned INT32 accumulator=0,instr, prefix=0;
   while(1)
   {
     fp->pc = pc;
@@ -562,6 +562,9 @@ static void eval_instruction(unsigned char *pc)
       CASE(F_PREFIX_CHARX256);
       prefix+=EXTRACT_UCHAR(pc++)<<8;
       break;
+
+      CASE(F_LDA); accumulator=GET_ARG(); break;
+
       /* Push number */
       CASE(F_CONST0); push_int(0); break;
       CASE(F_CONST1); push_int(1); break;
@@ -616,6 +619,84 @@ static void eval_instruction(unsigned char *pc)
       print_return_value();
       break;
 
+      CASE(F_EXTERNAL);
+      {
+	struct inherit *inherit;
+	struct program *p;
+	INT32 id=GET_ARG();
+	struct object *o=fp->context.parent;
+	INT32 i=fp->context.parent_identifier;
+	
+	while(1)
+	{
+	  if(!o)
+	    error("Parent no longer exists\n");
+
+	  if(!(p=o->prog))
+	    error("Attempting to access variable in destructed object\n");
+
+	  inherit=INHERIT_FROM_INT(p, i);
+
+	  if(!accumulator) break;
+	  --accumulator;
+
+	  if(p->identifier_references[id].inherit_offset==0)
+	  {
+	    i=o->parent_identifier;
+	    o=o->parent;
+	  }else{
+	    i=inherit->parent_identifier;
+	    o=inherit->parent;
+	  }
+	}
+
+	low_object_index_no_free(sp,
+				 o,
+				 id + inherit->identifier_level);
+	sp++;
+	print_return_value();
+	break;
+      }
+
+      CASE(F_EXTERNAL_LVALUE);
+      {
+	struct inherit *inherit;
+	struct program *p;
+	INT32 id=GET_ARG();
+	struct object *o=fp->context.parent;
+	INT32 i=fp->context.parent_identifier;
+	
+	while(1)
+	{
+	  if(!o)
+	    error("Parent no longer exists\n");
+
+	  if(!(p=o->prog))
+	    error("Attempting to access variable in destructed object\n");
+
+	  inherit=INHERIT_FROM_INT(p, i);
+
+	  if(!accumulator) break;
+	  accumulator--;
+
+	  if(p->identifier_references[id].inherit_offset==0)
+	  {
+	    i=o->parent_identifier;
+	    o=o->parent;
+	  }else{
+	    i=inherit->parent_identifier;
+	    o=inherit->parent;
+	  }
+	}
+
+	ref_push_object(o);
+	sp->type=T_LVALUE;
+	sp->u.integer=id + inherit->identifier_level;
+	sp++;
+	break;
+      }
+
+
       CASE(F_MARK_AND_LOCAL); *(mark_sp++)=sp;
       CASE(F_LOCAL);
       assign_svalue_no_free(sp++,fp->locals+GET_ARG());
@@ -1075,7 +1156,7 @@ static void eval_instruction(unsigned char *pc)
 
       CASE(F_CATCH);
       if(o_catch(pc+sizeof(INT32)))
-	return; /* There was a return inside the evaluated code */
+	return -1; /* There was a return inside the evaluated code */
       else
 	pc+=EXTRACT_INT(pc);
       break;
@@ -1122,34 +1203,59 @@ static void eval_instruction(unsigned char *pc)
 	break;
       }
 
+      CASE(F_APPLY_AND_RETURN);
+      {
+	INT32 args=sp - *--mark_sp;
+	if(fp->locals >= sp-args)
+	{
+	  MEMMOVE(sp-args+1,sp-args,args*sizeof(struct svalue));
+	  sp++;
+	  sp[-args-1].type=T_INT;
+	}
+	/* We sabotage the stack here */
+	assign_svalue(sp-args-1,fp->context.prog->constants+GET_ARG());
+	return args+1;
+      }
+
+      CASE(F_CALL_LFUN_AND_RETURN);
+      {
+	INT32 args=sp - *--mark_sp;
+	if(fp->locals >= sp-args)
+	{
+	  MEMMOVE(sp-args+1,sp-args,args*sizeof(struct svalue));
+	  sp++;
+	  sp[-args-1].type=T_INT;
+	}else{
+	  free_svalue(sp-args-1);
+	}
+	/* More stack sabotage */
+	sp[-args-1].u.object=fp->current_object;
+	sp[-args-1].subtype=GET_ARG()+fp->context.identifier_level;
+	sp[-args-1].type=T_FUNCTION;
+	fp->current_object->refs++;
+
+	return args+1;
+      }
+
       CASE(F_RETURN_1);
-      pop_n_elems(sp-fp->locals);
       push_int(1);
       goto do_return;
 
       CASE(F_RETURN_0);
-      pop_n_elems(sp-fp->locals);
       push_int(0);
       goto do_return;
 
       CASE(F_RETURN);
-      if(fp->locals != sp-1)
-      {
-	assign_svalue(fp->locals, sp-1);
-	pop_n_elems(sp - fp->locals - 1);
-      }
-
     do_return:
-#ifdef DEBUG
-      if(d_flag > 2)
-	do_gc();
-#endif
+#if defined(DEBUG) && defined(GC2)
+      if(d_flag > 2) do_gc();
       check_threads_etc();
+#endif
 
       /* fall through */
 
       CASE(F_DUMB_RETURN);
-      return;
+      return -1;
 
       CASE(F_NEGATE); 
       if(sp[-1].type == T_INT)
@@ -1313,12 +1419,368 @@ static void eval_instruction(unsigned char *pc)
       pop_stack();
       break;
 
+    CASE(F_CALL_FUNCTION);
+    mega_apply(APPLY_STACK,sp - *--mark_sp,0,0);
+    break;
+
+    CASE(F_CALL_FUNCTION_AND_RETURN);
+    return sp - *--mark_sp;
+
     default:
       fatal("Strange instruction %ld\n",(long)instr);
     }
   }
 }
 
+void mega_apply(enum apply_type type, INT32 args, void *arg1, void *arg2)
+{
+  struct object *o;
+  int fun, tailrecurse=-1;
+  struct svalue *save_sp=sp-args;
+
+  switch(type)
+  {
+  case APPLY_STACK:
+  apply_stack:
+  if(!args)
+    error("Too few arguments to `()\n");
+    args--;
+    if(sp-save_sp-args > (args<<2) + 32)
+    {
+      /* The test above assures these two areas
+       * are not overlapping
+       */
+      assign_svalues(save_sp, sp-args-1, args+1, BIT_MIXED);
+      pop_n_elems(sp-save_sp-args-1);
+    }
+    arg1=(void *)(sp-args-1);
+
+  case APPLY_SVALUE:
+  apply_svalue:
+  {
+    struct svalue *s=(struct svalue *)arg1;
+    switch(s->type)
+    {
+    case T_INT:
+      if (!s->u.integer) {
+	error("Attempt to call the NULL-value\n");
+      } else {
+	error("Attempt to call the value %d\n", s->u.integer);
+      }
+
+    case T_STRING:
+      if (s->u.string->len > 20) {
+	error("Attempt to call the string \"%20s\"...\n", s->u.string->str);
+      } else {
+	error("Attempt to call the string \"%s\"\n", s->u.string->str);
+      }
+    case T_MAPPING:
+      error("Attempt to call a mapping\n");
+    default:
+      error("Call to non-function value type:%d.\n", s->type);
+      
+    case T_FUNCTION:
+      if(s->subtype == FUNCTION_BUILTIN)
+      {
+	(*(s->u.efun->function))(args);
+	break;
+      }else{
+	o=s->u.object;
+	fun=s->subtype;
+	goto apply_low;
+      }
+      break;
+
+    case T_ARRAY:
+      apply_array(s->u.array,args);
+      break;
+
+    case T_PROGRAM:
+      push_object(clone_object(s->u.program,args));
+      break;
+
+    case T_OBJECT:
+      o=s->u.object;
+      fun=LFUN_CALL;
+      goto call_lfun;
+    }
+    break;
+  }
+
+  call_lfun:
+#ifdef DEBUG
+    if(fun < 0 || fun >= NUM_LFUNS)
+      fatal("Apply lfun on illegal value!\n");
+#endif
+    if(!o->prog)
+      error("Apply on destructed object.\n");
+    fun=FIND_LFUN(o->prog,fun);
+    goto apply_low;
+  
+
+  case APPLY_LOW:
+    o=(struct object *)arg1;
+    fun=(long)arg2;
+
+  apply_low:
+    {
+      struct program *p;
+      struct reference *ref;
+      struct frame new_frame;
+      struct identifier *function;
+      
+      if(fun<0)
+      {
+	pop_n_elems(args);
+	push_int(0);
+	return;
+      }
+      
+      check_threads_etc();
+      check_stack(256);
+      check_mark_stack(256);
+
+#ifdef DEBUG
+      if(d_flag>2) do_debug();
+#endif
+
+      p=o->prog;
+      if(!p)
+	error("Cannot call functions in destructed objects.\n");
+#ifdef DEBUG
+      if(fun>=(int)p->num_identifier_references)
+	fatal("Function index out of range.\n");
+#endif
+
+      ref = p->identifier_references + fun;
+#ifdef DEBUG
+      if(ref->inherit_offset>=p->num_inherits)
+	fatal("Inherit offset out of range in program.\n");
+#endif
+
+      /* init a new evaluation frame */
+      new_frame.parent_frame = fp;
+      new_frame.current_object = o;
+      new_frame.context = p->inherits[ ref->inherit_offset ];
+      if(!ref->inherit_offset) new_frame.context.parent=o->parent;
+
+      function = new_frame.context.prog->identifiers + ref->identifier_offset;
+  
+      new_frame.locals = sp - args;
+      new_frame.args = args;
+      new_frame.fun = fun;
+      new_frame.current_storage = o->storage+new_frame.context.storage_offset;
+      new_frame.pc = 0;
+      
+      new_frame.current_object->refs++;
+      new_frame.context.prog->refs++;
+      if(new_frame.context.parent) new_frame.context.parent->refs++;
+      
+#ifdef DEBUG
+      if(t_flag)
+      {
+	char *file, *f;
+	INT32 linep,e,nonblock;
+	char buf[50],*s;
+	
+	if((nonblock=query_nonblocking(2)))
+	  set_nonblocking(2,0);
+	
+	if(fp && fp->pc)
+	{
+	  file=get_line(fp->pc,fp->context.prog,&linep);
+	  while((f=STRCHR(file,'/'))) file=f+1;
+	}else{
+	  linep=0;
+	  file="-";
+	}
+	
+	init_buf();
+	sprintf(buf,"%lx->",(long)o);
+	my_strcat(buf);
+	my_strcat(function->name->str);
+	my_strcat("(");
+	for(e=0;e<args;e++)
+	{
+	  if(e) my_strcat(",");
+	  describe_svalue(sp-args+e,0,0);
+	}
+	my_strcat(")"); 
+	s=simple_free_buf();
+	if((long)strlen(s) > (long)TRACE_LEN)
+	{
+	  s[TRACE_LEN]=0;
+	  s[TRACE_LEN-1]='.';
+	  s[TRACE_LEN-2]='.';
+	  s[TRACE_LEN-2]='.';
+	}
+	fprintf(stderr,"- %s:%4ld: %s\n",file,(long)linep,s);
+	free(s);
+	
+	if(nonblock)
+	  set_nonblocking(2,1);
+      }
+#endif
+      
+      fp = &new_frame;
+      
+      if(function->func.offset == -1)
+	error("Calling undefined function '%s'.\n",function->name->str);
+      
+      switch(function->identifier_flags & (IDENTIFIER_FUNCTION | IDENTIFIER_CONSTANT))
+      {
+      case IDENTIFIER_C_FUNCTION:
+	fp->num_args=args;
+	new_frame.num_locals=args;
+	(*function->func.c_fun)(args);
+	break;
+	
+      case IDENTIFIER_CONSTANT:
+      {
+	struct svalue *s=fp->context.prog->constants+function->func.offset;
+	if(s->type == T_PROGRAM)
+	{
+	  struct object *tmp=parent_clone_object(s->u.program,
+						 o,
+						 fun,
+						 args);
+	  push_object(tmp);
+	  break;
+	}
+	/* Fall through */
+      }
+      
+      case 0:
+      {
+	if(sp-save_sp-args<=0)
+	{
+	  /* Create an extra svalue for tail recursion style call */
+	  sp++;
+	  MEMMOVE(sp-args,sp-args-1,sizeof(struct svalue)*args);
+	  sp[-args-1].type=T_INT;
+	}
+	low_object_index_no_free(sp-args-1,o,fun);
+	tailrecurse=args+1;
+	break;
+      }
+
+      case IDENTIFIER_PIKE_FUNCTION:
+      {
+	int num_args;
+	int num_locals;
+	unsigned char *pc;
+	pc=new_frame.context.prog->program + function->func.offset;
+	
+	num_locals=EXTRACT_UCHAR(pc++);
+	num_args=EXTRACT_UCHAR(pc++);
+	
+	/* adjust arguments on stack */
+	if(args < num_args) /* push zeros */
+	{
+	  clear_svalues(sp, num_args-args);
+	  sp += num_args-args;
+	  args += num_args-args;
+	}
+	
+	if(function->identifier_flags & IDENTIFIER_VARARGS)
+	{
+	  f_aggregate(args - num_args); /* make array */
+	  args = num_args+1;
+	}else{
+	  if(args > num_args)
+	  {
+	    /* pop excessive */
+	    pop_n_elems(args - num_args);
+	    args=num_args;
+	  }
+	}
+	
+	clear_svalues(sp, num_locals - args);
+	sp += num_locals - args;
+#ifdef DEBUG
+	if(num_locals < num_args)
+	  fatal("Wrong number of arguments or locals in function def.\n");
+#endif
+	new_frame.num_locals=num_locals;
+	new_frame.num_args=num_args;
+	tailrecurse=eval_instruction(pc);
+#ifdef DEBUG
+	if(sp<evaluator_stack)
+	  fatal("Stack error (also simple).\n");
+#endif
+	break;
+      }
+      
+      }
+
+#if 0
+      if(sp - new_frame.locals > 1)
+      {
+	pop_n_elems(sp - new_frame.locals -1);
+      }else if(sp - new_frame.locals < 1){
+#ifdef DEBUG
+	if(sp - new_frame.locals<0) fatal("Frame underflow.\n");
+#endif
+	sp->u.integer = 0;
+	sp->subtype=NUMBER_NUMBER;
+	sp->type = T_INT;
+	sp++;
+      }
+#endif
+      
+      if(new_frame.context.parent) free_object(new_frame.context.parent);
+      free_object(new_frame.current_object);
+      free_program(new_frame.context.prog);
+      
+      fp = new_frame.parent_frame;
+      
+      if(tailrecurse>=0)
+      {
+	args=tailrecurse;
+	goto apply_stack;
+      }
+
+#ifdef DEBUG
+      if(t_flag)
+      {
+	char *s;
+	int nonblock;
+	
+	if((nonblock=query_nonblocking(2)))
+	  set_nonblocking(2,0);
+	
+	init_buf();
+	my_strcat("Return: ");
+	describe_svalue(sp-1,0,0);
+	s=simple_free_buf();
+	if((long)strlen(s) > (long)TRACE_LEN)
+	{
+	  s[TRACE_LEN]=0;
+	  s[TRACE_LEN-1]='.';
+	  s[TRACE_LEN-2]='.';
+	  s[TRACE_LEN-2]='.';
+	}
+	fprintf(stderr,"%-*s%s\n",4,"-",s);
+	free(s);
+	
+	if(nonblock)
+	  set_nonblocking(2,1);
+      }
+#endif
+    }
+  }
+
+  if(save_sp+1 < sp)
+  {
+    assign_svalue(save_sp,sp-1);
+    pop_n_elems(sp-save_sp-1);
+  }
+
+  if(save_sp+1 > sp && type != APPLY_SVALUE)
+    push_int(0);
+}
+
+
 /* Put catch outside of eval_instruction, so
  * the setjmp won't affect the optimization of
  * eval_instruction
@@ -1334,13 +1796,13 @@ static int o_catch(unsigned char *pc)
     UNSETJMP(tmp);
     return 0;
   }else{
-    eval_instruction(pc);
+    int x=eval_instruction(pc);
+    if(x!=-1) mega_apply(APPLY_STACK, x, 0,0);
     UNSETJMP(tmp);
     return 1;
   }
 }
 
-
 int apply_low_safe_and_stupid(struct object *o, INT32 offset)
 {
   JMP_BUF tmp;
@@ -1357,6 +1819,7 @@ int apply_low_safe_and_stupid(struct object *o, INT32 offset)
   new_frame.fun = -1;
   new_frame.pc = 0;
   new_frame.current_storage=o->storage;
+  new_frame.context.parent=0;
   fp = & new_frame;
 
   new_frame.current_object->refs++;
@@ -1366,7 +1829,9 @@ int apply_low_safe_and_stupid(struct object *o, INT32 offset)
   {
     ret=1;
   }else{
-    eval_instruction(o->prog->program + offset);
+    int tmp=eval_instruction(o->prog->program + offset);
+    if(tmp!=-1) mega_apply(APPLY_STACK, tmp, 0,0);
+    
 #ifdef DEBUG
     if(sp<evaluator_stack)
       fatal("Stack error (simple).\n");
@@ -1382,207 +1847,6 @@ int apply_low_safe_and_stupid(struct object *o, INT32 offset)
   return ret;
 }
 
-void apply_low(struct object *o, int fun, int args)
-{
-  struct program *p;
-  struct reference *ref;
-  struct frame new_frame;
-  struct identifier *function;
-
-  if(fun<0)
-  {
-    pop_n_elems(args);
-    push_int(0);
-    return;
-  }
-
-  o->refs++;
-
-  fast_check_threads_etc(4);
-  check_stack(256);
-  check_mark_stack(256);
-
-#ifdef DEBUG
-  if(d_flag>2) do_debug();
-#endif
-
-  p=o->prog;
-  if(!p)
-    error("Cannot call functions in destructed objects.\n");
-#ifdef DEBUG
-  if(fun>=(int)p->num_identifier_references)
-    fatal("Function index out of range.\n");
-#endif
-
-  ref = p->identifier_references + fun;
-#ifdef DEBUG
-  if(ref->inherit_offset>=p->num_inherits)
-    fatal("Inherit offset out of range in program.\n");
-#endif
-
-  /* init a new evaluation frame */
-  new_frame.parent_frame = fp;
-  new_frame.current_object = o;
-  new_frame.context = p->inherits[ ref->inherit_offset ];
-  function = new_frame.context.prog->identifiers + ref->identifier_offset;
-  
-  new_frame.locals = sp - args;
-  new_frame.args = args;
-  new_frame.fun = fun;
-  new_frame.current_storage = o->storage+new_frame.context.storage_offset;
-  new_frame.pc = 0;
-
-/* new_frame.current_object->refs++;  Moved to beginning of function / Hubbe */
-  new_frame.context.prog->refs++;
-
-  if(t_flag)
-  {
-    char *file, *f;
-    INT32 linep,e,nonblock;
-    char buf[50],*s;
-
-    if((nonblock=query_nonblocking(2)))
-      set_nonblocking(2,0);
-
-    if(fp && fp->pc)
-    {
-      file=get_line(fp->pc,fp->context.prog,&linep);
-      while((f=STRCHR(file,'/'))) file=f+1;
-    }else{
-      linep=0;
-      file="-";
-    }
-
-    init_buf();
-    sprintf(buf,"%lx->",(long)o);
-    my_strcat(buf);
-    my_strcat(function->name->str);
-    my_strcat("(");
-    for(e=0;e<args;e++)
-    {
-      if(e) my_strcat(",");
-      describe_svalue(sp-args+e,0,0);
-    }
-    my_strcat(")"); 
-    s=simple_free_buf();
-    if((long)strlen(s) > (long)TRACE_LEN)
-    {
-      s[TRACE_LEN]=0;
-      s[TRACE_LEN-1]='.';
-      s[TRACE_LEN-2]='.';
-      s[TRACE_LEN-2]='.';
-    }
-    fprintf(stderr,"- %s:%4ld: %s\n",file,(long)linep,s);
-    free(s);
-
-    if(nonblock)
-      set_nonblocking(2,1);
-  }
-
-  fp = &new_frame;
-
-#ifdef PROFILING
-  function->num_calls++;
-#endif /* PROFILING */
-
-  if(function->func.offset == -1)
-    error("Calling undefined function '%s'.\n",function->name->str);
-
-  if(function->identifier_flags & IDENTIFIER_C_FUNCTION)
-  {
-    fp->num_args=args;
-    new_frame.num_locals=args;
-    (*function->func.c_fun)(args);
-  }else{
-    int num_args;
-    int num_locals;
-    unsigned char *pc;
-    pc=new_frame.context.prog->program + function->func.offset;
-
-    num_locals=EXTRACT_UCHAR(pc++);
-    num_args=EXTRACT_UCHAR(pc++);
-
-    /* adjust arguments on stack */
-    if(args < num_args) /* push zeros */
-    {
-      clear_svalues(sp, num_args-args);
-      sp += num_args-args;
-      args += num_args-args;
-    }
-
-    if(function->identifier_flags & IDENTIFIER_VARARGS)
-    {
-      f_aggregate(args - num_args); /* make array */
-      args = num_args+1;
-    }else{
-      if(args > num_args)
-      {
-	/* pop excessive */
-	pop_n_elems(args - num_args);
-	args=num_args;
-      }
-    }
-
-    clear_svalues(sp, num_locals - args);
-    sp += num_locals - args;
-#ifdef DEBUG
-    if(num_locals < num_args)
-      fatal("Wrong number of arguments or locals in function def.\n");
-#endif
-    new_frame.num_locals=num_locals;
-    new_frame.num_args=num_args;
-    eval_instruction(pc);
-#ifdef DEBUG
-    if(sp<evaluator_stack)
-      fatal("Stack error (also simple).\n");
-#endif
-  }
-
-  if(sp - new_frame.locals > 1)
-  {
-    pop_n_elems(sp - new_frame.locals -1);
-  }else if(sp - new_frame.locals < 1){
-#ifdef DEBUG
-    if(sp - new_frame.locals<0) fatal("Frame underflow.\n");
-#endif
-    sp->u.integer = 0;
-    sp->subtype=NUMBER_NUMBER;
-    sp->type = T_INT;
-    sp++;
-  }
-
-  free_object(new_frame.current_object);
-  free_program(new_frame.context.prog);
-
-  fp = new_frame.parent_frame;
-
-  if(t_flag)
-  {
-    char *s;
-    int nonblock;
-
-    if((nonblock=query_nonblocking(2)))
-      set_nonblocking(2,0);
-
-    init_buf();
-    my_strcat("Return: ");
-    describe_svalue(sp-1,0,0);
-    s=simple_free_buf();
-    if((long)strlen(s) > (long)TRACE_LEN)
-    {
-      s[TRACE_LEN]=0;
-      s[TRACE_LEN-1]='.';
-      s[TRACE_LEN-2]='.';
-      s[TRACE_LEN-2]='.';
-    }
-    fprintf(stderr,"%-*s%s\n",4,"-",s);
-    free(s);
-
-    if(nonblock)
-      set_nonblocking(2,1);
-  }
-}
-
 void safe_apply_low(struct object *o,int fun,int args)
 {
   JMP_BUF recovery;
@@ -1621,9 +1885,9 @@ void safe_apply_low(struct object *o,int fun,int args)
     }
   }
   UNSETJMP(recovery);
-
 }
 
+
 void safe_apply(struct object *o, char *fun ,INT32 args)
 {
 #ifdef DEBUG
@@ -1641,7 +1905,7 @@ void apply_lfun(struct object *o, int fun, int args)
   if(!o->prog)
     error("Apply on destructed object.\n");
 
-  apply_low(o, o->prog->lfuns[fun], args);
+  apply_low(o, (int)FIND_LFUN(o->prog,fun), args);
 }
 
 void apply_shared(struct object *o,
@@ -1656,129 +1920,6 @@ void apply(struct object *o, char *fun, int args)
   apply_low(o, find_identifier(fun, o->prog), args);
 }
 
-void strict_apply_svalue(struct svalue *s, INT32 args)
-{
-  struct svalue *save_sp;
-  save_sp=sp-args;
-  if(t_flag>1)
-  {
-    char *file, *f;
-    INT32 linep,e,nonblock;
-    char *st;
-
-    if((nonblock=query_nonblocking(2)))
-      set_nonblocking(2,0);
-
-    if(fp && fp->pc)
-    {
-      file=get_line(fp->pc,fp->context.prog,&linep);
-      while((f=STRCHR(file,'/'))) file=f+1;
-    }else{
-      linep=0;
-      file="-";
-    }
-
-    init_buf();
-    describe_svalue(s,0,0);
-    my_strcat("(");
-    for(e=0;e<args;e++)
-    {
-      if(e) my_strcat(",");
-      describe_svalue(sp-args+e,0,0);
-    }
-    my_strcat(")"); 
-    st=simple_free_buf();
-    if((long)strlen(st) > (long)TRACE_LEN)
-    {
-      st[TRACE_LEN]=0;
-      st[TRACE_LEN-1]='.';
-      st[TRACE_LEN-2]='.';
-      st[TRACE_LEN-2]='.';
-    }
-    fprintf(stderr,"- %s:%4ld: %s\n",file,(long)linep,st);
-    free(st);
-
-    if(nonblock)
-      set_nonblocking(2,1);
-  }
-
-  switch(s->type)
-  {
-  case T_FUNCTION:
-    if(s->subtype == FUNCTION_BUILTIN)
-    {
-      (*(s->u.efun->function))(args);
-    }else{
-      apply_low(s->u.object, s->subtype, args);
-    }
-    break;
-
-  case T_ARRAY:
-    apply_array(s->u.array,args);
-    break;
-
-  case T_PROGRAM:
-    {
-      struct object *o=clone_object(s->u.program,args);
-      push_object(o);
-    }
-    break;
-
-  case T_OBJECT:
-    if(!s->u.object->prog)
-      error("Calling a destructed object.\n");
-    
-    if(s->u.object->prog->lfuns[LFUN_CALL] == -1)
-      error("Calling object without `() operator\n");
-
-    apply_lfun(s->u.object, LFUN_CALL, args);
-    break;
-
-  case T_INT:
-    if (!s->u.integer) {
-      error("Attempt to call the NULL-value\n");
-    } else {
-      error("Attempt to call the value %d\n", s->u.integer);
-    }
-  case T_STRING:
-    if (s->u.string->len > 20) {
-      error("Attempt to call the string \"%20s\"...\n", s->u.string->str);
-    } else {
-      error("Attempt to call the string \"%s\"\n", s->u.string->str);
-    }
-  case T_MAPPING:
-    error("Attempt to call a mapping\n");
-  case T_MULTISET:
-    error("Attempt to call a multiset\n");
-  default:
-    error("Call to non-function value type:%d.\n", s->type);
-  }
-
-  if(t_flag>1 && sp>save_sp)
-  {
-    char *s;
-    int nonblock;
-    if((nonblock=query_nonblocking(2)))
-      set_nonblocking(2,0);
-
-    init_buf();
-    my_strcat("Return: ");
-    describe_svalue(sp-1,0,0);
-    s=simple_free_buf();
-    if((long)strlen(s) > (long)TRACE_LEN)
-    {
-      s[TRACE_LEN]=0;
-      s[TRACE_LEN-1]='.';
-      s[TRACE_LEN-2]='.';
-      s[TRACE_LEN-2]='.';
-    }
-    fprintf(stderr,"%-*s%s\n",4,"-",s);
-    free(s);
-
-    if(nonblock)
-      set_nonblocking(2,1);
-  }
-}
 
 void apply_svalue(struct svalue *s, INT32 args)
 {
diff --git a/src/interpret.h b/src/interpret.h
index 9b5fd6783e9cabbf0bc3f84f811b19b2de879b43..8a7d46afc16553bf1b18b4519c924bd9869f1bd6 100644
--- a/src/interpret.h
+++ b/src/interpret.h
@@ -43,6 +43,7 @@ struct frame
 #define push_object(O) do{ struct object  *_=(O); sp->u.object=_; sp++->type=T_OBJECT; }while(0)
 #define push_float(F) do{ float _=(F); sp->u.float_number=_; sp++->type=T_FLOAT; }while(0)
 #define push_text(T) push_string(make_shared_string((T)))
+#define push_constant_text(T) do{ sp->subtype=0; MAKE_CONSTANT_SHARED_STRING(sp->u.string,T); sp++->type=T_STRING; }while(0)
 
 #define ref_push_program(P) do{ struct program *_=(P); _->refs++; sp->u.program=_; sp++->type=T_PROGRAM; }while(0)
 #define ref_push_mapping(M) do{ struct mapping *_=(M); _->refs++; sp->u.mapping=_; sp++->type=T_MAPPING; }while(0)
@@ -53,6 +54,19 @@ struct frame
 
 #define push_svalue(S) do { struct svalue *_=(S); assign_svalue_no_free(sp,_); sp++; }while(0)
 
+enum apply_type
+{
+  APPLY_STACK, /* The function is the first argument */
+  APPLY_SVALUE, /* arg1 points to an svalue containing the function */
+   APPLY_LOW    /* arg1 is the object pointer,(int)arg2 the function */
+};
+
+#define apply_low(O,FUN,ARGS) \
+  mega_apply(APPLY_LOW, (ARGS), (void*)(O),(void*)(FUN))
+
+#define strict_apply_svalue(SVAL,ARGS) \
+  mega_apply(APPLY_SVALUE, (ARGS), (void*)(SVAL),0)
+
 #define APPLY_MASTER(FUN,ARGS) \
 do{ \
   static int fun_,master_cnt=0; \
@@ -103,8 +117,8 @@ void pop_n_elems(INT32 x);
 void reset_evaluator(void);
 struct backlog;
 void dump_backlog(void);
+void mega_apply(enum apply_type type, INT32 args, void *arg1, void *arg2);
 int apply_low_safe_and_stupid(struct object *o, INT32 offset);
-void apply_low(struct object *o, int fun, int args);
 void safe_apply_low(struct object *o,int fun,int args);
 void safe_apply(struct object *o, char *fun ,INT32 args);
 void apply_lfun(struct object *o, int fun, int args);
@@ -112,7 +126,6 @@ void apply_shared(struct object *o,
 		  struct pike_string *fun,
 		  int args);
 void apply(struct object *o, char *fun, int args);
-void strict_apply_svalue(struct svalue *s, INT32 args);
 void apply_svalue(struct svalue *s, INT32 args);
 void slow_check_stack(void);
 void cleanup_interpret(void);
diff --git a/src/language.yacc b/src/language.yacc
index 186321928026016148cdadcb1a266f08996ac730..3f9fa70ce4d4957c3007198c9d67aeab9d58db6e 100644
--- a/src/language.yacc
+++ b/src/language.yacc
@@ -11,9 +11,10 @@
  */
 %token F_PREFIX_256 F_PREFIX_512 F_PREFIX_768 F_PREFIX_1024
 %token F_PREFIX_CHARX256 F_PREFIX_WORDX256 F_PREFIX_24BITX256
-%token F_POP_VALUE F_POP_N_ELEMS F_MARK F_MARK2
-%token F_CALL_LFUN F_CALL_LFUN_AND_POP
+%token F_POP_VALUE F_POP_N_ELEMS F_MARK F_MARK2 F_LDA
+%token F_CALL_LFUN F_CALL_LFUN_AND_POP F_CALL_LFUN_AND_RETURN
 %token F_APPLY F_APPLY_AND_POP F_MARK_APPLY F_MARK_APPLY_POP
+%token F_APPLY_AND_RETURN
 
 %token F_BRANCH F_BRANCH_WHEN_ZERO F_BRANCH_WHEN_NON_ZERO
 %token F_BRANCH_WHEN_LT F_BRANCH_WHEN_GT
@@ -31,8 +32,10 @@
 /*
  * Basic value pushing
  */
-%token F_LFUN F_GLOBAL F_LOCAL F_2_LOCALS F_MARK_AND_LOCAL
-%token F_GLOBAL_LVALUE F_LOCAL_LVALUE
+%token F_LFUN
+%token F_GLOBAL F_GLOBAL_LVALUE
+%token F_LOCAL F_2_LOCALS F_LOCAL_LVALUE F_MARK_AND_LOCAL
+%token F_EXTERNAL F_EXTERNAL_LVALUE
 %token F_CLEAR_LOCAL F_CLEAR_2_LOCAL F_CLEAR_STRING_SUBTYPE
 %token F_CONSTANT F_FLOAT F_STRING F_ARROW_STRING
 %token F_NUMBER F_NEG_NUMBER F_CONST_1 F_CONST0 F_CONST1 F_BIGNUM
@@ -49,6 +52,7 @@
 %token F_ASSIGN_LOCAL F_ASSIGN_LOCAL_AND_POP
 %token F_ASSIGN_GLOBAL F_ASSIGN_GLOBAL_AND_POP
 %token F_ADD F_SUBTRACT F_ADD_INT F_ADD_NEG_INT
+%token F_ADD_TO_AND_POP
 %token F_MULTIPLY F_DIVIDE F_MOD
 
 %token F_LT F_GT F_EQ F_GE F_LE F_NE
@@ -63,7 +67,7 @@
 %token F_FOREACH
 
 %token F_SIZEOF F_SIZEOF_LOCAL
-%token F_ADD_TO_AND_POP
+%token F_CALL_FUNCTION F_CALL_FUNCTION_AND_RETURN
 
 /*
  * These are token values that needn't have an associated code for the
@@ -130,6 +134,7 @@
 %token F_WHILE
 %token F_XOR_EQ
 %token F_NOP
+%token F_UNDEFINED
 
 %token F_ALIGN
 %token F_POINTER
@@ -157,7 +162,7 @@
 /* This is the grammar definition of Pike. */
 
 #include "global.h"
-RCSID("$Id: language.yacc,v 1.50 1997/10/27 09:59:21 hubbe Exp $");
+RCSID("$Id: language.yacc,v 1.51 1998/01/13 22:56:43 hubbe Exp $");
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
@@ -177,19 +182,14 @@ RCSID("$Id: language.yacc,v 1.50 1997/10/27 09:59:21 hubbe Exp $");
 #include "docode.h"
 #include "machine.h"
 
-#define YYMAXDEPTH	600
+#define YYMAXDEPTH	1000
 
 #ifdef DEBUG
 #define YYDEBUG 1
 #endif
 
-void free_all_local_names(void);
-void add_local_name(struct pike_string *,struct pike_string *);
 
-/*
- * The names and types of arguments and auto variables.
- */
-struct locals *local_variables = 0;
+void add_local_name(struct pike_string *,struct pike_string *);
 
 static int varargs;
 static INT32  current_modifiers;
@@ -206,6 +206,7 @@ void fix_comp_stack(int sp)
   }
 }
 
+
 /*
  * Kludge for Bison not using prototypes.
  */
@@ -332,7 +333,6 @@ int yylex(YYSTYPE *yylval);
 %type <n> m_expr_list
 %type <n> m_expr_list2
 %type <n> new_local_name
-%type <n> optional_comma_expr
 %type <n> optional_else_part
 %type <n> return
 %type <n> sscanf
@@ -344,6 +344,7 @@ int yylex(YYSTYPE *yylval);
 %type <n> unused
 %type <n> unused2
 %type <n> while
+%type <n> optional_comma_expr
 %%
 
 all: program;
@@ -359,9 +360,7 @@ optional_semi_colon: /* empty */
 string_constant: low_string
   | string_constant '+' low_string
   {
-    $$=add_shared_strings($1,$3);
-    free_string($1);
-    free_string($3);
+    $$=add_and_free_shared_strings($1,$3);
   }
   ;
 
@@ -371,11 +370,9 @@ optional_rename_inherit: ':' F_IDENTIFIER { $$=$2; }
 
 program_ref: string_constant
   {
-    reference_shared_string($1);
-    push_string($1);
+    ref_push_string($1);
     push_string($1);
-    reference_shared_string(current_file);
-    push_string(current_file);
+    ref_push_string(lex.current_file);
     SAFE_APPLY_MASTER("handle_inherit", 2);
 
     if(sp[-1].type != T_PROGRAM)
@@ -388,43 +385,51 @@ program_ref: string_constant
       push_string(last_identifier);
       last_identifier->refs++;
     }else{
-      push_text("");
+      push_constant_text("");
     }
     
     resolv_constant($1);
-    if(sp[-1].type == T_OBJECT)
+    switch(sp[-1].type)
     {
-      struct program *p=sp[-1].u.object->prog;
-      if(!p)
+    case T_OBJECT:
+      if(!sp[-1].u.object->prog)
       {
 	pop_stack();
 	push_int(0);
       }else{
+	struct program *p=sp[-1].u.object->prog;
 	p->refs++;
 	pop_stack();
 	push_program(p);
       }
-    }
-    if(sp[-1].type != T_PROGRAM)
-    {
+      break;
+
+    case T_FUNCTION:
+      if(program_from_function(sp-1))
+	break;
+
+    default:
       yyerror("Illegal program identifier");
       pop_stack();
       push_int(0);
+      
+    case T_PROGRAM:
+      break;
     }
+
     free_node($1);
   }
   ;
           
 inheritance: modifiers F_INHERIT program_ref optional_rename_inherit ';'
   {
-    struct pike_string *s;
-    if(sp[-1].type == T_PROGRAM)
+    if(!(new_program->flags & PROGRAM_PASS_1_DONE))
     {
-      s=sp[-2].u.string;
+      struct pike_string *s=sp[-2].u.string;
       if($4) s=$4;
-      do_inherit(sp[-1].u.program,$1,s);
-      if($4) free_string($4);
+      do_inherit(sp-1,$1,s);
     }
+    if($4) free_string($4);
     pop_n_elems(2);
   }
   ;
@@ -441,19 +446,20 @@ import: modifiers F_IMPORT idents ';'
 constant_name: F_IDENTIFIER '=' expr0
   {
     int tmp;
-    node *n;
     /* This can be made more lenient in the future */
-    n=mknode(F_ARG_LIST,$3,0); /* Make sure it is optimized */
-    if(!is_const(n))
+
+    /* Ugly hack to make sure that $3 is optimized */
+    tmp=compiler_pass;
+    $3=mknode(F_ARG_LIST,$3,0);
+    compiler_pass=tmp;
+
+    if(!is_const($3))
     {
-      struct svalue tmp;
-      yyerror("Constant definition is not constant.");
-      tmp.type=T_INT;
-      tmp.u.integer=0;
-      add_constant($1,&tmp, current_modifiers);
+      if(compiler_pass==2)
+	yyerror("Constant definition is not constant.");
+      add_constant($1,0, current_modifiers); /* Prototype */
     } else {
-      tmp=eval_low(n);
-      free_node(n);
+      tmp=eval_low($3);
       if(tmp < 1)
       {
 	yyerror("Error in constant definition.");
@@ -462,8 +468,9 @@ constant_name: F_IDENTIFIER '=' expr0
 	add_constant($1,sp-1,current_modifiers);
 	pop_stack();
       }
-      free_string($1);
     }
+    if($3) free_node($3);
+    free_string($1);
   }
   ;
 
@@ -484,35 +491,49 @@ block_or_semi: block
 
 type_or_error: simple_type
   {
-    if(local_variables->current_type)
-      free_string(local_variables->current_type); 
-    local_variables->current_type=$1;
+    if(compiler_frame->current_type)
+      free_string(compiler_frame->current_type); 
+    compiler_frame->current_type=$1;
   }
   | /* empty */
   {
     yyerror("Missing type.");
-    copy_shared_string(local_variables->current_type,
+    copy_shared_string(compiler_frame->current_type,
 		       mixed_type_string);
   }
   
 
-def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
+def: modifiers type_or_error optional_stars F_IDENTIFIER 
+  {
+    push_compiler_frame();
+    if(!compiler_frame->previous ||
+       !compiler_frame->previous->current_type)
+    {
+      yyerror("Internal compiler fault");
+      copy_shared_string(compiler_frame->current_type,
+			 mixed_type_string);
+    }else{
+      copy_shared_string(compiler_frame->current_type,
+			 compiler_frame->previous->current_type);
+    }
+  }
+  '(' arguments ')'
   {
     int e;
     /* construct the function type */
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while(--$3>=0) push_type(T_ARRAY);
     
-    if(local_variables->current_return_type)
-      free_string(local_variables->current_return_type);
-    local_variables->current_return_type=pop_type();
+    if(compiler_frame->current_return_type)
+      free_string(compiler_frame->current_return_type);
+    compiler_frame->current_return_type=pop_type();
     
-    push_finished_type(local_variables->current_return_type);
+    push_finished_type(compiler_frame->current_return_type);
     
-    e=$6-1;
+    e=$7-1;
     if(varargs)
     {
-      push_finished_type(local_variables->variable[e].type);
+      push_finished_type(compiler_frame->variable[e].type);
       e--;
       varargs=0;
       pop_type_stack();
@@ -522,7 +543,7 @@ def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
     push_type(T_MANY);
     for(; e>=0; e--)
     {
-      push_finished_type(local_variables->variable[e].type);
+      push_finished_type(compiler_frame->variable[e].type);
       if($1 & ID_VARARGS)
       {
 	push_type(T_VOID);
@@ -532,40 +553,39 @@ def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
     push_type(T_FUNCTION);
     
     $<string>$=pop_type();
-    define_function($4,
-		    $<string>$,
-		    $1,
-		    IDENTIFIER_PIKE_FUNCTION,
-		    0);
+
+    if(compiler_pass==1)
+    {
+      define_function($4,
+		      $<string>$,
+		      $1,
+		      IDENTIFIER_PIKE_FUNCTION,
+		      0);
+    }
   }
   block_or_semi
   {
     int e;
-    if($9)
+    if($10)
     {
-      for(e=0; e<$6; e++)
+      for(e=0; e<$7; e++)
       {
-	if(!local_variables->variable[e].name ||
-	   !local_variables->variable[e].name->len)
-	{
-	  my_yyerror("Missing name for argument %d",e);
-	}
+	if(!compiler_frame->variable[e].name ||
+	   !compiler_frame->variable[e].name->len)
+	  {
+	    my_yyerror("Missing name for argument %d",e);
+	  }
       }
 
-      dooptcode($4, $9, $<string>8, $1);
+      dooptcode($4, $10, $<string>9, $1);
 #ifdef DEBUG
       if(recoveries && sp-evaluator_stack < recoveries->sp)
 	fatal("Stack error (underflow)\n");
 #endif
     }
-    if(local_variables->current_return_type)
-    {
-      free_string(local_variables->current_return_type);
-      local_variables->current_return_type=0;
-    }
-    free_all_local_names();
+    pop_compiler_frame();
     free_string($4);
-    free_string($<string>8);
+    free_string($<string>9);
   }
   | modifiers type_or_error name_list ';' {}
   | inheritance {}
@@ -575,11 +595,10 @@ def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
   | error ';' { yyerrok; }
   {
     reset_type_stack();
-/*    if(num_parse_error>5) YYACCEPT; */
+/*     if(num_parse_error>5) YYACCEPT; */
   }
   ;
 
-
 optional_dot_dot_dot: F_DOT_DOT_DOT { $$=1; }
   | /* empty */ { $$=0; }
   ;
@@ -588,7 +607,6 @@ optional_identifier: F_IDENTIFIER
   | /* empty */ { $$=0; }
   ;
 
-
 new_arg_name: type optional_dot_dot_dot optional_identifier
   {
     if(varargs) yyerror("Can't define more arguments after ...");
@@ -598,7 +616,9 @@ new_arg_name: type optional_dot_dot_dot optional_identifier
       push_type(T_ARRAY);
       varargs=1;
     }
-    if(!$3) $3=make_shared_string("");
+    if(!$3)
+      MAKE_CONSTANT_SHARED_STRING($3,"");
+
     if(islocal($3) >= 0)
       my_yyerror("Variable '%s' appears twice in argument list.",
 		 $3->str);
@@ -669,9 +689,10 @@ type3: F_INT_ID      { push_type(T_INT); }
 opt_object_type:  /* Empty */ { push_type_int(0); }
   | '(' program_ref ')'
   {
-    if(sp[-1].type == T_PROGRAM)
+    struct program *p=program_from_svalue(sp-1);
+    if(p)
     {
-      push_type_int(sp[-1].u.program->id);
+      push_type_int(p->id);
     }else{
       yyerror("Not a valid program specifier");
       push_type_int(0);
@@ -760,7 +781,7 @@ name_list: new_name
 new_name: optional_stars F_IDENTIFIER
   {
     struct pike_string *type;
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while($1--) push_type(T_ARRAY);
     type=pop_type();
     define_variable($2, type, current_modifiers);
@@ -770,7 +791,7 @@ new_name: optional_stars F_IDENTIFIER
   | optional_stars F_IDENTIFIER '='
   {
     struct pike_string *type;
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while($1--) push_type(T_ARRAY);
     type=pop_type();
     $<number>$=define_variable($2, type, current_modifiers);
@@ -789,14 +810,14 @@ new_name: optional_stars F_IDENTIFIER
 
 new_local_name: optional_stars F_IDENTIFIER
   {
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while($1--) push_type(T_ARRAY);
     add_local_name($2, pop_type());
     $$=mknode(F_ASSIGN,mkintnode(0), mklocalnode(islocal($2)));
   }
   | optional_stars F_IDENTIFIER '=' expr0
   {
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while($1--) push_type(T_ARRAY);
     add_local_name($2, pop_type());
     $$=mknode(F_ASSIGN,$4,mklocalnode(islocal($2)));
@@ -806,17 +827,11 @@ new_local_name: optional_stars F_IDENTIFIER
 
 block:'{'
   {
-    $<number>$=local_variables->current_number_of_locals;
+    $<number>$=compiler_frame->current_number_of_locals;
   } 
   statements '}'
   {
-    while(local_variables->current_number_of_locals > $<number>2)
-    {
-      int e;
-      e=--(local_variables->current_number_of_locals);
-      free_string(local_variables->variable[e].name);
-      free_string(local_variables->variable[e].type);
-    }
+    pop_local_variables($<number>2);
     $$=$3;
   }
   ;
@@ -861,12 +876,12 @@ continue: F_CONTINUE { $$=mknode(F_CONTINUE,0,0); } ;
 
 lambda: F_LAMBDA
   {
-    push_locals();
+    push_compiler_frame();
     $<number>$=comp_stackp;
     
-    if(local_variables->current_return_type)
-      free_string(local_variables->current_return_type);
-    copy_shared_string(local_variables->current_return_type,any_type_string);
+    if(compiler_frame->current_return_type)
+      free_string(compiler_frame->current_return_type);
+    copy_shared_string(compiler_frame->current_return_type,any_type_string);
   }
   func_args failsafe_block
   {
@@ -875,7 +890,6 @@ lambda: F_LAMBDA
     int f,e;
     struct pike_string *name;
     
-    setup_fake_program();
     fix_comp_stack($<number>2);
     
     push_type(T_MIXED);
@@ -883,7 +897,7 @@ lambda: F_LAMBDA
     e=$3-1;
     if(varargs)
     {
-      push_finished_type(local_variables->variable[e].type);
+      push_finished_type(compiler_frame->variable[e].type);
       e--;
       varargs=0;
       pop_type_stack();
@@ -892,28 +906,27 @@ lambda: F_LAMBDA
     }
     push_type(T_MANY);
     for(; e>=0; e--)
-      push_finished_type(local_variables->variable[e].type);
+      push_finished_type(compiler_frame->variable[e].type);
     
     push_type(T_FUNCTION);
     
     type=pop_type();
-    
-    sprintf(buf,"__lambda_%ld",
-	    (long)fake_program.num_identifier_references);
-    name=make_shared_string(buf);
-
-    f=dooptcode(name,
-	      mknode(F_ARG_LIST,$4,mknode(F_RETURN,mkintnode(0),0)),
-	      type,
-	      0);
-#ifdef DEBUG
-    if(recoveries && sp-evaluator_stack < recoveries->sp)
-      fatal("Stack error (underflow)\n");
-#endif
+
+    if(new_program->flags | PROGRAM_PASS_1_DONE)
+    {
+      sprintf(buf,"__lambda_%ld",
+	      (long)new_program->num_identifier_references);
+      name=make_shared_string(buf);
+      
+      f=dooptcode(name,
+		  mknode(F_ARG_LIST,$4,mknode(F_RETURN,mkintnode(0),0)),
+		  type,
+		  0);
+    }
     free_string(name);
     free_string(type);
     comp_stackp=$<number>2;
-    pop_locals();
+    pop_compiler_frame();
     $$=mkidentifiernode(f);
   }
   ;
@@ -922,41 +935,70 @@ failsafe_program: '{' program '}'
                 | error { yyerrok; }
                 ;
 
-class: modifiers F_CLASS optional_identifier
+class: modifiers F_CLASS F_IDENTIFIER
   {
-    start_new_program();
-    /* write(2, "start\n", 6); */
+    if(compiler_pass==1)
+    {
+      low_start_new_program(0, $3, $1);
+    }else{
+      int i;
+      struct program *p;
+      struct identifier *id;
+      i=isidentifier($3);
+      if(i<0)
+      {
+	low_start_new_program(new_program,0,0);
+	yyerror("Pass 2: program not defined!");
+      }else{
+	id=ID_FROM_INT(new_program, i);
+	if(IDENTIFIER_IS_CONSTANT(id->identifier_flags))
+	{
+	  struct svalue *s;
+	  s=PROG_FROM_INT(new_program,i)->constants+id->func.offset;
+	  if(s->type==T_PROGRAM)
+	  {
+	    low_start_new_program(s->u.program, $3, $1);
+	  }else{
+	    yyerror("Pass 2: constant redefined!");
+	    low_start_new_program(new_program, 0,0);
+	  }
+	}else{
+	  yyerror("Pass 2: class constant no longer constant!");
+	  low_start_new_program(new_program, 0,0);
+	}
+      }
+    }
   }
   failsafe_program
   {
-    struct svalue s;
-    /* write(2, "end\n", 4); */
-    s.u.program=end_program();
-    if(!s.u.program)
-    {
+    struct program *p;
+    if(compiler_pass == 1)
+      p=end_first_pass(0);
+    else
+      p=end_program();
+
+    $$=mkidentifiernode(isidentifier($3));
+
+    if(!p)
       yyerror("Class definition failed.");
-      s.type=T_INT;
-      s.subtype=0;
-    } else {
-      s.type=T_PROGRAM;
-      s.subtype=0;
-    }
-    if($3)
-    { 
-      add_constant($3, &s, $1);
-      free_string($3);
-    }
-    $$=mksvaluenode(&s);
-    free_svalue(&s);
+    else
+      free_program(p);
+
+    free_string($3);
   }
   ;
 
-cond: F_IF '(' comma_expr ')' statement optional_else_part
+cond: F_IF
+  {
+    $<number>$=compiler_frame->current_number_of_locals;
+  }
+  '(' comma_expr ')' statement optional_else_part
   {
-    $$=mknode('?',$3,mknode(':',$5,$6));
+    $$=mknode('?',$4,mknode(':',$6,$7));
     $$->line_number=$1;
     $$=mkcastnode(void_type_string,$$);
     $$->line_number=$1;
+    pop_local_variables($<number>2);
   }
   ;
 
@@ -964,10 +1006,15 @@ optional_else_part: { $$=0; }
   | F_ELSE statement { $$=$2; }
   ;      
 
-foreach: F_FOREACH '(' expr0 ',' lvalue ')' statement
+foreach: F_FOREACH
+  {
+    $<number>$=compiler_frame->current_number_of_locals;
+  }
+  '(' expr0 ',' lvalue ')' statement
   {
-    $$=mknode(F_FOREACH,mknode(F_VAL_LVAL,$3,$5),$7);
+    $$=mknode(F_FOREACH, mknode(F_VAL_LVAL,$4,$6),$8);
     $$->line_number=$1;
+    pop_local_variables($<number>2);
   }
   ;
 
@@ -978,22 +1025,32 @@ do: F_DO statement F_WHILE '(' comma_expr ')' ';'
   }
   ;
 
-for: F_FOR '(' unused  ';' for_expr ';' unused ')' statement
+for: F_FOR
   {
-    int i=current_line;
-    current_line=$1;
-    $$=mknode(F_ARG_LIST,mkcastnode(void_type_string,$3),mknode(F_FOR,$5,mknode(':',$9,$7)));
-    current_line=i;
+    $<number>$=compiler_frame->current_number_of_locals;
+  }
+  '(' unused  ';' for_expr ';' unused ')' statement
+  {
+    int i=lex.current_line;
+    lex.current_line=$1;
+    $$=mknode(F_ARG_LIST,mkcastnode(void_type_string,$4),mknode(F_FOR,$6,mknode(':',$10,$8)));
+    lex.current_line=i;
+    pop_local_variables($<number>2);
   }
   ;
 
 
-while:  F_WHILE '(' comma_expr ')' statement
+while:  F_WHILE
+  {
+    $<number>$=compiler_frame->current_number_of_locals;
+  }
+  '(' comma_expr ')' statement
   {
-    int i=current_line;
-    current_line=$1;
-    $$=mknode(F_FOR,$3,mknode(':',$5,NULL));
-    current_line=i;
+    int i=lex.current_line;
+    lex.current_line=$1;
+    $$=mknode(F_FOR,$4,mknode(':',$6,NULL));
+    lex.current_line=i;
+    pop_local_variables($<number>2);
   }
   ;
 
@@ -1001,10 +1058,15 @@ for_expr: /* EMPTY */ { $$=mkintnode(1); }
   | comma_expr
   ;
 
-switch:	F_SWITCH '(' comma_expr ')' statement
+switch:	F_SWITCH
+  {
+    $<number>$=compiler_frame->current_number_of_locals;
+  }
+  '(' comma_expr ')' statement
   {
-    $$=mknode(F_SWITCH,$3,$5);
+    $$=mknode(F_SWITCH,$4,$6);
     $$->line_number=$1;
+    pop_local_variables($<number>2);
   }
   ;
 
@@ -1014,13 +1076,13 @@ case: F_CASE comma_expr ':'
   }
   | F_CASE comma_expr F_DOT_DOT optional_comma_expr ':'
   {
-    $$=mknode(F_CASE,$4?$2:0,$4?$4:$2);
+     $$=mknode(F_CASE,$4?$2:0,$4?$4:$2);
   }
   ;
 
 return: F_RETURN
   {
-    if(!match_types(local_variables->current_return_type,
+    if(!match_types(compiler_frame->current_return_type,
 		    void_type_string))
     {
       yyerror("Must return a value for a non-void function.");
@@ -1046,9 +1108,9 @@ optional_comma_expr: { $$=0; }
 comma_expr: comma_expr2
   | type2
   {
-    if(local_variables->current_type)
-      free_string(local_variables->current_type);
-    local_variables->current_type=pop_type();
+    if(compiler_frame->current_type)
+      free_string(compiler_frame->current_type);
+    compiler_frame->current_type=pop_type();
   } local_name_list { $$=$3; }
   ;
           
@@ -1197,35 +1259,36 @@ low_idents: F_IDENTIFIER
       $$=mklocalnode(i);
     }else if((i=isidentifier($1))>=0){
       $$=mkidentifiernode(i);
-    }else if(find_module_identifier($1)){
-      $$=mkconstantsvaluenode(sp-1);
-      pop_stack();
-    }else{
+    }else if(!($$=find_module_identifier($1))){
       $$=0;
       if(!num_parse_error)
       {
-	if( get_master() )
-	{
-	  reference_shared_string($1);
-	  push_string($1);
-	  reference_shared_string(current_file);
-	  push_string(current_file);
-	  SAFE_APPLY_MASTER("resolv", 2);
-	  
-	  if(throw_value.type == T_STRING)
-	  {
-	    my_yyerror("%s",throw_value.u.string->str);
-	  }
-	  else if(IS_ZERO(sp-1) && sp[-1].subtype==1)
-	  {
-	    my_yyerror("'%s' undefined.", $1->str);
-	  }else{
-	    $$=mkconstantsvaluenode(sp-1);
-	  }
-	  pop_stack();
-	}else{
-	  my_yyerror("'%s' undefined.", $1->str);
-	}
+	if(get_master())
+	   {
+	     reference_shared_string($1);
+	     push_string($1);
+	     ref_push_string(lex.current_file);
+	     SAFE_APPLY_MASTER("resolv", 2);
+	
+	     if(throw_value.type == T_STRING)
+	     {
+	       my_yyerror("%s",throw_value.u.string->str);
+	     }
+	     else if(IS_ZERO(sp-1) && sp[-1].subtype==1)
+	     {
+	       my_yyerror("'%s' undefined.", $1->str);
+	     }else{
+	       $$=mkconstantsvaluenode(sp-1);
+	     }
+	     pop_stack();
+	   }else{
+	     if(compiler_pass==2)
+	     {
+	       my_yyerror("'%s' undefined.", $1->str);
+	     }else{
+	       $$=mknode(F_UNDEFINED,0,0);
+	     }
+	   }
       }
     }
     free_string($1);
@@ -1249,10 +1312,9 @@ low_idents: F_IDENTIFIER
     int f;
     struct reference *idp;
 
-    setup_fake_program();
     f=reference_inherited_identifier($1,$3);
-    idp=fake_program.identifier_references+f;
-    if (f<0 || ID_FROM_PTR(&fake_program,idp)->func.offset == -1)
+    idp=new_program->identifier_references+f;
+    if (f<0)
     {
       my_yyerror("Undefined identifier %s::%s", $1->str,$3->str);
       $$=mkintnode(0);
@@ -1268,10 +1330,9 @@ low_idents: F_IDENTIFIER
     int e,i;
 
     $$=0;
-    setup_fake_program();
-    for(e=1;e<(int)fake_program.num_inherits;e++)
+    for(e=1;e<(int)new_program->num_inherits;e++)
     {
-      if(fake_program.inherits[e].inherit_level!=1) continue;
+      if(new_program->inherits[e].inherit_level!=1) continue;
       i=low_reference_inherited_identifier(e,$2);
       if(i==-1) continue;
       if($$)
@@ -1358,9 +1419,7 @@ lvalue_list: /* empty */ { $$ = 0; }
 low_string: F_STRING 
   | low_string F_STRING
   {
-    $$=add_shared_strings($1,$2);
-    free_string($1);
-    free_string($2);
+    $$=add_and_free_shared_strings($1,$2);
   }
   ;
 
@@ -1386,24 +1445,20 @@ void yyerror(char *str)
   if ( get_master() )
   {
     sp->type = T_STRING;
-    copy_shared_string(sp->u.string, current_file);
+    copy_shared_string(sp->u.string, lex.current_file);
     sp++;
     sp->type = T_INT;
-    sp->u.integer = current_line;
+    sp->u.integer = lex.current_line;
     sp++;
     sp->type = T_STRING;
     sp->u.string = make_shared_string(str);
     sp++;
     SAFE_APPLY_MASTER("compile_error",3);
     pop_stack();
-#ifdef DEBUG
-    if(recoveries && sp-evaluator_stack < recoveries->sp)
-      fatal("Stack error (underflow)\n");
-#endif
   }else{
     (void)fprintf(stderr, "%s:%ld: %s\n",
-		  current_file->str,
-		  (long)current_line,
+		  lex.current_file->str,
+		  (long)lex.current_line,
 		  str);
     fflush(stderr);
   }
@@ -1413,18 +1468,18 @@ void yyerror(char *str)
 void add_local_name(struct pike_string *str,
 		    struct pike_string *type)
 {
-  if (local_variables->current_number_of_locals == MAX_LOCAL)
+  if (compiler_frame->current_number_of_locals == MAX_LOCAL)
   {
     yyerror("Too many local variables");
   }else {
-    local_variables->variable[local_variables->current_number_of_locals].type = type;
-    local_variables->variable[local_variables->current_number_of_locals].name = str;
-    local_variables->current_number_of_locals++;
-    if(local_variables->current_number_of_locals > 
-       local_variables->max_number_of_locals)
+    compiler_frame->variable[compiler_frame->current_number_of_locals].type = type;
+    compiler_frame->variable[compiler_frame->current_number_of_locals].name = str;
+    compiler_frame->current_number_of_locals++;
+    if(compiler_frame->current_number_of_locals > 
+       compiler_frame->max_number_of_locals)
     {
-      local_variables->max_number_of_locals=
-	local_variables->current_number_of_locals;
+      compiler_frame->max_number_of_locals=
+	compiler_frame->current_number_of_locals;
     }
   }
 }
@@ -1433,27 +1488,8 @@ void add_local_name(struct pike_string *str,
 int islocal(struct pike_string *str)
 {
   int e;
-  for(e=local_variables->current_number_of_locals-1;e>=0;e--)
-    if(local_variables->variable[e].name==str)
+  for(e=compiler_frame->current_number_of_locals-1;e>=0;e--)
+    if(compiler_frame->variable[e].name==str)
       return e;
   return -1;
 }
-
-void free_all_local_names(void)
-{
-  int e;
-
-  for (e=0; e<local_variables->current_number_of_locals; e++)
-  {
-    if(local_variables->variable[e].name)
-    {
-      free_string(local_variables->variable[e].name);
-      free_string(local_variables->variable[e].type);
-    }
-    local_variables->variable[e].name=0;
-    local_variables->variable[e].type=0;
-  }
-  local_variables->current_number_of_locals = 0;
-  local_variables->max_number_of_locals = 0;
-}
-
diff --git a/src/las.c b/src/las.c
index 736d579f882df609046032ba8d21f93b019559a9..0f72239e0678908412de61bd4d3203bb63770f5a 100644
--- a/src/las.c
+++ b/src/las.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: las.c,v 1.39 1997/10/05 03:39:25 grubba Exp $");
+RCSID("$Id: las.c,v 1.40 1998/01/13 22:56:44 hubbe Exp $");
 
 #include "language.h"
 #include "interpret.h"
@@ -34,7 +34,6 @@ int lasdebug=0;
 static node *eval(node *);
 static void optimize(node *n);
 
-dynamic_buffer areas[NUM_AREAS];
 node *init_node = 0;
 int num_parse_error;
 int cumulative_parse_error=0;
@@ -46,6 +45,7 @@ int car_is_node(node *n)
 {
   switch(n->token)
   {
+  case F_EXTERNAL:
   case F_IDENTIFIER:
   case F_CONSTANT:
   case F_LOCAL:
@@ -60,6 +60,7 @@ int cdr_is_node(node *n)
 {
   switch(n->token)
   {
+  case F_EXTERNAL:
   case F_IDENTIFIER:
   case F_CONSTANT:
   case F_LOCAL:
@@ -135,9 +136,9 @@ struct node_chunk
 static struct node_chunk *node_chunks=0;
 static node *free_nodes=0;
 
-void free_all_nodes(void)
+void free_all_nodes()
 {
-  if(!local_variables)
+  if(!compiler_frame)
   {
     node *tmp;
     struct node_chunk *tmp2;
@@ -240,7 +241,7 @@ static node *mkemptynode(void)
   res=free_nodes;
   free_nodes=CAR(res);
   res->token=0;
-  res->line_number=current_line;
+  res->line_number=lex.current_line;
   res->type=0;
   res->node_info=0;
   res->tree_info=0;
@@ -273,6 +274,10 @@ node *mknode(short token,node *a,node *b)
     }
     break;
 
+  case F_UNDEFINED:
+    res->node_info |= OPT_EXTERNAL_DEPEND | OPT_SIDE_EFFECT;
+    break;
+
   case F_RETURN:
     res->node_info |= OPT_RETURN;
     break;
@@ -310,7 +315,9 @@ node *mknode(short token,node *a,node *b)
 
   if(a) a->parent = res;
   if(b) b->parent = res;
-  if(!num_parse_error) optimize(res);
+
+  if(!num_parse_error && compiler_pass==2)
+    optimize(res);
 
 #ifdef DEBUG
   if(d_flag > 3)
@@ -372,13 +379,12 @@ node *mkefuncallnode(char *function, node *args)
   struct pike_string *name;
   node *n;
   name = findstring(function);
-  if(!name || !find_module_identifier(name))
+  if(!name || !(n=find_module_identifier(name)))
   {
     my_yyerror("Internally used efun undefined: %s",function);
     return mkintnode(0);
   }
-  n=mkapplynode(mksvaluenode(sp-1), args);
-  pop_stack();
+  n=mkapplynode(n, args);
   return n;
 }
 
@@ -394,7 +400,7 @@ node *mklocalnode(int var)
 {
   node *res = mkemptynode();
   res->token = F_LOCAL;
-  copy_shared_string(res->type, local_variables->variable[var].type);
+  copy_shared_string(res->type, compiler_frame->variable[var].type);
   res->node_info = OPT_NOT_CONST;
   res->tree_info=res->node_info;
 #ifdef __CHECKER__
@@ -408,11 +414,10 @@ node *mkidentifiernode(int i)
 {
   node *res = mkemptynode();
   res->token = F_IDENTIFIER;
-  setup_fake_program();
-  copy_shared_string(res->type, ID_FROM_INT(&fake_program, i)->type);
+  copy_shared_string(res->type, ID_FROM_INT(new_program, i)->type);
 
   /* FIXME */
-  if(IDENTIFIER_IS_CONSTANT(ID_FROM_INT(&fake_program, i)->identifier_flags))
+  if(IDENTIFIER_IS_CONSTANT(ID_FROM_INT(new_program, i)->identifier_flags))
   {
     res->node_info = OPT_EXTERNAL_DEPEND;
   }else{
@@ -427,6 +432,27 @@ node *mkidentifiernode(int i)
   return res;
 }
 
+node *mkexternalnode(int level,
+		     int i,
+		     struct identifier *id)
+{
+  node *res = mkemptynode();
+  res->token = F_EXTERNAL;
+
+  copy_shared_string(res->type, id->type);
+
+  /* FIXME */
+  res->node_info = OPT_NOT_CONST;
+  res->tree_info=res->node_info;
+
+#ifdef __CHECKER__
+  CDR(res)=0;
+#endif
+  res->u.integer.a = level;
+  res->u.integer.b = i;
+  return res;
+}
+
 node *mkcastnode(struct pike_string *type,node *n)
 {
   node *res;
@@ -451,6 +477,9 @@ node *mkcastnode(struct pike_string *type,node *n)
 void resolv_constant(node *n)
 {
   struct identifier *i;
+  struct program *p;
+  INT32 numid;
+
   if(!n)
   {
     push_int(0);
@@ -459,31 +488,49 @@ void resolv_constant(node *n)
     {
     case F_CONSTANT:
       push_svalue(& n->u.sval);
-      break;
+      return;
 
-    case F_IDENTIFIER:
-      setup_fake_program();
-      i=ID_FROM_INT(& fake_program, n->u.number);
-	
-      if(IDENTIFIER_IS_CONSTANT(i->identifier_flags))
+    case F_EXTERNAL:
+      p=parent_compilation(n->u.integer.a);
+      if(!p)
       {
-	push_svalue(PROG_FROM_INT(&fake_program, n->u.number)->constants +
-		    i->func.offset);
-      }else{
-	yyerror("Identifier is not a constant");
+	yyerror("Failed to resolv external constant");
 	push_int(0);
+	return;
       }
+      numid=n->u.integer.b;
+      break;
+
+    case F_IDENTIFIER:
+      p=new_program;
+      numid=n->u.number;
       break;
 
     case F_LOCAL:
-	yyerror("Expected constant, got local variable");
-	push_int(0);
-	break;
+      yyerror("Expected constant, got local variable");
+      push_int(0);
+      return;
 
     case F_GLOBAL:
-	yyerror("Expected constant, got global variable");
-	push_int(0);
-	break;
+      yyerror("Expected constant, got global variable");
+      push_int(0);
+      return;
+
+    default:
+      yyerror("Expected constant, got something else");
+      push_int(0);
+      return;
+    }
+
+    i=ID_FROM_INT(p, numid);
+    
+    if(IDENTIFIER_IS_CONSTANT(i->identifier_flags))
+    {
+      push_svalue(PROG_FROM_INT(new_program, numid)->constants +
+		  i->func.offset);
+    }else{
+      yyerror("Identifier is not a constant");
+      push_int(0);
     }
   }
 }
@@ -798,8 +845,7 @@ static void low_print_tree(node *foo,int needlval)
 
   case F_IDENTIFIER:
     if(needlval) putchar('&');
-    setup_fake_program();
-    printf("%s",ID_FROM_INT(&fake_program, foo->u.number)->name->str);
+    printf("%s",ID_FROM_INT(new_program, foo->u.number)->name->str);
     break;
 
   case F_ASSIGN:
@@ -1235,8 +1281,7 @@ void fix_type_field(node *n)
       switch(CAR(n)->token)
       {
       case F_IDENTIFIER:
-	setup_fake_program();
-	name=ID_FROM_INT(&fake_program, CAR(n)->u.number)->name->str;
+	name=ID_FROM_INT(new_program, CAR(n)->u.number)->name->str;
 	break;
 	
       case F_CONSTANT:
@@ -1281,11 +1326,11 @@ void fix_type_field(node *n)
     {
       yyerror("You cannot return a void expression");
     }
-    if(local_variables &&
-       local_variables->current_return_type &&
-       !match_types(local_variables->current_return_type,CAR(n)->type) &&
+    if(compiler_frame &&
+       compiler_frame->current_return_type &&
+       !match_types(compiler_frame->current_return_type,CAR(n)->type) &&
        !(
-	 local_variables->current_return_type==void_type_string &&
+	 compiler_frame->current_return_type==void_type_string &&
 	 CAR(n)->token == F_CONSTANT &&
 	 IS_ZERO(& CAR(n)->u.sval)
 	 )
@@ -1364,7 +1409,7 @@ static void zapp_try_optimize(node *n)
 static void optimize(node *n)
 {
   node *tmp1, *tmp2, *tmp3;
-  INT32 save_line = current_line;
+  INT32 save_line = lex.current_line;
   do
   {
     if(car_is_node(n) && !(CAR(n)->node_info & OPT_OPTIMIZED))
@@ -1377,7 +1422,7 @@ static void optimize(node *n)
       n=CDR(n);
       continue;
     }
-    current_line = n->line_number;
+    lex.current_line = n->line_number;
 
 
     n->tree_info = n->node_info;
@@ -1807,7 +1852,7 @@ static void optimize(node *n)
     n->node_info |= OPT_OPTIMIZED;
     n=n->parent;
   }while(n);
-  current_line = save_line;
+  lex.current_line = save_line;
 }
 
 struct timer_oflo
@@ -1842,10 +1887,9 @@ int eval_low(node *n)
 #endif
 
   if(num_parse_error) return -1;
-  setup_fake_program();
 
-  num_strings=fake_program.num_strings;
-  num_constants=fake_program.num_constants;
+  num_strings=new_program->num_strings;
+  num_constants=new_program->num_constants;
   jump=PC;
 
   store_linenumbers=0;
@@ -1853,7 +1897,6 @@ int eval_low(node *n)
   ins_f_byte(F_DUMB_RETURN);
   store_linenumbers=1;
 
-  setup_fake_program();
   ret=-1;
   if(!num_parse_error)
   {
@@ -1896,21 +1939,19 @@ int eval_low(node *n)
     remove_callback(tmp_callback);
   }
 
-  while(fake_program.num_strings > num_strings)
+  while(new_program->num_strings > num_strings)
   {
-    fake_program.num_strings--;
-    free_string(fake_program.strings[fake_program.num_strings]);
-    areas[A_STRINGS].s.len-=sizeof(struct pike_string *);
+    new_program->num_strings--;
+    free_string(new_program->strings[new_program->num_strings]);
   }
 
-  while(fake_program.num_constants > num_constants)
+  while(new_program->num_constants > num_constants)
   {
-    fake_program.num_constants--;
-    free_svalue(fake_program.constants + fake_program.num_constants);
-    areas[A_CONSTANTS].s.len-=sizeof(struct svalue);
+    new_program->num_constants--;
+    free_svalue(new_program->constants + new_program->num_constants);
   }
 
-  areas[A_PROGRAM].s.len=jump;
+  new_program->num_program=jump;
 
   return ret;
 }
@@ -2036,16 +2077,10 @@ int dooptcode(struct pike_string *name,
   int args, vargs, ret;
   struct svalue *foo;
 
-#ifdef DEBUG
-  if(recoveries && sp-evaluator_stack < recoveries->sp)
-    fatal("Stack error before dooptcode (underflow)\n");
-#endif
-
 #ifdef DEBUG
   if(a_flag > 1)
     fprintf(stderr,"Doing function '%s' at %x\n",name->str,PC);
 #endif
-  last_function_opt_info=OPT_SIDE_EFFECT;
 
   args=count_arguments(type);
   if(args < 0) 
@@ -2055,44 +2090,44 @@ int dooptcode(struct pike_string *name,
   }else{
     vargs=0;
   }
-  n=mknode(F_ARG_LIST,n,0);
-
-  if((foo=is_stupid_func(n, args, vargs)))
+  if(compiler_pass==1)
   {
-    if(foo->type == T_FUNCTION && foo->subtype==FUNCTION_BUILTIN)
+    tmp.offset=-1;
+  }else{
+    n=mknode(F_ARG_LIST,n,0);
+    
+    if((foo=is_stupid_func(n, args, vargs)))
     {
-      tmp.c_fun=foo->u.efun->function;
-      ret=define_function(name,
-			  type,
-			  modifiers,
-			  IDENTIFIER_C_FUNCTION | vargs,
-			  &tmp);
-      free_node(n);
-      return ret;
+      if(foo->type == T_FUNCTION && foo->subtype==FUNCTION_BUILTIN)
+      {
+	tmp.c_fun=foo->u.efun->function;
+	ret=define_function(name,
+			    type,
+			    modifiers,
+			    IDENTIFIER_C_FUNCTION | vargs,
+			    &tmp);
+	free_node(n);
+	return ret;
+      }
     }
-  }
-  
-  tmp.offset=PC;
-  ins_byte(local_variables->max_number_of_locals, A_PROGRAM);
-  ins_byte(args, A_PROGRAM);
+
+    tmp.offset=PC;
+    add_to_program(compiler_frame->max_number_of_locals);
+    add_to_program(args);
   
 #ifdef DEBUG
-  if(a_flag > 2)
-  {
-    fprintf(stderr,"Coding: ");
-    print_tree(n);
-  }
+    if(a_flag > 2)
+    {
+      fprintf(stderr,"Coding: ");
+      print_tree(n);
+    }
 #endif
-  if(!num_parse_error)
-  {
-    do_code_block(n);
+    if(!num_parse_error)
+    {
+      do_code_block(n);
+    }
   }
   
-#ifdef DEBUG
-  if(recoveries && sp-evaluator_stack < recoveries->sp)
-    fatal("Stack error after do_code_block (underflow)\n");
-#endif
-
   ret=define_function(name,
 		      type,
 		      modifiers,
@@ -2103,6 +2138,4 @@ int dooptcode(struct pike_string *name,
   return ret;
 }
 
-INT32 get_opt_info(void) { return last_function_opt_info; }
-
 
diff --git a/src/las.h b/src/las.h
index 46fda27e69e6ff861a7f5d64219c9c819ded4bb1..f47fa7916100c9a9d60171ff918ff4f49a8857a7 100644
--- a/src/las.h
+++ b/src/las.h
@@ -7,21 +7,34 @@
 #define LAS_H
 
 #include "global.h"
+#include "pike_types.h"
 #include "svalue.h"
 #include "dynamic_buffer.h"
 #include "program.h"
 
 #define MAX_GLOBAL_VARIABLES 1000
 
+
+void yyerror(char *s);
+int islocal(struct pike_string *str);
+int verify_declared(struct pike_string *str);
+
+
+extern node *init_node;
+extern int num_parse_error;
+extern int cumulative_parse_error;
+extern struct compiler_frame *compiler_frame;
+
 struct local_variable
 {
   struct pike_string *name;
   struct pike_string *type;
 };
 
-struct locals
+struct compiler_frame
 {
-  struct locals *next;
+  struct compiler_frame *previous;
+
   struct pike_string *current_type;
   struct pike_string *current_return_type;
   int current_number_of_locals;
@@ -29,36 +42,6 @@ struct locals
   struct local_variable variable[MAX_LOCAL];
 };
 
-void yyerror(char *s);
-int islocal(struct pike_string *str);
-int verify_declared(struct pike_string *str);
-
-struct node_s
-{
-  unsigned INT16 token;
-  INT16 line_number;
-  INT16 node_info;
-  INT16 tree_info;
-  struct pike_string *type;
-  struct node_s *parent;
-  union 
-  {
-    int number;
-    struct svalue sval;
-    struct
-    {
-      struct node_s *a,*b;
-    } node;
-  } u;
-};
-
-typedef struct node_s node;
-
-extern struct locals *local_variables;
-extern node *init_node;
-extern int num_parse_error;
-extern int cumulative_parse_error;
-
 #define OPT_OPTIMIZED       0x1    /* has been processed by optimize(),
 				    * only used in node_info
 				    */
@@ -79,7 +62,7 @@ int car_is_node(node *n);
 int cdr_is_node(node *n);
 INT32 count_args(node *n);
 struct node_chunk;
-void free_all_nodes(void);
+void free_all_nodes();
 void free_node(node *n);
 node *mknode(short token,node *a,node *b);
 node *mkstrnode(struct pike_string *str);
@@ -90,6 +73,9 @@ node *mkefuncallnode(char *function, node *args);
 node *mkopernode(char *oper_id, node *arg1, node *arg2);
 node *mklocalnode(int var);
 node *mkidentifiernode(int i);
+node *mkexternalnode(int level,
+		     int i,
+		     struct identifier *id);
 node *mkcastnode(struct pike_string *type,node *n);
 void resolv_constant(node *n);
 node *index_node(node *n, struct pike_string * id);
@@ -113,7 +99,6 @@ int dooptcode(struct pike_string *name,
 	      node *n,
 	      struct pike_string *type,
 	      int modifiers);
-INT32 get_opt_info(void);
 /* Prototypes end here */
 
 #define CAR(n) ((n)->u.node.a)
@@ -125,20 +110,9 @@ INT32 get_opt_info(void);
 
 #define GAUGE_RUSAGE_INDEX 0
 
-#define A_PROGRAM 0
-#define A_STRINGS 1
-#define A_INHERITS 2
-#define A_IDENTIFIERS 3
-#define A_IDENTIFIER_REFERENCES 4
-#define A_CONSTANTS 5
-#define A_LINENUMBERS 6
-#define NUM_AREAS 7
-
 #define add_to_mem_block(N,Data,Size) low_my_binary_strcat(Data,Size,areas+N)
-#define IDENTIFIERP(i) (((struct reference *)areas[A_IDENTIFIER_REFERENCES].s.str)+i)
-#define INHERIT(i) (((struct inherit *)areas[A_INHERITS].s.str)+i)
-#define PC (areas[A_PROGRAM].s.len)
-
-extern dynamic_buffer areas[NUM_AREAS];
+#define IDENTIFIERP(i) (new_program->identifier_references+(i))
+#define INHERIT(i) (new_program->inherits+(i))
+#define PC (new_program->num_program)
 
 #endif
diff --git a/src/lex.c b/src/lex.c
index 859bbfabdd133828f48600d9604d14803fefbda1..5fb4368e3896aa655864a696eedf458c4c1e40a8 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: lex.c,v 1.36 1998/01/02 01:05:47 hubbe Exp $");
+RCSID("$Id: lex.c,v 1.37 1998/01/13 22:56:45 hubbe Exp $");
 #include "language.h"
 #include "array.h"
 #include "lex.h"
@@ -25,9 +25,11 @@ RCSID("$Id: lex.c,v 1.36 1998/01/02 01:05:47 hubbe Exp $");
 #include "mapping.h"
 
 #include "pike_macros.h"
+
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
+
 #include <ctype.h>
 #include <math.h>
 #include <fcntl.h>
@@ -35,27 +37,6 @@ RCSID("$Id: lex.c,v 1.36 1998/01/02 01:05:47 hubbe Exp $");
 #include "time_stuff.h"
 
 #define LEXDEBUG 0
-#define EXPANDMAX 500000
-
-struct pike_string *current_file;
-
-INT32 current_line;
-INT32 old_line;
-INT32 total_lines;
-INT32 nexpands;
-int pragma_all_inline;          /* inline all possible inlines */
-
-struct pike_predef_s
-{
-  char *name;
-  char *value;
-  struct pike_predef_s *next;
-};
-
-static struct pike_predef_s *pike_predefs=0;
-
-static int calc(void);
-static void calc1(void);
 
 void exit_lex(void)
 {
@@ -73,74 +54,8 @@ void exit_lex(void)
     }
   }
 #endif
-
-
-  while(local_variables)
-  {
-    int e;
-    struct locals *l;
-    for(e=0;e<local_variables->current_number_of_locals;e++)
-    {
-      free_string(local_variables->variable[e].name);
-      free_string(local_variables->variable[e].type);
-    }
-    if(local_variables->current_type)
-      free_string(local_variables->current_type);
-    if(local_variables->current_return_type)
-      free_string(local_variables->current_return_type);
-    l=local_variables->next;
-    free((char *)local_variables);
-    local_variables=l;
-  }
-
-  if(current_file) free_string(current_file);
-  free_reswords();
 }
 
-struct keyword reserved_words[] =
-{
-{ "array",	F_ARRAY_ID, },
-{ "break",	F_BREAK, },
-{ "case",	F_CASE, },
-{ "catch",	F_CATCH, },
-{ "class",	F_CLASS, },
-{ "constant",	F_CONSTANT, },
-{ "continue",	F_CONTINUE, },
-{ "default",	F_DEFAULT, },
-{ "do",		F_DO, },
-{ "else",	F_ELSE, },
-{ "float",	F_FLOAT_ID, },
-{ "for",	F_FOR, },
-{ "foreach",	F_FOREACH, },
-{ "function",	F_FUNCTION_ID, },
-{ "gauge",	F_GAUGE, },
-{ "if",		F_IF, },
-{ "import",	F_IMPORT, },
-{ "inherit",	F_INHERIT, },
-{ "inline",	F_INLINE, },
-{ "int",	F_INT_ID, },
-{ "lambda",	F_LAMBDA, },
-{ "mapping",	F_MAPPING_ID, },
-{ "mixed",	F_MIXED_ID, },
-{ "multiset",	F_MULTISET_ID, },
-{ "nomask",	F_NO_MASK, },
-{ "object",	F_OBJECT_ID, },
-{ "predef",	F_PREDEF, },
-{ "private",	F_PRIVATE, },
-{ "program",	F_PROGRAM_ID, },
-{ "protected",	F_PROTECTED, },
-{ "public",	F_PUBLIC, },
-{ "return",	F_RETURN, },
-{ "sscanf",	F_SSCANF, },
-{ "static",	F_STATIC, },
-{ "string",	F_STRING_ID, },
-{ "switch",	F_SWITCH, },
-{ "typeof",	F_TYPEOF, },
-{ "varargs",	F_VARARGS, },
-{ "void",	F_VOID_ID, },
-{ "while",	F_WHILE, },
-};
-
 struct keyword instr_names[]=
 {
 { "!",			F_NOT },	
@@ -230,6 +145,9 @@ struct keyword instr_names[]=
 { "local function call and pop",F_CALL_LFUN_AND_POP, I_HASARG },
 { "local function",	F_LFUN, I_HASARG },	
 { "local",		F_LOCAL, I_HASARG },	
+{ "external",		F_EXTERNAL, I_HASARG },
+{ "& external",		F_EXTERNAL_LVALUE, I_HASARG },
+{ "LDA",			F_LDA, I_HASARG },
 { "mark & local",	F_MARK_AND_LOCAL, I_HASARG },	
 { "ltosval2",		F_LTOSVAL2 },
 { "lvalue to svalue",	F_LTOSVAL },	
@@ -259,7 +177,7 @@ struct keyword instr_names[]=
 { "|",			F_OR },
 { "|=",			F_OR_EQ },	
 { "~",			F_COMPL },
-{ "label",		F_LABEL,I_HASARG },
+{ "label",		F_LABEL,1 },
 { "align",		F_ALIGN, I_HASARG },
 { "call",		F_APPLY, I_HASARG },
 { "clear local",	F_CLEAR_LOCAL, I_HASARG },
@@ -285,7 +203,10 @@ struct keyword instr_names[]=
 { "add -integer",       F_ADD_NEG_INT, I_HASARG },
 { "mark & call",        F_MARK_APPLY, I_HASARG },
 { "mark, call & pop",   F_MARK_APPLY_POP, I_HASARG },
-{ "+= and pop",         F_ADD_TO_AND_POP },
+{ "apply and return",   F_APPLY_AND_RETURN, I_HASARG },
+{ "call lfun & return", F_CALL_LFUN_AND_RETURN, I_HASARG },
+{ "call function",      F_CALL_FUNCTION, 0 },
+{ "call function & return", F_CALL_FUNCTION_AND_RETURN, 0 },
 };
 
 struct instr instrs[F_MAX_INSTR - F_OFFSET];
@@ -296,9 +217,7 @@ struct reserved
   int token;
 };
 
-struct hash_table *reswords;
-
-void init_lex(void)
+void init_lex()
 {
   unsigned int i;
   for(i=0; i<NELEM(instr_names);i++)
@@ -312,24 +231,6 @@ void init_lex(void)
     instrs[instr_names[i].token - F_OFFSET].name = instr_names[i].word;
     instrs[instr_names[i].token - F_OFFSET].flags=instr_names[i].flags;
   }
-
-  reswords=create_hash_table();
-
-  for(i=0; i<NELEM(reserved_words); i++)
-  {
-    struct reserved *r=ALLOC_STRUCT(reserved);
-    r->token = reserved_words[i].token;
-    r->link.s = make_shared_string(reserved_words[i].word);
-    reswords=hash_insert(reswords, &r->link);
-  }
-
-  /* Enlarge this hashtable heruetically */
-  reswords = hash_rehash(reswords, 2<<my_log2(NELEM(reserved_words)));
-}
-
-void free_reswords(void)
-{
-  free_hashtable(reswords,0);
 }
 
 char *low_get_f_name(int n,struct program *p)
@@ -393,1926 +294,576 @@ char *get_token_name(int n)
   }
 }
 
-/* foo must be a shared string */
-static int lookup_resword(struct pike_string *s)
-{
-  struct hash_entry *h;
-  h=hash_lookup(reswords, s);
-  if(!h) return -1;
-  return BASEOF(h, reserved, link)->token;
-}
-
+struct lex lex;
 
+#define LOOK() (*(lex.pos))
+#define GETC() (*(lex.pos++))
+#define GOBBLE(c) (LOOK()==c?(lex.pos++,1):0)
+#define SKIPSPACE() do { while(ISSPACE(LOOK()) && LOOK()!='\n') lex.pos++; }while(0)
+#define SKIPWHITE() do { while(ISSPACE(LOOK())) lex.pos++; }while(0)
+#define SKIPUPTO(X) do { while(LOOK()!=(X) && LOOK()) lex.pos++; }while(0)
 
-/*** input routines ***/
-struct inputstate
-{
-  struct inputstate *next;
-  int fd;
-  unsigned char *data;
-  INT32 buflen;
-  INT32 pos;
-  int dont_free_data;
-
-  int (*my_getc)(void);
-  int (*gobble)(int);
-  int (*look)(void);
-  void (*my_ungetc)(int);
-  void (*ungetstr)(char *,INT32);
-};
-
-#define MY_EOF 4711
-
-struct inputstate *istate=NULL;
-
-static void link_inputstate(struct inputstate *i)
-{
-  i->next=istate;
-  istate=i;
-}
-
-static void free_inputstate(struct inputstate *i)
-{
-  if(!i) return;
-  if(i->fd>=0)
-  {
-  retry:
-    if(close(i->fd)< 0)
-      if(errno == EINTR)
-	goto retry;
-  }
-  if(i->data && !i->dont_free_data) free(i->data);
-  free_inputstate(i->next);
-  free((char *)i);
-}
-
-static struct inputstate *new_inputstate(void);
-static struct inputstate *memory_inputstate(INT32 size);
-
-static int default_gobble(int c)
-{
-  if(istate->look()==c)
-  {
-    istate->my_getc();
-    return 1;
-  }else{
-    return 0;
-  }
+#define READBUF(X) {				\
+  register int C;				\
+  buf=lex.pos;					\
+  while((C=LOOK()) && (X)) lex.pos++;		\
+  len=lex.pos - buf;				\
 }
 
-static void default_ungetstr(char *s,INT32 len)
-{
-  link_inputstate(memory_inputstate(len+1000));
-  istate->ungetstr(s,len);
-}
+#define TWO_CHAR(X,Y) ((X)<<8)+(Y)
+#define ISWORD(X) (len==(long)strlen(X) && !MEMCMP(buf,X,strlen(X)))
 
-static void default_ungetc(int s)
-{
-  char c=s;
-  istate->ungetstr(&c,1);
-}
+/*** Lexical analyzing ***/
 
-static int default_look(void)
+static int char_const(void)
 {
   int c;
-  c=istate->my_getc();
-  istate->my_ungetc(c);
-  return c;
-}
-
-static struct inputstate *new_inputstate(void)
-{
-  struct inputstate *i;
-  i=(struct inputstate *)xalloc(sizeof(struct inputstate));
-  i->fd=-1;
-  i->data=NULL;
-  i->next=NULL;
-  i->dont_free_data=0;
-  i->gobble=default_gobble;
-  i->ungetstr=default_ungetstr;
-  i->my_ungetc=default_ungetc;
-  i->look=default_look;
-  return i;
-}
-
-/*** end of file input ***/
-static int end_getc(void) { return MY_EOF; }
-static int end_gobble(int c) { return c==MY_EOF; }
-static void end_ungetc(int c)
-{
-  if(c==MY_EOF) return;
-  default_ungetc(c);
-}
-
-static struct inputstate *end_inputstate(void)
-{
-  struct inputstate *i;
-  i=new_inputstate();
-  i->gobble=end_gobble;
-  i->look=end_getc;
-  i->my_getc=end_getc;
-  i->my_ungetc=end_ungetc;
-  return i;
-}
-
-/*** MEMORY input ***/
-static void memory_ungetstr(char *s,INT32 len)
-{
-  INT32 tmp;
-  tmp=MINIMUM(len,istate->pos);
-  if(tmp)
-  {
-    istate->pos -= tmp;
-    MEMCPY(istate->data + istate->pos , s+len-tmp , tmp);
-    len-=tmp;
-  }
-  if(len) default_ungetstr(s,len);
-}
-
-static void memory_ungetc(int s)
-{
-  if(istate->pos)
-  {
-    istate->pos --;
-    istate->data[istate->pos]=s;
-  }else{
-    default_ungetc(s);
-  }
-}
-
-static int memory_getc(void)
-{
-  if(istate->pos<istate->buflen)
-  {
-#if LEXDEBUG>9
-    fprintf(stderr,"lex: reading from memory '%c' (%d).\n",istate->data[istate->pos],istate->data[istate->pos]);
-#endif
-    return istate->data[(istate->pos)++];
-  }else{
-    struct inputstate *i;
-    i=istate;
-    istate=i->next;
-    if(!i->dont_free_data) free(i->data);
-    free((char *)i);
-    return istate->my_getc();
-  }
-}
-
-static int memory_look(void)
-{
-  if(istate->pos<istate->buflen)
+  switch(c=GETC())
   {
-    return istate->data[istate->pos];
-  }else{
-    struct inputstate *i;
-    i=istate;
-    istate=i->next;
-    if(!i->dont_free_data) free(i->data);
-    free((char *)i);
-    return istate->look();
+    case 0:
+      lex.pos--;
+      yyerror("Unexpected end of file\n");
+      return 0;
+      
+    case '0': case '1': case '2': case '3':
+    case '4': case '5': case '6': case '7':
+      c-='0';
+      if(LOOK()<'0' || LOOK()>'8') return c;
+      c=c*8+(GETC()-'0');
+      if(LOOK()<'0' || LOOK()>'8') return c;
+      c=c*8+(GETC()-'0');
+      return c;
+      
+    case 'r': return '\r';
+    case 'n': return '\n';
+    case 't': return '\t';
+    case 'b': return '\b';
+      
+    case '\n':
+      lex.current_line++;
+      return '\n';
+      
+      
+    case 'x':
+      switch(LOOK())
+      {
+	default: return c;
+	case '0': case '1': case '2': case '3':
+	case '4': case '5': case '6': case '7':
+	case '8': case '9':
+	  c=GETC()-'0';
+	  break;
+	  
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+	  c=GETC()-'a'+10;
+	  break;
+	  
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+	  c=GETC()-'A'+10;
+	  break;
+      }
+      switch(LOOK())
+      {
+	default: return c;
+	case '0': case '1': case '2': case '3':
+	case '4': case '5': case '6': case '7':
+	case '8': case '9':
+	  c=c*16+GETC()-'0';
+	  break;
+	  
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+	  c=c*16+GETC()-'a'+10;
+	  break;
+	  
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+	  c=c*16+GETC()-'a'+10;
+	  break;
+      }
+      return c;
+    
   }
+  return c;
 }
 
-/* allocate an empty memory state */
-static struct inputstate *memory_inputstate(INT32 size)
-{
-  struct inputstate *i;
-  if(!size) size=10000;
-  i=new_inputstate();
-  i->data=(unsigned char *)xalloc(size);
-  i->buflen=size;
-  i->pos=size;
-  i->ungetstr=memory_ungetstr;
-  i->my_getc=memory_getc;
-  i->look=memory_look;
-  i->my_ungetc=memory_ungetc;
-  return i;
-}
-
-static void prot_memory_ungetstr(char *s,INT32 len)
+static struct pike_string *readstring(void)
 {
-  INT32 tmp;
-  tmp=MINIMUM(len,istate->pos);
-  if(tmp)
+  int c;
+  dynamic_buffer tmp;
+  initialize_buf(&tmp);
+  
+  while(1)
   {
-    if(!MEMCMP(istate->data + istate->pos - tmp, s+len-tmp , tmp))
+    switch(c=GETC())
     {
-      istate->pos-=tmp;
-      len-=tmp;
+    case 0:
+      lex.pos--;
+      yyerror("End of file in string.");
+      break;
+      
+    case '\n':
+      lex.current_line++;
+      yyerror("Newline in string.");
+      break;
+      
+    case '\\':
+      low_my_putchar(char_const(),&tmp);
+      continue;
+      
+    case '"':
+      break;
+      
+    default:
+      low_my_putchar(c,&tmp);
+      continue;
     }
+    break;
   }
-  if(len) default_ungetstr(s,len);
+  return low_free_buf(&tmp);
 }
 
-static void prot_memory_ungetc(int s)
+int yylex(YYSTYPE *yylval)
+#if LEXDEBUG>4
 {
-  if(istate->pos && istate->data[istate->pos-1] == s)
+  int t;
+  int yylex2(YYSTYPE *);
+  t=yylex2(yylval);
+  if(t<256)
   {
-    istate->pos--;
+    fprintf(stderr,"yylex() -> '%c' (%d)\n",t,t);
   }else{
-    default_ungetc(s);
+    fprintf(stderr,"yylex() -> %s (%d)\n",get_f_name(t),t);
   }
+  return t;
 }
 
-/* allocate a memory, read-only, inputstate */
-static struct inputstate *prot_memory_inputstate(char *data,INT32 len)
+static int yylex2(YYSTYPE *yylval)
+#endif
 {
-  struct inputstate *i;
-  i=new_inputstate();
-  i->data=(unsigned char *)data;
-  i->buflen=len;
-  i->dont_free_data=1;
-  i->pos=0;
-  i->my_getc=memory_getc;
-  i->look=memory_look;
-  i->ungetstr=prot_memory_ungetstr;
-  i->my_ungetc=prot_memory_ungetc;
-  return i;
-}
+  INT32 c,len;
+  char *buf;
 
-/*** FILE input ***/
+#ifdef __CHECKER__
+  MEMSET((char *)yylval,0,sizeof(YYSTYPE));
+#endif
+#ifdef MALLOC_DEBUG
+  check_sfltable();
+#endif
 
-#define READAHEAD 8192
-static int file_getc(void)
-{
-  unsigned char buf[READAHEAD];
-  int got;
-  do {
-    got=read(istate->fd, buf, READAHEAD);
-    if(got > 0)
-    {
-      default_ungetstr((char *)buf, got);
-      return istate->my_getc();
-    }
-    else if(got==0 || errno != EINTR)
+  while(1)
+  {
+    switch(c=GETC())
     {
-      struct inputstate *i;
-      if(got<0 && errno != EINTR)
-	my_yyerror("Lex: Read failed with error %d\n",errno);
-
-      i=istate->next;
-      close(istate->fd);
-      free((char *)istate);
-      istate=i;
-      return istate->my_getc();
-    }
-  }while(1);
-}
-
-static struct inputstate *file_inputstate(int fd)
-{
-  struct inputstate *i;
-  i=new_inputstate();
-  i->fd=fd;
-  i->my_getc=file_getc;
-  return i;
-}
-
-static int GETC(void)
-{
-  int c;
-  c=istate->my_getc();
-  if(c=='\n') current_line++;
-  return c;
-}
+    case 0:
+      lex.pos--;
+      return 0;
 
-static void UNGETC(int c)
-{
-  if(c=='\n') current_line--;
-  istate->my_ungetc(c);
-}
+    case '\n':
+      lex.current_line++;
+      continue;
 
-static void UNGETSTR(char *s,INT32 len)
-{
-  INT32 e;
-  for(e=0;e<len;e++) if(s[e]=='\n') current_line--;
-  istate->ungetstr(s,len);
-}
+    case '#':
+      SKIPSPACE();
+      READBUF(C!=' ' && C!='\t' && C!='\n');
 
-static int GOBBLE(char c)
-{
-  if(istate->gobble(c))
-  {
-    if(c=='\n') current_line++;
-    return 1;
-  }else{
-    return 0;
-  }
-}
+      switch(len>0?buf[0]:0)
+      {
+	char *p;
+	
+      case 'l':
+	if(!ISWORD("line")) goto badhash;
+	READBUF(C!=' ' && C!='\t' && C!='\n');
+	
+      case '0': case '1': case '2': case '3': case '4':
+      case '5': case '6': case '7': case '8': case '9':
+	lex.current_line=atoi(buf)-1;
+	SKIPSPACE();
+	if(GOBBLE('"'))
+	{
+	  struct pike_string *tmp=readstring();
+	  free_string(lex.current_file);
+	  lex.current_file=tmp;
+	}
+	break;
+	
+      case 'e':
+	if(ISWORD("error"))
+	{
+	  SKIPSPACE();
+	  READBUF(C!='\n');
+	  yyerror(buf);
+	  break;
+	}
+	goto badhash;
 
-#define LOOK() (istate->look())
-#define SKIPWHITE() { int c; while(ISSPACE(c=GETC())); UNGETC(c); }
-#define SKIPTO(X) { int c; while((c=GETC())!=(X) && (c!=MY_EOF)); }
-#define SKIPUPTO(X) { int c; while((c=GETC())!=(X) && (c!=MY_EOF)); UNGETC(c); }
-#define READBUF(X) { \
-  register unsigned INT32 p; \
-  register int C; \
-  for(p=0;(C=GETC())!=MY_EOF && p<sizeof(buf) && (X);p++) \
-  buf[p]=C; \
-  if(p==sizeof(buf)) { \
-    yyerror("Internal buffer overflow.\n"); p--; \
-  } \
-  UNGETC(C); \
-  buf[p]=0; \
-}
+      case 'p':
+	if(ISWORD("pragma"))
+	{
+	  SKIPSPACE();
+	  READBUF(C!='\n');
+	  if (strcmp(buf, "all_inline") == 0)
+	  {
+	    lex.pragmas |= PRAGMA_ALL_INLINE;
+	  }
+	  break;
+	}
+	
+      badhash:
+	my_yyerror("Unknown directive #%s.",buf);
+	SKIPUPTO('\n');
+	continue;
+      }
+      continue;
 
-static char buf[1024];
+    case ' ':
+    case '\t':
+      continue;
 
-/*** Define handling ***/
+    case '\'':
+      switch(c=GETC())
+      {
+      case 0:
+	lex.pos--;
+	yyerror("Unexpected end of file\n");
+	break;
 
-struct define
-{
-  struct hash_entry link; /* must be first */
-  void (*magic)(void);
-  int args;
-  struct array *parts;
-};
+	case '\\':
+	  c=char_const();
+      }
+      if(!GOBBLE('\''))
+	yyerror("Unterminated character constant.");
+      yylval->number=c;
+      return F_NUMBER;
+	
+    case '"':
+      yylval->string=readstring();
+      return F_STRING;
+  
+    case ':':
+      if(GOBBLE(':')) return F_COLON_COLON;
+      return c;
 
-struct hash_table *defines = 0;
-
-#define find_define(N) (defines?BASEOF(hash_lookup(defines, N), define, link):0)
-
-/* argument must be shared string */
-static void undefine(struct pike_string *name)
-{
-  struct define *d;
-
-  d=find_define(name);
-
-  if(!d) return;
-
-  defines=hash_unlink(defines, & d->link);
-  free_string(d->link.s);
-  free_array(d->parts);
-  free((char *)d);
-}
-
-/* name and as are supposed to be SHARED strings */
-static void add_define(struct pike_string *name,
-		       int args,
-		       int parts_on_stack,
-		       void (*magic)(void))
-{
-  struct define *d;
-
-  f_aggregate(parts_on_stack);
-  if(sp[-1].type != T_ARRAY)
-  {
-    yyerror("Define failed for unknown reason.\n");
-    free_string(name);
-    pop_stack();
-    return;
-  }
-
-#if 0
-  if(find_define(name))
-  {
-    my_yyerror("Redefining '%s'",name->str);
-    free_string(name);
-    pop_stack();
-    return;
-  }
-#else
-  undefine(name);
-#endif
-
-  d=(struct define *)xalloc(sizeof(struct define));
-  d->link.s=name;
-  d->args=args;
-  d->magic=magic;
-  d->parts=sp[-1].u.array;
-  sp--;
-
-  defines=hash_insert(defines, & d->link);
-}
-
-static void simple_add_define(char *name,char *as,void (*magic)(void))
-{
-  if(magic)
-  {
-    add_define(make_shared_string(name),-1,0,magic);
-  }else{
-    push_string(make_shared_string(as));
-    add_define(make_shared_string(name),-1,1,magic);
-  }
-}
-
-static void free_one_define(struct hash_entry *h)
-{
-  struct define *d;
-  d=BASEOF(h, define, link);
-  if(d->parts) free_array(d->parts);
-  free((void *)d);
-}
-
-static void free_all_defines(void)
-{
-  if(defines)
-    free_hashtable(defines, free_one_define);
-  defines=0;
-}
-
-static void do_define(void)
-{
-  int c,e,t,argc;
-  struct svalue *save_sp=sp;
-  struct svalue *args_sp;
-  struct pike_string *s, *s2;
-
-  SKIPWHITE();
-  READBUF(isidchar(C));
-
-  s=make_shared_string(buf);
-
-  if(GOBBLE('('))
-  {
-    argc=0;
-
-    SKIPWHITE();
-    READBUF(isidchar(C));
-    if(buf[0])
-    {
-      push_string(make_shared_string(buf));
-      argc++;
-      SKIPWHITE();
-      while(GOBBLE(','))
+    case '.':
+      if(GOBBLE('.'))
       {
-        SKIPWHITE();
-        READBUF(isidchar(C));
-        push_string(make_shared_string(buf));
-        argc++;
+	if(GOBBLE('.')) return F_DOT_DOT_DOT;
+	return F_DOT_DOT;
       }
-    }
-    SKIPWHITE();
-
-    if(!GOBBLE(')'))
-      yyerror("Missing ')'");
-  }else{
-    argc=-1;
-  }
-
-  args_sp=sp;
-
-  init_buf();
-  t=0;
-  sp->type=T_STRING;
-  sp->u.string=make_shared_string("");
-  sp++;
-
-  while(1)
-  {
-    int tmp;
-
-    c=GETC();
-    if(c=='\\') if(GOBBLE('\n')) continue;
-    if( (t!=!!isidchar(c) && argc>0) || c=='\n' || c==MY_EOF)
+      return c;
+  
+    case '0':
+      if(GOBBLE('x') || GOBBLE('X'))
+      {
+	yylval->number=STRTOL(lex.pos, &lex.pos, 16);
+	return F_NUMBER;
+      }
+  
+    case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
     {
-      s2=free_buf();
-      tmp=0;
-      for(e=0;e<argc;e++)
+      char *p1, *p2;
+      double f;
+      long l;
+      lex.pos--;
+      f=my_strtod(lex.pos, &p1);
+      l=STRTOL(lex.pos, &p2, 0);
+
+      if(p1>p2)
       {
-	if(save_sp[e].u.string==s2)
-	{
-	  free_string(s2);
-	  push_int(e);
-	  tmp=1;
-	  break;
-	}
+	lex.pos=p1;
+	yylval->fnum=(float)f;
+	return F_FLOAT;
+      }else{
+	lex.pos=p2;
+	yylval->number=l;
+	return F_NUMBER;
       }
-      if(!tmp)
+  
+    case '-':
+      if(GOBBLE('=')) return F_SUB_EQ;
+      if(GOBBLE('>')) return F_ARROW;
+      if(GOBBLE('-')) return F_DEC;
+      return '-';
+  
+    case '+':
+      if(GOBBLE('=')) return F_ADD_EQ;
+      if(GOBBLE('+')) return F_INC;
+      return '+';
+  
+    case '&':
+      if(GOBBLE('=')) return F_AND_EQ;
+      if(GOBBLE('&')) return F_LAND;
+      return '&';
+  
+    case '|':
+      if(GOBBLE('=')) return F_OR_EQ;
+      if(GOBBLE('|')) return F_LOR;
+      return '|';
+
+    case '^':
+      if(GOBBLE('=')) return F_XOR_EQ;
+      return '^';
+  
+    case '*':
+      if(GOBBLE('=')) return F_MULT_EQ;
+      return '*';
+
+    case '%':
+      if(GOBBLE('=')) return F_MOD_EQ;
+      return '%';
+  
+    case '/':
+      if(GOBBLE('=')) return F_DIV_EQ;
+      return '/';
+  
+    case '=':
+      if(GOBBLE('=')) return F_EQ;
+      return '=';
+  
+    case '<':
+      if(GOBBLE('<'))
       {
-	push_string(s2);
-	if(sp[-2].type==T_STRING) f_add(2);
+	if(GOBBLE('=')) return F_LSH_EQ;
+	return F_LSH;
       }
-      if(c=='\n' || c==MY_EOF)
+      if(GOBBLE('=')) return F_LE;
+      return '<';
+  
+    case '>':
+      if(GOBBLE(')')) return F_MULTISET_END;
+      if(GOBBLE('=')) return F_GE;
+      if(GOBBLE('>'))
       {
-	push_string(make_shared_string(" "));
-	if(sp[-2].type==T_STRING) f_add(2);
-	break;
+	if(GOBBLE('=')) return F_RSH_EQ;
+	return F_RSH;
       }
-      t=!!isidchar(c);
-      init_buf();
-    }
-    my_putchar(c);
-  }
-  UNGETC(c);
-  add_define(s,argc,sp-args_sp,0);
-  while(sp>save_sp) pop_stack();
-}
+      return '>';
 
-/* s is a shared string */
-static int expand_define(struct pike_string *s, int save_newline)
-{
-  struct svalue *save_sp=sp;
-  struct define *d;
-  int len,e,tmp,args;
-  d=find_define(s);
-  if(!d) return 0;
+    case '!':
+      if(GOBBLE('=')) return F_NE;
+      return F_NOT;
 
-  if(nexpands>EXPANDMAX)
-  {
-    yyerror("Macro limit exceeded.");
-    return 0;
-  }
+    case '(':
+      if(GOBBLE('<')) return F_MULTISET_START;
+      return '(';
 
-  if(d->magic)
-  {
-    d->magic();
-    return 1;
-  }
+    case '?':
+    case ',':
+    case '~':
+    case '@':
+    case ')':
+    case '[':
+    case ']':
+    case '{':
+    case ';':
+    case '}': return c;
 
-  if(d->args >= 0)
-  {
-    if(!save_newline)
+    case '`':
     {
-      SKIPWHITE();
-    }else{
-      do { e=GETC(); }while(ISSPACE(e) && e!='\n');
-      UNGETC(e);
-    }
+      char *tmp;
+      int offset=2;
+      if(GOBBLE('`')) offset--;
+      if(GOBBLE('`')) offset--;
+      
+      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 '<':
+	if(GOBBLE('<')) { tmp="```<<"; break; }
+	if(GOBBLE('=')) { tmp="```<="; break; }
+	tmp="```<";
+	break;
 
-    if(GOBBLE('('))
-    {
-      int parlvl,quote;
-      int c;
-      args=0;
+      case '>':
+	if(GOBBLE('>')) { tmp="```>>"; break; }
+	if(GOBBLE('=')) { tmp="```>="; break; }
+	tmp="```>";
+	break;
 
-      SKIPWHITE();
-      init_buf();
-      parlvl=1;
-      quote=0;
-      while(parlvl)
-      {
-	switch(c=GETC())
+      case '!':
+	if(GOBBLE('=')) { tmp="```!="; break; }
+	tmp="```!";
+	break;
+
+      case '=':
+	if(GOBBLE('=')) { tmp="```=="; break; }
+	tmp="```=";
+	break;
+
+      case '(':
+	if(GOBBLE(')')) 
 	{
-	case MY_EOF:
-	  yyerror("Unexpected end of file.");
-	  while(sp>save_sp) pop_stack();
-	  return 0;
-	case '"': if(!(quote&2)) quote^=1; break;
-	case '\'': if(!(quote&1)) quote^=2; break;
-	case '(': if(!quote) parlvl++; break;
-	case ')': if(!quote) parlvl--; break;
-	case '\\': my_putchar(c); c=GETC(); break;
-	case ',':
-	  if(!quote && parlvl==1)
-	  {
-	    push_string(free_buf());
-	    init_buf();
-	    args++;
-	    continue;
-	  }
+	  tmp="```()";
+	  break;
 	}
-	if(parlvl) my_putchar(c);
-      }
-      push_string(free_buf());
-      if(args==0 && !d->args && !sp[-1].u.string->len)
-      {
-	pop_stack();
-      }else{
-	args++;
-      }
-    }else{
-      args=0;
-    }
-  } else {
-    args=-1;
-  }
-  
-  if(args>d->args)
-  {
-    my_yyerror("Too many arguments to macro '%s'.\n",s->str);
-    while(sp>save_sp) pop_stack();
-    return 0;
-  }
+	yyerror("Illegal ` identifier.");
+	tmp="``";
+	break;
+	
+      case '-':
+	if(GOBBLE('>'))
+	{
+	  tmp="```->";
+	  if(GOBBLE('=')) tmp="```->=";
+	}else{
+	  tmp="```-";
+	}
+	break;
 
-  if(args<d->args)
-  {
-    my_yyerror("Too few arguments to macro '%s'.\n",s->str);
-    while(sp>save_sp) pop_stack();
-    return 0;
-  }
-  len=0;
-  for(e=d->parts->size-1;e>=0;e--)
-  {
-    switch(ITEM(d->parts)[e].type)
-    {
-    case T_STRING:
-      tmp=ITEM(d->parts)[e].u.string->len;
-      UNGETSTR(ITEM(d->parts)[e].u.string->str,tmp);
-      break;
+      case '[':
+	if(GOBBLE(']'))
+	{
+	  tmp="```[]";
+	  if(GOBBLE('=')) tmp="```[]=";
+	  break;
+	}
 
-    case T_INT:
-      tmp=save_sp[ITEM(d->parts)[e].u.integer].u.string->len;
-      UNGETSTR(save_sp[ITEM(d->parts)[e].u.integer].u.string->str,tmp);
-      break;
+      default:
+	yyerror("Illegal ` identifier.");
+	lex.pos--;
+	tmp="``";
+	break;
+      }
 
-    default: tmp=0;
+      yylval->string=make_shared_string(tmp+offset);
+      return F_IDENTIFIER;
     }
-    len+=tmp;
-  }
-  while(sp>save_sp) pop_stack();
-  nexpands+=len;
-  return 1;
-}
 
-/*** Handle include ****/
-
-static void handle_include(char *name, int local_include)
-{
-  int fd;
-  char buf[400];
-  struct pike_string *s;
-
-  s=make_shared_string(name);
-  push_string(s);
-  reference_shared_string(s);
-  push_string(current_file);
-  reference_shared_string(current_file);
-  push_int(local_include);
-  
-  SAFE_APPLY_MASTER("handle_include",3);
   
-  if(sp[-1].type != T_STRING)
-  {
-    my_yyerror("Couldn't include file '%s'.",s->str);
-    return;
-  }
-  free_string(s);
-  
- retry:
-  fd=open(sp[-1].u.string->str,O_RDONLY);
-  if(fd < 0)
-  {
-    if(errno == EINTR) goto retry;
-
-#ifdef HAVE_STRERROR    
-    my_yyerror("Couldn't open file to include '%s'. (%s)",sp[-1].u.string->str,strerror(errno));
-#else
-    my_yyerror("Couldn't open file to include '%s'. (ERRNO=%d)",sp[-1].u.string->str,errno);
-#endif
-    return;
-  }
+    default:
+      if(isidchar(c))
+      {
+	struct pike_string *s;
+	lex.pos--;
+	READBUF(isidchar(C));
 
-  UNGETSTR("\" 2",3);
-  UNGETSTR(current_file->str,current_file->len);
-  sprintf(buf,"\n# %ld \"",(long)current_line+1);
-  UNGETSTR(buf,strlen(buf));
+	yylval->number=lex.current_line;
 
-  total_lines+=current_line-old_line;
-  old_line=current_line=1;
-  free_string(current_file);
-  current_file=sp[-1].u.string;
-  sp--;
-  link_inputstate(file_inputstate(fd));
-  UNGETSTR("\n",1);
-}
-
-/*** Lexical analyzing ***/
-
-static int char_const(void)
-{
-  int c;
-  switch(c=GETC())
-  {
-    case 'x':
-      switch(LOOK())
-      {
-	default: return c;
-	case '0': case '1': case '2': case '3':
-	case '4': case '5': case '6': case '7':
-	case '8': case '9':
-	  c=GETC()-'0';
+	if(len>1 && len<10)
+	{
+	  switch(TWO_CHAR(buf[0],buf[1]))
+	  {
+	  case TWO_CHAR('a','r'):
+	    if(ISWORD("array")) return F_ARRAY_ID;
 	  break;
-	  
-	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-	  c=GETC()-'a'+10;
+	  case TWO_CHAR('b','r'):
+	    if(ISWORD("break")) return F_BREAK;
 	  break;
-
-	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-	  c=GETC()-'A'+10;
+	  case TWO_CHAR('c','a'):
+	    if(ISWORD("case")) return F_CASE;
+	    if(ISWORD("catch")) return F_CATCH;
 	  break;
-      }
-      switch(LOOK())
-      {
-	default: return c;
-	case '0': case '1': case '2': case '3':
-	case '4': case '5': case '6': case '7':
-	case '8': case '9':
-	  c=c*16+GETC()-'0';
+	  case TWO_CHAR('c','l'):
+	    if(ISWORD("class")) return F_CLASS;
 	  break;
-	  
-	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-	  c=c*16+GETC()-'a'+10;
+	  case TWO_CHAR('c','o'):
+	    if(ISWORD("constant")) return F_CONSTANT;
+	    if(ISWORD("continue")) return F_CONTINUE;
 	  break;
-
-	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-	  c=c*16+GETC()-'a'+10;
+	  case TWO_CHAR('d','e'):
+	    if(ISWORD("default")) return F_DEFAULT;
 	  break;
-      }
-      return c;
-      
-    case '0': case '1': case '2': case '3':
-    case '4': case '5': case '6': case '7':
-      c-='0';
-      if(LOOK()<'0' || LOOK()>'8') return c;
-      c=c*8+(GETC()-'0');
-      if(LOOK()<'0' || LOOK()>'8') return c;
-      c=c*8+(GETC()-'0');
-      return c;
-      
-    case 'r': return '\r';
-    case 'n': return '\n';
-    case 't': return '\t';
-    case 'b': return '\b';
-  }
-  return c;
-}
-
-#define SKIPTO_ENDIF 1
-#define SKIPTO_ELSE 2
-
-static void do_skip(int to)
-{
-  int lvl;
-#if LEXDEBUG>3
-  fprintf(stderr,"Skipping from %ld to ",(long)current_line);
-#endif
-  lvl=1;
-  while(lvl)
-  {
-    switch(GETC())
-    {
-    case '/':
-      if(GOBBLE('*'))
-      {
-	do{
-	  SKIPTO('*');
-	  if(LOOK()==MY_EOF)
-	  {
-	    yyerror("Unexpected end of file while skipping comment.");
-	    return;
-	  }
-	}while(!GOBBLE('/'));
-      }
-      continue;
-
-    case MY_EOF:
-      yyerror("Unexpected end of file while skipping.");
-      return;
-
-    case '\\':
-      GETC();
-      continue;
-	
-    case '\n':
-      if(GOBBLE('#'))
-      {
-	SKIPWHITE();
-	READBUF(C!=' ' && C!='\t' && C!='\n');
-    
-	switch(buf[0])
-	{
-	case 'l':
-	  if(strcmp("line",buf)) break;
-	  READBUF(C!=' ' && C!='\t' && C!='\n');
-
-	case '0': case '1': case '2': case '3': case '4':
-	case '5': case '6': case '7': case '8': case '9':
-	  SKIPWHITE();
-	  READBUF(C!='\n');
-	  if(buf[0]=='"' &&
-	     buf[strlen(buf)-1]=='2' &&
-	     ISSPACE(buf[strlen(buf)-2]))
-	  {
-	    if(lvl)
-	    {
-	      yyerror("Unterminated '#if' conditional.");
-	      num_parse_error+=1000;
-	    }
-	  }
-	  continue;
-
-	case 'i':
-	  if(!strcmp("include",buf)) continue;
-	  if(!strcmp("if",buf) || !strcmp("ifdef",buf) || !strcmp("ifndef",buf))
-	  {
-	    lvl++;
-	    continue;
-	  }
+	  case TWO_CHAR('d','o'):
+	    if(ISWORD("do")) return F_DO;
 	  break;
-
-	case 'e':
-	  if(!strcmp("endif",buf))
-	  { 
-	    lvl--;
-	    if(lvl<0)
-	    {
-	      yyerror("Unbalanced '#endif'\n");
-	      lvl=0;
-	    }
-	    continue;
-	  }
-	  if(!strcmp("else",buf))
-	  {
-	    if(lvl==1 && to==SKIPTO_ELSE) lvl=0;
-	    continue;
-	  }
-	  if(!strcmp("elif",buf) || !strcmp("elseif",buf))
-	  {
-	    if(lvl==1 && to==SKIPTO_ELSE && calc()) lvl--;
-	    continue;
-	  }
-	  if(!strcmp("error",buf)) continue;
+	  case TWO_CHAR('e','l'):
+	    if(ISWORD("else")) return F_ELSE;
 	  break;
-
-	case 'd':
-	  if(!strcmp("define",buf)) continue;
+	  case TWO_CHAR('f','l'):
+	    if(ISWORD("float")) return F_FLOAT_ID;
 	  break;
-
-	case 'u':
-	  if(!strcmp("undef",buf)) continue;
+	  case TWO_CHAR('f','o'):
+	    if(ISWORD("for")) return F_FOR;
+	    if(ISWORD("foreach")) return F_FOREACH;
 	  break;
-
-	case 'p':
-	  if(!strcmp("pragma",buf)) continue;
+	  case TWO_CHAR('f','u'):
+	    if(ISWORD("function")) return F_FUNCTION_ID;
 	  break;
-	}
-    
-	my_yyerror("Unknown directive #%s.",buf);
-	SKIPUPTO('\n');
-	continue;
-      }
-    }
-  }
-#if LEXDEBUG>3
-  fprintf(stderr,"%ld in %s.\n",(long)current_line,current_file->str);
-#endif
-}
-
-static int do_lex(int literal, YYSTYPE *yylval)
-#if LEXDEBUG>4
-{
-  int t;
-  int do_lex2(int literal, YYSTYPE *yylval);
-  t=do_lex2(literal, yylval);
-  if(t<256)
-  {
-    fprintf(stderr,"do_lex(%d) -> '%c' (%d)\n",literal,t,t);
-  }else{
-    fprintf(stderr,"do_lex(%d) -> %s (%d)\n",literal,get_f_name(t),t);
-  }
-  return t;
-}
-
-static int do_lex2(int literal, YYSTYPE *yylval)
-#endif
-{
-  int c;
-#ifdef MALLOC_DEBUG
-  check_sfltable();
-#endif
-  while(1)
-  {
-    switch(c=GETC())
-    {
-    case '\n':
-      if(literal)
-      {
-	UNGETC('\n');
-	return '\n';
-      }
-      if(GOBBLE('#'))
-      {
-	if(GOBBLE('!'))
-	{
-	  SKIPUPTO('\n');
-	  continue;
-	}
-            
-	SKIPWHITE();
-	READBUF(C!=' ' && C!='\t' && C!='\n');
-
-	switch(buf[0])
-	{
-	  char *p;
-
-	case 'l':
-	  if(strcmp("line",buf)) goto badhash;
-	  READBUF(C!=' ' && C!='\t' && C!='\n');
-
-	case '0': case '1': case '2': case '3': case '4':
-	case '5': case '6': case '7': case '8': case '9':
-	  total_lines+=current_line-old_line;
-	  old_line=current_line=atoi(buf)-1;
-	  SKIPWHITE();
-	  READBUF(C!='\n');
-
-	  p=buf;
-	  if(*p=='"' && STRCHR(p+1,'"'))
-	  {
-	    char *p2;
-	    p++;
-	    if((p2=STRCHR(p+1,'"')))
-	    {
-	      *p2=0;
-	      free_string(current_file);
-	      current_file=make_shared_string(p);
-	    }
-	  }
+	  case TWO_CHAR('g','a'):
+	    if(ISWORD("gauge")) return F_GAUGE;
 	  break;
-
-	case 'i':
-	  if(!strcmp("include",buf))
-	  {
-	    SKIPWHITE();
-	    c=do_lex(1, yylval);
-	    if(c=='<')
-	    {
-	      READBUF(C!='>' && C!='\n');
-	      if(!GOBBLE('>'))
-	      {
-		yyerror("Missing `>`");
-		SKIPUPTO('\n');
-		continue;
-	      }
-	    }else{
-	      if(c!=F_STRING)
-	      {
-		yyerror("Couldn't find include filename.\n");
-		SKIPUPTO('\n');
-		continue;
-	      }
-	    }
-	    handle_include(buf, c==F_STRING);
-	    break;
-	  }
-
-	  if(!strcmp("if",buf))
-	  {
-	    if(!calc()) do_skip(SKIPTO_ELSE);
-	    break;
-	  }
-
-	  if(!strcmp("ifdef",buf))
-	  {
-	    struct pike_string *s;
-	    SKIPWHITE();
-	    READBUF(isidchar(C));
-	    s=findstring(buf);
-	    if(!s || !find_define(s)) do_skip(SKIPTO_ELSE);
-	    break;
-	  }
-
-	  if(!strcmp("ifndef",buf))
-	  {
-	    struct pike_string *s;
-	    SKIPWHITE();
-	    READBUF(isidchar(C));
-	    s=findstring(buf);
-	    if(s && find_define(s)) do_skip(SKIPTO_ELSE);
-	    break;
-	  }
-	  goto badhash;
-
-	case 'e':
-	  if(!strcmp("endif",buf)) break;
-	  if(!strcmp("else",buf))
-	  {
-	    SKIPUPTO('\n');
-	    do_skip(SKIPTO_ENDIF);
-	    break;
-	  }
-	  if(!strcmp("elif",buf) || !strcmp("elseif",buf))
-	  {
-	    SKIPUPTO('\n');
-	    do_skip(SKIPTO_ENDIF);
-	    break;
-	  }
-	  if(!strcmp("error",buf))
-	  {
-	    SKIPWHITE();
-	    READBUF(C!='\n');
-	    yyerror(buf);
-	    break;
-	  }
-	  goto badhash;
-
-	case 'u':
-	  if(!strcmp("undef",buf))
-	  {
-	    struct pike_string *s;
-	    SKIPWHITE();
-	    READBUF(isidchar(C));
-	    if((s=findstring(buf))) undefine(s);
-	    break;
-	  }
-	  goto badhash;
-
-	case 'd':
-	  if(!strcmp("define",buf))
-	  {
-	    do_define();
-	    break;
-	  }
-	  goto badhash;
-
-	case 'p':
-	  if(!strcmp("pragma",buf))
-	  {
-	    SKIPWHITE();
-	    READBUF(C!='\n');
-	    if (strcmp(buf, "all_inline") == 0)
-	    {
-	      pragma_all_inline = 1;
-	    }
+	  case TWO_CHAR('i','f'):
+	    if(ISWORD("if")) return F_IF;
+	  break;
+	  case TWO_CHAR('i','m'):
+	    if(ISWORD("import")) return F_IMPORT;
+	  break;
+	  case TWO_CHAR('i','n'):
+	    if(ISWORD("int")) return F_INT_ID;
+	    if(ISWORD("inherit")) return F_INHERIT;
+	    if(ISWORD("inline")) return F_INLINE;
+	  break;
+	  case TWO_CHAR('l','a'):
+	    if(ISWORD("lambda")) return F_LAMBDA;
+	  break;
+	  case TWO_CHAR('m','a'):
+	    if(ISWORD("mapping")) return F_MAPPING_ID;
+	  break;
+	  case TWO_CHAR('m','i'):
+	    if(ISWORD("mixed")) return F_MIXED_ID;
+	  break;
+	  case TWO_CHAR('m','u'):
+	    if(ISWORD("multiset")) return F_MULTISET_ID;
+	  break;
+	  case TWO_CHAR('n','o'):
+	    if(ISWORD("nomask")) return F_NO_MASK;
+	  break;
+	  case TWO_CHAR('o','b'):
+	    if(ISWORD("object")) return F_OBJECT_ID;
+	  break;
+	  case TWO_CHAR('p','r'):
+	    if(ISWORD("predef")) return F_PREDEF;
+	    if(ISWORD("program")) return F_PROGRAM_ID;
+	    if(ISWORD("private")) return F_PRIVATE;
+	    if(ISWORD("protected")) return F_PROTECTED;
 	    break;
-	  }
-
-	badhash:
-	  my_yyerror("Unknown directive #%s.",buf);
-	  SKIPUPTO('\n');
-	  continue;
-	  
-	}
-      }
-      continue;
-
-    case ' ':
-    case '\t':
-      continue;
-
-    case MY_EOF:
-      return 0;
-  
-    case '\'':
-      c=GETC();
-      if(c=='\\') c=char_const();
-      if(GETC()!='\'')
-	yyerror("Unterminated character constant.");
-      yylval->number=c;
-      return F_NUMBER;
-	
-    case '"':
-      init_buf();
-      while(1)
-      {
-	c=GETC();
-
-	switch(c)
-	{
-	case MY_EOF:
-	  yyerror("End of file in string.");
-	  free(simple_free_buf());
-	  return 0;
-
-	case '\n':
-	  yyerror("Newline in string.");
-	  free(simple_free_buf());
-	  return 0;
-
-	case '\\':
-	  my_putchar(char_const());
-	  continue;
-	  
-	case '"':
 	  break;
-
-	default:
-	  my_putchar(c);
-	  continue;
+	  case TWO_CHAR('p','u'):
+	    if(ISWORD("public")) return F_PUBLIC;
+	  break;
+	  case TWO_CHAR('r','e'):
+	    if(ISWORD("return")) return F_RETURN;
+	  break;
+	  case TWO_CHAR('s','s'):
+	    if(ISWORD("sscanf")) return F_SSCANF;
+	  break;
+	  case TWO_CHAR('s','t'):
+	    if(ISWORD("static")) return F_STATIC;
+	    if(ISWORD("string")) return F_STRING_ID;
+	  break;
+	  case TWO_CHAR('s','w'):
+	    if(ISWORD("switch")) return F_SWITCH;
+	  break;
+	  case TWO_CHAR('t','y'):
+	    if(ISWORD("typeof")) return F_TYPEOF;
+	  break;
+	  case TWO_CHAR('v','a'):
+	    if(ISWORD("varargs")) return F_VARARGS;
+	  break;
+	  case TWO_CHAR('v','o'):
+	    if(ISWORD("void")) return F_VOID_ID;
+	  break;
+	  case TWO_CHAR('w','h'):
+	    if(ISWORD("while")) return F_WHILE;
+	  break;
+	  }
 	}
-	break;
-      }
-      if(literal)
-      {
-	strncpy(buf,return_buf(),sizeof(buf));
-	buf[sizeof(buf)-1]=0;
-	yylval->str=buf;
+	yylval->string=make_shared_binary_string(buf,len);
+	return F_IDENTIFIER;
       }else{
-	yylval->string=free_buf();
+	char buff[100];
+	sprintf(buff, "Illegal character (hex %02x) '%c'", c, c);
+	yyerror(buff);
+	return ' ';
       }
-      return F_STRING;
-  
-    case ':':
-      if(GOBBLE(':')) return F_COLON_COLON;
-      return c;
+    }
+    }
+  }
+}
 
-    case '.':
-      if(GOBBLE('.'))
-      {
-	if(GOBBLE('.')) return F_DOT_DOT_DOT;
-	return F_DOT_DOT;
-      }
-      return c;
-  
-    case '0':
-      if(GOBBLE('x'))
-      {
-	READBUF(isxdigit(C));
-	yylval->number=STRTOL(buf,NULL,16);
-	return F_NUMBER;
-      }
-  
-    case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-    {
-      char *p, *p2;
-      int isfloat=0;
-      double d;
-
-      UNGETC(c);
-      READBUF(isdigit(C) || C=='.');
-
-      p=STRCHR(buf,'.');
-      
-      if(p)
-      {
-	if(p[1]=='.')
-	{
-	  UNGETSTR(p,strlen(p));
-	  *p=0;
-	  p=NULL;
-	}else if((p=STRCHR(p+1,'.')))
-	{
-	  UNGETSTR(p,strlen(p));
-	  *p=0;
-	}
-
-	if((p=STRCHR(buf,'.')))
-	{
-	  isfloat=1;
-	}
-      }
-
-      d=STRTOD(buf, NULL);
-
-      if(GOBBLE('e') || GOBBLE('E'))
-      {
-	int neg;
-	if(GOBBLE('-'))
-	  neg=1;
-	else if(GOBBLE('+'))
-	  neg=0;
-	else
-	  neg=0;
-	
-	READBUF(isdigit(C));
-        if(neg)
-	  d /= pow(10.0,STRTOD(buf,NULL));
-        else
-	  d *= pow(10.0,STRTOD(buf,NULL));
-	isfloat=1;
-      }
-      if(isfloat)
-      {
-	yylval->fnum=(float)d;
-	return F_FLOAT;
-      }
-
-      if(buf[0]=='0')
-	yylval->number=STRTOL(buf,NULL,8);
-      else
-	yylval->number=STRTOL(buf,NULL,10);
-      return F_NUMBER;
-    }
-  
-    case '-':
-      if(GOBBLE('=')) return F_SUB_EQ;
-      if(GOBBLE('>')) return F_ARROW;
-      if(GOBBLE('-')) return F_DEC;
-      return '-';
-  
-    case '+':
-      if(GOBBLE('=')) return F_ADD_EQ;
-      if(GOBBLE('+')) return F_INC;
-      return '+';
-  
-    case '&':
-      if(GOBBLE('=')) return F_AND_EQ;
-      if(GOBBLE('&')) return F_LAND;
-      return '&';
-  
-    case '|':
-      if(GOBBLE('=')) return F_OR_EQ;
-      if(GOBBLE('|')) return F_LOR;
-      return '|';
-
-    case '^':
-      if(GOBBLE('=')) return F_XOR_EQ;
-      return '^';
-  
-    case '*':
-      if(GOBBLE('=')) return F_MULT_EQ;
-      return '*';
-
-    case '%':
-      if(GOBBLE('=')) return F_MOD_EQ;
-      return '%';
-  
-    case '/':
-      if(GOBBLE('*'))
-      {
-	do{
-	  SKIPTO('*');
-	  if(LOOK()==MY_EOF)
-	  {
-	    yyerror("Unexpected end of file while skipping comment.");
-	    return 0;
-	  }
-	} while(!GOBBLE('/'));
-	continue;
-      }else if(GOBBLE('/'))
-      {
-	SKIPUPTO('\n');
-	continue;
-      }
-       /* Fallthrough */
-      if(GOBBLE('=')) return F_DIV_EQ;
-      return '/';
-  
-    case '=':
-      if(GOBBLE('=')) return F_EQ;
-      return '=';
-  
-    case '<':
-      if(GOBBLE('<'))
-      {
-	if(GOBBLE('=')) return F_LSH_EQ;
-	return F_LSH;
-      }
-      if(GOBBLE('=')) return F_LE;
-      return '<';
-  
-    case '>':
-      if(GOBBLE(')')) return F_MULTISET_END;
-      if(GOBBLE('=')) return F_GE;
-      if(GOBBLE('>'))
-      {
-	if(GOBBLE('=')) return F_RSH_EQ;
-	return F_RSH;
-      }
-      return '>';
-
-    case '!':
-      if(GOBBLE('=')) return F_NE;
-      return F_NOT;
-
-    case '(':
-      if(GOBBLE('<')) return F_MULTISET_START;
-      return '(';
-
-    case '?':
-    case ',':
-    case '~':
-    case '@':
-    case ')':
-    case '[':
-    case ']':
-    case '{':
-    case ';':
-    case '}': return c;
-
-    case '`':
-    {
-      char *tmp;
-      int offset=2;
-      if(GOBBLE('`')) offset--;
-      if(GOBBLE('`')) offset--;
-      
-      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 '<':
-	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;
-
-      case '(':
-	if(GOBBLE(')')) 
-	{
-	  tmp="```()";
-	  break;
-	}
-	yyerror("Illegal ` identifier.");
-	tmp="``";
-	break;
-	
-      case '-':
-	if(GOBBLE('>'))
-	{
-	  tmp="```->";
-	  if(GOBBLE('=')) tmp="```->=";
-	}else{
-	  tmp="```-";
-	}
-	break;
-
-      case '[':
-	if(GOBBLE(']'))
-	{
-	  tmp="```[]";
-	  if(GOBBLE('=')) tmp="```[]=";
-	  break;
-	}
-
-      default:
-	yyerror("Illegal ` identifier.");
-	tmp="``";
-	break;
-
-      }
-
-      if(literal)
-      {
-	yylval->str=tmp+offset;
-      }else{
-	yylval->string=make_shared_string(tmp+offset);
-      }
-      return F_IDENTIFIER;
-    }
-
-  
-    default:
-      if(isidchar(c))
-      {
-	struct pike_string *s;
-	UNGETC(c);
-	READBUF(isidchar(C));
-
-	if(!literal)
-	{
-	  /* identify identifier, if it is not a shared string,
-	   * then it is neither a define, reserved word, local variable
-	   * or efun, at least not yet.
-	   */
-
-	  s=findstring(buf);
-	  if(s)
-	  {
-	    int i;
-	    if(expand_define(s,0)) continue;
-
-	    i=lookup_resword(s);
-	    if(i >= 0)
-	    {
-	      yylval->number=current_line;
-	      return i;
-	    }
-
-	    reference_shared_string(s);
-	  }else{
-	    s=make_shared_string(buf);
-	  }
-	  yylval->string=s;
-	  return F_IDENTIFIER;
-	}
-  
-	yylval->str=buf;
-	return F_IDENTIFIER;
-      }else{
-	char buff[100];
-	sprintf(buff, "Illegal character (hex %02x) '%c'", c, c);
-	yyerror(buff);
-	return ' ';
-      }
-    }
-  }
-}
-
-int yylex(YYSTYPE *yylval)
-{
-#ifdef __CHECKER__
-  MEMSET((char *)yylval,0,sizeof(YYSTYPE));
-#endif
-  return do_lex(0, yylval);
-}
-
-static YYSTYPE my_yylval;
-static int lookahead;
-
-static void low_lex(void)
-{
-  while(1)
-  {
-    struct pike_string *s;
-
-    lookahead=do_lex(1, &my_yylval);
-    if(lookahead == F_IDENTIFIER)
-    {
-      if(!strcmp("defined",my_yylval.str))
-      {
-	SKIPWHITE();
-	if(!GOBBLE('('))
-	{
-	  yyerror("Missing '(' in defined.\n");
-	  return;
-	}
-	READBUF(isidchar(C));
-	if(!GOBBLE(')'))
-	{
-	  yyerror("Missing ')' in defined.\n");
-	  return;
-	}
-	s=findstring(buf);
-
-	if(s && find_define(s))
-	  UNGETSTR(" 1 ",3);
-	else
-	  UNGETSTR(" 0 ",3);
-
-	continue;
-      }
-
-      if(!strcmp("efun",my_yylval.str) || !strcmp("constant",my_yylval.str))
-      {
-	int res = 0;
-	struct svalue *oldsp = sp;
-	struct svalue *sv;
-
-	SKIPWHITE();
-	if (!GOBBLE('(')) {
-	  yyerror("Missing '(' in #if constant().\n");
-	  return;
-	}
-	READBUF(isidchar(C));
-
-	push_text(buf);
-	if ((sv = low_mapping_string_lookup(get_builtin_constants(),
-					    sp[-1].u.string))) {
-	  pop_stack();
-	  push_svalue(sv);
-	  res = 1;
-	} else if (get_master()) {
-	  current_file->refs++;
-	  push_string(current_file);
-
-	  SAFE_APPLY_MASTER("resolv", 2);
-
-	  if ((throw_value.type != T_STRING) &&
-	      (!(IS_ZERO(sp-1) && sp[-1].subtype == 1))) {
-	    res = 1;
-	  }
-	}
-
-	while(GOBBLE('.')) {
-	  READBUF(isidchar(C));
-	  if (res) {
-	    JMP_BUF recovery;
-
-	    push_text(buf);
-
-	    free_svalue(&throw_value);
-	    throw_value.type = T_INT;
-
-	    if (SETJMP(recovery)) {
-	      res = 0;
-	    } else {
-	      f_index(2);
-	      if (IS_ZERO(sp-1) && sp[-1].subtype == 1) {
-		res = 0;
-	      }
-	    }
-	    UNSETJMP(recovery);
-	  }
-	}
-	
-	if (!GOBBLE(')')) {
-	  yyerror("Missing ')' in #if constant().\n");
-	  return;
-	}
-
-	if (sp > oldsp) {
-	  pop_n_elems(sp - oldsp);
-	}
-
-	if (res) {
-	  UNGETSTR(" 1 ", 3);
-	} else {
-	  UNGETSTR(" 0 ", 3);
-	}
-	continue;
-      }
-
-      s=findstring(my_yylval.str);
-      if(!s || !expand_define(s,1))
-	UNGETSTR(" 0 ",3);
-      continue;
-    }
-
-    break;
-  }
-}
-
-static void calcC(void)
-{
-  switch(lookahead)
-  {
-    case '(':
-      low_lex();
-      calc1();
-      if(lookahead != ')')
-	error("Missing ')'\n");
-      break;
-
-    case F_FLOAT:
-      push_float(my_yylval.fnum);
-      break;
-
-    case F_STRING:
-      push_string(make_shared_string(my_yylval.str));
-      break;
-
-    case F_NUMBER:
-      push_int(my_yylval.number);
-      break;
-
-    default:
-      push_int(0);
-      yyerror("Syntax error in #if.");
-      return;
-  }
-
-  low_lex();
-
-  while(lookahead=='[')
-  {
-    low_lex();
-    calc1();
-    f_index(2);
-    if(lookahead!=']')
-      error("Missing ']'\n");
-    else
-      low_lex();
-  }
-}
-
-static void calcB(void)
-{
-  switch(lookahead)
-  {
-    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();
-  }
-}
-
-static void calcA(void)
-{
-  calcB();
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case '/': low_lex(); calcB(); o_divide(); continue;
-      case '*': low_lex(); calcB(); o_multiply(); continue;
-      case '%': low_lex(); calcB(); o_mod(); continue;
-    }
-    break;
-  }
-}
-
-static void calc9(void)
-{
-  calcA();
-
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case '+': low_lex(); calcA(); f_add(2); continue;
-      case '-': low_lex(); calcA(); o_subtract(); continue;
-    }
-    break;
-  }
-}
-
-static void calc8(void)
-{
-  calc9();
-
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case F_LSH: low_lex(); calc9(); o_lsh(); continue;
-      case F_RSH: low_lex(); calc9(); o_rsh(); continue;
-    }
-    break;
-  }
-}
-
-static void calc7b(void)
-{
-  calc8();
-
-  while(1)
-  {
-    switch(lookahead)
-    {
-      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;
-  }
-}
-
-static void calc7(void)
-{
-  calc7b();
-
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case F_EQ: low_lex(); calc7b(); f_eq(2); continue;
-      case F_NE: low_lex(); calc7b(); f_ne(2); continue;
-    }
-    break;
-  }
-}
-
-static void calc6(void)
-{
-  calc7();
-
-  while(lookahead=='&')
-  {
-    low_lex();
-    calc7();
-    o_and();
-  }
-}
-
-static void calc5(void)
-{
-  calc6();
-
-  while(lookahead=='^')
-  {
-    low_lex();
-    calc6();
-    o_xor();
-  }
-}
-
-static void calc4(void)
-{
-  calc5();
-
-  while(lookahead=='|')
-  {
-    low_lex();
-    calc5();
-    o_or();
-  }
-}
-
-static void calc3(void)
-{
-  calc4();
-
-  while(lookahead==F_LAND)
-  {
-    low_lex();
-    check_destructed(sp-1);
-    if(IS_ZERO(sp-1))
-    {
-      calc4();
-      pop_stack();
-    }else{
-      pop_stack();
-      calc4();
-    }
-  }
-}
-
-static void calc2(void)
-{
-  calc3();
-
-  while(lookahead==F_LOR)
-  {
-    low_lex();
-    check_destructed(sp-1);
-    if(!IS_ZERO(sp-1))
-    {
-      calc3();
-      pop_stack();
-    }else{
-      pop_stack();
-      calc3();
-    }
-  }
-}
-
-static void calc1(void)
-{
-  calc2();
-
-  if(lookahead=='?')
-  {
-    low_lex();
-    calc1();
-    if(lookahead!=':')
-      error("Colon expected.\n");
-    low_lex();
-    calc1();
-
-    check_destructed(sp-3);
-    assign_svalue(sp-3,IS_ZERO(sp-3)?sp-1:sp-2);
-    pop_n_elems(2);
-  }
-
-}
-
-static int calc(void)
-{
-  JMP_BUF recovery;
-  int ret;
-
-  ret=0;
-  if (SETJMP(recovery))
-  {
-    if(throw_value.type == T_ARRAY && throw_value.u.array->size)
-    {
-      union anything *a;
-      a=low_array_get_item_ptr(throw_value.u.array, 0, T_STRING);
-      if(a)
-      {
-	yyerror(a->string->str);
-      }else{
-	yyerror("Nonstandard error format.\n");
-      }
-    }else{
-      yyerror("Nonstandard error format.\n");
-    }
-    ret=-1;
-  }else{
-    low_lex();
-    calc1();
-    if(lookahead!='\n')
-    {
-      SKIPUPTO('\n');
-      yyerror("Extra characters after #if expression.");
-    }else{
-      UNGETC('\n');
-    }
-    check_destructed(sp-1);
-    ret=!IS_ZERO(sp-1);
-    pop_stack();
-  }
-  UNSETJMP(recovery);
-
-  return ret;
-}
-
-/*** Magic defines ***/
-static void insert_current_line(void)
-{
-  char buf[20];
-  sprintf(buf," %ld ",(long)current_line);
-  UNGETSTR(buf,strlen(buf));
-}
-
-static void insert_current_file_as_string(void)
-{
-  UNGETSTR("\"",1);
-  UNGETSTR(current_file->str, current_file->len);
-  UNGETSTR("\"",1);
-}
-
-static void insert_current_time_as_string(void)
-{
-  time_t tmp;
-  char *buf;
-  time(&tmp);
-  buf=ctime(&tmp);
-
-  UNGETSTR("\"",1);
-  UNGETSTR(buf+11, 8);
-  UNGETSTR("\"",1);
-}
-
-static void insert_current_date_as_string(void)
-{
-  time_t tmp;
-  char *buf;
-  time(&tmp);
-  buf=ctime(&tmp);
-
-  UNGETSTR("\"",1);
-  UNGETSTR(buf+19, 5);
-  UNGETSTR(buf+4, 6);
-  UNGETSTR("\"",1);
-}
-
-/*** ***/
-
-static void start_new(void)
-{
-  struct pike_predef_s *tmpf;
-
-  free_all_defines();
-
-  simple_add_define("__PIKE__", "1",0);
-  
-  for (tmpf=pike_predefs; tmpf; tmpf=tmpf->next)
-    simple_add_define(tmpf->name, tmpf->value,0);
-
-  simple_add_define("__LINE__",0,insert_current_line);
-  simple_add_define("__FILE__",0,insert_current_file_as_string);
-  simple_add_define("__DATE__",0,insert_current_date_as_string);
-  simple_add_define("__TIME__",0,insert_current_time_as_string);
-
-  free_inputstate(istate);
-  istate=NULL;
-  link_inputstate(end_inputstate());
-  old_line=current_line = 1;
-  pragma_all_inline=0;
-  nexpands=0;
-  if(current_file) free_string(current_file);
-  current_file=0;
-}
-
-void start_new_file(int fd,struct pike_string *filename)
-{
-  start_new();
-  copy_shared_string(current_file,filename);
-  
-  link_inputstate(file_inputstate(fd));
-  UNGETSTR("\n",1);
-}
-
-void start_new_string(char *s,INT32 len,struct pike_string *name)
-{
-  start_new();
-  copy_shared_string(current_file,name);
-  link_inputstate(prot_memory_inputstate(s,len));
-  UNGETSTR("\n",1);
-}
-
-void end_new_file(void)
-{
-  if(current_file)
-  {
-    free_string(current_file);
-    current_file=0;
-  }
-
-  free_inputstate(istate);
-  istate=NULL;
-  free_all_defines();
-  total_lines+=current_line-old_line;
-}
-
-
-#if 0
-void add_predefine(char *s)
-{
-  char buffer1[100],buffer2[10000];
-  struct pike_predef_s *tmp;
-
-  if(sscanf(s,"%[^=]=%[ -~=]",buffer1,buffer2) ==2)
-  {
-    s=buffer1;
-  }else{
-    buffer2[0]='1';
-    buffer2[1]=0;
-  }
-  tmp=ALLOC_STRUCT(pike_predef_s);
-  tmp->name=(char *)xalloc(strlen(s)+1);
-  strcpy(tmp->name,s);
-  tmp->value=(char *)xalloc(strlen(buffer2)+1);
-  strcpy(tmp->value,buffer2);
-  tmp->next=pike_predefs;
-  pike_predefs=tmp;
-}
-#endif
diff --git a/src/lex.h b/src/lex.h
index f26e42c47037e4cde9a3c706e44144fb2e07e099..df6a17815016ce0d110b09b3df3ae9762c3029ac 100644
--- a/src/lex.h
+++ b/src/lex.h
@@ -44,44 +44,32 @@ struct instr
 struct hash_entry;
 #endif
 
-#ifndef STRUCT_INPUTSTATE_DECLARED
-#define STRUCT_INPUTSTATE_DECLARED
-struct inputstate;
-#endif
-
 #ifndef STRUCT_HASH_TABLE_DECLARED
 #define STRUCT_HASH_TABLE_DECLARED
 struct hash_table;
 #endif
 
-extern struct instr instrs[];
-extern struct hash_table *defines;
-extern struct pike_string *current_file;
-extern INT32 current_line;
-extern INT32 old_line;
-extern INT32 total_lines;
-extern INT32 nexpands;
-extern int pragma_all_inline;          /* inline all possible inlines */
-extern struct inputstate *istate;
+#define PRAGMA_ALL_INLINE 1
 
-extern struct pike_predef_s * pike_predefs;
+struct lex
+{
+  char *pos;
+  char *end;
+  INT32 current_line;
+  INT32 pragmas;
+  struct pike_string *current_file;
+};
+
+extern struct lex lex;
+extern struct instr instrs[];
 
 /* Prototypes begin here */
-struct pike_predef_s;
 void exit_lex(void);
 struct reserved;
-void init_lex(void);
-void free_reswords(void);
+void init_lex();
 char *low_get_f_name(int n,struct program *p);
 char *get_f_name(int n);
 char *get_token_name(int n);
-struct inputstate;
-struct define;
-void free_one_define(struct hash_entry *h);
-void start_new_file(int fd,struct pike_string *filename);
-void start_new_string(char *s,INT32 len,struct pike_string *name);
-void end_new_file(void);
-void add_predefine(char *s);
 /* Prototypes end here */
 
 #endif
diff --git a/src/main.c b/src/main.c
index 079bd693db4fe2800b5ae1b7c6185d12e71d06d8..221df21c688b974cb5f8aee3c88b411c4607f1b3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: main.c,v 1.31 1998/01/10 21:19:09 hubbe Exp $");
+RCSID("$Id: main.c,v 1.32 1998/01/13 22:56:45 hubbe Exp $");
 #include "fdlib.h"
 #include "backend.h"
 #include "module.h"
@@ -93,6 +93,28 @@ void main(int argc, char **argv)
   master_file = 0;
 #ifdef HAVE_GETENV
   master_file = getenv("PIKE_MASTER");
+#endif
+#if __NT__
+  {
+    char buffer[4096];
+    DWORD len=sizeof(buffer)-1,type=REG_SZ;
+    
+    if(RegQueryValueEx(HKEY_CURRENT_USER,
+		       "SOFTWARE\\Idonex\\Pike\\0.6\\PIKE_MASTER",
+		       0,
+		       &type,
+		       buffer,
+		       &len)==ERROR_SUCCESS ||
+       RegQueryValueEx(HKEY_CURRENT_USER,
+		       "SOFTWARE\\Idonex\\Pike\\0.6\\PIKE_MASTER",
+		       0,
+		       &type,
+		       buffer,
+		       &len)==ERROR_SUCCESS)
+    {
+      master_file=strdup(buffer);
+    }
+  }
 #endif
   if(!master_file) master_file = DEFAULT_MASTER;
 
diff --git a/src/modules/Image/blit.c b/src/modules/Image/blit.c
index ea5266e003525ed8c589c847cebbbf4ac04d147b..bdb5aafb579bc155a0874ab257e7fe2735ae0cbb 100644
--- a/src/modules/Image/blit.c
+++ b/src/modules/Image/blit.c
@@ -1,10 +1,10 @@
-/* $Id: blit.c,v 1.25 1997/12/22 23:26:43 hubbe Exp $ */
+/* $Id: blit.c,v 1.26 1998/01/13 22:59:21 hubbe Exp $ */
 #include "global.h"
 
 /*
 **! module Image
 **! note
-**!	$Id: blit.c,v 1.25 1997/12/22 23:26:43 hubbe Exp $
+**!	$Id: blit.c,v 1.26 1998/01/13 22:59:21 hubbe Exp $
 **! class image
 */
 
@@ -25,6 +25,9 @@
 #include "image.h"
 
 extern struct program *image_program;
+#ifdef THIS
+#undef THIS /* Needed for NT */
+#endif
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/colortable.c b/src/modules/Image/colortable.c
index 32735b50a9056cc33318586abd4ca8877e941d98..6c2924cc22237c3fe8720aa51745c2f855a7ddc1 100644
--- a/src/modules/Image/colortable.c
+++ b/src/modules/Image/colortable.c
@@ -1,11 +1,11 @@
 #include <config.h>
 
-/* $Id: colortable.c,v 1.32 1998/01/11 20:50:33 mirar Exp $ */
+/* $Id: colortable.c,v 1.33 1998/01/13 22:59:21 hubbe Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: colortable.c,v 1.32 1998/01/11 20:50:33 mirar Exp $
+**!	$Id: colortable.c,v 1.33 1998/01/13 22:59:21 hubbe Exp $
 **! class colortable
 **!
 **!	This object keeps colortable information,
@@ -21,7 +21,7 @@
 #undef COLORTABLE_REDUCE_DEBUG
 
 #include "global.h"
-RCSID("$Id: colortable.c,v 1.32 1998/01/11 20:50:33 mirar Exp $");
+RCSID("$Id: colortable.c,v 1.33 1998/01/13 22:59:21 hubbe Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -78,6 +78,9 @@ extern struct program *image_program;
 #define SQ(x) ((x)*(x))
 static INLINE int sq(int x) { return x*x; }
 
+#ifdef THIS
+#undef THIS /* Needed for NT */
+#endif
 #define THIS ((struct neo_colortable *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/dct.c b/src/modules/Image/dct.c
index 6e30807082bd586d6495efdb9b73c989e73bdfd1..b43d0873ee1d4ca944b29416ce2bca68b6f36f19 100644
--- a/src/modules/Image/dct.c
+++ b/src/modules/Image/dct.c
@@ -1,9 +1,9 @@
-/* $Id: dct.c,v 1.10 1997/12/22 23:26:45 hubbe Exp $ */
+/* $Id: dct.c,v 1.11 1998/01/13 22:59:22 hubbe Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: dct.c,v 1.10 1997/12/22 23:26:45 hubbe Exp $
+**!	$Id: dct.c,v 1.11 1998/01/13 22:59:22 hubbe Exp $
 **! class image
 */
 
@@ -25,6 +25,9 @@
 #include "image.h"
 
 extern struct program *image_program;
+#ifdef THIS
+#undef THIS /* Needed for NT */
+#endif
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/image.c b/src/modules/Image/image.c
index 57a35710a0d78838595bd489139b78726e7963cc..88c0e6539896f3bd9848a7c7f579be911d9c9e25 100644
--- a/src/modules/Image/image.c
+++ b/src/modules/Image/image.c
@@ -1,9 +1,9 @@
-/* $Id: image.c,v 1.72 1998/01/08 18:44:27 mirar Exp $ */
+/* $Id: image.c,v 1.73 1998/01/13 22:59:23 hubbe Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: image.c,v 1.72 1998/01/08 18:44:27 mirar Exp $
+**!	$Id: image.c,v 1.73 1998/01/13 22:59:23 hubbe Exp $
 **! class image
 **!
 **!	The main object of the <ref>Image</ref> module, this object
@@ -82,7 +82,7 @@
 
 #include "stralloc.h"
 #include "global.h"
-RCSID("$Id: image.c,v 1.72 1998/01/08 18:44:27 mirar Exp $");
+RCSID("$Id: image.c,v 1.73 1998/01/13 22:59:23 hubbe Exp $");
 #include "pike_macros.h"
 #include "object.h"
 #include "constants.h"
@@ -100,6 +100,10 @@ RCSID("$Id: image.c,v 1.72 1998/01/08 18:44:27 mirar Exp $");
 struct program *image_program;
 extern struct program *image_colortable_program;
 
+#ifdef THIS
+#undef THIS /* Needed for NT */
+#endif
+
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/matrix.c b/src/modules/Image/matrix.c
index 611487c89e41ce811a50b0ddd2aeeb84c239f68c..ae757b1b7e22bf4e0681b63aedf97e51d88e6831 100644
--- a/src/modules/Image/matrix.c
+++ b/src/modules/Image/matrix.c
@@ -1,9 +1,9 @@
-/* $Id: matrix.c,v 1.12 1998/01/06 21:39:29 mirar Exp $ */
+/* $Id: matrix.c,v 1.13 1998/01/13 22:59:23 hubbe Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: matrix.c,v 1.12 1998/01/06 21:39:29 mirar Exp $
+**!	$Id: matrix.c,v 1.13 1998/01/13 22:59:23 hubbe Exp $
 **! class image
 */
 
@@ -26,6 +26,10 @@
 #include "image.h"
 
 extern struct program *image_program;
+#ifdef THIS
+#undef THIS /* Needed for NT */
+#endif
+
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/operator.c b/src/modules/Image/operator.c
index e999d68fde6d35c60b51c49242ca6a6bdeac7dd9..c9e3a571424ca06a5de9b3bf05ffc9bbd6b8c9fc 100644
--- a/src/modules/Image/operator.c
+++ b/src/modules/Image/operator.c
@@ -1,9 +1,9 @@
-/* $Id: operator.c,v 1.10 1997/12/22 23:26:48 hubbe Exp $ */
+/* $Id: operator.c,v 1.11 1998/01/13 22:59:23 hubbe Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: operator.c,v 1.10 1997/12/22 23:26:48 hubbe Exp $
+**!	$Id: operator.c,v 1.11 1998/01/13 22:59:23 hubbe Exp $
 **! class image
 */
 
@@ -26,6 +26,9 @@
 #include "image.h"
 
 extern struct program *image_program;
+#ifdef THIS
+#undef THIS
+#endif
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/pattern.c b/src/modules/Image/pattern.c
index 8b7ba8f94ba111f270214945455a23db9c6ccee7..07205152f2c464905b9c0f90632e821a04a99aea 100644
--- a/src/modules/Image/pattern.c
+++ b/src/modules/Image/pattern.c
@@ -1,9 +1,9 @@
-/* $Id: pattern.c,v 1.10 1997/12/22 23:26:49 hubbe Exp $ */
+/* $Id: pattern.c,v 1.11 1998/01/13 22:59:24 hubbe Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: pattern.c,v 1.10 1997/12/22 23:26:49 hubbe Exp $
+**!	$Id: pattern.c,v 1.11 1998/01/13 22:59:24 hubbe Exp $
 **! class image
 */
 
@@ -25,6 +25,10 @@
 #include "image.h"
 
 extern struct program *image_program;
+#ifdef THIS
+#undef THIS
+#endif
+
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/pnm.c b/src/modules/Image/pnm.c
index c93e0574772c811aff35b383626cffd8cd6710a2..febed8a0a13ad8f3ba72203410a26c5db9a0af62 100644
--- a/src/modules/Image/pnm.c
+++ b/src/modules/Image/pnm.c
@@ -1,9 +1,9 @@
-/* $Id: pnm.c,v 1.8 1997/11/02 03:46:52 mirar Exp $ */
+/* $Id: pnm.c,v 1.9 1998/01/13 22:59:24 hubbe Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: pnm.c,v 1.8 1997/11/02 03:46:52 mirar Exp $
+**!	$Id: pnm.c,v 1.9 1998/01/13 22:59:24 hubbe Exp $
 **! class image
 */
 
@@ -24,6 +24,9 @@
 
 #include "image.h"
 
+#ifdef THIS
+#undef THIS
+#endif
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/polyfill.c b/src/modules/Image/polyfill.c
index a79d890e66a910fdbea4b2f2d3fcd490025cb922..e278eebedd5b4cc31bfab8dc23119f74c304b91a 100644
--- a/src/modules/Image/polyfill.c
+++ b/src/modules/Image/polyfill.c
@@ -1,5 +1,5 @@
 #include "global.h"
-RCSID("$Id: polyfill.c,v 1.17 1998/01/06 21:39:30 mirar Exp $");
+RCSID("$Id: polyfill.c,v 1.18 1998/01/13 22:59:24 hubbe Exp $");
 
 /* Prototypes are needed for these */
 extern double floor(double);
@@ -21,6 +21,9 @@ extern double floor(double);
 
 #include "image.h"
 
+#ifdef THIS
+#undef THIS
+#endif
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
@@ -29,7 +32,7 @@ extern double floor(double);
 /*
 **! module Image
 **! note
-**!	$Id: polyfill.c,v 1.17 1998/01/06 21:39:30 mirar Exp $
+**!	$Id: polyfill.c,v 1.18 1998/01/13 22:59:24 hubbe Exp $
 **! class image
 */
 
diff --git a/src/modules/Image/togif.c b/src/modules/Image/togif.c
index 8c926d198a4fb484e8fe92400280cc89d71ec774..6df4b0a6157b090b7645a302ea0e22626b0fe993 100644
--- a/src/modules/Image/togif.c
+++ b/src/modules/Image/togif.c
@@ -2,7 +2,7 @@
 
 togif 
 
-$Id: togif.c,v 1.28 1997/11/26 15:41:35 mirar Exp $ 
+$Id: togif.c,v 1.29 1998/01/13 22:59:25 hubbe Exp $ 
 
 old GIF API compat stuff
 
@@ -11,7 +11,7 @@ old GIF API compat stuff
 /*
 **! module Image
 **! note
-**!	$Id: togif.c,v 1.28 1997/11/26 15:41:35 mirar Exp $
+**!	$Id: togif.c,v 1.29 1998/01/13 22:59:25 hubbe Exp $
 **! class image
 */
 
@@ -36,6 +36,10 @@ old GIF API compat stuff
 #include "image.h"
 #include "colortable.h"
 
+#ifdef THIS
+#undef THIS /* Needed for NT */
+#endif
+
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Image/x.c b/src/modules/Image/x.c
index baecb6764f647046a5fa23c328a91dcb4e97dd69..4703b39b8795653baadd7449394ef345081290b8 100644
--- a/src/modules/Image/x.c
+++ b/src/modules/Image/x.c
@@ -1,4 +1,4 @@
-/* $Id: x.c,v 1.16 1997/11/11 01:26:17 grubba Exp $ */
+/* $Id: x.c,v 1.17 1998/01/13 22:59:25 hubbe Exp $ */
 
 /*
 **! module Image
@@ -12,7 +12,7 @@
 
 #include "stralloc.h"
 #include "global.h"
-RCSID("$Id: x.c,v 1.16 1997/11/11 01:26:17 grubba Exp $");
+RCSID("$Id: x.c,v 1.17 1998/01/13 22:59:25 hubbe Exp $");
 #include "pike_macros.h"
 #include "object.h"
 #include "constants.h"
@@ -29,6 +29,9 @@ RCSID("$Id: x.c,v 1.16 1997/11/11 01:26:17 grubba Exp $");
 
 extern struct program *image_colortable_program;
 
+#ifdef THIS
+#undef THIS
+#endif
 #define THIS ((struct image *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Pipe/pipe.c b/src/modules/Pipe/pipe.c
index e5546bbdfe35e0f224b686ec803536d4deea7109..0a380a3e9885d254a246b122ef59e9ca33516f93 100644
--- a/src/modules/Pipe/pipe.c
+++ b/src/modules/Pipe/pipe.c
@@ -22,7 +22,7 @@
 #include <fcntl.h>
 
 #include "global.h"
-RCSID("$Id: pipe.c,v 1.14 1997/10/10 18:59:47 grubba Exp $");
+RCSID("$Id: pipe.c,v 1.15 1998/01/13 23:00:35 hubbe Exp $");
 
 #include "threads.h"
 #include "stralloc.h"
@@ -71,6 +71,9 @@ RCSID("$Id: pipe.c,v 1.14 1997/10/10 18:59:47 grubba Exp $");
 
 static struct program *pipe_program, *output_program;
 
+#ifdef THIS
+#undef THIS
+#endif
 #define THIS ((struct pipe *)(fp->current_storage))
 #define THISOBJ (fp->current_object)
 
diff --git a/src/modules/Regexp/glue.c b/src/modules/Regexp/glue.c
index d6eda2a4cf1d65b7966502b9e3e5bb0bea36818c..ef48173a29bc87e4644bfdc2fb2c455cbb80d6f0 100644
--- a/src/modules/Regexp/glue.c
+++ b/src/modules/Regexp/glue.c
@@ -37,6 +37,10 @@ struct regexp_glue
 #endif /* USE_SYSTEM_REGEXP */
 
 
+#ifdef THIS
+#undef THIS
+#endif
+
 #define THIS ((struct regexp_glue *)(fp->current_storage))
 
 static void do_free(void)
diff --git a/src/modules/_Crypto/cbc.c b/src/modules/_Crypto/cbc.c
index d3644cdbf40b5580068d01b766b4849b7b53a667..fdbf61bbe3b11edfe0a18b6d5ed98ddbbd3b6902 100644
--- a/src/modules/_Crypto/cbc.c
+++ b/src/modules/_Crypto/cbc.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cbc.c,v 1.9 1997/11/16 22:25:39 nisse Exp $
+ * $Id: cbc.c,v 1.10 1998/01/13 23:01:10 hubbe Exp $
  *
  * CBC (Cipher Block Chaining Mode) crypto module for Pike.
  *
@@ -35,6 +35,7 @@ struct pike_crypto_cbc {
   INT32 mode;
 };
 
+#undef THIS
 #define THIS	((struct pike_crypto_cbc *)(fp->current_storage))
 /*
  * Globals
diff --git a/src/modules/_Crypto/crypto.c b/src/modules/_Crypto/crypto.c
index 8d960e4de8be730cfb9e10c6e3c4baf6436f31db..05cded80b1f81abd3f63c2ef750174e7d67a8824 100644
--- a/src/modules/_Crypto/crypto.c
+++ b/src/modules/_Crypto/crypto.c
@@ -1,5 +1,5 @@
 /*
- * $Id: crypto.c,v 1.23 1997/12/22 23:28:30 hubbe Exp $
+ * $Id: crypto.c,v 1.24 1998/01/13 23:01:11 hubbe Exp $
  *
  * A pike module for getting access to some common cryptos.
  *
@@ -55,6 +55,7 @@ static const char *crypto_functions[] = {
   NULL
 };
 
+#undef THIS
 #define THIS	((struct pike_crypto *)(fp->current_storage))
 
 static struct program *pike_crypto_program;
diff --git a/src/modules/_Crypto/des.c b/src/modules/_Crypto/des.c
index dc53c2b0f883b15ba28f2c2cdb34be54f634539d..f1405408647149682d6b6f45a689f70987d4019b 100644
--- a/src/modules/_Crypto/des.c
+++ b/src/modules/_Crypto/des.c
@@ -1,5 +1,5 @@
 /*
- * $Id: des.c,v 1.10 1997/12/22 23:28:31 hubbe Exp $
+ * $Id: des.c,v 1.11 1998/01/13 23:01:11 hubbe Exp $
  *
  * A pike module for getting access to some common cryptos.
  *
@@ -43,6 +43,7 @@ struct pike_crypto_des {
 		    unsigned INT32 *method, unsigned INT8 *src);
 };
 
+#undef THIS
 #define THIS ((struct pike_crypto_des *) fp->current_storage)
 
 /*
diff --git a/src/modules/_Crypto/pipe.c b/src/modules/_Crypto/pipe.c
index 604534d351804713fafe4e922fcbb8bb2b89982e..883fc79eed23631b1772ab358b99d306df25e4f1 100644
--- a/src/modules/_Crypto/pipe.c
+++ b/src/modules/_Crypto/pipe.c
@@ -1,5 +1,5 @@
 /*
- * $Id: pipe.c,v 1.10 1997/11/16 22:25:45 nisse Exp $
+ * $Id: pipe.c,v 1.11 1998/01/13 23:01:11 hubbe Exp $
  *
  * PIPE crypto module for Pike.
  *
@@ -35,6 +35,7 @@ struct pike_crypto_pipe {
   INT32 mode;
 };
 
+#undef THIS
 #define THIS	((struct pike_crypto_pipe *)(fp->current_storage))
 /*
  * Globals
diff --git a/src/modules/_Crypto/sha.c b/src/modules/_Crypto/sha.c
index e165fe2290c56e1253bb57e3602a2c09af0940dd..6a20b9c93c2deb19f2665d3e56d0bc0fb3876dae 100644
--- a/src/modules/_Crypto/sha.c
+++ b/src/modules/_Crypto/sha.c
@@ -14,6 +14,7 @@
 #include "program.h"
 #include "error.h"
 #include "module_support.h"
+#include "las.h"
 
 #include <sha.h>
 
diff --git a/src/modules/files/socktest.pike b/src/modules/files/socktest.pike
index fbca185280b9266d844fd7ece7d8702ebe922b34..0094853eb4bcc3a82c0289eea003212179b1009f 100755
--- a/src/modules/files/socktest.pike
+++ b/src/modules/files/socktest.pike
@@ -1,6 +1,6 @@
 #!/usr/local/bin/pike
 
-/* $Id: socktest.pike,v 1.5 1997/09/16 07:32:16 hubbe Exp $ */
+/* $Id: socktest.pike,v 1.6 1998/01/13 23:01:25 hubbe Exp $ */
 
 import Stdio;
 import String;
@@ -238,7 +238,7 @@ void finish()
       case 5..26:
 	tests=(_tests-2)*2;
 	werror("Testing "+(tests*2)+" sockets. ");
-	for(e=0;e<tests;e++) stdtest();
+	for(int e=0;e<tests;e++) stdtest();
 	break;
 
       case 27..48:
diff --git a/src/modules/system/system.c b/src/modules/system/system.c
index 38575d74c8eb5a1adf031c0b0de5a2cab698e283..fcac2124ef2aceee16e5d46f82a663640ccece23 100644
--- a/src/modules/system/system.c
+++ b/src/modules/system/system.c
@@ -1,5 +1,5 @@
 /*
- * $Id: system.c,v 1.36 1998/01/11 00:00:19 grubba Exp $
+ * $Id: system.c,v 1.37 1998/01/13 23:01:47 hubbe Exp $
  *
  * System-call module for Pike
  *
@@ -14,7 +14,11 @@
 #include "system.h"
 
 #include "global.h"
-RCSID("$Id: system.c,v 1.36 1998/01/11 00:00:19 grubba Exp $");
+RCSID("$Id: system.c,v 1.37 1998/01/13 23:01:47 hubbe Exp $");
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "module_support.h"
 #include "las.h"
 #include "interpret.h"
@@ -60,10 +64,6 @@ RCSID("$Id: system.c,v 1.36 1998/01/11 00:00:19 grubba Exp $");
 #include <sys/stat.h>
 #endif /* HAVE_SYS_STAT_H */
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-
 /*
  * Functions
  */
@@ -778,7 +778,7 @@ static void describe_hostent(struct hostent *hp)
   for (p = hp->h_addr_list; *p != 0; p++) {
     struct in_addr in;
  
-    memcpy(&in.s_addr, *p, sizeof (in.s_addr));
+    MEMCPY(&in.s_addr, *p, sizeof (in.s_addr));
     push_text(inet_ntoa(in));
     nelem++;
   }
@@ -793,7 +793,7 @@ static void describe_hostent(struct hostent *hp)
 #else
   {
     struct in_addr in;
-    memcpy(&in.s_addr, ret->h_addr, sizeof (in.s_addr));
+    MEMCPY(&in.s_addr, hp->h_addr, sizeof (in.s_addr));
     push_text(inet_ntoa(in));
   }
 
diff --git a/src/object.c b/src/object.c
index fa6d5ef972217ff512d530ee64e43fa3432a74c5..7498e505a86337fdf6fc3cf31507aaf714097a62 100644
--- a/src/object.c
+++ b/src/object.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: object.c,v 1.30 1998/01/02 01:05:48 hubbe Exp $");
+RCSID("$Id: object.c,v 1.31 1998/01/13 22:56:46 hubbe Exp $");
 #include "object.h"
 #include "dynamic_buffer.h"
 #include "interpret.h"
@@ -19,6 +19,8 @@ RCSID("$Id: object.c,v 1.30 1998/01/02 01:05:48 hubbe Exp $");
 #include "gc.h"
 #include "backend.h"
 #include "callback.h"
+#include "cpp.h"
+#include "builtin_functions.h"
 
 struct object *master_object = 0;
 struct program *master_program =0;
@@ -28,7 +30,7 @@ struct object fake_object = { 1 }; /* start with one reference */
 
 void setup_fake_object(void)
 {
-  fake_object.prog=&fake_program;
+  fake_object.prog=new_program;
   fake_object.next=0;
   fake_object.refs=0xffffff;
 }
@@ -39,6 +41,9 @@ struct object *low_clone(struct program *p)
   struct object *o;
   struct frame frame;
 
+  if(!(p->flags & PROGRAM_FINISHED))
+    error("Attempting to clone an unfinished program\n");
+
 #ifdef PROFILING
   p->num_clones++;
 #endif /* PROFILING */
@@ -49,12 +54,22 @@ struct object *low_clone(struct program *p)
 
   o->prog=p;
   p->refs++;
+  o->parent=0;
+  o->parent_identifier=0;
   o->next=first_object;
   o->prev=0;
   if(first_object)
     first_object->prev=o;
   first_object=o;
   o->refs=1;
+  return o;
+}
+
+static void call_c_initializers(struct object *o)
+{
+  int e;
+  struct frame frame;
+  struct program *p=o->prog;
 
   frame.parent_frame=fp;
   frame.current_object=o;
@@ -103,11 +118,9 @@ struct object *low_clone(struct program *p)
 
   free_object(frame.current_object);
   fp = frame.parent_frame;
-
-  return o;
 }
 
-static void init_object(struct object *o, int args)
+static void call_pike_initializers(struct object *o, int args)
 {
   apply_lfun(o,LFUN___INIT,0);
   pop_stack();
@@ -118,10 +131,26 @@ static void init_object(struct object *o, int args)
 struct object *clone_object(struct program *p, int args)
 {
   struct object *o=low_clone(p);
-  init_object(o,args);
+  call_c_initializers(o);
+  call_pike_initializers(o,args);
   return o;
 }
 
+struct object *parent_clone_object(struct program *p,
+				   struct object *parent,
+				   int parent_identifier,
+				   int args)
+{
+  struct object *o=low_clone(p);
+  o->parent=parent;
+  parent->refs++;
+  o->parent_identifier=parent_identifier;
+  call_c_initializers(o);
+  call_pike_initializers(o,args);
+  return o;
+}
+
+
 struct object *get_master(void)
 {
   extern char *master_file;
@@ -143,13 +172,35 @@ struct object *get_master(void)
 
   if(!master_program)
   {
-    master_name=make_shared_string(master_file);
-    master_program=compile_file(master_name);
-    free_string(master_name);
-    if(!master_program) return 0;
+    INT32 len;
+    struct pike_string *s;
+
+
+    FILE *f=fopen(master_file,"r");
+    fseek(f,0,SEEK_END);
+    len=ftell(f);
+    fseek(f,0,SEEK_SET);
+    s=begin_shared_string(len);
+    fread(s->str,1,len,f);
+    fclose(f);
+    push_string(end_shared_string(s));
+    push_text(master_file);
+    f_cpp(2);
+    f_compile(1);
+
+    if(sp[-1].type != T_PROGRAM)
+    {
+      pop_stack();
+      return 0;
+    }
+    master_program=sp[-1].u.program;
+    sp--;
   }
   master_object=clone_object(master_program,0);
 
+  call_c_initializers(master_object);
+  call_pike_initializers(master_object,0);
+
   apply_lfun(master_object,LFUN___INIT,0);
   pop_stack();
   apply_lfun(master_object,LFUN_CREATE,0);
@@ -181,9 +232,16 @@ void destruct(struct object *o)
 
   o->refs++;
 
-  if(o->prog->lfuns[LFUN_DESTROY] != -1)
+  if(o->parent)
+  {
+    free_object(o->parent);
+    o->parent=0;
+  }
+
+  e=FIND_LFUN(o->prog,LFUN_DESTROY);
+  if(e != -1)
   {
-    safe_apply_low(o, o->prog->lfuns[LFUN_DESTROY], 0);
+    safe_apply_low(o, e, 0);
     pop_stack();
   }
 
@@ -293,7 +351,7 @@ void destruct_objects_to_destruct(void)
 
 void really_free_object(struct object *o)
 {
-  if(o->prog && (o->prog->flags & PROG_DESTRUCT_IMMEDIATE))
+  if(o->prog && (o->prog->flags & PROGRAM_DESTRUCT_IMMEDIATE))
   {
     o->refs++;
     destruct(o);
@@ -353,8 +411,16 @@ void low_object_index_no_free(struct svalue *to,
     {
       struct svalue *s;
       s=PROG_FROM_INT(p,f)->constants + i->func.offset;
-      check_destructed(s);
-      assign_svalue_no_free(to, s);
+      if(s->type==T_PROGRAM)
+      {
+	to->type=T_FUNCTION;
+	to->subtype=f;
+	to->u.object=o;
+	o->refs++;
+      }else{
+	check_destructed(s);
+	assign_svalue_no_free(to, s);
+      }
       break;
     }
 
@@ -389,10 +455,23 @@ void object_index_no_free2(struct svalue *to,
     return; /* make gcc happy */
   }
 
-  if(index->type != T_STRING)
+  switch(index->type)
+  {
+  case T_STRING:
+    f=find_shared_string_identifier(index->u.string, p);
+    free_string(index->u.string);
+    index->type=T_LVALUE;
+    index->u.integer=f;
+    break;
+    
+  case T_LVALUE:
+    f=index->u.integer;
+    break;
+      
+  default:
     error("Lookup on non-string value.\n");
+  }
 
-  f=find_shared_string_identifier(index->u.string, p);
   if(f < 0)
   {
     to->type=T_INT;
@@ -419,7 +498,7 @@ void object_index_no_free(struct svalue *to,
   }
   lfun=ARROW_INDEX_P(index) ? LFUN_ARROW : LFUN_INDEX;
 
-  if(p->lfuns[lfun] != -1)
+  if(FIND_LFUN(p, lfun) != -1)
   {
     push_svalue(index);
     apply_lfun(o,lfun,1);
@@ -478,10 +557,25 @@ void object_set_index2(struct object *o,
     return; /* make gcc happy */
   }
 
-  if(index->type != T_STRING)
+  switch(index->type)
+  {
+  case T_STRING:
+    f=find_shared_string_identifier(index->u.string, p);
+    if(f<0)
+      error("No such variable (%s) in object.\n", index->u.string->str);
+    free_string(index->u.string);
+    index->type=T_LVALUE;
+    index->u.integer=f;
+    break;
+
+  case T_LVALUE:
+    f=index->u.integer;
+    break;
+
+  default:
     error("Lookup on non-string value.\n");
+  }
 
-  f=find_shared_string_identifier(index->u.string, p);
   if(f < 0)
   {
     error("No such variable (%s) in object.\n", index->u.string->str);
@@ -505,7 +599,7 @@ void object_set_index(struct object *o,
 
   lfun=ARROW_INDEX_P(index) ? LFUN_ASSIGN_ARROW : LFUN_ASSIGN_INDEX;
 
-  if(p->lfuns[lfun] != -1)
+  if(FIND_LFUN(p,lfun) != -1)
   {
     push_svalue(index);
     push_svalue(from);
@@ -564,13 +658,27 @@ union anything *object_get_item_ptr(struct object *o,
   }
 
   f=ARROW_INDEX_P(index) ? LFUN_ASSIGN_ARROW : LFUN_ASSIGN_INDEX;
-  if(p->lfuns[f] != -1)
+  if(FIND_LFUN(p,f) != -1)
     error("Cannot do incremental operations on overloaded index (yet).\n");
 
-  if(index->type != T_STRING)
+  switch(index->type)
+  {
+  case T_STRING:
+    f=find_shared_string_identifier(index->u.string, p);
+    free_string(index->u.string);
+    index->type=T_LVALUE;
+    index->u.integer=f;
+    break;
+
+  case T_LVALUE:
+    f=index->u.integer;
+    break;
+
+  default:
     error("Lookup on non-string value.\n");
+    return 0;
+  }
 
-  f=find_shared_string_identifier(index->u.string, p);
   if(f < 0)
   {
     error("No such variable in object.\n");
@@ -733,10 +841,10 @@ struct array *object_indices(struct object *o)
   if(!p)
     error("indices() on destructed object.\n");
 
-  if(p->lfuns[LFUN__INDICES]==-1)
+  if(FIND_LFUN(p,LFUN__INDICES) == -1)
   {
-    a=allocate_array_no_init(p->num_identifier_indexes,0);
-    for(e=0;e<(int)p->num_identifier_indexes;e++)
+    a=allocate_array_no_init(p->num_identifier_index,0);
+    for(e=0;e<(int)p->num_identifier_index;e++)
     {
       copy_shared_string(ITEM(a)[e].u.string,
 			 ID_FROM_INT(p,p->identifier_index[e])->name);
@@ -762,10 +870,10 @@ struct array *object_values(struct object *o)
   if(!p)
     error("values() on destructed object.\n");
 
-  if(p->lfuns[LFUN__INDICES]==-1)
+  if(FIND_LFUN(p,LFUN__VALUES)==-1)
   {
-    a=allocate_array_no_init(p->num_identifier_indexes,0);
-    for(e=0;e<(int)p->num_identifier_indexes;e++)
+    a=allocate_array_no_init(p->num_identifier_index,0);
+    for(e=0;e<(int)p->num_identifier_index;e++)
     {
       low_object_index_no_free(ITEM(a)+e, o, p->identifier_index[e]);
     }
@@ -791,6 +899,9 @@ void gc_mark_object_as_referenced(struct object *o)
     if(!o || !(p=o->prog)) return; /* Object already destructed */
     o->refs++;
 
+    if(o->parent)
+      gc_mark_object_as_referenced(o);
+
     frame.parent_frame=fp;
     frame.current_object=o;  /* refs already updated */
     frame.locals=0;
@@ -842,6 +953,14 @@ void gc_check_all_objects(void)
 
   for(o=first_object;o;o=o->next)
   {
+#ifdef DEBUG
+    if(o->parent)
+      if(gc_check(o->parent)==-2)
+	fprintf(stderr,"(in object at %lx -> parent)\n",(long)o);
+#else
+    if(o->parent)
+      gc_check(o->parent);
+#endif
     if(o->prog)
     {
       INT32 e,d;
diff --git a/src/object.h b/src/object.h
index 90bf3280e8dd12e4544cab046592d63a104abde2..04aea59f0104e84c8901b0da947cd88fc11cfb71 100644
--- a/src/object.h
+++ b/src/object.h
@@ -18,6 +18,8 @@ struct object
 {
   INT32 refs;                    /* Reference count, must be first. */
   struct program *prog;
+  struct object *parent;
+  INT16 parent_identifier;
   struct object *next;
   struct object *prev;
   char storage[1];
@@ -40,6 +42,10 @@ extern struct program *master_program;
 void setup_fake_object(void);
 struct object *low_clone(struct program *p);
 struct object *clone_object(struct program *p, int args);
+struct object *parent_clone_object(struct program *p,
+				   struct object *parent,
+				   int parent_identifier,
+				   int args);
 struct object *get_master(void);
 struct object *master(void);
 void destruct(struct object *o);
diff --git a/src/opcodes.c b/src/opcodes.c
index 6fb18a40e88f0347c0d22ed907b6db3ef90b0c63..28d78548962517d04a1e57db5a394cddc2258d05 100644
--- a/src/opcodes.c
+++ b/src/opcodes.c
@@ -90,7 +90,7 @@ void cast(struct pike_string *s)
       push_string(describe_type(s));
       if(!sp[-2].u.object->prog)
 	error("Cast called on destructed object.\n");
-      if(sp[-2].u.object->prog->lfuns[LFUN_CAST] == -1)
+      if(FIND_LFUN(sp[-2].u.object->prog,LFUN_CAST) == -1)
 	error("No cast method in object.\n");
       apply_lfun(sp[-2].u.object, LFUN_CAST, 1);
       free_svalue(sp-2);
@@ -235,7 +235,7 @@ void f_cast(void)
       push_string(s);
       if(!sp[-2].u.object->prog)
 	error("Cast called on destructed object.\n");
-      if(sp[-2].u.object->prog->lfuns[LFUN_CAST] == -1)
+      if(FIND_LFUN(sp[-2].u.object->prog,LFUN_CAST) == -1)
 	error("No cast method in object.\n");
       apply_lfun(sp[-2].u.object, LFUN_CAST, 1);
       free_svalue(sp-2);
diff --git a/src/operators.c b/src/operators.c
index dbc6eb4b0a19a90ed31873a6657fb87330401c3c..504471bfa0085e6a7f624ec875b6be362d7aafc3 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -5,7 +5,7 @@
 \*/
 #include <math.h>
 #include "global.h"
-RCSID("$Id: operators.c,v 1.21 1997/12/03 22:46:17 hubbe Exp $");
+RCSID("$Id: operators.c,v 1.22 1998/01/13 22:56:47 hubbe Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "multiset.h"
@@ -49,7 +49,7 @@ COMPARISON(f_ge,"`>=",!is_lt(sp-2,sp-1))
 #define CALL_OPERATOR(OP, args) \
  if(!sp[-args].u.object->prog) \
    error("Operator %s called in destructed object.\n",lfun_names[OP]); \
- if(sp[-args].u.object->prog->lfuns[OP] == -1) \
+ if(FIND_LFUN(sp[-args].u.object->prog,OP) == -1) \
    error("No operator %s in object.\n",lfun_names[OP]); \
  apply_lfun(sp[-args].u.object, OP, args-1); \
  free_svalue(sp-2); \
@@ -76,7 +76,7 @@ void f_add(INT32 args)
       {
 	if(sp[-args].type == T_OBJECT &&
 	  sp[-args].u.object->prog &&
-	  sp[-args].u.object->prog->lfuns[LFUN_ADD] != -1)
+	   FIND_LFUN(sp[-args].u.object->prog,LFUN_ADD) != -1)
 	{
 	  apply_lfun(sp[-args].u.object, LFUN_ADD, args-1);
 	  free_svalue(sp-2);
@@ -88,7 +88,7 @@ void f_add(INT32 args)
 	{
 	  if(sp[e-args].type == T_OBJECT &&
 	     sp[e-args].u.object->prog &&
-	     sp[e-args].u.object->prog->lfuns[LFUN_RADD] != -1)
+	     FIND_LFUN(sp[e-args].u.object->prog,LFUN_RADD) != -1)
 	  {
 	    struct svalue *tmp=sp+e-args;
 	    check_stack(e);
@@ -391,7 +391,7 @@ static int call_lfun(int left, int right)
 {
   if(sp[-2].type == T_OBJECT &&
      sp[-2].u.object->prog &&
-     sp[-2].u.object->prog->lfuns[left] != -1)
+     FIND_LFUN(sp[-2].u.object->prog,left) != -1)
   {
     apply_lfun(sp[-2].u.object, left, 1);
     free_svalue(sp-2);
@@ -402,7 +402,7 @@ static int call_lfun(int left, int right)
 
   if(sp[-1].type == T_OBJECT &&
      sp[-1].u.object->prog &&
-     sp[-1].u.object->prog->lfuns[right] != -1)
+     FIND_LFUN(sp[-1].u.object->prog,right) != -1)
   {
     push_svalue(sp-2);
     apply_lfun(sp[-2].u.object, right, 1);
@@ -1418,6 +1418,21 @@ static int generate_sizeof(node *n)
   return 1;
 }
 
+void f_call_function(INT32 args)
+{
+  mega_apply(APPLY_STACK,args,0,0);
+}
+
+static int generate_call_function(node *n)
+{
+  node **arg;
+  emit2(F_MARK);
+  do_docode(CDR(n),DO_NOT_COPY);
+  emit2(F_CALL_FUNCTION);
+  return 1;
+}
+
+
 void init_operators(void)
 {
   add_efun2("`[]",f_index,
@@ -1462,4 +1477,9 @@ void init_operators(void)
 
   add_efun2("`~",f_compl,"function(object:mixed)|function(int:int)|function(float:float)|function(string:string)",OPT_TRY_OPTIMIZE,0,generate_compl);
   add_efun2("sizeof", f_sizeof, "function(string|multiset|array|mapping|object:int)",0,0,generate_sizeof);
+
+  add_efun2("`()",f_call_function,"function(mixed,mixed ...:mixed)",OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND,0,generate_call_function);
+
+  /* This one should be removed */
+  add_efun2("call_function",f_call_function,"function(mixed,mixed ...:mixed)",OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND,0,generate_call_function);
 }
diff --git a/src/peep.c b/src/peep.c
index 92b620e729845f3cde40e083aea99d790338ef0e..0339a6054714bd67b25b2d2c0b5859a41ca43ee6 100644
--- a/src/peep.c
+++ b/src/peep.c
@@ -111,7 +111,7 @@ void ins_f_byte(unsigned int b)
   if(b>255)
     error("Instruction too big %d\n",b);
 #endif
-  ins_byte((unsigned char)b,A_PROGRAM);
+  add_to_program((unsigned char)b);
 }
 
 static void ins_f_byte_with_arg(unsigned int a,unsigned INT32 b)
@@ -127,20 +127,20 @@ static void ins_f_byte_with_arg(unsigned int a,unsigned INT32 b)
     if( b < 256*256)
     {
       ins_f_byte(F_PREFIX_CHARX256);
-      ins_byte(b>>8, A_PROGRAM);
+      add_to_program(b>>8);
     }else if(b < 256*256*256) {
       ins_f_byte(F_PREFIX_WORDX256);
-      ins_byte(b >> 16, A_PROGRAM);
-      ins_byte(b >> 8, A_PROGRAM);
+      add_to_program(b>>16);
+      add_to_program(b>>8);
     }else{
       ins_f_byte(F_PREFIX_24BITX256);
-      ins_byte(b >> 24, A_PROGRAM);
-      ins_byte(b >> 16, A_PROGRAM);
-      ins_byte(b >> 8, A_PROGRAM);
+      add_to_program(b>>24);
+      add_to_program(b>>16);
+      add_to_program(b>>8);
     }
   }
   ins_f_byte(a);
-  ins_byte(b, A_PROGRAM);
+  add_to_program(b);
 }
 
 void assemble(void)
@@ -248,11 +248,11 @@ void assemble(void)
     {
     case F_NOP: break;
     case F_ALIGN:
-      while(PC % c->arg) ins_byte(0, A_PROGRAM);
+      while(PC % c->arg) add_to_program(0);
       break;
 
     case F_BYTE:
-      ins_byte(c->arg, A_PROGRAM);
+      add_to_program(c->arg);
       break;
 
     case F_LABEL:
@@ -276,7 +276,7 @@ void assemble(void)
 	if(c->arg > max_label || c->arg < 0) fatal("Jump to unknown label?\n");
 #endif
 	tmp=PC;
-	ins_int(jumps[c->arg],A_PROGRAM);
+	ins_int(jumps[c->arg], (void(*)(char))add_to_program);
 	jumps[c->arg]=tmp;
 	break;
 
@@ -352,7 +352,7 @@ int insopt(int f, INT32 b, int cl, struct pike_string *cf)
 
   p->opcode=f;
   p->line=cl;
-  copy_shared_string(p->file, current_file);
+  copy_shared_string(p->file, lex.current_file);
   p->arg=b;
 
   return p - (p_instr *)instrbuf.s.str;
diff --git a/src/peep.in b/src/peep.in
index 95f88f4741222913fad4d88e8a55d22543304a62..93f78ccc7c3690e19d23efe3034120eb2a5eaafb 100644
--- a/src/peep.in
+++ b/src/peep.in
@@ -150,3 +150,6 @@ NUMBER [$1a < 0] SUBTRACT : ADD_INT (-$1a)
 
 LTOSVAL2 ADD ASSIGN_AND_POP : ADD_TO_AND_POP
 LTOSVAL ADD ASSIGN_AND_POP : ADD_TO_AND_POP
+
+APPLY RETURN : APPLY_AND_RETURN($1a)
+CALL_FUNCTION RETURN : CALL_FUNCTION_AND_RETURN
diff --git a/src/pike_types.c b/src/pike_types.c
index c474489b4512a45add485efd24b6e1f2c26b3459..005eccad0e5e65d6e1999aae53a882f16f9798bd 100644
--- a/src/pike_types.c
+++ b/src/pike_types.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: pike_types.c,v 1.26 1997/09/29 00:57:55 hubbe Exp $");
+RCSID("$Id: pike_types.c,v 1.27 1998/01/13 22:56:48 hubbe Exp $");
 #include <ctype.h>
 #include "svalue.h"
 #include "pike_types.h"
@@ -715,7 +715,7 @@ static char *low_match_types(char *a,char *b, int flags)
     struct program *p;
     if((p=id_to_program(EXTRACT_INT(a+1))))
     {
-      int i=p->lfuns[LFUN_CALL];
+      int i=FIND_LFUN(p,LFUN_CALL);
       if(i == -1) return 0;
       return low_match_types(ID_FROM_INT(p, i)->type->str, b, flags);
     }
@@ -727,7 +727,7 @@ static char *low_match_types(char *a,char *b, int flags)
     struct program *p;
     if((p=id_to_program(EXTRACT_INT(b+1))))
     {
-      int i=p->lfuns[LFUN_CALL];
+      int i=FIND_LFUN(p,LFUN_CALL);
       if(i == -1) return 0;
       return low_match_types(a, ID_FROM_INT(p, i)->type->str, flags);
     }
@@ -927,13 +927,13 @@ static struct pike_string *low_index_type(char *t, node *n)
     {
       if(n->token == F_ARROW)
       {
-	if(p->lfuns[LFUN_ARROW] != -1 || p->lfuns[LFUN_ASSIGN_ARROW] != -1)
+	if(FIND_LFUN(p,LFUN_ARROW)!=-1 || FIND_LFUN(p,LFUN_ASSIGN_ARROW)!=-1)
 	{
 	  reference_shared_string(mixed_type_string);
 	  return mixed_type_string;
 	}
       }else{
-	if(p->lfuns[LFUN_INDEX] != -1 || p->lfuns[LFUN_ASSIGN_INDEX] != -1)
+	if(FIND_LFUN(p,LFUN_INDEX) != -1 || FIND_LFUN(p,LFUN_ASSIGN_INDEX) != -1)
 	{
 	  reference_shared_string(mixed_type_string);
 	  return mixed_type_string;
@@ -1046,10 +1046,10 @@ static int low_check_indexing(char *type, char *index_type, node *n)
     {
       if(n->token == F_ARROW)
       {
-	if(p->lfuns[LFUN_ARROW] != -1 || p->lfuns[LFUN_ASSIGN_ARROW] != -1)
+	if(FIND_LFUN(p,LFUN_ARROW) != -1 || FIND_LFUN(p,LFUN_ASSIGN_ARROW) != -1)
 	return 1;
       }else{
-	if(p->lfuns[LFUN_INDEX] != -1 || p->lfuns[LFUN_ASSIGN_INDEX] != -1)
+	if(FIND_LFUN(p,LFUN_INDEX) != -1 || FIND_LFUN(p,LFUN_ASSIGN_INDEX) != -1)
 	return 1;
       }
       return !!low_match_types(string_type_string->str, index_type,0);
@@ -1188,7 +1188,7 @@ struct pike_string *get_type_of_svalue(struct svalue *s)
   case T_PROGRAM:
   {
     char *a;
-    int id=s->u.program->lfuns[LFUN_CREATE];
+    int id=FIND_LFUN(s->u.program,LFUN_CREATE);
     if(id>=0)
     {
       a=ID_FROM_INT(s->u.program, id)->type->str;
diff --git a/src/pike_types.h b/src/pike_types.h
index 0c407f8c10b288d39b5232c35756a018007ce92e..bf7934a3d1cbde7a36286ac97adbffd86d6402ee 100644
--- a/src/pike_types.h
+++ b/src/pike_types.h
@@ -6,7 +6,36 @@
 #ifndef PIKE_TYPES_H
 #define PIKE_TYPES_H
 
-#include "las.h"
+#include "svalue.h"
+
+struct node_s
+{
+  unsigned INT16 token;
+  INT16 line_number;
+  INT16 node_info;
+  INT16 tree_info;
+  struct pike_string *type;
+  struct node_s *parent;
+  union 
+  {
+    int number;
+    struct svalue sval;
+    struct
+    {
+      struct node_s *a,*b;
+    } node;
+    struct
+    {
+      int a,b;
+    } integer;
+  } u;
+};
+
+#ifndef STRUCT_NODE_S_DECLARED
+#define STRUCT_NODE_S_DECLARED
+#endif
+
+typedef struct node_s node;
 
 extern int max_correct_args;
 extern struct pike_string *string_type_string;
diff --git a/src/program.c b/src/program.c
index da209785ff1f849b6237afce33237c2fdf201708..c4d2e1a18bc92e0c24d8d03fd31d5ff40b3b14a0 100644
--- a/src/program.c
+++ b/src/program.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: program.c,v 1.47 1998/01/02 01:05:51 hubbe Exp $");
+RCSID("$Id: program.c,v 1.48 1998/01/13 22:56:49 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -28,25 +28,22 @@ RCSID("$Id: program.c,v 1.47 1998/01/02 01:05:51 hubbe Exp $");
 #include <errno.h>
 #include <fcntl.h>
 
+
+#undef ATTRIBUTE
+#define ATTRIBUTE(X)
+
+
 /*
  * Define the size of the cache that is used for method lookup.
  */
 #define FIND_FUNCTION_HASHSIZE 4711
 
 
-#define FILE_STATE
-#define PROGRAM_STATE
-
 #define STRUCT
 #include "compilation.h"
-#undef STRUCT
 
 #define DECLARE
 #include "compilation.h"
-#undef DECLARE
-
-#undef FILE_STATE
-#undef PROGRAM_STATE
 
 
 char *lfun_names[] = {
@@ -91,17 +88,61 @@ char *lfun_names[] = {
 };
 
 struct program *first_program = 0;
+static int current_program_id=0;
 
-struct program fake_program;
+struct program *new_program=0;
+struct program *malloc_size_program=0;
 
-static int current_program_id=0;
+int compiler_pass;
+int compilation_depth;
+struct compiler_frame *compiler_frame=0;
 static INT32 last_line = 0;
 static INT32 last_pc = 0;
 static struct pike_string *last_file = 0;
-dynamic_buffer inherit_names;
 dynamic_buffer used_modules;
 
-void free_all_local_names(void);
+/* So what if we don't have templates? / Hubbe */
+
+#ifdef DEBUG
+#define CHECK_FOO(NUMTYPE,TYPE,NAME)				\
+  if(malloc_size_program-> PIKE_CONCAT(num_,NAME) < new_program-> PIKE_CONCAT(num_,NAME))	\
+    fatal("new_program->num_" #NAME " is out of order\n");	\
+  if(new_program->flags & PROGRAM_OPTIMIZED)			\
+    fatal("Tried to reallocate fixed program.\n")
+
+#else
+#define CHECK_FOO(NUMTYPE,TYPE,NAME)
+#endif
+
+#define FOO(NUMTYPE,TYPE,NAME)						\
+void PIKE_CONCAT(add_to_,NAME) (TYPE ARG) {						\
+  CHECK_FOO(NUMTYPE,TYPE,NAME);						\
+  if(malloc_size_program->PIKE_CONCAT(num_,NAME) == new_program->PIKE_CONCAT(num_,NAME)) {	\
+    void *tmp;								\
+    malloc_size_program->PIKE_CONCAT(num_,NAME) *= 2;				\
+    malloc_size_program->PIKE_CONCAT(num_,NAME)++;					\
+    tmp=realloc((char *)new_program->NAME,				\
+                sizeof(TYPE) *						\
+		malloc_size_program->PIKE_CONCAT(num_,NAME));			\
+    if(!tmp) fatal("Out of memory.\n");					\
+    new_program->NAME=tmp;						\
+  }									\
+  new_program->NAME[new_program->PIKE_CONCAT(num_,NAME)++]=(ARG);                   \
+}
+
+#include "program_areas.h"
+
+void ins_int(INT32 i, void (*func)(char tmp))
+{
+  int e;
+  for(e=0;e<(long)sizeof(i);e++) func(EXTRACT_UCHAR(((char *)&i)+e));
+}
+
+void ins_short(INT16 i, void (*func)(char tmp))
+{
+  int e;
+  for(e=0;e<(long)sizeof(i);e++) func(EXTRACT_UCHAR(((char *)&i)+e));
+}
 
 void use_module(struct svalue *s)
 {
@@ -116,19 +157,18 @@ void use_module(struct svalue *s)
 }
 
 
-static int low_find_shared_string_identifier(struct pike_string *name,
-					     struct program *prog);
 
-int find_module_identifier(struct pike_string *ident)
+int low_find_shared_string_identifier(struct pike_string *name,
+				      struct program *prog);
+
+
+
+struct node_s *find_module_identifier(struct pike_string *ident)
 {
   JMP_BUF tmp;
+  node *ret;
 
-#ifdef DEBUG
-  if(recoveries && sp-evaluator_stack < recoveries->sp)
-    fatal("Stack error in compiation (underflow)\n");
-#endif
-
- if(SETJMP(tmp))
+  if(SETJMP(tmp))
   {
     ONERROR tmp;
     SET_ONERROR(tmp,exit_on_error,"Error in handle_error in master object!");
@@ -152,7 +192,9 @@ int find_module_identifier(struct pike_string *ident)
       {
 /*	fprintf(stderr,"MOD: %s, %d %d\n",ident->str, current_line, sp[-1].type); */
 	UNSETJMP(tmp);
-	return 1;
+	ret=mksvaluenode(sp-1);
+	pop_stack();
+	return ret;
       }
       pop_stack();
     }
@@ -160,122 +202,240 @@ int find_module_identifier(struct pike_string *ident)
   UNSETJMP(tmp);
 
   {
-    struct program_state *p;
-    for(p=previous_program_state;p;p=p->previous)
+    struct program_state *p=previous_program_state;
+    int n;
+    for(n=0;n<compilation_depth;n++,p=p->previous)
     {
-      INT32 i;
-      if(previous_file_state &&
-	 previous_file_state->previous_program_state==p->previous)
-	break;
-
-      i=low_find_shared_string_identifier(ident, &p->fake_program);
+      int i=low_find_shared_string_identifier(ident, p->new_program);
       if(i!=-1)
       {
 	struct identifier *id;
-	id=ID_FROM_INT(&p->fake_program, i);
+	id=ID_FROM_INT(p->new_program, i);
 	if(IDENTIFIER_IS_CONSTANT(id->identifier_flags))
 	{
-	  push_svalue(PROG_FROM_INT(&p->fake_program, i)->constants+
-		      id->func.offset);
-	  return 1;
+	  ret=mksvaluenode(PROG_FROM_INT(p->new_program, i)->constants+
+			   id->func.offset);
+	  return ret;
 	}else{
-	  yyerror("Identifier is not a constant");
-	  return 0;
+	  return mkexternalnode(n, i, id);
 	}
       }
     }
   }
-
   return 0;
 }
 
-/* This should be optimized */
+struct program *parent_compilation(int level)
+{
+  int n;
+  struct program_state *p=previous_program_state;
+  for(n=0;n<level;n++)
+  {
+    if(n>=compilation_depth) return 0;
+    p=p->previous;
+    if(!p) return 0;
+  }
+  return p->new_program;
+}
+
+#define ID_TO_PROGRAM_CACHE_SIZE 512
+struct program *id_to_program_cache[ID_TO_PROGRAM_CACHE_SIZE];
+
 struct program *id_to_program(INT32 id)
 {
   struct program *p;
+  INT32 h;
+  if(!id) return 0;
+  h=id & (ID_TO_PROGRAM_CACHE_SIZE-1);
+
+  if((p=id_to_program_cache[h]))
+    if(p->id==id) return p;
+  
   if(id) 
-    for(p=first_program;p;p=p->next)
-      if(id==p->id)
-	return p;
+    {
+      for(p=first_program;p;p=p->next)
+	{
+	  if(id==p->id)
+	    {
+	      if(id_to_program_cache[h])
+		free_program(id_to_program_cache[h]);
+	      
+	      id_to_program_cache[h]=p;
+	      p->refs++;
+	      return p;
+	    }
+	}
+    }
   return 0;
 }
 
-#define SETUP(X,Y,TYPE,AREA) \
-   fake_program.X=(TYPE *)areas[AREA].s.str; \
-   fake_program.Y=areas[AREA].s.len/sizeof(TYPE)
+/* Here starts routines which are used to build new programs */
 
-/*
- * This routine sets up the struct fake_program to work almost like a
- * normal program, but all pointers points to the program we are currently
- * compiling
+/* Re-allocate all the memory in the program in one chunk. because:
+ * 1) The individual blocks are munch bigger than they need to be
+ * 2) cuts down on malloc overhead (maybe)
+ * 3) localizes memory access (decreases paging)
  */
-void setup_fake_program(void)
-{
-  fake_program.refs=0xffffff;
-  SETUP(program, program_size, unsigned char, A_PROGRAM);
-  SETUP(strings, num_strings, struct pike_string *, A_STRINGS);
-  SETUP(inherits, num_inherits, struct inherit, A_INHERITS);
-  SETUP(identifiers, num_identifiers, struct identifier, A_IDENTIFIERS);
-  SETUP(identifier_references, num_identifier_references, struct reference, A_IDENTIFIER_REFERENCES);
-  SETUP(constants, num_constants, struct svalue, A_CONSTANTS);
-  SETUP(linenumbers, num_linenumbers, char, A_LINENUMBERS);
-
-  fake_program.inherits[0].prog=&fake_program;
-  fake_program.next=0;
-  fake_program.prev=0;
-  fake_program.flags=0;
-/*
-  fake_program.lfuns=0;
-  fake_prog.num_lfuns=0;
-*/
-#ifdef PROFILING
-  fake_program.num_clones = 0;
-#endif /* PROFILING */
-  fake_object.prog=&fake_program;
+void optimize_program(struct program *p)
+{
+  SIZE_T size=0;
+  char *data;
+
+  /* Already done (shouldn't happen, but who knows?) */
+  if(p->flags & PROGRAM_OPTIMIZED) return;
+
+#define FOO(NUMTYPE,TYPE,NAME) \
+  size+=MY_ALIGN(p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]));
+#include "program_areas.h"
+
+  data=malloc(size);
+  if(!data) return; /* We are out of memory, but we don't care! */
+
+  size=0;
+
+#define FOO(NUMTYPE,TYPE,NAME) \
+  MEMCPY(data+size,p->NAME,p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0])); \
+  free((char *)p->NAME); \
+  p->NAME=(TYPE *)(data+size); \
+  size+=MY_ALIGN(p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]));
+#include "program_areas.h"
+
+  p->total_size=size + sizeof(struct program);
+
+  p->flags |= PROGRAM_OPTIMIZED;
 }
 
-/* Here starts routines which are used to build new programs */
+/* internal function to make the index-table */
+static int funcmp(const void *a,const void *b)
+{
+  return
+    my_order_strcmp(ID_FROM_INT(new_program, *(unsigned short *)a)->name,
+		    ID_FROM_INT(new_program, *(unsigned short *)b)->name);
+}
+
+void fixate_program(void)
+{
+  INT32 i,e,t;
+  if(new_program->flags & PROGRAM_FIXED) return;
+#ifdef DEBUG
+  if(new_program->flags & PROGRAM_OPTIMIZED)
+    fatal("Cannot fixate optimized program\n");
+#endif
+
+  /* Ok, sort for binsearch */
+  for(e=i=0;i<(int)new_program->num_identifier_references;i++)
+  {
+    struct reference *funp;
+    struct identifier *fun;
+    funp=new_program->identifier_references+i;
+    if(funp->id_flags & (ID_HIDDEN|ID_STATIC)) continue;
+    if(funp->id_flags & ID_INHERITED)
+    {
+      if(funp->id_flags & ID_PRIVATE) continue;
+      fun=ID_FROM_PTR(new_program, funp);
+/*	  if(fun->func.offset == -1) continue; * prototype */
+      
+      /* check for multiple definitions */
+      for(t=i+1;t>=0 && t<(int)new_program->num_identifier_references;t++)
+      {
+	struct reference *funpb;
+	struct identifier *funb;
+	
+	funpb=new_program->identifier_references+t;
+	if(funpb->id_flags & (ID_HIDDEN|ID_STATIC)) continue;
+	funb=ID_FROM_PTR(new_program,funpb);
+	/* if(funb->func.offset == -1) continue; * prototype */
+	if(fun->name==funb->name) t=-10;
+      }
+      if(t<0) continue;
+    }
+    add_to_identifier_index(i);
+  }
+  fsort((void *)new_program->identifier_index,
+	new_program->num_identifier_index,
+	sizeof(unsigned short),(fsortfun)funcmp);
+  
+  
+  for(i=0;i<NUM_LFUNS;i++)
+    new_program->lfuns[i]=find_identifier(lfun_names[i],new_program);
+  
+  new_program->flags |= PROGRAM_FIXED;
+}
 
 /*
  * Start building a new program
  */
-void start_new_program(void)
+void low_start_new_program(struct program *p,
+			   struct pike_string *name,
+			   int flags)
 {
   int e;
 
   threads_disabled++;
-  if(local_variables)
-    setup_fake_program();
-#define PROGRAM_STATE
+  compilation_depth++;
+
+  if(!p)
+  {
+    p=ALLOC_STRUCT(program);
+    MEMSET(p, 0, sizeof(struct program));
+    
+    p->refs=1;
+    p->id=++current_program_id;
+    
+    if((p->next=first_program)) first_program->prev=p;
+    first_program=p;
+  }else{
+    p->refs++;
+  }
+
+  if(name)
+  {
+    struct svalue s;
+    s.type=T_PROGRAM;
+    s.u.program=p;
+    add_constant(name, &s, flags);
+  }
+
 #define PUSH
 #include "compilation.h"
-#undef PUSH
-#undef PROGRAM_STATE
-
-  if(previous_program_state->fake_program.num_inherits)
-    previous_program_state->fake_program.inherits[0].prog=
-      &previous_program_state->fake_program;
 
   init_type_stack();
 
-  for(e=0; e<NUM_AREAS; e++) low_reinit_buf(areas + e);
-  low_reinit_buf(& inherit_names);
   low_reinit_buf(& used_modules);
-  fake_program.id = ++current_program_id;
 
+  if(p && (p->flags & PROGRAM_FINISHED))
   {
-    struct inherit inherit;
-    struct pike_string *name;
-    
-    inherit.prog=&fake_program;
-    inherit.inherit_level=0;
-    inherit.identifier_level=0;
-    inherit.storage_offset=0;
-    add_to_mem_block(A_INHERITS,(char *)&inherit,sizeof inherit);
-    name=make_shared_string("this");
-    low_my_binary_strcat((char *)&name,sizeof(name), &inherit_names);
+    yyerror("Pass2: Program already done");
+    p=0;
+  }
+
+  malloc_size_program = ALLOC_STRUCT(program);
+  new_program=p;
+
+  if(new_program->program)
+  {
+#define FOO(NUMTYPE,TYPE,NAME) \
+    malloc_size_program->PIKE_CONCAT(num_,NAME)=new_program->PIKE_CONCAT(num_,NAME);
+#include "program_areas.h"
+  }else{
+    static struct pike_string *s;
+    struct inherit i;
+
+#define START_SIZE 64
+#define FOO(NUMTYPE,TYPE,NAME) \
+    malloc_size_program->PIKE_CONCAT(num_,NAME)=START_SIZE; \
+    new_program->NAME=(TYPE *)xalloc(sizeof(TYPE) * START_SIZE);
+#include "program_areas.h"
+
+    i.prog=new_program;
+    i.identifier_level=0;
+    i.storage_offset=0;
+    i.inherit_level=0;
+    i.parent=0;
+    i.parent_identifier=0;
+    i.name=0;
+    add_to_inherits(i);
   }
- 
 
   {
     struct svalue tmp;
@@ -287,18 +447,25 @@ void start_new_program(void)
     use_module(& tmp);
   }
 
+  init_node=0;
   num_parse_error=0;
-  local_variables=ALLOC_STRUCT(locals);
-  local_variables->next=0;
-  local_variables->current_number_of_locals=0;
-  local_variables->max_number_of_locals=0;
-  local_variables->current_type=0;
-  local_variables->current_return_type=0;
+
+  push_compiler_frame();
 }
 
-static void low_free_program(struct program *p)
+void start_new_program(void)
+{
+  low_start_new_program(0,0,0);
+}
+
+
+void really_free_program(struct program *p)
 {
   unsigned INT16 e;
+
+  if(id_to_program_cache[p->id & (ID_TO_PROGRAM_CACHE_SIZE-1)]==p)
+    id_to_program_cache[p->id & (ID_TO_PROGRAM_CACHE_SIZE-1)]=0;
+
   for(e=0; e<p->num_strings; e++)
     free_string(p->strings[e]);
 
@@ -312,12 +479,11 @@ static void low_free_program(struct program *p)
     free_svalue(p->constants+e);
 
   for(e=1; e<p->num_inherits; e++)
+  {
     free_program(p->inherits[e].prog);
-}
-
-void really_free_program(struct program *p)
-{
-  low_free_program(p);
+    if(p->inherits[e].parent)
+      free_object(p->inherits[e].parent);
+  }
 
   if(p->prev)
     p->prev->next=p->next;
@@ -327,13 +493,24 @@ void really_free_program(struct program *p)
   if(p->next)
     p->next->prev=p->prev;
 
+  if(p->flags & PROGRAM_OPTIMIZED)
+    {
+      if(p->program)
+	  free(p->program);
+#define FOO(NUMTYPE,TYPE,NAME) p->NAME=0;
+#include "program_areas.h"
+    }else{
+#define FOO(NUMTYPE,TYPE,NAME) \
+  if(p->NAME) { free((char *)p->NAME); p->NAME=0; }
+#include "program_areas.h"
+    }
+
   free((char *)p);
 
   GC_FREE();
 }
 
 #ifdef DEBUG
-
 void dump_program_desc(struct program *p)
 {
   int e,d,q;
@@ -349,93 +526,54 @@ void dump_program_desc(struct program *p)
   }
 */
 
-  fprintf(stderr,"All identifiers: (this=%08x)\n",(unsigned int)p);
+  fprintf(stderr,"All identifiers:\n");
   for(e=0;e<(int)p->num_identifier_references;e++)
   {
     fprintf(stderr,"%3d:",e);
     for(d=0;d<INHERIT_FROM_INT(p,e)->inherit_level;d++) fprintf(stderr,"  ");
-    fprintf(stderr," (%08x) %s;\t",
-	    (unsigned int)INHERIT_FROM_INT(p,e)->prog,
-	    ID_FROM_INT(p,e)->name->str);
-    if(p->identifier_references[e].id_flags&ID_HIDDEN)
-      fprintf(stderr," (hidden)");
-    if(p->identifier_references[e].id_flags&ID_INHERITED)
-      fprintf(stderr," (inherited)");
-    fprintf(stderr,"\n");
+    fprintf(stderr,"%s;\n",ID_FROM_INT(p,e)->name->str);
   }
   fprintf(stderr,"All sorted identifiers:\n");
-  for(q=0;q<(int)p->num_identifier_indexes;q++)
+  for(q=0;q<(int)p->num_identifier_index;q++)
   {
     e=p->identifier_index[q];
     fprintf(stderr,"%3d (%3d):",e,q);
     for(d=0;d<INHERIT_FROM_INT(p,e)->inherit_level;d++) fprintf(stderr,"  ");
-    fprintf(stderr," (%08x) %s;\t",
-	    (unsigned int)INHERIT_FROM_INT(p,e)->prog,
-	    ID_FROM_INT(p,e)->name->str);
-    if(p->identifier_references[e].id_flags & ID_HIDDEN)
-      fprintf(stderr," (hidden)");
-    if(p->identifier_references[e].id_flags&ID_INHERITED)
-      fprintf(stderr," (inherited)");
-    fprintf(stderr,"\n");
+    fprintf(stderr,"%s;\n", ID_FROM_INT(p,e)->name->str);
   }
 }
 #endif
 
 static void toss_compilation_resources(void)
 {
-  struct pike_string **names;
-  struct svalue *modules;
-  int e;
-
-  for (e=0; e<NUM_AREAS; e++) toss_buffer(areas+e);
-
-  names=(struct pike_string **)inherit_names.s.str;
-  e=inherit_names.s.len / sizeof(struct pike_string *);
-  while(--e>=0) if(names[e]) free_string(names[e]);
-  toss_buffer(& inherit_names);
+  free_program(new_program);
+  new_program=0;
 
-  modules=(struct svalue *)used_modules.s.str;
-  e=used_modules.s.len / sizeof(struct svalue);
-  while(--e>=0) free_svalue(modules+e);
-  toss_buffer(& used_modules);
-
-  /* Clean up */
-  while(local_variables)
-  {
-    struct locals *l;
-    for(e=0;e<local_variables->current_number_of_locals;e++)
+  if(malloc_size_program)
     {
-      free_string(local_variables->variable[e].name);
-      free_string(local_variables->variable[e].type);
+      free((char *)malloc_size_program);
+      malloc_size_program=0;
     }
   
-    if(local_variables->current_type)
-      free_string(local_variables->current_type);
-
-    if(local_variables->current_return_type)
-      free_string(local_variables->current_return_type);
-
-    l=local_variables->next;
-    free((char *)local_variables);
-    local_variables=l;
-  }
+  while(compiler_frame)
+    pop_compiler_frame();
 
   if(last_file)
   {
     free_string(last_file);
     last_file=0;
   }
-}
+  
+  {
+    struct svalue *modules=(struct svalue *)used_modules.s.str;
+    INT32 e;
 
-/*
- * Something went wrong.
- * toss resources of program we were building
- */
-void toss_current_program(void)
-{
-  setup_fake_program();
-  low_free_program(&fake_program);
-  toss_compilation_resources();
+    for(e=0;e<(long)(used_modules.s.len / sizeof(struct svalue));e++)
+      free_svalue(modules+e);
+
+    toss_buffer(&used_modules);
+  }
+  
 }
 
 #ifdef DEBUG
@@ -465,6 +603,10 @@ void check_program(struct program *p)
   if(p->storage_needed < 0)
     fatal("Program->storage_needed < 0.\n");
 
+  if(p->num_identifier_index > p->num_identifier_references)
+    fatal("Too many identifier index entries in program!\n");
+
+#if 0
   size=MY_ALIGN(sizeof(struct program));
   size+=MY_ALIGN(p->num_linenumbers);
   size+=MY_ALIGN(p->program_size);
@@ -485,8 +627,8 @@ void check_program(struct program *p)
   if(size < (INT32)p->total_size)
     fatal("Program size is in error.\n");
 
-
-#define CHECKRANGE(X,Y) if((char *)(p->X) < (char *)p || (char *)(p->X)> ((char *)p)+size) fatal("Program->%s is wrong.\n",Y)
+#define CHECKRANGE(X,Y) \
+if((char *)(p->X) < (char *)p || (char *)(p->X)> ((char *)p)+size) fatal("Program->%s is wrong.\n",Y)
 
   CHECKRANGE(program,"program");
   CHECKRANGE(strings,"strings");
@@ -509,11 +651,10 @@ void check_program(struct program *p)
     if(p->checksum != checksum)
       fatal("Someone changed a program!!!\n");
   }
+#endif
 
   for(e=0;e<(int)p->num_constants;e++)
-  {
     check_svalue(p->constants + e);
-  }
 
   for(e=0;e<(int)p->num_strings;e++)
     check_string(p->strings[e]);
@@ -534,14 +675,13 @@ void check_program(struct program *p)
   {
     if(p->identifier_references[e].inherit_offset > p->num_inherits)
       fatal("Inherit offset is wrong!\n");
-    
+
     if(p->identifier_references[e].identifier_offset >
        p->inherits[p->identifier_references[e].inherit_offset].prog->num_identifiers)
       fatal("Identifier offset is wrong!\n");
   }
-    
 
-  for(e=0;e<(int)p->num_identifier_indexes;e++)
+  for(e=0;e<(int)p->num_identifier_index;e++)
   {
     if(p->identifier_index[e] > p->num_identifier_references)
       fatal("Program->identifier_indexes[%ld] is wrong\n",(long)e);
@@ -549,189 +689,44 @@ void check_program(struct program *p)
 
   for(e=0;e<(int)p->num_inherits;e++)
   {
-    struct program *tmp_prog=p->inherits[e].prog;
-    INT32 d;
-
     if(p->inherits[e].storage_offset < 0)
       fatal("Inherit->storage_offset is wrong.\n");
-
-    for(d=0;d<(int)tmp_prog->num_identifiers;d++)
-    {
-      struct identifier *id=tmp_prog->identifiers+d;
-
-      if(IDENTIFIER_IS_VARIABLE(id->identifier_flags))
-      {
-	INT32 offset,size,e2;
-	offset=p->inherits[e].storage_offset + id->func.offset;
-	size=id->run_time_type == T_MIXED ? sizeof(struct svalue) : sizeof(union anything);
-
-	if(offset < 0 || offset+size > p->storage_needed)
-	  fatal("Variable located outside allocated space.\n");
-
-
-	for(e2=0;e2<(int)p->num_inherits;e2++)
-	{
-	  struct program *tmp_prog2=p->inherits[e2].prog;
-	  INT32 d2;
-
-	  for(d2=0;d2<(int)tmp_prog2->num_identifiers;d2++)
-	  {
-	    struct identifier *id2=tmp_prog2->identifiers+d2;
-
-	    if(e==e2 && d==d2) continue;
-
-	    if(IDENTIFIER_IS_VARIABLE(id2->identifier_flags))
-	    {
-	      INT32 offset2,size2;
-
-	      offset2=p->inherits[e2].storage_offset + id2->func.offset;
-	      size2=id2->run_time_type == T_MIXED ? sizeof(struct svalue) : sizeof(union anything);
-	      if( (offset > offset2) ?
-		  (offset2+size2 > offset) : 
-		  (offset+size > offset2))
-	      {
-		fatal("Variable %s (%ld+%ld) and %s (%ld+%ld) overlap.\n",
-		      id->name->str, (long)offset, (long)size,
-		      id2->name->str, (long)offset2, (long)size2);
-	      }
-	    }
-	  }
-	}
-      }
-    }
   }
 }
 #endif
 
-/* internal function to make the index-table */
-static int funcmp(const void *a,const void *b)
+struct program *end_first_pass(int finish)
 {
-  return
-    my_order_strcmp(ID_FROM_INT(&fake_program, *(unsigned short *)a)->name,
-		    ID_FROM_INT(&fake_program, *(unsigned short *)b)->name);
-}
-
-/*
- * Finish this program, returning the newly built program
- */
-
-#define INS_BLOCK(PTR,PTRS,TYPE,AREA) \
-prog->PTR=(TYPE *)p; \
-if((prog->PTRS = areas[AREA].s.len/sizeof(TYPE))) \
-{ \
-  MEMCPY(p,areas[AREA].s.str, areas[AREA].s.len); \
-  p+=MY_ALIGN(areas[AREA].s.len); \
-}
-
-struct program *end_program(void)
-{
-  struct pike_string **names;
-  int size, i,e,t;
-  char *p;
   struct program *prog;
 
   /*
    * Define the __INIT function, but only if there was any code
    * to initialize.
    */
-  if (init_node)
+  if(init_node)
   {
     union idptr tmp;
     struct pike_string *s;
-    push_locals();
     s=make_shared_string("__INIT");
     dooptcode(s,
 	      mknode(F_ARG_LIST,
 		     init_node,mknode(F_RETURN,mkintnode(0),0)),
 	      function_type_string,
 	      0);
-    pop_locals();
     free_string(s);
     init_node=0;
   }
 
+  pop_compiler_frame(); /* Pop __INIT local variables */
+
   exit_type_stack();
 
-  if (num_parse_error > 0)
+  if(num_parse_error > 0)
   {
-    toss_current_program();
     prog=0;
   }else{
-    setup_fake_program();
-    size = MY_ALIGN(sizeof (struct program));
-    for (i=0; i<NUM_AREAS; i++) size += MY_ALIGN(areas[i].s.len);
-    size+=MY_ALIGN(fake_program.num_identifier_references * sizeof(unsigned short));
-
-    p = (char *)xalloc(size);
-    prog = (struct program *)p;
-    *prog = fake_program;
-    prog->total_size = size;
-    prog->refs = 1;
-    prog->flags=0;
-    p += MY_ALIGN(sizeof (struct program));
-
-    INS_BLOCK(program,program_size,unsigned char,A_PROGRAM);
-    INS_BLOCK(linenumbers,num_linenumbers,char,A_LINENUMBERS);
-    INS_BLOCK(identifiers,num_identifiers,struct identifier,A_IDENTIFIERS);
-    INS_BLOCK(identifier_references,num_identifier_references,struct reference,A_IDENTIFIER_REFERENCES);
-    INS_BLOCK(strings,num_strings,struct pike_string *,A_STRINGS);
-    INS_BLOCK(inherits,num_inherits,struct inherit,A_INHERITS);
-    INS_BLOCK(constants,num_constants,struct svalue,A_CONSTANTS);
-
-#ifdef PROFILING
-    /* There is probably a better place for this, but... */
-    for (i=0; i < prog->num_identifiers; i++) {
-      prog->identifiers[i].num_calls = 0;
-    }
-#endif /* PROFILING */
-
-    /* Ok, sort for binsearch */
-    prog->identifier_index=(unsigned short *)p;
-    for(e=i=0;i<(int)prog->num_identifier_references;i++)
-    {
-      struct reference *funp;
-      struct identifier *fun;
-      funp=prog->identifier_references+i;
-      if(funp->id_flags & (ID_HIDDEN|ID_STATIC)) continue;
-
-      if(funp->id_flags & ID_INHERITED)
-      {
-	fun=ID_FROM_PTR(prog, funp);
-	/* if(fun->func.offset == -1) continue; prototype */
-	
-	/* check for multiple definitions */
-	for(t=i+1;t>=0 && t<(int)prog->num_identifier_references;t++)
-	{
-	  struct reference *funpb;
-	  struct identifier *funb;
-	  
-	  funpb=prog->identifier_references+t;
-	  if(funpb->id_flags & (ID_HIDDEN|ID_STATIC)) continue;
-	  funb=ID_FROM_PTR(prog,funpb);
-	  if(funb->func.offset == -1) continue; /* prototype */
-	  if(fun->name==funb->name) t=-10;
-	}
-	if(t<0) continue;
-      }
-
-      prog->identifier_index[e]=i;
-      e++;
-    }
-    prog->num_identifier_indexes=e;
-    fsort((void *)prog->identifier_index, e,sizeof(unsigned short),(fsortfun)funcmp);
-
-    p+=MY_ALIGN(prog->num_identifier_indexes*sizeof(unsigned short));
-
-    toss_compilation_resources();
-
-    prog->inherits[0].prog=prog;
-    prog->prev=0;
-    if((prog->next=first_program))
-      first_program->prev=prog;
-    first_program=prog;
-
-    for(i=0;i<NUM_LFUNS;i++)
-      prog->lfuns[i]=find_identifier(lfun_names[i],prog);
+    prog=new_program;
+    prog->refs++;
 
 #ifdef DEBUG
     check_program(prog);
@@ -739,21 +734,37 @@ struct program *end_program(void)
       dump_program_desc(prog);
 #endif
 
+    new_program->flags |= PROGRAM_PASS_1_DONE;
+
+    if(finish)
+    {
+      fixate_program();
+      optimize_program(new_program);
+      new_program->flags |= PROGRAM_FINISHED;
+    }
+
     GC_ALLOC();
   }
+  toss_compilation_resources();
 
-#define PROGRAM_STATE
 #define POP
 #include "compilation.h"
-#undef POP
-#undef PROGRAM_STATE
-  if(fake_program.num_inherits)
-    fake_program.inherits[0].prog=&fake_program;
+
+  compilation_depth--;
   threads_disabled--;
   free_all_nodes();
   return prog;
 }
 
+/*
+ * Finish this program, returning the newly built program
+ */
+struct program *end_program(void)
+{
+  return end_first_pass(1);
+}
+
+
 /*
  * Allocate needed for this program in the object structure.
  * An offset to the data is returned.
@@ -761,9 +772,9 @@ struct program *end_program(void)
 SIZE_T add_storage(SIZE_T size)
 {
   SIZE_T offset;
-  offset=fake_program.storage_needed;
+  offset=new_program->storage_needed;
   size=MY_ALIGN(size);
-  fake_program.storage_needed += size;
+  new_program->storage_needed += size;
   return offset;
 }
 
@@ -773,7 +784,7 @@ SIZE_T add_storage(SIZE_T size)
  */
 void set_init_callback(void (*init)(struct object *))
 {
-  fake_program.init=init;
+  new_program->init=init;
 }
 
 /*
@@ -782,7 +793,7 @@ void set_init_callback(void (*init)(struct object *))
  */
 void set_exit_callback(void (*exit)(struct object *))
 {
-  fake_program.exit=exit;
+  new_program->exit=exit;
 }
 
 /*
@@ -791,48 +802,42 @@ void set_exit_callback(void (*exit)(struct object *))
  */
 void set_gc_mark_callback(void (*m)(struct object *))
 {
-  fake_program.gc_marked=m;
+  new_program->gc_marked=m;
 }
 
-
-int low_reference_inherited_identifier(int e,struct pike_string *name)
+int low_reference_inherited_identifier(int e,
+				       struct pike_string *name)
 {
   struct reference funp;
   struct program *p;
   int i,d;
 
-  p=fake_program.inherits[e].prog;
+  p=new_program->inherits[e].prog;
   i=find_shared_string_identifier(name,p);
   if(i==-1) return i;
 
   if(p->identifier_references[i].id_flags & ID_HIDDEN)
     return -1;
 
-  if(ID_FROM_INT(p,i)->func.offset == -1) /* prototype */
-    return -1;
-
   funp=p->identifier_references[i];
   funp.inherit_offset+=e;
   funp.id_flags|=ID_HIDDEN;
 
-  for(d=0;d<(int)fake_program.num_identifier_references;d++)
+  for(d=0;d<(int)new_program->num_identifier_references;d++)
   {
     struct reference *fp;
-    fp=fake_program.identifier_references+d;
+    fp=new_program->identifier_references+d;
 
     if(!MEMCMP((char *)fp,(char *)&funp,sizeof funp)) return d;
   }
 
-  add_to_mem_block(A_IDENTIFIER_REFERENCES,(char *)&funp,sizeof funp);
-  return fake_program.num_identifier_references;
+  add_to_identifier_references(funp);
+  return new_program->num_identifier_references -1;
 }
 
-
-
 int reference_inherited_identifier(struct pike_string *super_name,
 				   struct pike_string *function_name)
 {
-  struct pike_string **names;
   int e,i;
 
 #ifdef DEBUG
@@ -840,24 +845,14 @@ int reference_inherited_identifier(struct pike_string *super_name,
     fatal("reference_inherited_function on nonshared string.\n");
 #endif
 
-  names=(struct pike_string **)inherit_names.s.str;
-  setup_fake_program();
-
-  for(e=fake_program.num_inherits-1;e>0;e--)
+  for(e=new_program->num_inherits-1;e>0;e--)
   {
-    if(fake_program.inherits[e].inherit_level!=1) continue;
-    if(!names[e]) continue;
+    if(new_program->inherits[e].inherit_level!=1) continue;
+    if(!new_program->inherits[e].name) continue;
 
     if(super_name)
-    {
-      int l;
-      l=names[e]->len;
-      if(l<super_name->len) continue;
-      if(strncmp(super_name->str,
-		 names[e]->str+l-super_name->len,
-		 super_name->len))
+      if(super_name != new_program->inherits[e].name)
 	continue;
-    }
 
     i=low_reference_inherited_identifier(e,function_name);
     if(i==-1) continue;
@@ -868,45 +863,78 @@ int reference_inherited_identifier(struct pike_string *super_name,
 
 void rename_last_inherit(struct pike_string *n)
 {
-  struct pike_string **names;
-  int e;
-  names=(struct pike_string **)inherit_names.s.str;
-  e=inherit_names.s.len / sizeof(struct pike_string *);
-  free_string(names[e-1]);
-  copy_shared_string(names[e-1],n);
+  if(new_program->inherits[new_program->num_inherits].name)
+    free_string(new_program->inherits[new_program->num_inherits].name);
+  copy_shared_string(new_program->inherits[new_program->num_inherits].name,
+		     n);
 }
 
 /*
  * make this program inherit another program
  */
-void do_inherit(struct program *p,INT32 flags, struct pike_string *name)
+void do_inherit(struct svalue *prog,
+		INT32 flags,
+		struct pike_string *name)
 {
   int e, inherit_offset, storage_offset;
   struct inherit inherit;
   struct pike_string *s;
 
-  setup_fake_program();
+  struct program *p=program_from_svalue(prog);
 
-  inherit_offset = fake_program.num_inherits;
+  
+  if(!p)
+  {
+    yyerror("Illegal program pointer.");
+    return;
+  }
 
-  storage_offset=fake_program.storage_needed;
+  inherit_offset = new_program->num_inherits;
+
+  storage_offset=new_program->storage_needed;
   add_storage(p->storage_needed);
 
   for(e=0; e<(int)p->num_inherits; e++)
   {
     inherit=p->inherits[e];
     inherit.prog->refs++;
-    inherit.identifier_level += fake_program.num_identifier_references;
+    inherit.identifier_level += new_program->num_identifier_references;
     inherit.storage_offset += storage_offset;
     inherit.inherit_level ++;
-    add_to_mem_block(A_INHERITS,(char *)&inherit,sizeof inherit);
-    
-    low_my_binary_strcat((char *)&name,sizeof(name),&inherit_names);
+    if(!e)
+    {
+      if(prog->type == T_FUNCTION)
+      {
+	inherit.parent=prog->u.object;
+	inherit.parent_identifier=prog->subtype;
+      }
+    }
+    if(inherit.parent) inherit.parent->refs++;
+
     if(name)
     {
-      reference_shared_string(name);
-      name=0;
+      if(e==0)
+      {
+	inherit.name=name;
+	reference_shared_string(name);
+      }
+      else if(inherit.name)
+      {
+	struct pike_string *s;
+	s=begin_shared_string(inherit.name->len + name->len + 2);
+	MEMCPY(s->str,name->str,name->len);
+	MEMCPY(s->str+name->len,"::",2);
+	MEMCPY(s->str+name->len+2,inherit.name->str,inherit.name->len);
+	inherit.name=end_shared_string(s);
+      }
+      else
+      {
+	inherit.name=0;
+      }
+    }else{
+      inherit.name=0;
     }
+    add_to_inherits(inherit);
   }
 
   for (e=0; e < (int)p->num_identifier_references; e++)
@@ -923,7 +951,7 @@ void do_inherit(struct program *p,INT32 flags, struct pike_string *name)
     {
       int n;
       n = isidentifier(name);
-      if (n != -1 && ID_FROM_INT(&fake_program,n)->func.offset != -1)
+      if (n != -1 && ID_FROM_INT(new_program,n)->func.offset != -1)
 	my_yyerror("Illegal to redefine 'nomask' function/variable \"%s\"",name->str);
     }
 
@@ -935,7 +963,7 @@ void do_inherit(struct program *p,INT32 flags, struct pike_string *name)
       fun.id_flags |= flags;
 
     fun.id_flags |= ID_INHERITED;
-    add_to_mem_block(A_IDENTIFIER_REFERENCES, (char *)&fun, sizeof fun);
+    add_to_identifier_references(fun);
   }
 
   /* Ska det h{r vara s} h{r? */
@@ -953,12 +981,13 @@ void do_inherit(struct program *p,INT32 flags, struct pike_string *name)
   }
 }
 
-void simple_do_inherit(struct pike_string *s, INT32 flags,struct pike_string *name)
+void simple_do_inherit(struct pike_string *s,
+		       INT32 flags,
+		       struct pike_string *name)
 {
   reference_shared_string(s);
   push_string(s);
-  reference_shared_string(current_file);
-  push_string(current_file);
+  ref_push_string(lex.current_file);
   SAFE_APPLY_MASTER("handle_inherit", 2);
 
   if(sp[-1].type != T_PROGRAM)
@@ -973,7 +1002,7 @@ void simple_do_inherit(struct pike_string *s, INT32 flags,struct pike_string *na
     free_string(s);
     s=name;
   }
-  do_inherit(sp[-1].u.program, flags, s);
+  do_inherit(sp-1, flags, s);
   free_string(s);
   pop_stack();
 }
@@ -984,17 +1013,17 @@ void simple_do_inherit(struct pike_string *s, INT32 flags,struct pike_string *na
 int isidentifier(struct pike_string *s)
 {
   INT32 e;
-  setup_fake_program();
-  for(e=(int)fake_program.num_identifier_references-1;e>=0;e--)
+  for(e=new_program->num_identifier_references-1;e>=0;e--)
   {
-    if(fake_program.identifier_references[e].id_flags & ID_HIDDEN) continue;
+    if(new_program->identifier_references[e].id_flags & ID_HIDDEN) continue;
     
-    if(ID_FROM_INT(& fake_program, e)->name == s)
+    if(ID_FROM_INT(new_program, e)->name == s)
       return e;
   }
   return -1;
 }
 
+/* argument must be a shared string */
 int low_define_variable(struct pike_string *name,
 			struct pike_string *type,
 			INT32 flags,
@@ -1002,33 +1031,37 @@ int low_define_variable(struct pike_string *name,
 			INT32 run_time_type)
 {
   int n;
+
   struct identifier dummy;
   struct reference ref;
-  
+
+#ifdef DEBUG
+  if(new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))
+    fatal("Attempting to add variable to fixed program\n");
+#endif
+
   copy_shared_string(dummy.name, name);
   copy_shared_string(dummy.type, type);
   dummy.identifier_flags = 0;
   dummy.run_time_type=run_time_type;
   dummy.func.offset=offset;
-  
 #ifdef PROFILING
-  dummy.num_calls = 0;
-#endif /* PROFILING */
+  dummy.num_calls=0;
+#endif
 
   ref.id_flags=flags;
-  ref.identifier_offset=areas[A_IDENTIFIERS].s.len / sizeof dummy;
+  ref.identifier_offset=new_program->num_identifiers;
   ref.inherit_offset=0;
-
-  add_to_mem_block(A_IDENTIFIERS, (char *)&dummy, sizeof dummy);
-  fake_program.num_identifiers ++;
-
-  n=areas[A_IDENTIFIER_REFERENCES].s.len / sizeof ref;
-  add_to_mem_block(A_IDENTIFIER_REFERENCES, (char *)&ref, sizeof ref);
-  fake_program.num_identifier_references ++;
-
+  
+  add_to_identifiers(dummy);
+  
+  n=new_program->num_identifier_references;
+  add_to_identifier_references(ref);
+  
   return n;
 }
 
+
 int map_variable(char *name,
 		 char *type,
 		 INT32 flags,
@@ -1061,34 +1094,53 @@ int define_variable(struct pike_string *name,
   if(type == void_type_string)
     yyerror("Variables can't be of type void");
   
-  setup_fake_program();
   n = isidentifier(name);
 
+  if(new_program->flags & PROGRAM_PASS_1_DONE)
+  {
+    if(n==-1)
+      yyerror("Pass2: Variable disappeared!");
+    else
+      return n;
+  }
+
+#ifdef DEBUG
+  if(new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))
+    fatal("Attempting to add variable to fixed program\n");
+#endif
+
   if(n != -1)
   {
-    setup_fake_program();
 
     if (IDENTIFIERP(n)->id_flags & ID_NOMASK)
       my_yyerror("Illegal to redefine 'nomask' variable/functions \"%s\"", name->str);
 
-    if(PROG_FROM_INT(& fake_program, n) == &fake_program)
+    if(PROG_FROM_INT(new_program, n) == new_program)
       my_yyerror("Variable '%s' defined twice.",name->str);
 
-    if(ID_FROM_INT(& fake_program, n)->type != type)
+    if(ID_FROM_INT(new_program, n)->type != type)
       my_yyerror("Illegal to redefine inherited variable with different type.");
 
-    if(ID_FROM_INT(& fake_program, n)->identifier_flags != flags)
+    if(ID_FROM_INT(new_program, n)->identifier_flags != flags)
       my_yyerror("Illegal to redefine inherited variable with different type.");
 
   } else {
     int run_time_type=compile_type_to_runtime_type(type);
-    if(run_time_type == T_FUNCTION) run_time_type = T_MIXED;
-    
-    n=low_define_variable(name, type, flags,
+
+    switch(run_time_type)
+    {
+    case T_FUNCTION:
+    case T_PROGRAM:
+      run_time_type = T_MIXED;
+    }
+
+    n=low_define_variable(name,type,flags,
 			  add_storage(run_time_type == T_MIXED ?
 				      sizeof(struct svalue) :
 				      sizeof(union anything)),
 			  run_time_type);
+				      
+
   }
 
   return n;
@@ -1109,7 +1161,7 @@ int simple_add_variable(char *name,
   return ret;
 }
 
-
+/* FIXME: add_constant with c==0 means declaration */
 int add_constant(struct pike_string *name,
 		 struct svalue *c,
 		 INT32 flags)
@@ -1123,9 +1175,37 @@ int add_constant(struct pike_string *name,
     fatal("define_constant on nonshared string.\n");
 #endif
 
-  setup_fake_program();
   n = isidentifier(name);
 
+
+  if(new_program->flags & PROGRAM_PASS_1_DONE)
+  {
+    if(n==-1)
+    {
+      yyerror("Pass2: Constant disappeared!");
+    }else{
+#if 1
+      struct identifier *id;
+      id=ID_FROM_INT(new_program,n);
+      if(id->func.offset>=0)
+      {
+	struct pike_string *s;
+	struct svalue *c=PROG_FROM_INT(new_program,n)->constants+
+	  id->func.offset;
+	s=get_type_of_svalue(c);
+	free_string(id->type);
+	id->type=s;
+      }
+#endif
+      return n;
+    }
+  }
+
+#ifdef DEBUG
+  if(new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))
+    fatal("Attempting to add constant to fixed program\n");
+#endif
+
   copy_shared_string(dummy.name, name);
   dummy.type = get_type_of_svalue(c);
   
@@ -1134,31 +1214,28 @@ int add_constant(struct pike_string *name,
   
   dummy.func.offset=store_constant(c, 0);
 
-#ifdef PROFILING
-  /* Not strictly necessary, but... */
-  dummy.num_calls = 0;
-#endif /* PROFILING */
-
   ref.id_flags=flags;
-  ref.identifier_offset=fake_program.num_identifiers;
+  ref.identifier_offset=new_program->num_identifiers;
   ref.inherit_offset=0;
 
-  add_to_mem_block(A_IDENTIFIERS, (char *)&dummy, sizeof dummy);
-  fake_program.num_identifiers ++;
+#ifdef PROFILEING
+  dummy.num_calls=0;
+#endif
+
+  add_to_identifiers(dummy);
 
   if(n != -1)
   {
-    if (IDENTIFIERP(n)->id_flags & ID_NOMASK)
+    if(IDENTIFIERP(n)->id_flags & ID_NOMASK)
       my_yyerror("Illegal to redefine 'nomask' identifier \"%s\"", name->str);
 
-    if(PROG_FROM_INT(& fake_program, n) == &fake_program)
+    if(PROG_FROM_INT(new_program, n) == new_program)
       my_yyerror("Identifier '%s' defined twice.",name->str);
 
-    fake_program.identifier_references[n]=ref;
+    new_program->identifier_references[n]=ref;
   } else {
-    n=areas[A_IDENTIFIER_REFERENCES].s.len / sizeof ref;
-    add_to_mem_block(A_IDENTIFIER_REFERENCES, (char *)&ref, sizeof ref);
-    fake_program.num_identifier_references ++;
+    n=new_program->num_identifier_references;
+    add_to_identifier_references(ref);
   }
 
   return n;
@@ -1270,14 +1347,13 @@ INT32 define_function(struct pike_string *name,
 
   i=isidentifier(name);
 
-  setup_fake_program();
 
   if(i >= 0)
   {
     /* already defined */
 
-    funp=ID_FROM_INT(&fake_program, i);
-    ref=fake_program.identifier_references[i];
+    funp=ID_FROM_INT(new_program, i);
+    ref=new_program->identifier_references[i];
 
     if(ref.inherit_offset == 0) /* not inherited */
     {
@@ -1294,11 +1370,7 @@ INT32 define_function(struct pike_string *name,
       }
     }
 
-    /* it's just another prototype, don't define anything */
-    if(!func || func->offset == -1) return i;
-
-    if((ref.id_flags & ID_NOMASK) &&
-       !(funp->func.offset == -1))
+    if((ref.id_flags & ID_NOMASK) && !(funp->func.offset == -1))
     {
       my_yyerror("Illegal to redefine 'nomask' function %s.",name->str);
     }
@@ -1326,17 +1398,13 @@ INT32 define_function(struct pike_string *name,
       else
 	fun.func.offset = -1;
 
-#ifdef PROFILING
-      fun.num_calls = 0;
-#endif /* PROFILING */
-
-      ref.identifier_offset=fake_program.num_identifiers;
-      add_to_mem_block(A_IDENTIFIERS, (char *)&fun, sizeof(fun));
+      ref.identifier_offset=new_program->num_identifiers;
+      add_to_identifiers(fun);
     }
 
     ref.inherit_offset = 0;
     ref.id_flags = flags;
-    fake_program.identifier_references[i]=ref;
+    new_program->identifier_references[i]=ref;
   }else{
     /* define it */
 
@@ -1352,16 +1420,19 @@ INT32 define_function(struct pike_string *name,
     else
       fun.func.offset = -1;
 
-    i=fake_program.num_identifiers;
-    add_to_mem_block(A_IDENTIFIERS, (char *)&fun, sizeof(fun));
+    i=new_program->num_identifiers;
+#ifdef PROFILING
+    fun.num_calls = 0;
+#endif /* PROFILING */
+
+    add_to_identifiers(fun);
 
     ref.id_flags = flags;
     ref.identifier_offset = i;
     ref.inherit_offset = 0;
 
-    i=fake_program.num_identifier_references;
-    add_to_mem_block(A_IDENTIFIER_REFERENCES, (char *)&ref, sizeof ref);
-
+    i=new_program->num_identifier_references;
+    add_to_identifier_references(ref);
   }
   return i;
 }
@@ -1371,18 +1442,23 @@ INT32 define_function(struct pike_string *name,
  * lookup the number of a function in a program given the name in
  * a shared_string
  */
-static int low_find_shared_string_identifier(struct pike_string *name,
-					     struct program *prog)
+int low_find_shared_string_identifier(struct pike_string *name,
+				      struct program *prog)
 {
   int max,min,tst;
   struct reference *funp;
   struct identifier *fun;
-  unsigned short *funindex;
 
-  funindex = prog->identifier_index;
-  if(funindex)
+  if(prog->flags & PROGRAM_FIXED)
   {
-    max = prog->num_identifier_indexes;
+    unsigned short *funindex = prog->identifier_index;
+
+#ifdef DEBUG
+    if(!funindex)
+      fatal("No funindex in fixed program\n");
+#endif
+  
+    max = prog->num_identifier_index;
     min = 0;
     while(max != min)
     {
@@ -1401,7 +1477,7 @@ static int low_find_shared_string_identifier(struct pike_string *name,
       funp = prog->identifier_references + i;
       if(funp->id_flags & ID_HIDDEN) continue;
       fun = ID_FROM_PTR(prog, funp);
-      if(fun->func.offset == -1) continue; /* Prototype */
+      /* if(fun->func.offset == -1) continue; * Prototype */
       if(!is_same_string(fun->name,name)) continue;
       if(funp->id_flags & ID_INHERITED)
       {
@@ -1448,7 +1524,7 @@ int find_shared_string_identifier(struct pike_string *name,
 				  struct program *prog)
 {
 #ifdef FIND_FUNCTION_HASHSIZE
-  if(prog!=&fake_program)
+  if(prog -> flags & PROGRAM_FIXED)
   {
     unsigned int hashval;
     hashval=my_hash_string(name);
@@ -1483,31 +1559,30 @@ int find_identifier(char *name,struct program *prog)
 int store_prog_string(struct pike_string *str)
 {
   unsigned int i;
-  struct pike_string **p;
-
-  p = (struct pike_string **)areas[A_STRINGS].s.str;
 
-  for (i=0;i<areas[A_STRINGS].s.len / sizeof str;i++)
-    if (p[i] == str)
+  for (i=0;i<new_program->num_strings;i++)
+    if (new_program->strings[i] == str)
       return i;
 
   reference_shared_string(str);
-  add_to_mem_block(A_STRINGS, (char *)&str, sizeof str);
+  add_to_strings(str);
   return i;
 }
 
 int store_constant(struct svalue *foo, int equal)
 {
-  struct svalue *s,tmp;
+  struct svalue tmp;
   unsigned int e;
-  s=(struct svalue *)areas[A_CONSTANTS].s.str;
 
-  for(e=0;e<areas[A_CONSTANTS].s.len / sizeof(struct svalue);e++)
-    if(equal ? is_equal(s+e,foo) : is_eq(s+e,foo))
+  for(e=0;e<new_program->num_constants;e++)
+  {
+    struct svalue *s=new_program->constants + e;
+    if(equal ? is_equal(s,foo) : is_eq(s,foo))
       return e;
+  }
 
   assign_svalue_no_free(&tmp,foo);
-  add_to_mem_block(A_CONSTANTS,(char *)&tmp,sizeof(struct svalue));
+  add_to_constants(tmp);
   return e;
 }
 
@@ -1536,21 +1611,25 @@ static int get_small_number(char **q)
 
 void start_line_numbering(void)
 {
-  if(last_file) { free_string(last_file); last_file=0; }
+  if(last_file)
+    {
+      free_string(last_file);
+      last_file=0;
+    }
   last_pc=last_line=0;
 }
 
-static void insert_small_number(int a,int area)
+static void insert_small_number(INT32 a)
 {
   if(a>-127 && a<127)
   {
-    ins_byte(a,area);
+    add_to_linenumbers(a);
   }else if(a>=-32768 && a<32768){
-    ins_signed_byte(-127,area);
-    ins_short(a,area);
+    add_to_linenumbers(a);
+    ins_short(a, add_to_linenumbers);
   }else{
-    ins_signed_byte(-128,area);
-    ins_int(a,area);
+    add_to_linenumbers(-128);
+    ins_int(a, add_to_linenumbers);
   }	
 }
 
@@ -1562,13 +1641,14 @@ void store_linenumber(INT32 current_line, struct pike_string *current_file)
     {
       char *tmp;
       if(last_file) free_string(last_file);
-      ins_byte(127,A_LINENUMBERS);
-      for(tmp=current_file->str; *tmp; tmp++) ins_byte(*tmp,A_LINENUMBERS);
-      ins_byte(0,A_LINENUMBERS);
+      add_to_linenumbers(127);
+      for(tmp=current_file->str; *tmp; tmp++)
+	add_to_linenumbers(*tmp);
+      add_to_linenumbers(0);
       copy_shared_string(last_file, current_file);
     }
-    insert_small_number(PC-last_pc,A_LINENUMBERS);
-    insert_small_number(current_line-last_line,A_LINENUMBERS);
+    insert_small_number(PC-last_pc);
+    insert_small_number(current_line-last_line);
     last_line=current_line;
     last_pc=PC;
   }
@@ -1589,20 +1669,18 @@ char *get_line(unsigned char *pc,struct program *prog,INT32 *linep)
   if (prog == 0) return "Unkown program";
   offset = pc - prog->program;
 
-  if(prog == & fake_program)
+  if(prog == new_program)
   {
     linep[0]=0;
     return "Optimizer";
   }
 
-#ifdef DEBUG
-  if (offset > (INT32)prog->program_size || offset<0)
-    fatal("Illegal offset %ld in program.\n", (long)offset);
-#endif
-
   cnt=prog->linenumbers;
   off=line=0;
   file="Line not found";
+  if (offset > (INT32)prog->num_program || offset<0)
+    return file;
+
   while(cnt < prog->linenumbers + prog->num_linenumbers)
   {
     if(*cnt == 127)
@@ -1618,10 +1696,10 @@ char *get_line(unsigned char *pc,struct program *prog,INT32 *linep)
   return file;
 }
 
-void my_yyerror(char *fmt,...)
+void my_yyerror(char *fmt,...)  ATTRIBUTE((format(printf,1,2)))
 {
   va_list args;
-  char buf[1000];
+  char buf[8192];
   va_start(args,fmt);
   VSPRINTF(buf,fmt,args);
 
@@ -1632,85 +1710,45 @@ void my_yyerror(char *fmt,...)
   va_end(args);
 }
 
-/*
- * Compile an PIKE file. Input is supposed to be initalized already.
- */
-void compile(void)
-{
-  int yyparse(void);
-
-  start_line_numbering();
-
-  num_parse_error = 0;
-  init_node=0;
-
-  yyparse();  /* Parse da program */
-#ifdef DEBUG
-  if(recoveries && sp-evaluator_stack < recoveries->sp)
-    fatal("Stack error in compilation (underflow after yyparse)\n");
-#endif
-  free_all_local_names();
-}
-
-struct program *compile_file(struct pike_string *file_name)
+struct program *compile(struct pike_string *prog)
 {
-  int fd;
   struct program *p;
+  struct lex save_lex;
+  int save_depth=compilation_depth;
+  void yyparse(void);
 
-  while(1)
-  {
-    fd=open(file_name->str,O_RDONLY);
-    if(fd >= 0) break;
-    if(errno != EINTR)
-    {
-#ifdef HAVE_STRERROR
-      error("Couldn't open file '%s'. (%s)\n",file_name->str,strerror(errno));
-#else
-      error("Couldn't open file '%s'. (ERRNO=%d)\n",file_name->str,errno);
-#endif
-    }
-  }
+  save_lex=lex;
 
-#define FILE_STATE
-#define PUSH
-#include "compilation.h"
-#undef PUSH
+  lex.end=prog->str+prog->len;
+  lex.current_line=1;
+  lex.current_file=make_shared_string("-");
+  lex.pragmas=0;
 
-  start_new_file(fd,file_name);
   start_new_program();
-  compile();
-  p=end_program();
-  end_new_file();
+  compilation_depth=0;
 
-#define POP
-#include "compilation.h"
-#undef POP
-#undef FILE_STATE
+  start_line_numbering();
 
-  if(!p) error("Failed to compile %s.\n",file_name->str);
-  return p;
-}
+  compiler_pass=1;
+  lex.pos=prog->str;
+  yyparse();  /* Parse da program */
 
-struct program *compile_string(struct pike_string *prog,
-			       struct pike_string *name)
-{
-  struct program *p;
+  p=end_first_pass(0);
+  
+  if(p && !num_parse_error)
+  {
+    low_start_new_program(p,0,0);
+    compiler_pass=2;
+    lex.pos=prog->str;
+    yyparse();  /* Parse da program again */
+    p=end_program();
+  }
 
-#define FILE_STATE
-#define PUSH
-#include "compilation.h"
-#undef PUSH
 
-  start_new_string(prog->str,prog->len,name);
-  start_new_program();
-  compile();
-  p=end_program();
-  end_new_file();
+  free_string(lex.current_file);
+  lex=save_lex;
 
-#define POP
-#include "compilation.h"
-#undef POP
-#undef FILE_STATE
+  compilation_depth=save_depth;
 
   if(!p) error("Compilation failed.\n");
   return p;
@@ -1786,10 +1824,25 @@ void cleanup_program(void)
 #endif
 }
 
+#ifdef GC2
+
 void gc_mark_program_as_referenced(struct program *p)
 {
   if(gc_mark(p))
+  {
+    int e;
     gc_mark_svalues(p->constants, p->num_constants);
+
+    for(e=0;e<p->num_inherits;e++)
+    {
+      if(p->inherits[e].parent)
+	gc_mark_object_as_referenced(p->inherits[e].parent);
+
+      if(e)
+	gc_mark_program_as_referenced(p->inherits[e].prog);
+    }
+      
+  }
 }
 
 void gc_check_all_programs(void)
@@ -1797,9 +1850,30 @@ void gc_check_all_programs(void)
   struct program *p;
   for(p=first_program;p;p=p->next)
   {
-    debug_gc_check_svalues(p->constants, p->num_constants, T_PROGRAM, p);
+    int e;
+    gc_check_svalues(p->constants, p->num_constants);
 
+    for(e=0;e<p->num_inherits;e++)
+    {
+      if(p->inherits[e].parent)
+      {
 #ifdef DEBUG
+	if(gc_check(p->inherits[e].parent)==-2)
+	  fprintf(stderr,"(program at 0x%lx -> inherit[%d].parent)\n",
+		  (long)p,
+		  e);
+#else
+	gc_check(p->inherits[e].parent);
+#endif
+      }
+
+      if(d_flag && p->inherits[e].name)
+	gc_check(p->inherits[e].name);
+
+      if(e)
+	gc_check(p->inherits[e].prog);
+    }
+
     if(d_flag)
     {
       int e;
@@ -1812,7 +1886,6 @@ void gc_check_all_programs(void)
 	gc_check(p->identifiers[e].type);
       }
     }
-#endif
   }
 }
 
@@ -1832,8 +1905,17 @@ void gc_free_all_unreferenced_programs(void)
   {
     if(gc_do_free(p))
     {
+      int e;
       p->refs++;
       free_svalues(p->constants, p->num_constants, -1);
+      for(e=0;e<p->num_inherits;e++)
+      {
+	if(p->inherits[e].parent)
+	{
+	  free_object(p->inherits[e].parent);
+	  p->inherits[e].parent=0;
+	}
+      }
       next=p->next;
       free_program(p);
     }else{
@@ -1842,6 +1924,8 @@ void gc_free_all_unreferenced_programs(void)
   }
 }
 
+#endif /* GC2 */
+
 
 void count_memory_in_programs(INT32 *num_, INT32 *size_)
 {
@@ -1855,31 +1939,50 @@ void count_memory_in_programs(INT32 *num_, INT32 *size_)
   *num_=num;
   *size_=size;
 }
-void push_locals(void)
+
+void push_compiler_frame(void)
+{
+  struct compiler_frame *f;
+  f=ALLOC_STRUCT(compiler_frame);
+  f->current_type=0;
+  f->current_return_type=0;
+  f->current_number_of_locals=0;
+  f->max_number_of_locals=0;
+  f->previous=compiler_frame;
+  compiler_frame=f;
+}
+
+void pop_local_variables(int level)
 {
-  struct locals *l;
-  l=ALLOC_STRUCT(locals);
-  l->current_type=0;
-  l->current_return_type=0;
-  l->next=local_variables;
-  l->current_number_of_locals=0;
-  l->max_number_of_locals=0;
-  local_variables=l;
+  while(compiler_frame->current_number_of_locals > level)
+  {
+    int e;
+    e=--(compiler_frame->current_number_of_locals);
+    free_string(compiler_frame->variable[e].name);
+    free_string(compiler_frame->variable[e].type);
+  }
 }
 
-void pop_locals(void)
+
+void pop_compiler_frame(void)
 {
-  struct locals *l;
-  free_all_local_names();
-  l=local_variables->next;
-  if(local_variables->current_type)
-    free_string(local_variables->current_type);
-  if(local_variables->current_return_type)
-    free_string(local_variables->current_return_type);
-  free((char *)local_variables);
+  struct compiler_frame *f;
+  int e;
+  f=compiler_frame;
+#ifdef DEBUG
+  if(!f)
+    fatal("Popping out of compiler frames\n");
+#endif
 
-  local_variables=l;
-  /* insert check if ( local->next == parent locals ) here */
+  pop_local_variables(0);
+  if(f->current_type)
+    free_string(f->current_type);
+  
+  if(f->current_return_type)
+    free_string(f->current_return_type);
+
+  compiler_frame=f->previous;
+  free((char *)f);
 }
 
 
@@ -1897,7 +2000,7 @@ char *get_storage(struct object *o, struct program *p)
   oid=o->prog->id;
   pid=p->id;
   hval=oid*9248339 + pid;
-  hval %= GET_STORAGE_CACHE_SIZE;
+  hval%=GET_STORAGE_CACHE_SIZE;
 #ifdef DEBUG
   if(hval>GET_STORAGE_CACHE_SIZE)
     fatal("hval>GET_STORAGE_CACHE_SIZE");
@@ -1926,3 +2029,89 @@ char *get_storage(struct object *o, struct program *p)
   if(offset == -1) return 0;
   return o->storage + offset;
 }
+
+struct program *low_program_from_function(struct program *p,
+					  INT32 i)
+{
+  struct svalue *f;
+  struct identifier *id=ID_FROM_INT(p, i);
+  if(!IDENTIFIER_IS_CONSTANT(id->identifier_flags)) return 0;
+  if(id->func.offset==-1) return 0;
+  f=PROG_FROM_INT(p,i)->constants + id->func.offset;
+  if(f->type!=T_PROGRAM) return 0;
+  return f->u.program;
+}
+
+struct program *program_from_function(struct svalue *f)
+{
+  struct identifier *id;
+  if(f->type != T_FUNCTION) return 0;
+  if(f->subtype == FUNCTION_BUILTIN) return 0;
+  if(!f->u.object->prog) return 0;
+  return low_program_from_function(f->u.object->prog, f->subtype);
+}
+
+struct program *program_from_svalue(struct svalue *s)
+{
+  switch(s->type)
+  {
+  case T_FUNCTION:
+    return program_from_function(s);
+  case T_PROGRAM:
+    return s->u.program;
+  default:
+    return 0;
+  }
+}
+
+#define FIND_CHILD_HASHSIZE 5003
+struct find_child_cache_s
+{
+  INT32 pid,cid,id;
+};
+
+static struct find_child_cache_s find_child_cache[FIND_CHILD_HASHSIZE];
+
+int find_child(struct program *parent, struct program *child)
+{
+  INT32 h=(parent->id  * 9248339 + child->id) % FIND_CHILD_HASHSIZE;
+  if(find_child_cache[h].pid == parent->id &&
+     find_child_cache[h].cid == child->id)
+  {
+    return find_child_cache[h].id;
+  }else{
+    INT32 i;
+    for(i=0;i<parent->num_identifier_references;i++)
+    {
+      if(low_program_from_function(parent, i)==child)
+      {
+	find_child_cache[h].pid=parent->id;
+	find_child_cache[h].cid=child->id;
+	find_child_cache[h].id=i;
+	return i;
+      }
+    }
+  }
+  return -1;
+}
+
+void yywarning(char *fmt, ...) ATTRIBUTE((format(printf,1,2)))
+{
+  char buf[4711];
+  va_list args;
+  va_start(args,fmt);
+  VSPRINTF(buf, fmt, args);
+  va_end(args);
+
+  if(strlen(buf)>sizeof(buf))
+    fatal("Buffer overfloat in yywarning!\n");
+
+  if(get_master())
+  {
+    ref_push_string(lex.current_file);
+    push_int(lex.current_line);
+    push_text(buf);
+    SAFE_APPLY_MASTER("compile_warning",3);
+    pop_stack();
+  }
+}
diff --git a/src/program.h b/src/program.h
index d545499b18e934e073f2d7d24a28ae5b293673e8..209efcdcd032a007f0532128c1bee9a3025c6a03 100644
--- a/src/program.h
+++ b/src/program.h
@@ -8,6 +8,8 @@
 
 #include <stdarg.h>
 #include "global.h"
+#include "pike_types.h"
+#include "svalue.h"
 
 #define LFUN___INIT 0
 #define LFUN_CREATE 1
@@ -57,6 +59,11 @@ extern char *lfun_names[];
 struct svalue;
 #endif
 
+#ifndef STRUCT_NODE_S_DECLARED
+#define STRUCT_NODE_S_DECLARED
+struct node_s;
+#endif
+
 #ifndef STRUCT_OBJECT_DECLARED
 #define STRUCT_OBJECT_DECLARED
 struct object;
@@ -133,35 +140,48 @@ struct reference
 {
   unsigned INT16 inherit_offset;
   unsigned INT16 identifier_offset;
-  INT16 id_flags; /* ID_* static, private etc.. */
+  INT16 id_flags; /* static, private etc.. */
 };
 
+
 struct inherit
 {
-  struct program *prog;
   INT16 inherit_level; /* really needed? */
   INT16 identifier_level;
+  INT16 parent_identifier;
   INT32 storage_offset;
+  struct object *parent;
+  struct program *prog;
+  struct pike_string *name;
 };
 
-#define PROG_DESTRUCT_IMMEDIATE 1
+/* program parts have been realloced into one block */
+#define PROGRAM_OPTIMIZED 1
+
+/* program has gone through pass 1 of compiler, prototypes etc. will
+ * not change from now on
+ */
+#define PROGRAM_FIXED 2
+
+/* Program is done and can be cloned */
+#define PROGRAM_FINISHED 4
+
+/* Program has gone through first compiler pass */
+#define PROGRAM_PASS_1_DONE 8
+
+/* Program will be destructed as soon at it runs out of references. */
+#define PROGRAM_DESTRUCT_IMMEDIATE 15
 
 struct program
 {
   INT32 refs;
   INT32 id;             /* used to identify program in caches */
+  INT32 flags;
   INT32 storage_needed; /* storage needed in the object struct */
 
   struct program *next;
   struct program *prev;
-  unsigned char *program;
-  struct pike_string **strings;
-  struct inherit *inherits;
-  struct reference *identifier_references;
-  struct identifier *identifiers;
-  unsigned INT16 *identifier_index;
-  struct svalue *constants;
-  char *linenumbers;
+
   void (*init)(struct object *);
   void (*exit)(struct object *);
   void (*gc_marked)(struct object *);
@@ -173,15 +193,13 @@ struct program
 #endif /* PROFILING */
 
   SIZE_T total_size;
-  SIZE_T num_linenumbers;
-  SIZE_T program_size;
-  unsigned INT16 flags;
-  unsigned INT16 num_constants;
-  unsigned INT16 num_strings;
-  unsigned INT16 num_identifiers;
-  unsigned INT16 num_identifier_references;
-  unsigned INT16 num_identifier_indexes;
-  unsigned INT16 num_inherits;
+
+#define FOO(NUMTYPE,TYPE,NAME) TYPE * NAME ;
+#include "program_areas.h"
+
+#define FOO(NUMTYPE,TYPE,NAME) NUMTYPE PIKE_CONCAT(num_,NAME) ;
+#include "program_areas.h"
+  
   INT16 lfuns[NUM_LFUNS];
 };
 
@@ -192,33 +210,51 @@ struct program
 #define PROG_FROM_INT(P,X) PROG_FROM_PTR(P,(P)->identifier_references+(X))
 #define ID_FROM_INT(P,X) ID_FROM_PTR(P,(P)->identifier_references+(X))
 
+#define FIND_LFUN(P,N) ((P)->flags & PROGRAM_FIXED?(P)->lfuns[(N)]:find_identifier(lfun_names[(N)],(P)))
+
 #define free_program(p) do{ struct program *_=(p); if(!--_->refs) really_free_program(_); }while(0)
 
 extern struct object fake_object;
-extern struct program fake_program;
+extern struct program *new_program;
 extern struct program *first_program;
+extern int compiler_pass;
+
+#define FOO(NUMTYPE,TYPE,NAME) void PIKE_CONCAT(add_to_,NAME(TYPE ARG));
+#include "program_areas.h"
 
 /* Prototypes begin here */
+void ins_int(INT32 i, void (*func)(char tmp));
+void ins_short(INT16 i, void (*func)(char tmp));
 void use_module(struct svalue *s);
-int find_module_identifier(struct pike_string *ident);
+struct node_s *find_module_identifier(struct pike_string *ident);
+struct program *parent_compilation(int level);
 struct program *id_to_program(INT32 id);
-void setup_fake_program(void);
+void optimize_program(struct program *p);
+void fixate_program(void);
+void low_start_new_program(struct program *p,
+			   struct pike_string *name,
+			   int flags);
 void start_new_program(void);
 void really_free_program(struct program *p);
 void dump_program_desc(struct program *p);
-void toss_current_program(void);
 void check_program(struct program *p);
+struct program *end_first_pass(int finish);
 struct program *end_program(void);
 SIZE_T add_storage(SIZE_T size);
 void set_init_callback(void (*init)(struct object *));
 void set_exit_callback(void (*exit)(struct object *));
 void set_gc_mark_callback(void (*m)(struct object *));
-int low_reference_inherited_identifier(int e,struct pike_string *name);
+int low_reference_inherited_identifier(int e,
+				       struct pike_string *name);
 int reference_inherited_identifier(struct pike_string *super_name,
 				   struct pike_string *function_name);
 void rename_last_inherit(struct pike_string *n);
-void do_inherit(struct program *p,INT32 flags, struct pike_string *name);
-void simple_do_inherit(struct pike_string *s, INT32 flags,struct pike_string *name);
+void do_inherit(struct svalue *prog,
+		INT32 flags,
+		struct pike_string *name);
+void simple_do_inherit(struct pike_string *s,
+		       INT32 flags,
+		       struct pike_string *name);
 int isidentifier(struct pike_string *s);
 int low_define_variable(struct pike_string *name,
 			struct pike_string *type,
@@ -261,6 +297,8 @@ INT32 define_function(struct pike_string *name,
 		      INT16 flags,
 		      INT8 function_flags,
 		      union idptr *func);
+int low_find_shared_string_identifier(struct pike_string *name,
+				      struct program *prog);
 struct ff_hash;
 int find_shared_string_identifier(struct pike_string *name,
 				  struct program *prog);
@@ -270,11 +308,8 @@ int store_constant(struct svalue *foo, int equal);
 void start_line_numbering(void);
 void store_linenumber(INT32 current_line, struct pike_string *current_file);
 char *get_line(unsigned char *pc,struct program *prog,INT32 *linep);
-void my_yyerror(char *fmt,...);
-void compile(void);
-struct program *compile_file(struct pike_string *file_name);
-struct program *compile_string(struct pike_string *prog,
-			       struct pike_string *name);
+void my_yyerror(char *fmt,...)  ATTRIBUTE((format(printf,1,2)));
+struct program *compile(struct pike_string *prog);
 void add_function(char *name,void (*cfun)(INT32),char *type,INT16 flags);
 void check_all_programs(void);
 void cleanup_program(void);
@@ -283,16 +318,18 @@ void gc_check_all_programs(void);
 void gc_mark_all_programs(void);
 void gc_free_all_unreferenced_programs(void);
 void count_memory_in_programs(INT32 *num_, INT32 *size_);
-void push_locals(void);
-void pop_locals(void);
+void push_compiler_frame(void);
+void pop_local_variables(int level);
+void pop_compiler_frame(void);
 char *get_storage(struct object *o, struct program *p);
+struct program *low_program_from_function(struct program *p,
+					  INT32 i);
+struct program *program_from_function(struct svalue *f);
+struct program *program_from_svalue(struct svalue *s);
+struct find_child_cache_s;
+int find_child(struct program *parent, struct program *child);
+void yywarning(char *fmt, ...) ATTRIBUTE((format(printf,1,2)));
 /* Prototypes end here */
 
 
-void my_yyerror(char *fmt,...) ATTRIBUTE((format (printf, 1, 2)));
-
 #endif
-
-
-
-
diff --git a/src/program_areas.h b/src/program_areas.h
new file mode 100644
index 0000000000000000000000000000000000000000..e932bf85bd10c69565581681fd8927e605370700
--- /dev/null
+++ b/src/program_areas.h
@@ -0,0 +1,14 @@
+/* Who needs templates anyway? / Hubbe */
+
+/* Program *must* be first! */
+FOO(SIZE_T,unsigned char,program)
+FOO(SIZE_T,char,linenumbers)
+FOO(unsigned INT16,struct inherit,inherits)
+FOO(unsigned INT16,struct pike_string *,strings)
+FOO(unsigned INT16,struct reference,identifier_references)
+FOO(unsigned INT16,struct identifier,identifiers)
+FOO(unsigned INT16,unsigned INT16,identifier_index)
+FOO(unsigned INT16,struct svalue, constants)
+
+#undef FOO
+
diff --git a/src/stralloc.c b/src/stralloc.c
index 68a80f4517e600b450b62a76c17a651308696ee1..4ab1c7838de35c079560faf371e9ed7ac7d977b1 100644
--- a/src/stralloc.c
+++ b/src/stralloc.c
@@ -503,6 +503,16 @@ struct pike_string *add_shared_strings(struct pike_string *a,
   return ret;
 }
 
+struct pike_string *add_and_free_shared_strings(struct pike_string *a,
+						struct pike_string *b)
+{
+  INT32 alen=a->len;
+  a=realloc_shared_string(a,alen + b->len);
+  MEMCPY(a->str+alen,b->str,b->len);
+  free_string(b);
+  return end_shared_string(a);
+}
+
 /*** replace function ***/
 struct pike_string *string_replace(struct pike_string *str,
 				     struct pike_string *del,
diff --git a/src/stralloc.h b/src/stralloc.h
index 397c8d639f76cd163cc6a525178f3a1397d6a481..265a551bed4a54de55110d43118bafd032db65b9 100644
--- a/src/stralloc.h
+++ b/src/stralloc.h
@@ -33,6 +33,11 @@ struct pike_string *debug_findstring(const struct pike_string *foo);
 
 #define reference_shared_string(s) (s)->refs++
 #define copy_shared_string(to,s) ((to)=(s))->refs++
+#define MAKE_CONSTANT_SHARED_STRING(var, text)	\
+ do { static struct pike_string *str_;		\
+    if(!str_) str_=make_shared_string((text));	\
+    copy_shared_string((var), str_);		\
+ }while(0)
 
 /* Prototypes begin here */
 struct pike_string *binary_findstring(const char *foo, INT32 l);
@@ -56,6 +61,8 @@ struct pike_string *realloc_unlinked_string(struct pike_string *a, INT32 size);
 struct pike_string *realloc_shared_string(struct pike_string *a, INT32 size);
 struct pike_string *add_shared_strings(struct pike_string *a,
 					 struct pike_string *b);
+struct pike_string *add_and_free_shared_strings(struct pike_string *a,
+						struct pike_string *b);
 struct pike_string *string_replace(struct pike_string *str,
 				     struct pike_string *del,
 				     struct pike_string *to);
diff --git a/src/svalue.c b/src/svalue.c
index 940d406be5628d33e7e415b28987d1ae8b968efd..a772c1f9c28fdbd80c9c5cc06bcd61f771fd6c8f 100644
--- a/src/svalue.c
+++ b/src/svalue.c
@@ -333,9 +333,9 @@ unsigned INT32 hash_svalue(struct svalue *s)
       break;
     }
 
-    if(s->u.object->prog->lfuns[LFUN___HASH] != -1)
+    if(FIND_LFUN(s->u.object->prog,LFUN___HASH) != -1)
     {
-      safe_apply_low(s->u.object, s->u.object->prog->lfuns[LFUN___HASH], 0);
+      safe_apply_low(s->u.object, FIND_LFUN(s->u.object->prog,LFUN___HASH), 0);
       if(sp[-1].type == T_INT)
       {
 	q=sp[-1].u.integer;
@@ -375,9 +375,9 @@ int svalue_is_true(struct svalue *s)
   case T_OBJECT:
     if(!s->u.object->prog) return 0;
 
-    if(s->u.object->prog->lfuns[LFUN_NOT]!=-1)
+    if(FIND_LFUN(s->u.object->prog,LFUN_NOT)!=-1)
     {
-      safe_apply_low(s->u.object,s->u.object->prog->lfuns[LFUN_NOT],0);
+      safe_apply_low(s->u.object,FIND_LFUN(s->u.object->prog,LFUN_NOT),0);
       if(sp[-1].type == T_INT && sp[-1].u.integer == 0)
       {
 	pop_stack();
@@ -394,6 +394,8 @@ int svalue_is_true(struct svalue *s)
     
 }
 
+#define TWO_TYPES(X,Y) (((X)<<8)|(Y))
+
 int is_eq(struct svalue *a, struct svalue *b)
 {
   check_type(a->type);
@@ -406,9 +408,24 @@ int is_eq(struct svalue *a, struct svalue *b)
 
   if (a->type != b->type)
   {
-    if(a->type == T_OBJECT)
+    switch(TWO_TYPES((1<<a->type),(1<<b->type)))
     {
-      if(a->u.object->prog->lfuns[LFUN_EQ] != -1)
+    case TWO_TYPES(BIT_FUNCTION,BIT_PROGRAM):
+      return program_from_function(a) == b->u.program;
+    
+    case TWO_TYPES(BIT_PROGRAM,BIT_FUNCTION):
+      return program_from_function(b) == a->u.program;
+
+    case TWO_TYPES(BIT_OBJECT, BIT_ARRAY):
+    case TWO_TYPES(BIT_OBJECT, BIT_MAPPING):
+    case TWO_TYPES(BIT_OBJECT, BIT_MULTISET):
+    case TWO_TYPES(BIT_OBJECT, BIT_OBJECT):
+    case TWO_TYPES(BIT_OBJECT, BIT_FUNCTION):
+    case TWO_TYPES(BIT_OBJECT, BIT_PROGRAM):
+    case TWO_TYPES(BIT_OBJECT, BIT_STRING):
+    case TWO_TYPES(BIT_OBJECT, BIT_INT):
+    case TWO_TYPES(BIT_OBJECT, BIT_FLOAT):
+      if(FIND_LFUN(a->u.object->prog,LFUN_EQ) != -1)
       {
       a_is_obj:
 	assign_svalue_no_free(sp, b);
@@ -423,11 +440,17 @@ int is_eq(struct svalue *a, struct svalue *b)
 	  return 1;
 	}
       }
-    }
-
-    if(b->type == T_OBJECT)
-    {
-      if(b->u.object->prog->lfuns[LFUN_EQ] != -1)
+    if(b->type != T_OBJECT) return 0;
+
+    case TWO_TYPES(BIT_ARRAY,BIT_OBJECT):
+    case TWO_TYPES(BIT_MAPPING,BIT_OBJECT):
+    case TWO_TYPES(BIT_MULTISET,BIT_OBJECT):
+    case TWO_TYPES(BIT_FUNCTION,BIT_OBJECT):
+    case TWO_TYPES(BIT_PROGRAM,BIT_OBJECT):
+    case TWO_TYPES(BIT_STRING,BIT_OBJECT):
+    case TWO_TYPES(BIT_INT,BIT_OBJECT):
+    case TWO_TYPES(BIT_FLOAT,BIT_OBJECT):
+      if(FIND_LFUN(b->u.object->prog,LFUN_EQ) != -1)
       {
       b_is_obj:
 	assign_svalue_no_free(sp, a);
@@ -449,10 +472,10 @@ int is_eq(struct svalue *a, struct svalue *b)
   switch(a->type)
   {
   case T_OBJECT:
-    if(a->u.object->prog->lfuns[LFUN_EQ] != -1)
+    if(FIND_LFUN(a->u.object->prog,LFUN_EQ) != -1)
       goto a_is_obj;
 
-    if(b->u.object->prog->lfuns[LFUN_EQ] != -1)
+    if(FIND_LFUN(b->u.object->prog,LFUN_EQ) != -1)
       goto b_is_obj;
 
   case T_MULTISET:
@@ -578,7 +601,7 @@ int is_lt(struct svalue *a,struct svalue *b)
     a_is_object:
       if(!a->u.object->prog)
 	error("Comparison on destructed object.\n");
-      if(a->u.object->prog->lfuns[LFUN_LT] == -1)
+      if(FIND_LFUN(a->u.object->prog,LFUN_LT) == -1)
 	error("Object lacks '<\n");
       assign_svalue_no_free(sp, b);
       sp++;
@@ -597,7 +620,7 @@ int is_lt(struct svalue *a,struct svalue *b)
     {
       if(!b->u.object->prog)
 	error("Comparison on destructed object.\n");
-      if(b->u.object->prog->lfuns[LFUN_GT] == -1)
+      if(FIND_LFUN(b->u.object->prog,LFUN_GT) == -1)
 	error("Object lacks '>\n");
       assign_svalue_no_free(sp, a);
       sp++;
@@ -878,7 +901,12 @@ TYPE_FIELD gc_check_svalues(struct svalue *s, int num)
     case T_OBJECT:
       if(s->u.object->prog)
       {
-	gc_check(s->u.object);
+#ifdef DEBUG
+	if(gc_check(s->u.object) == -2)
+	  fprintf(stderr,"(in svalue at %lx, type = %d)\n",(long)s,s->type);
+#else	  
+	  gc_check(s->u.object);
+#endif
       }else{
 	free_svalue(s);
 	s->type=T_INT;
@@ -1030,9 +1058,9 @@ INT32 pike_sizeof(struct svalue *s)
   case T_OBJECT:
     if(!s->u.object->prog)
       error("sizeof() on destructed object.\n");
-    if(s->u.object->prog->lfuns[LFUN__SIZEOF] == -1)
+    if(FIND_LFUN(s->u.object->prog,LFUN__SIZEOF) == -1)
     {
-      return s->u.object->prog->num_identifier_indexes;
+      return s->u.object->prog->num_identifier_index;
     }else{
       apply_lfun(s->u.object, LFUN__SIZEOF, 0);
       if(sp[-1].type != T_INT)
diff --git a/src/testsuite.in b/src/testsuite.in
index 0a35be4b6673de8506584b8aadb09627a346a0a4..d25d1e73db21614be3e387192f86223cd85cb20e 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -1,4 +1,4 @@
-test_true([["$Id: testsuite.in,v 1.63 1998/01/03 07:12:11 hubbe Exp $"]])
+test_true([["$Id: testsuite.in,v 1.64 1998/01/13 22:56:51 hubbe Exp $"]])
 test_eq(1e1,10.0)
 test_eq(1E1,10.0)
 test_eq(1e+1,10.0)
@@ -7,8 +7,19 @@ test_eq(1e-1,0.1)
 test_eq('\x20',32)
 test_eq("\x20","\040")
 
-test_eq(class { static int foo=17; }()->foo,0)
-test_eval_error(class { static int foo=17; }()->foo=18;)
+
+test_any([[object o=class foo{int c;class bar{void create(){c++;};}}(); o->bar(); return o->c;]],1)
+test_do([[add_constant("GURKA2",class foo { int c; class bar{void create() {c+=17;}}}()); ]])
+test_any([[class x { inherit GURKA2.bar; }(); return GURKA2->c;]],17)
+test_any([[class x { inherit GURKA2.bar; }(); return GURKA2->c;]],34)
+
+test_do([[add_constant("GURKA2",class foo { int c; class bar{void create() { class sune { void create() {c+=17;}}(); }}}()); ]])
+test_any([[class x { inherit GURKA2.bar; }(); return GURKA2->c;]],17)
+test_any([[class x { inherit GURKA2.bar; }(); return GURKA2->c;]],34)
+test_do([[add_constant("GURKA2");]]);
+
+test_eq(class c { static int foo=17; }()->foo,0)
+test_eval_error(class c { static int foo=17; }()->foo=18;)
 test_equal( [[ ({ (["foo":"bar"]), (<"foo">), ([]) })->foo ]], [[ ({"bar",1,0}) ]])
 test_any([[mixed a=({([]),0}); a[1]=a; return a->foo[0];]],0)
 test_eval_error([[return column(({0}),"foo");]])
@@ -30,7 +41,7 @@ test_compile_error([[void foo() { return destruct(this_object()); }]])
 test_any([[class foo { constant x=17; }; class bar { inherit foo; constant x=18; }; return bar()->x;]],18)
 test_program([[inline string foo(string s){ while(s[0] == ' ' || s[0] == '\t') s = s[1..]; return(s); } string a() { return foo("   bar"); }]])
 test_true([[lambda(function f) {return 1;}(object_program(this_object()));]])
-test_eq([[class { int `()(){ return 4711; } }()(); ]],4711)
+test_eq([[class c { int `()(){ return 4711; } }()(); ]],4711)
 teste_eval_error(mixed foo=({}); sort(@foo); )
 test_compile_error([[int foo() { return 1} ; constant foo=(["foo":foo]); return foo->foo();]])
 test_compile_error([[class T{void p(object e,object f){lambda::create(f);}}]])
@@ -73,13 +84,12 @@ test_any([[float p=2.0; p--; return p;]],1.0);
 test_any([[float p=2.0; return --p;]],1.0);
 
 test_compile_error(int foo() { LJjjjjJJJ ; })
-test_true(clone(class { constant i=1; })->i)
-test_true(clone(class { constant i=0; mixed `->(string s) { if(s=="i") return 1; }})->i)
-test_true(clone(class { constant i=1; mixed `->(string s) { return 0; }})["i"])
-test_true(clone(class { constant i=0; mixed `[](string s) { if(s=="i") return 1; }})["i"])
-test_eq([[class{mixed `[](int a,int b) { return a+b; }}()[1..4]]],5)
-test_true(clone(class { mixed `[]=(mixed a, mixed b) { if(a!=b) throw(1); }})[1]=1)
-test_true(clone(class { mixed `->=(mixed a, mixed b) { if(a!=b) throw(1); }})->i="i")
+test_true(clone(class c { constant i=1; })->i)
+test_true(clone(class c { constant i=0; mixed `->(string s) { if(s=="i") return 1; }})->i)
+test_true(clone(class c { constant i=1; mixed `->(string s) { return 0; }})["i"])
+test_true(clone(class c { constant i=0; mixed `[](string s) { if(s=="i") return 1; }})["i"])
+test_true(clone(class c { mixed `[]=(mixed a, mixed b) { if(a!=b) throw(1); }})[1]=1)
+test_true(clone(class c { mixed `->=(mixed a, mixed b) { if(a!=b) throw(1); }})->i="i")
 
 test_compile(class A {}; class B { inherit A; })
 
@@ -99,9 +109,9 @@ test_program(inherit test;)
 test_program(inherit test; int a() { return foo; } )
 test_define_program(test,[[class TEST { int a() { return 1; } }]])
 test_program(inherit test; inherit TEST; )
-test_compile_error(class { object(Stdio.File) foo; object(Regexp) bar=foo; })
-test_do(class { object foo; object(Regexp) bar=foo; })
-test_do(class { object(Stdio.File) foo; object bar=foo; })
+test_compile_error(class c { object(Stdio.File) foo; object(Regexp) bar=foo; })
+test_do(class c { object foo; object(Regexp) bar=foo; })
+test_do(class c { object(Stdio.File) foo; object bar=foo; })
 test_any(if(int i=1) return i; return 0;,1)
 test_compile(for(int i=0;i<100;i++) return 0;)
 test_compile(foreach(({}),mixed i){})
@@ -376,20 +386,20 @@ ifefun(gc,
 [[
   test_true(intp(gc()));
   test_any([[ array a=({0}); a[0]=a; gc(); a=0; return gc() > 0; ]],1);
-  test_any([[object o=class {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);
-  test_any([[object o=class {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);
+  test_any([[object o=class c {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);
+  test_any([[object o=class c {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);
   test_any([[mapping m=([]); m[m]=m; gc(); m=0; return gc() > 0; ]],1);
   test_any([[multiset m=(<>); m[m]=1; gc(); m=0; return gc() > 0; ]],1);
 ]])
 
 
 test_eq("\377"[0],255)
-test_do(add_constant("foo",clone(class {int i;})))
+test_do(add_constant("foo",clone(class c {int i;})))
 test_eq(foo->i,0)
 test_do(foo->i=17)
 test_eq(foo->i,17)
 test_do(add_constant("foo"));
-test_do(add_constant("foo",clone(class {int *i=({0});})))
+test_do(add_constant("foo",clone(class c {int *i=({0});})))
 test_eq(foo->i[0],0)
 test_do(foo->i[0]=17)
 test_eq(foo->i[0],17)
@@ -419,12 +429,12 @@ test_eq(typeof(0.0),"float")
 test_eq(typeof(all_constants()["all_constants"]),"mixed")
 
 // class
-test_true(programp(class {}))
-test_true(functionp(clone(class { int foo() { return 1; }})->foo))
-test_true(clone(class { int foo() { return 1; }})->foo())
-test_true(clone(class { int i=1; })->i)
-test_false(clone(class { int foo() { return 1; }})->bar)
-test_eq(clone(clone(class { program foo=class { int i=20; }; })->foo)->i,20)
+test_true(programp(class c {}))
+test_true(functionp(clone(class c { int foo() { return 1; }})->foo))
+test_true(clone(class c { int foo() { return 1; }})->foo())
+test_true(clone(class c { int i=1; })->i)
+test_false(clone(class c { int foo() { return 1; }})->bar)
+test_eq(clone(clone(class c { program foo=class c { int i=20; }; })->foo)->i,20)
 
 // type checks
 test_compile_error([[} int foo() { return]]);
@@ -969,15 +979,13 @@ test_any(int e;string t=""; for(e=0;e<10;e++) switch(e) { default: t+=e; case 4.
 test_any([[float e,q; q=0.0; for(e=0.1;e<10.0;e+=1.0) switch(e) { default: q+=e; case 4.0..8.0: } return q]],0.1+1.1+2.1+3.1+8.1+9.1)
 
 // testing preprocessor
-test_program([[
-#include <simulate.h>
-mixed a() { return explode ; }
-]])
-test_program([[
-#include "lib/include/simulate.h"
-mixed a() { return implode; }
-]])
-
+test_any(int e; object o=clone(Stdio.File); if(!o->open("conftest.h","wct")) return -1; e=o->write("return 17;\n"); if(!o->close()) return -1; return e,11)
+test_any([[
+#include "conftest.h"
+]],17)
+dnltest_any([[
+dnl#include <conftest.h>
+dnl]],17)
 test_true(intp(__LINE__))
 test_true(stringp(__FILE__))
 test_true(stringp(__DATE__))
@@ -1702,6 +1710,7 @@ test_search3($1,($1[..strlen($1)-3]))
 test_search3($1,($1[1..]))
 ]])
 
+dnl some m4 doesn't handle 8 bit characters...
 test_search4("SUNE")
 test_search4("kapit\344l>")
 test_search4("-------------------+")
@@ -1785,7 +1794,7 @@ test_program(inherit test; inherit test2; mixed a() { setw(20); setb(22); return
 test_program(inherit test2; inherit test; mixed a() { w=20; b=22; return getw()==20 && getb()==22; })
 test_program(inherit test2; inherit test; mixed a() { setw(20); setb(22); return w==20 && b==22; })
 
-test_eval_error(clone(class{int i;void foo(){ destruct(this_object());i=0;}})->foo())
+test_eval_error(clone(class c{int i;void foo(){ destruct(this_object());i=0;}})->foo())
 
 // Pike modules
 // LR
diff --git a/src/threads.c b/src/threads.c
index 6221538f632125e77b9d170618a19675300d81ae..951d67e567071577e894c6c423eccd743ca21198 100644
--- a/src/threads.c
+++ b/src/threads.c
@@ -1,5 +1,5 @@
 #include "global.h"
-RCSID("$Id: threads.c,v 1.50 1998/01/03 07:12:12 hubbe Exp $");
+RCSID("$Id: threads.c,v 1.51 1998/01/13 22:56:51 hubbe Exp $");
 
 int num_threads = 1;
 int threads_disabled = 0;
@@ -74,9 +74,10 @@ int co_destroy(COND_T *c)
 {
   struct cond_t_queue *t;
   mt_lock(& c->lock);
-  n=c->head;
-  c->head=c->tail=0;
-  if(t) return EBUSY;
+  t=c->head;
+  mt_unlock(& c->lock);
+  if(t) return -1;
+  mt_destroy(& c->lock);
   return 0;
 }
 
@@ -191,7 +192,9 @@ void f_thread_create(INT32 args)
   arg->id=clone_object(thread_id_prog,0);
   ((struct thread_state *)arg->id->storage)->status=THREAD_RUNNING;
 
-  tmp=th_create(&dummy,new_thread_func,arg);
+  tmp=th_create(&((struct thread_state *)arg->id->storage)->id,
+		new_thread_func,
+		arg);
 
   if(!tmp)
   {
@@ -509,6 +512,7 @@ void init_thread_obj(struct object *o)
 void exit_thread_obj(struct object *o)
 {
   co_destroy(& THIS_THREAD->status_change);
+  th_destroy(& THIS_THREAD->id);
 }
 
 #ifdef DEBUG
@@ -577,7 +581,7 @@ void th_init(void)
   set_init_callback(init_mutex_key_obj);
   set_exit_callback(exit_mutex_key_obj);
   mutex_key=end_program();
-  mutex_key->flags|=PROG_DESTRUCT_IMMEDIATE;
+  mutex_key->flags|=PROGRAM_DESTRUCT_IMMEDIATE;
   if(!mutex_key)
     fatal("Failed to initialize mutex_key program!\n");
 
diff --git a/src/threads.h b/src/threads.h
index 70282721e1fd2973b1ae301bdc1a34fa1a74a260..728821091696ab67a85afe6c10e87acff4595cc2 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -154,11 +154,12 @@ extern struct object *thread_id;
 
 #ifdef NT_THREADS
 #include <process.h>
+#include <windows.h>
 
 #define THREAD_T HANDLE
 #define th_setconcurrency(X)
-#define th_create(ID,fun,arg)  _beginthreadex(NULL, 2*1024*1024, fun, arg, 0, ID)
-#define th_exit(foo) _endthreadex(foo)
+#define th_create(ID,fun,arg)  (!(*(ID)=_beginthread(fun, 2*1024*1024, arg)))
+#define th_exit(foo) _endthread(foo)
 #define th_self() GetCurrentThread()
 #define th_destroy(X) CloseHandle(*(X))
 #define th_yield() Sleep(0)
@@ -189,10 +190,10 @@ struct cond_t_queue
   EVENT_T event;
 };
 
-struct cond_t_s
+typedef struct cond_t_s
 {
   MUTEX_T lock;
-  struct cond_t_queue *head, *tail
+  struct cond_t_queue *head, *tail;
 } COND_T;
 
 #define COND_T struct cond_t_s
@@ -221,6 +222,7 @@ struct thread_state {
   char swapped;
   char status;
   COND_T status_change;
+  THREAD_T id;
 
   /* Swapped variables */
   struct svalue *sp,*evaluator_stack;