diff --git a/.gitattributes b/.gitattributes
index 0d8129bf23f40ecd4d2fb36cfe5e153d02f59f70..4aeb7164f77aae434f55acfa9179911d8ed62436 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -743,6 +743,7 @@ testfont binary
 /src/peep.c foreign_ident
 /src/peep.h foreign_ident
 /src/peep.in foreign_ident
+/src/pike_compiler.h foreign_ident
 /src/pike_cpulib.c foreign_ident
 /src/pike_cpulib.h foreign_ident
 /src/pike_dlfcn.h foreign_ident
diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 71aed750e99d1234062aecb7f5c20e3bd11535ba..3a258a571689f143d3527c999d6e35b8149d794d 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: builtin_functions.c,v 1.651 2008/01/29 20:10:06 grubba Exp $
+|| $Id: builtin_functions.c,v 1.652 2008/04/14 10:14:35 grubba Exp $
 */
 
 #include "global.h"
@@ -44,6 +44,7 @@
 #include "docode.h"
 #include "lex.h"
 #include "pike_float.h"
+#include "pike_compiler.h"
 
 #ifdef HAVE_POLL
 #ifdef HAVE_POLL_H
@@ -1463,6 +1464,8 @@ PMOD_EXPORT void f_zero_type(INT32 args)
 
 static int generate_zero_type(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
+  CHECK_COMPILER();
   if(count_args(CDR(n)) != 1) return 0;
   if(do_docode(CDR(n),DO_NOT_COPY) != 1)
     Pike_fatal("Count args was wrong in generate_zero_type().\n");
@@ -2386,9 +2389,24 @@ PMOD_EXPORT void f_all_constants(INT32 args)
  */
 PMOD_EXPORT void f_get_active_compilation_handler(INT32 args)
 {
+  struct compilation *c = NULL;
+
+  if (compilation_program) {
+    struct pike_frame *compiler_frame = Pike_fp;
+
+    while (compiler_frame &&
+	   (compiler_frame->context->prog != compilation_program)) {
+      compiler_frame = compiler_frame->next;
+    }
+
+    if (compiler_frame) {
+      c = (struct compilation *)compiler_frame->current_storage;
+    }
+  }
+  
   pop_n_elems(args);
-  if (compat_handler) {
-    ref_push_object(compat_handler);
+  if (c && c->compat_handler) {
+    ref_push_object(c->compat_handler);
   } else {
     push_int(0);
   }
@@ -2408,9 +2426,24 @@ PMOD_EXPORT void f_get_active_compilation_handler(INT32 args)
  */
 PMOD_EXPORT void f_get_active_error_handler(INT32 args)
 {
+  struct compilation *c = NULL;
+
+  if (compilation_program) {
+    struct pike_frame *compiler_frame = Pike_fp;
+
+    while (compiler_frame &&
+	   (compiler_frame->context->prog != compilation_program)) {
+      compiler_frame = compiler_frame->next;
+    }
+
+    if (compiler_frame) {
+      c = (struct compilation *)compiler_frame->current_storage;
+    }
+  }
+  
   pop_n_elems(args);
-  if (error_handler) {
-    ref_push_object(error_handler);
+  if (c && c->handler) {
+    ref_push_object(c->handler);
   } else {
     push_int(0);
   }
@@ -2550,6 +2583,8 @@ static node *optimize_this_object(node *n)
 static int generate_this_object(node *n)
 {
   int level;
+  struct compilation *c = THIS_COMPILATION;
+  CHECK_COMPILER();
 
   if (CDR (n)) {
     if (CDR (n)->token != F_CONSTANT)
@@ -4076,62 +4111,14 @@ node *optimize_replace(node *n)
  */
 PMOD_EXPORT void f_compile(INT32 args)
 {
-  struct program *p=0;
-  struct object *o;
-  struct object *placeholder=0;
-  int major=-1;
-  int minor=-1;
-
-
-  check_all_args("compile",args,
-		 BIT_STRING,
-		 BIT_VOID | BIT_INT | BIT_OBJECT,
-		 BIT_VOID | BIT_INT,
-		 BIT_VOID | BIT_INT,
-		 BIT_VOID | BIT_INT | BIT_PROGRAM,
-		 BIT_VOID | BIT_INT | BIT_OBJECT,
-		 0);
-
-  check_c_stack(65536);
-
-  o=0;
-  switch(args)
-  {
-    case 3:
-      SIMPLE_BAD_ARG_ERROR("compile", 4, "int");
-    default:
-      if(Pike_sp[5-args].type == T_OBJECT) {
-	if (Pike_sp[5-args].subtype) {
-	  Pike_error("compile: "
-		     "Subtyped placeholder objects are not supported yet.\n");
-	}
-	placeholder=Pike_sp[5-args].u.object;
-      }
-
-    case 5:
-      if(Pike_sp[4-args].type == T_PROGRAM)
-	p=Pike_sp[4-args].u.program;
+  struct object *ce = clone_object(compilation_program, 0);
+  ONERROR err;
 
-    case 4:
-      major=Pike_sp[2-args].u.integer;
-      minor=Pike_sp[3-args].u.integer;
-      
-    case 2:
-      if(Pike_sp[1-args].type == T_OBJECT) {
-	if (Pike_sp[1-args].subtype) {
-	  Pike_error("compile: "
-		     "Subtyped handler objects are not supported yet.\n");
-	}
-	o=Pike_sp[1-args].u.object;
-      }
-      
-    case 0: case 1: break;
-  }
+  SET_ONERROR(err, do_free_object, ce);
 
-  p = compile(Pike_sp[-args].u.string, o, major, minor, p, placeholder);
+  apply_low(ce, CE_COMPILE_FUN_NUM, args);
 
-  pop_n_elems(args);
-  push_program(p);
+  CALL_AND_UNSET_ONERROR(err);
 }
 
 
diff --git a/src/compilation.h b/src/compilation.h
index ed13e0f46468ea2f2d74e2acd3ed105c72c08385..64c3840af61f2b623e3f030a5e6261811f7bdcf3 100644
--- a/src/compilation.h
+++ b/src/compilation.h
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: compilation.h,v 1.34 2008/04/10 10:42:29 grubba Exp $
+|| $Id: compilation.h,v 1.35 2008/04/14 10:14:35 grubba Exp $
 */
 
 /*
@@ -97,6 +97,47 @@
 #endif
 
 
+#ifdef INIT
+#define IMEMBER(X,Y,Z) MEMCPY((char *)&(c->Y), (char *)&(Pike_compiler->Y), sizeof(c->Y));
+#define STACKMEMBER(X,Y,Z) (c->Y=Pike_compiler->Y);
+#define ZMEMBER(X,Y,Z) MEMSET((char *)&(c->Y), 0, sizeof(c->Y));
+#define SNAME(X,Y) { \
+      c->previous = Pike_compiler;
+#define SEND \
+      Pike_compiler = c; \
+      }
+
+#endif
+
+
+#ifdef EXIT
+#define IMEMBER(X,Y,Z) 
+#define ZMEMBER(X,Y,Z) 
+
+#define STACKMEMBER(X,Y,Z) DO_DEBUG_CODE( \
+    if(c->Y < oLd->Y) \
+      Pike_fatal("Stack " #Y " shrunk %ld steps compilation, currently: %p.\n", \
+            PTRDIFF_T_TO_LONG(oLd->Y - c->Y), c->Y); )
+
+#define SNAME(X,Y) { \
+    struct X *oLd = c->previous;
+
+#define SEND							\
+    if (Pike_compiler == c) {					\
+      Pike_compiler=oLd;					\
+    } else {							\
+      struct program_state *tmp = Pike_compiler;		\
+      while (tmp && (tmp->previous != c))			\
+        tmp = tmp->previous;					\
+      if (tmp) tmp->previous = oLd;				\
+      else Pike_fatal("Lost track of compiler_state %p\n", c);	\
+    }								\
+  }
+#undef PCODE
+#define PCODE(X) X
+#endif
+
+
 #ifdef PIKE_DEBUG
 #define STRMEMBER(X,Y) \
   PCODE(if(Pike_compiler->X) Pike_fatal("Variable " #X " not deallocated properly.\n");) \
@@ -144,6 +185,8 @@
 
 #undef EXTERN
 #undef STRUCT
+#undef EXIT
+#undef INIT
 #undef PUSH
 #undef POP
 #undef DECLARE
diff --git a/src/docode.c b/src/docode.c
index c4b5efb837fd081bb67a8025cc1489ee7922493f..320d5ce33b8aa98c994b9eed5479a667daddd541 100644
--- a/src/docode.c
+++ b/src/docode.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: docode.c,v 1.196 2008/03/22 13:22:20 grubba Exp $
+|| $Id: docode.c,v 1.197 2008/04/14 10:14:35 grubba Exp $
 */
 
 #include "global.h"
@@ -27,6 +27,7 @@
 #include "lex.h"
 #include "mapping.h"
 #include "multiset.h"
+#include "pike_compiler.h"
 
 static int do_docode2(node *n, int flags);
 
@@ -187,6 +188,7 @@ int alloc_label(void) { return ++label_no; }
 
 int do_jump(int token,INT32 lbl)
 {
+  struct compilation *c = THIS_COMPILATION;
   if(lbl==-1) lbl=alloc_label();
   emit1(token, lbl);
   return lbl;
@@ -201,6 +203,7 @@ static int lbl_cache[LBLCACHESIZE];
 
 static int do_branch(INT32 lbl)
 {
+  struct compilation *c = THIS_COMPILATION;
   if(lbl==-1)
   {
     lbl=alloc_label();
@@ -232,6 +235,7 @@ static int do_branch(INT32 lbl)
 
 static void low_insert_label(int lbl)
 {
+  struct compilation *c = THIS_COMPILATION;
   lbl_cache[ lbl % LBLCACHESIZE ] = CURRENT_INSTR;
   emit1(F_LABEL, lbl);
 }
@@ -245,6 +249,7 @@ static int ins_label(int lbl)
 
 void do_pop(int x)
 {
+  struct compilation *c = THIS_COMPILATION;
 #ifdef PIKE_DEBUG
   if (x < 0) Pike_fatal("Cannot do pop of %d args.\n", x);
 #endif
@@ -259,22 +264,26 @@ void do_pop(int x)
 
 static void do_pop_mark(void *ignored)
 {
+  struct compilation *c = THIS_COMPILATION;
   emit0(F_POP_MARK);
 }
 
 static void do_pop_to_mark(void *ignored)
 {
+  struct compilation *c = THIS_COMPILATION;
   emit0(F_POP_TO_MARK);
 }
 
 static void do_cleanup_synch_mark(void)
 {
+  struct compilation *c = THIS_COMPILATION;
   if (d_flag > 2)
     emit0(F_CLEANUP_SYNCH_MARK);
 }
 
 static void do_escape_catch(void)
 {
+  struct compilation *c = THIS_COMPILATION;
   emit0(F_ESCAPE_CATCH);
 }
 
@@ -284,16 +293,17 @@ int do_docode(node *n, int flags)
 {
   int i;
   int stack_depth_save = current_stack_depth;
-  int save_current_line=lex.current_line;
+  struct compilation *c = THIS_COMPILATION;
+  int save_current_line = c->lex.current_line;
   if(!n) return 0;
-  lex.current_line=n->line_number;
+  c->lex.current_line=n->line_number;
 #ifdef PIKE_DEBUG
   if (current_stack_depth == -4711) Pike_fatal("do_docode() used outside docode().\n");
 #endif
   i=do_docode2(n, flags);
   current_stack_depth = stack_depth_save + i;
 
-  lex.current_line=save_current_line;
+  c->lex.current_line=save_current_line;
   return i;
 }
 
@@ -312,9 +322,9 @@ static void code_expression(node *n, int flags, char *err)
   case 1: return;
   case 2:
     Pike_fatal("Internal compiler error (%s), line %ld, file %s\n",
-	  err,
-	  (long)lex.current_line,
-	  lex.current_file?lex.current_file->str:"Unknown");
+	       err,
+	       (long)THIS_COMPILATION->lex.current_line,
+	       THIS_COMPILATION->lex.current_file->str);
   }
 }
 
@@ -412,6 +422,7 @@ static INT32 count_cases(node *n)
 
 int generate_call_function(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   emit0(F_MARK);
   PUSH_CLEANUP_FRAME(do_pop_mark, 0);
   do_docode(CDR(n),DO_NOT_COPY);
@@ -433,6 +444,7 @@ static INLINE struct compiler_frame *find_local_frame(INT32 depth)
 static int do_lfun_call(int id, node *args)
 {
 #if 1
+  struct compilation *c = THIS_COMPILATION;
   struct reference *ref =
     Pike_compiler->new_program->identifier_references + id;
 
@@ -509,6 +521,7 @@ static int do_lfun_call(int id, node *args)
 static void emit_apply_builtin(char *func)
 {
   INT32 tmp1;
+  struct compilation *c = THIS_COMPILATION;
   struct pike_string *n1=make_shared_string(func);
   node *n=find_module_identifier(n1,0);
   free_string(n1);
@@ -535,6 +548,7 @@ static void emit_apply_builtin(char *func)
 static int do_encode_automap_arg_list(node *n,
 				      int flags)
 {
+  struct compilation *c = THIS_COMPILATION;
   int stack_depth_save = current_stack_depth;
   if(!n) return 0;
   switch(n->token)
@@ -572,6 +586,7 @@ static int do_encode_automap_arg_list(node *n,
 static void emit_builtin_svalue(char *func)
 {
   INT32 tmp1;
+  struct compilation *c = THIS_COMPILATION;
   struct pike_string *n1=make_shared_string(func);
   node *n=find_module_identifier(n1,0);
   free_string(n1);
@@ -594,6 +609,7 @@ static void emit_builtin_svalue(char *func)
 
 static void emit_range (node *n DO_IF_DEBUG (COMMA int num_args))
 {
+  struct compilation *c = THIS_COMPILATION;
   node *low = CADR (n), *high = CDDR (n);
   int bound_types;
 
@@ -640,6 +656,7 @@ static void emit_range (node *n DO_IF_DEBUG (COMMA int num_args))
 
 static void emit_multi_assign(node *vals, node *vars, int no)
 {
+  struct compilation *c = THIS_COMPILATION;
   node *var;
   node *val;
   node **valp = my_get_arg(&vals, no);
@@ -762,6 +779,7 @@ static void emit_multi_assign(node *vals, node *vars, int no)
 
 static int do_docode2(node *n, int flags)
 {
+  struct compilation *c = THIS_COMPILATION;
   ptrdiff_t tmp1,tmp2,tmp3;
   int ret;
 
@@ -2128,7 +2146,7 @@ static int do_docode2(node *n, int flags)
 	      if (!match_types(case_val->type, current_switch.type)) {
 		yytype_error("Type mismatch in case.",
 			     current_switch.type, case_val->type, 0);
-	      } else if (lex.pragmas & ID_STRICT_TYPES) {
+	      } else if (c->lex.pragmas & ID_STRICT_TYPES) {
 		yytype_error("Type mismatch in case.",
 			     current_switch.type, case_val->type, YYTE_IS_WARNING);
 	      }
@@ -2261,11 +2279,11 @@ static int do_docode2(node *n, int flags)
       struct statement_label_name *lbl_name;
       for (lbl_name = label->name; lbl_name; lbl_name = lbl_name->next)
 	if (lbl_name->str == name.str) {
-	  INT32 save_line = lex.current_line;
-	  lex.current_line = name.line_number;
+	  INT32 save_line = c->lex.current_line;
+	  c->lex.current_line = name.line_number;
 	  my_yyerror("Duplicate nested labels, previous one on line %d.",
 		     lbl_name->line_number);
-	  lex.current_line = save_line;
+	  c->lex.current_line = save_line;
 	  goto label_check_done;
 	}
     }
@@ -2657,6 +2675,7 @@ static int do_docode2(node *n, int flags)
 /* Used to generate code for functions. */
 INT32 do_code_block(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   INT32 entry_point;
 #ifdef PIKE_DEBUG
   if (current_stack_depth != -4711) Pike_fatal("Reentrance in do_code_block().\n");
diff --git a/src/docode.h b/src/docode.h
index bc3ee3aa8587a444e7f15fae2a79bd836b2d731b..c27f3c9febe665c03fc42ba92004515156792d4c 100644
--- a/src/docode.h
+++ b/src/docode.h
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: docode.h,v 1.19 2003/11/19 17:19:29 grubba Exp $
+|| $Id: docode.h,v 1.20 2008/04/14 10:14:38 grubba Exp $
 */
 
 #ifndef DOCODE_H
@@ -17,9 +17,9 @@
 
 #define WANT_LVALUE (DO_LVALUE | DO_INDIRECT)
 
-#define emit0(X)     insert_opcode0((X),lex.current_line, lex.current_file)
-#define emit1(X,Y)   insert_opcode1((X),(Y),lex.current_line, lex.current_file)
-#define emit2(X,Y,Z) insert_opcode2((X),(Y),(Z),lex.current_line, lex.current_file)
+#define emit0(X)     insert_opcode0((X),c->lex.current_line, c->lex.current_file)
+#define emit1(X,Y)   insert_opcode1((X),(Y),c->lex.current_line, c->lex.current_file)
+#define emit2(X,Y,Z) insert_opcode2((X),(Y),(Z),c->lex.current_line, c->lex.current_file)
 
 /* Prototypes begin here */
 void upd_int(int offset, INT32 tmp);
diff --git a/src/dynamic_load.c b/src/dynamic_load.c
index f9a283e432de4cd48abc01a947a40e6fa83a5338..ce9053d84d4155388f2075eb024bde57f985e74f 100644
--- a/src/dynamic_load.c
+++ b/src/dynamic_load.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: dynamic_load.c,v 1.89 2006/07/05 19:06:32 mast Exp $
+|| $Id: dynamic_load.c,v 1.90 2008/04/14 10:14:38 grubba Exp $
 */
 
 #ifdef TESTING
@@ -389,9 +389,7 @@ static void cleanup_compilation(struct compilation_save *save)
   if (p) {
     free_program(p);
   }
-  free_string(lex.current_file);
   compilation_depth = save->compilation_depth;
-  lex = save->lex;
 }
 
 /*! @decl program load_module(string module_name)
@@ -538,9 +536,8 @@ void f_load_module(INT32 args)
   new_module->init=init;
   new_module->exit=exit;
 
-  save.lex = lex;
-  lex.current_line=1;
-  lex.current_file=make_shared_string("-");
+  enter_compiler(new_module->name, 1);
+
   save.compilation_depth=compilation_depth;
   compilation_depth=-1;
   start_new_program();
@@ -570,9 +567,8 @@ void f_load_module(INT32 args)
   pop_n_elems(args);
   {
     struct program *p = end_program();
-    free_string(lex.current_file);
+    exit_compiler();
     compilation_depth = save.compilation_depth;
-    lex = save.lex;
     if (p) {
       if (
 #if 0
diff --git a/src/encode.c b/src/encode.c
index 5f7bb0b868976d811653a0d8ef540466bd7e0ac1..b2cc0a5951c4acb2d3b29ea257484c63f6567269 100644
--- a/src/encode.c
+++ b/src/encode.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: encode.c,v 1.262 2008/02/29 14:27:09 grubba Exp $
+|| $Id: encode.c,v 1.263 2008/04/14 10:14:38 grubba Exp $
 */
 
 #include "global.h"
@@ -30,6 +30,7 @@
 #include "pike_types.h"
 #include "opcodes.h"
 #include "peep.h"
+#include "pike_compiler.h"
 
 /* #define ENCODE_DEBUG */
 
@@ -2413,11 +2414,6 @@ static void cleanup_new_program_decode (int *orig_compilation_depth)
   compilation_depth = *orig_compilation_depth;
 }
 
-static void set_lex_pragmas(ptrdiff_t old_pragmas)
-{
-  lex.pragmas = DO_NOT_WARN((INT32)old_pragmas);
-}
-
 static DECLSPEC(noreturn) void decode_error (struct svalue *decoding,
 					     struct svalue *other,
 					     char *msg, ...)
@@ -3648,7 +3644,8 @@ static void decode_value2(struct decode_data *data)
 	  int entry_type;
 	  INT16 id_flags;
 	  INT16 p_flags;
-	  ptrdiff_t old_pragmas = lex.pragmas;
+	  ptrdiff_t old_pragmas;
+	  struct compilation *c;
 #define FOO(NUMTYPE,Y,ARGTYPE,NAME) \
           NUMTYPE PIKE_CONCAT(local_num_, NAME) = 0;
 #include "program_areas.h"
@@ -3704,11 +3701,15 @@ static void decode_value2(struct decode_data *data)
 	  else
 	    p = NULL;
 
+	  enter_compiler(NULL, 0);
+
+	  c = THIS_COMPILATION;
+
 	  /* We don't want to be affected by #pragma save_parent or
 	   * __pragma_save_parent__.
 	   */
-	  lex.pragmas = (old_pragmas & ~ID_SAVE_PARENT)|ID_DONT_SAVE_PARENT;
-	  SET_ONERROR(err2, set_lex_pragmas, (ptrdiff_t) old_pragmas);
+	  old_pragmas = c->lex.pragmas;
+	  c->lex.pragmas = (old_pragmas & ~ID_SAVE_PARENT)|ID_DONT_SAVE_PARENT;
 
 	  /* Start the new program. */
 	  orig_compilation_depth = compilation_depth;
@@ -4400,8 +4401,7 @@ static void decode_value2(struct decode_data *data)
 	  compilation_depth = orig_compilation_depth;
 	  push_program(p);
 
-	  /* Restore lex.pragmas. */
-	  CALL_AND_UNSET_ONERROR(err2);
+	  exit_compiler();
 
 	  EDB(5, dump_program_tables(p, data->depth));
 #ifdef PIKE_DEBUG
diff --git a/src/language.yacc b/src/language.yacc
index 0bae5b9a2991fe3da196bbbcbc61101d2841cecb..ee7c8e64f1a181949ec1428b7d33e2b82d09a8b0 100644
--- a/src/language.yacc
+++ b/src/language.yacc
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: language.yacc,v 1.410 2008/04/06 11:49:58 grubba Exp $
+|| $Id: language.yacc,v 1.411 2008/04/14 10:14:38 grubba Exp $
 */
 
 %pure_parser
@@ -189,9 +189,10 @@ static void __yy_memcpy(char *to, YY_FROM_CONST char *from,
 }
 
 %{
-/* Needs to be included after YYSTYPE is defined. */
+/* Need to be included after YYSTYPE is defined. */
 #define INCLUDED_FROM_LANGUAGE_YACC
 #include "lex.h"
+#include "pike_compiler.h"
 %}
 
 %{
@@ -948,12 +949,13 @@ def: modifiers optional_attributes type_or_error optional_constant optional_star
     {
       int f;
       node *check_args = NULL;
-      struct pike_string *save_file = lex.current_file;
-      int save_line = lex.current_line;
+      struct compilation *c = THIS_COMPILATION;
+      struct pike_string *save_file = c->lex.current_file;
+      int save_line  = c->lex.current_line;
       int num_required_args = 0;
       struct identifier *i;
-      lex.current_file = $6->current_file;
-      lex.current_line = $6->line_number;
+      c->lex.current_file = $6->current_file;
+      c->lex.current_line = $6->line_number;
 
       if (($1 & ID_EXTERN) && (Pike_compiler->compiler_pass == 1)) {
 	yywarning("Extern declared function definition.");
@@ -1044,8 +1046,8 @@ def: modifiers optional_attributes type_or_error optional_constant optional_star
 	  /* Prepend the arg checking code. */
 	  $13 = mknode(F_COMMA_EXPR, mknode(F_POP_VALUE, check_args, NULL), $13);
 	}
-	lex.current_line = l;
-	lex.current_file = f;
+	c->lex.current_line = l;
+	c->lex.current_file = f;
       }
 
       f=dooptcode($6->u.sval.u.string, $13, $<n>12->u.sval.u.type, $1);
@@ -1073,8 +1075,8 @@ def: modifiers optional_attributes type_or_error optional_constant optional_star
       }
 #endif
 
-      lex.current_line = save_line;
-      lex.current_file = save_file;
+      c->lex.current_line = save_line;
+      c->lex.current_file = save_file;
     } else {
       /* Prototype; don't warn about unused arguments. */
       for (e = Pike_compiler->compiler_frame->current_number_of_locals; e--;) {
@@ -1140,13 +1142,13 @@ def: modifiers optional_attributes type_or_error optional_constant optional_star
   | modifiers
    '{' 
     {
-      $<number>$=lex.pragmas;
-      lex.pragmas|=$1;
+      $<number>$=THIS_COMPILATION->lex.pragmas;
+      THIS_COMPILATION->lex.pragmas|=$1;
     }
       program
    close_brace_or_eof
     {
-      lex.pragmas=$<number>3;
+      THIS_COMPILATION->lex.pragmas=$<number>3;
     }
   ;
 
@@ -1188,7 +1190,7 @@ new_arg_name: type7 optional_dot_dot_dot optional_identifier
     i = add_local_name($3->u.sval.u.string, compiler_pop_type(),0);
     if (i >= 0 &&
 	(!$3->u.sval.u.string->len ||
-	 !(lex.pragmas & ID_STRICT_TYPES))) {
+	 !(THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES))) {
       /* Only warn about unused arguments in strict types mode. */
       Pike_compiler->compiler_frame->variable[i].flags |= LOCAL_VAR_IS_USED;
     }
@@ -1303,7 +1305,8 @@ magic_identifier: TOK_IDENTIFIER
 
 modifiers: modifier_list
  {
-   $$=Pike_compiler->current_modifiers=$1 | (lex.pragmas & ID_MODIFIER_MASK);
+   $$=Pike_compiler->current_modifiers=$1 |
+     (THIS_COMPILATION->lex.pragmas & ID_MODIFIER_MASK);
  }
  ;
 
@@ -1852,7 +1855,7 @@ new_local_name: optional_stars TOK_IDENTIFIER
     while($1--) push_type(T_ARRAY);
     id = add_local_name($2->u.sval.u.string, compiler_pop_type(),0);
     if (id >= 0) {
-      if (!(lex.pragmas & ID_STRICT_TYPES)) {
+      if (!(THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES)) {
 	/* Only warn about unused initialized variables in strict types mode. */
 	Pike_compiler->compiler_frame->variable[id].flags |= LOCAL_VAR_IS_USED;
       }
@@ -1900,7 +1903,7 @@ new_local_name2: TOK_IDENTIFIER
     add_ref($<n>0->u.sval.u.type);
     id = add_local_name($1->u.sval.u.string, $<n>0->u.sval.u.type, 0);
     if (id >= 0) {
-      if (!(lex.pragmas & ID_STRICT_TYPES)) {
+      if (!(THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES)) {
 	/* Only warn about unused initialized variables in strict types mode. */
 	Pike_compiler->compiler_frame->variable[id].flags |= LOCAL_VAR_IS_USED;
       }
@@ -2139,10 +2142,11 @@ lambda: TOK_LAMBDA line_number_info push_compiler_frame1
     struct pike_type *type;
     int f,e;
     struct pike_string *name;
-    struct pike_string *save_file = lex.current_file;
-    int save_line = lex.current_line;
-    lex.current_file = $2->current_file;
-    lex.current_line = $2->line_number;
+    struct compilation *c = THIS_COMPILATION;
+    struct pike_string *save_file = c->lex.current_file;
+    int save_line = c->lex.current_line;
+    c->lex.current_file = $2->current_file;
+    c->lex.current_line = $2->line_number;
 
     debug_malloc_touch($7);
     $7=mknode(F_COMMA_EXPR,$7,mknode(F_RETURN,mkintnode(0),0));
@@ -2212,8 +2216,8 @@ lambda: TOK_LAMBDA line_number_info push_compiler_frame1
     }
     free_string(name);
     free_type(type);
-    lex.current_line = save_line;
-    lex.current_file = save_file;
+    c->lex.current_line = save_line;
+    c->lex.current_file = save_file;
     free_node ($2);
     pop_compiler_frame();
   }
@@ -2306,10 +2310,11 @@ local_function: TOK_IDENTIFIER push_compiler_frame1 func_args
   {
     int localid;
     struct identifier *i=ID_FROM_INT(Pike_compiler->new_program, $<number>4);
-    struct pike_string *save_file = lex.current_file;
-    int save_line = lex.current_line;
-    lex.current_file = $1->current_file;
-    lex.current_line = $1->line_number;
+    struct compilation *c = THIS_COMPILATION;
+    struct pike_string *save_file = c->lex.current_file;
+    int save_line = c->lex.current_line;
+    c->lex.current_file = $1->current_file;
+    c->lex.current_line = $1->line_number;
 
     $5=mknode(F_COMMA_EXPR,$5,mknode(F_RETURN,mkintnode(0),0));
 
@@ -2321,8 +2326,8 @@ local_function: TOK_IDENTIFIER push_compiler_frame1 func_args
 
     i->opt_flags = Pike_compiler->compiler_frame->opt_flags;
 
-    lex.current_line = save_line;
-    lex.current_file = save_file;
+    c->lex.current_line = save_line;
+    c->lex.current_file = save_file;
     pop_compiler_frame();
     free_node($1);
 
@@ -2437,10 +2442,11 @@ local_function2: optional_stars TOK_IDENTIFIER push_compiler_frame1 func_args
   {
     int localid;
     struct identifier *i=ID_FROM_INT(Pike_compiler->new_program, $<number>5);
-    struct pike_string *save_file = lex.current_file;
-    int save_line = lex.current_line;
-    lex.current_file = $2->current_file;
-    lex.current_line = $2->line_number;
+    struct compilation *c = THIS_COMPILATION;
+    struct pike_string *save_file = c->lex.current_file;
+    int save_line = c->lex.current_line;
+    c->lex.current_file = $2->current_file;
+    c->lex.current_line = $2->line_number;
 
     debug_malloc_touch($6);
     $6=mknode(F_COMMA_EXPR,$6,mknode(F_RETURN,mkintnode(0),0));
@@ -2454,8 +2460,8 @@ local_function2: optional_stars TOK_IDENTIFIER push_compiler_frame1 func_args
 
     i->opt_flags = Pike_compiler->compiler_frame->opt_flags;
 
-    lex.current_line = save_line;
-    lex.current_file = save_file;
+    c->lex.current_line = save_line;
+    c->lex.current_file = save_file;
     pop_compiler_frame();
     free_node($2);
 
@@ -2646,8 +2652,8 @@ class: TOK_CLASS line_number_info optional_identifier
   }
   {
     /* Clear scoped modifiers. */
-    $<number>$ = lex.pragmas;
-    lex.pragmas &= ~ID_MODIFIER_MASK;
+    $<number>$ = THIS_COMPILATION->lex.pragmas;
+    THIS_COMPILATION->lex.pragmas &= ~ID_MODIFIER_MASK;
   }
   optional_create_arguments failsafe_program
   {
@@ -2807,7 +2813,7 @@ class: TOK_CLASS line_number_info optional_identifier
     free_node($2);
     free_node($3);
     check_tree($$,0);
-    lex.pragmas = $<number>5;
+    THIS_COMPILATION->lex.pragmas = $<number>5;
   }
   ;
 
@@ -2970,7 +2976,7 @@ optional_else_part: { $$=0; }
 
 safe_lvalue: lvalue
   {
-    if (!(lex.pragmas & ID_STRICT_TYPES) && $1) {
+    if (!(THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES) && $1) {
       if ($1->token == F_ARRAY_LVALUE) {
 	mark_lvalues_as_used(CAR($1));
       } else if (($1->token == F_LOCAL) && !($1->u.integer.b)) {
@@ -3213,7 +3219,7 @@ expr0: expr01
   | bad_expr_ident '=' expr0 { $$=$3; }
   | open_bracket_with_line_info low_lvalue_list ']' '=' expr0
   {
-    if (!(lex.pragmas & ID_STRICT_TYPES)) {
+    if (!(THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES)) {
       mark_lvalues_as_used($2);
     }
     $$=mknode(F_ASSIGN,$5,mknode(F_ARRAY_LVALUE,$2,0));
@@ -3386,10 +3392,11 @@ optional_block: /* EMPTY */ { $$=0; }
     struct pike_type *type;
     int f/*, e */;
     struct pike_string *name;
-    struct pike_string *save_file = lex.current_file;
-    int save_line = lex.current_line;
-    lex.current_file = $2->current_file;
-    lex.current_line = $2->line_number;
+    struct compilation *c = THIS_COMPILATION;
+    struct pike_string *save_file = c->lex.current_file;
+    int save_line = c->lex.current_line;
+    c->lex.current_file = $2->current_file;
+    c->lex.current_line = $2->line_number;
 
     /* block code */
     unuse_modules(Pike_compiler->num_used_modules - $<number>1);
@@ -3443,8 +3450,8 @@ optional_block: /* EMPTY */ { $$=0; }
       $$ = mkidentifiernode(f);
     }
 
-    lex.current_line = save_line;
-    lex.current_file = save_file;
+    c->lex.current_line = save_line;
+    c->lex.current_file = save_file;
     free_node ($2);
     free_string(name);
     free_type(type);
@@ -3489,7 +3496,7 @@ apply:
 implicit_modifiers:
   {
     $$ = Pike_compiler->current_modifiers = ID_STATIC|ID_INLINE|ID_PRIVATE |
-      (lex.pragmas & ID_MODIFIER_MASK);
+      (THIS_COMPILATION->lex.pragmas & ID_MODIFIER_MASK);
   }
   ;
 
@@ -4072,7 +4079,7 @@ catch: TOK_CATCH
 
 sscanf: TOK_SSCANF '(' expr0 ',' expr0 lvalue_list ')'
   {
-    if ($6 && !(lex.pragmas & ID_STRICT_TYPES)) {
+    if ($6 && !(THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES)) {
       mark_lvalues_as_used($6);
     }
     $$=mknode(F_SSCANF,mknode(F_ARG_LIST,$3,$5),$6);
@@ -4311,6 +4318,7 @@ bad_expr_ident:
 
 void low_yyerror(struct pike_string *str)
 {
+  struct compilation *c = THIS_COMPILATION;
   extern int cumulative_parse_error;
 
   STACK_LEVEL_START(0);
@@ -4320,38 +4328,19 @@ void low_yyerror(struct pike_string *str)
     Pike_fatal("Stack error (underflow)\n");
 #endif
 
+  CHECK_COMPILER();
+
   if (Pike_compiler->num_parse_error > 20) return;
   Pike_compiler->num_parse_error++;
   cumulative_parse_error++;
 
-  if ((error_handler && error_handler->prog) || get_master())
-  {
-    if (lex.current_file) {
-      ref_push_string(lex.current_file);
-    } else {
-      /* yyerror() can be called from define_function(), which
-       * can be called by the C module initialization code.
-       */
-      push_empty_string();
-    }
-    push_int(lex.current_line);
-    ref_push_string(str);
-    low_safe_apply_handler("compile_error", error_handler, compat_handler, 3);
-    pop_stack();
-  }else{
-    if (lex.current_file) {
-      (void)fprintf(stderr, "%s:%ld: %s\n",
-		    lex.current_file->str,
-		    (long)lex.current_line,
-		    str->str);
-    } else {
-      (void)fprintf(stderr, "NULL:%ld: %s\n",
-		    (long)lex.current_line,
-		    str->str);
-    }
-    fflush(stderr);
-  }
-
+  push_int(2);	/* ERROR */
+  ref_push_string(c->lex.current_file);
+  push_int(c->lex.current_line);
+  push_constant_text("parse");
+  ref_push_string(str);
+  apply_current(0, 5);	/* report(). */
+  pop_stack();
   STACK_LEVEL_DONE(0);
 }
 
@@ -4376,7 +4365,7 @@ static struct pike_string *get_new_name()
   sprintf(buf,"__lambda_%ld_%ld_line_%d",
 	  (long)Pike_compiler->new_program->id,
 	  (long)(Pike_compiler->local_class_counter++ & 0xffffffff), /* OSF/1 cc bug. */
-	  (int) lex.current_line);
+	  (int) THIS_COMPILATION->lex.current_line);
   return make_shared_string(buf);
 }
 
@@ -4450,9 +4439,9 @@ int low_add_local_name(struct compiler_frame *frame,
     reference_shared_string(str);
     frame->variable[var].def = def;
 
-    frame->variable[var].line=lex.current_line;
-    frame->variable[var].file=lex.current_file;
-    reference_shared_string(lex.current_file);
+    frame->variable[var].line = THIS_COMPILATION->lex.current_line;
+    copy_shared_string(frame->variable[var].file,
+		       THIS_COMPILATION->lex.current_file);
 
     frame->variable[var].flags = 0;
 
@@ -4642,17 +4631,18 @@ static void safe_inc_enum(void)
 
 static int call_handle_import(struct pike_string *s)
 {
+  struct compilation *c = THIS_COMPILATION;
   int args;
 
   ref_push_string(s);
-  ref_push_string(lex.current_file);
-  if (error_handler && error_handler->prog) {
-    ref_push_object(error_handler);
+  ref_push_string(c->lex.current_file);
+  if (c->handler && c->handler->prog) {
+    ref_push_object(c->handler);
     args = 3;
   }
   else args = 2;
 
-  if (safe_apply_handler("handle_import", error_handler, compat_handler,
+  if (safe_apply_handler("handle_import", c->handler, c->compat_handler,
 			 args, BIT_MAPPING|BIT_OBJECT|BIT_PROGRAM|BIT_ZERO))
     if (Pike_sp[-1].type != T_INT)
       return 1;
diff --git a/src/las.c b/src/las.c
index ae592f52ce3ebc79824b81ce3c56e50effcc3ab4..22126237d0b1a3639044de85a5445bb74cdc5038 100644
--- a/src/las.c
+++ b/src/las.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: las.c,v 1.405 2008/02/26 21:51:37 grubba Exp $
+|| $Id: las.c,v 1.406 2008/04/14 10:14:39 grubba Exp $
 */
 
 #include "global.h"
@@ -30,6 +30,7 @@
 #include "opcodes.h"
 #include "pikecode.h"
 #include "gc.h"
+#include "pike_compiler.h"
 #include "block_alloc.h"
 
 /* Define this if you want the optimizer to be paranoid about aliasing
@@ -375,7 +376,7 @@ static int check_node_type(node *n, struct pike_type *t, const char *msg)
     yytype_error(msg, t, n->type, 0);
     return 0;
   }
-  if (lex.pragmas & ID_STRICT_TYPES) {
+  if (THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES) {
     yytype_error(msg, t, n->type, YYTE_IS_WARNING);
   }
   if (runtime_options & RUNTIME_CHECK_TYPES) {
@@ -620,6 +621,8 @@ static node *debug_mkemptynode(void)
 {
   node *res=alloc_node_s();
 
+  CHECK_COMPILER();
+
 #ifdef __CHECKER__
   MEMSET(res, 0, sizeof(node));
 #endif /* __CHECKER__ */
@@ -627,8 +630,8 @@ static node *debug_mkemptynode(void)
   res->refs = 0;
   add_ref(res);	/* For DMALLOC... */
   res->token=0;
-  res->line_number=lex.current_line;
-  copy_shared_string(res->current_file, lex.current_file);
+  res->line_number=THIS_COMPILATION->lex.current_line;
+  copy_shared_string(res->current_file, THIS_COMPILATION->lex.current_file);
   res->type=0;
   res->name=0;
   res->node_info=0;
@@ -3235,6 +3238,7 @@ struct pike_type *new_check_call(struct pike_string *fun_name,
 
 void fix_type_field(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   struct pike_type *type_a, *type_b;
   struct pike_type *old_type;
 
@@ -3365,7 +3369,7 @@ void fix_type_field(node *n)
 	  yytype_error("Bad type in assignment.",
 		       CDR(n)->type, CAR(n)->type, 0);
 	} else {
-	  if (lex.pragmas & ID_STRICT_TYPES) {
+	  if (c->lex.pragmas & ID_STRICT_TYPES) {
 	    struct pike_string *t1 = describe_type(CAR(n)->type);
 	    struct pike_string *t2 = describe_type(CDR(n)->type);
 #ifdef PIKE_DEBUG
@@ -3580,7 +3584,7 @@ void fix_type_field(node *n)
       s = pop_type();
       f = CAR(n)->type?CAR(n)->type:mixed_type_string;
       n->type = check_call(s, f,
-			   (lex.pragmas & ID_STRICT_TYPES) &&
+			   (c->lex.pragmas & ID_STRICT_TYPES) &&
 			   !(n->node_info & OPT_WEAK_TYPE));
       args = count_arguments(s);
       max_args = count_arguments(f);
@@ -3838,7 +3842,7 @@ void fix_type_field(node *n)
 
       n->type = check_call(call_type,
 			   op_node->type ? op_node->type : mixed_type_string,
-			   (lex.pragmas & ID_STRICT_TYPES) &&
+			   (c->lex.pragmas & ID_STRICT_TYPES) &&
 			   !(op_node->node_info & OPT_WEAK_TYPE));
       if (n->type) {
 	/* Type check ok. */
@@ -3902,7 +3906,7 @@ void fix_type_field(node *n)
 	  yytype_error("Type mismatch in case range.",
 		       CAR(n)->type, CDR(n)->type, 0);
 	}
-      } else if ((lex.pragmas & ID_STRICT_TYPES) &&
+      } else if ((c->lex.pragmas & ID_STRICT_TYPES) &&
 		 (CAR(n)->type != CDR(n)->type)) {
 	/* The type should be the same for both CAR & CDR. */
 	if (!pike_types_le(CDR(n)->type, CAR(n)->type)) {
@@ -4016,7 +4020,7 @@ void fix_type_field(node *n)
 		if (!match_types(CADAR(n)->type, index_type)) {
 		  yytype_error("Type mismatch for index in foreach().",
 			       index_type, CADAR(n)->type, 0);
-		} else if (lex.pragmas & ID_STRICT_TYPES) {
+		} else if (c->lex.pragmas & ID_STRICT_TYPES) {
 		  yytype_error("Type mismatch for index in foreach().",
 			       index_type, CADAR(n)->type, YYTE_IS_WARNING);
 		}
@@ -4046,7 +4050,7 @@ void fix_type_field(node *n)
 		if (!match_types(CDDAR(n)->type, value_type)) {
 		  yytype_error("Type mismatch for value in foreach().",
 			       value_type, CDDAR(n)->type, 0);
-		} else if (lex.pragmas & ID_STRICT_TYPES) {
+		} else if (c->lex.pragmas & ID_STRICT_TYPES) {
 		  yytype_error("Type mismatch for value in foreach().",
 			       value_type, CDDAR(n)->type, YYTE_IS_WARNING);
 		}
@@ -4064,7 +4068,7 @@ void fix_type_field(node *n)
 	  if (!pike_types_le(array_zero, CAAR(n)->type)) {
 	    yyerror("Bad argument 1 to foreach().");
 	  } else {
-	    if ((lex.pragmas & ID_STRICT_TYPES) &&
+	    if ((c->lex.pragmas & ID_STRICT_TYPES) &&
 		!pike_types_le(CAAR(n)->type, array_type_string)) {
 	      struct pike_string *t = describe_type(CAAR(n)->type);
 	      yywarning("Argument 1 to foreach() is not always an array.");
@@ -4944,9 +4948,10 @@ static node *localopt(node *n)
 static void optimize(node *n)
 {
   node *tmp1, *tmp2, *tmp3;
+  struct compilation *c = THIS_COMPILATION;
   struct pike_string *save_file =
-    dmalloc_touch(struct pike_string *, lex.current_file);
-  INT32 save_line = lex.current_line;
+    dmalloc_touch(struct pike_string *, c->lex.current_file);
+  INT32 save_line = c->lex.current_line;
 
   do
   {
@@ -4963,8 +4968,8 @@ static void optimize(node *n)
       continue;
     }
 
-    lex.current_line = n->line_number;
-    lex.current_file = dmalloc_touch(struct pike_string *, n->current_file);
+    c->lex.current_line = n->line_number;
+    c->lex.current_file = dmalloc_touch(struct pike_string *, n->current_file);
 
     n->tree_info = n->node_info;
     if(car_is_node(n)) n->tree_info |= CAR(n)->tree_info;
@@ -5078,8 +5083,8 @@ static void optimize(node *n)
     n=n->parent;
   }while(n);
 
-  lex.current_line = save_line;
-  lex.current_file = dmalloc_touch(struct pike_string *, save_file);
+  c->lex.current_line = save_line;
+  c->lex.current_file = dmalloc_touch(struct pike_string *, save_file);
 }
 
 void optimize_node(node *n)
@@ -5392,6 +5397,8 @@ int dooptcode(struct pike_string *name,
   int args, vargs, ret;
   struct svalue *foo;
 
+  CHECK_COMPILER();
+
   optimize_node(n);
 
   check_tree(n, 0);
@@ -5451,10 +5458,12 @@ int dooptcode(struct pike_string *name,
 	   tmp.c_fun != f_backtrace)
 	{
 #ifdef PIKE_DEBUG
+	  struct compilation *c = THIS_COMPILATION;
+
 	  if(a_flag > 1)
 	    fprintf(stderr,"%s:%d: IDENTIFIER OPTIMIZATION %s == %s\n",
-		    lex.current_file->str,
-		    lex.current_line,
+		    c->lex.current_file->str,
+		    c->lex.current_line,
 		    name->str,
 		    foo->u.efun->name->str);
 #endif
diff --git a/src/lex.c b/src/lex.c
index 74edceed54885ec251e4e687670eb92a42dfc275..0ccfea6a807a6e9abceb7571aff6a2a2b8c9af01 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -2,20 +2,20 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: lex.c,v 1.120 2004/11/01 01:33:30 mast Exp $
+|| $Id: lex.c,v 1.121 2008/04/14 10:14:40 grubba Exp $
 */
 
 #include "global.h"
 #include "lex.h"
 #include "stuff.h"
 #include "bignum.h"
+#include "pike_compiler.h"
+#include "interpret.h"
 
 #include <ctype.h>
 
 #define LEXDEBUG 0
 
-struct lex lex;
-
 /* Must do like this since at least gcc is a little too keen on
  * optimizing INT_TYPE_MUL_OVERFLOW otherwise. */
 static unsigned INT32 eight = 8, sixteen = 16, ten = 10;
@@ -34,9 +34,12 @@ static unsigned INT32 eight = 8, sixteen = 16, ten = 10;
 
 int yylex(YYSTYPE *yylval)
 {
+  struct lex *lex;
+  CHECK_COMPILER();
+  lex = &THIS_COMPILATION->lex;
 #if LEXDEBUG>8
   fprintf(stderr, "YYLEX: Calling lexer at 0x%08lx\n",
-	  (long)lex.current_lexer);
+	  (long)lex->current_lexer);
 #endif /* LEXDEBUG > 8 */
-  return(lex.current_lexer(yylval));
+  return(lex->current_lexer(lex, yylval));
 }
diff --git a/src/lex.h b/src/lex.h
index 91e7e518fc6375d2e2b3ef4319eedec858a22562..df6efe6106eaaaeb7fdb74221bc58160e7334fe2 100644
--- a/src/lex.h
+++ b/src/lex.h
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: lex.h,v 1.35 2004/11/01 01:33:30 mast Exp $
+|| $Id: lex.h,v 1.36 2008/04/14 10:14:40 grubba Exp $
 */
 
 #ifndef LEX_H
@@ -26,20 +26,18 @@ struct lex
   INT32 current_line;
   INT32 pragmas;
   struct pike_string *current_file;
-  int (*current_lexer)(YYSTYPE *);
+  int (*current_lexer)(struct lex *, YYSTYPE *);
 };
 
-extern struct lex lex;
-
 /* Prototypes begin here */
 
 int parse_esc_seq0 (p_wchar0 *buf, int *chr, ptrdiff_t *len);
 int parse_esc_seq1 (p_wchar1 *buf, int *chr, ptrdiff_t *len);
 int parse_esc_seq2 (p_wchar2 *buf, int *chr, ptrdiff_t *len);
 
-int yylex0(YYSTYPE *);
-int yylex1(YYSTYPE *);
-int yylex2(YYSTYPE *);
+int yylex0(struct lex *, YYSTYPE *);
+int yylex1(struct lex *, YYSTYPE *);
+int yylex2(struct lex *, YYSTYPE *);
 
 /* Prototypes end here */
 
diff --git a/src/lexer.h b/src/lexer.h
index f6b7988c26f093e783570f7db6b4d647bd85de46..c85e1546bc304ed14f5a8a3175bdb62dbaed0279 100644
--- a/src/lexer.h
+++ b/src/lexer.h
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: lexer.h,v 1.65 2008/04/04 13:16:46 grubba Exp $
+|| $Id: lexer.h,v 1.66 2008/04/14 10:14:40 grubba Exp $
 */
 
 /*
@@ -30,17 +30,17 @@
 
 #define WCHAR p_wchar0
 
-#define LOOK() EXTRACT_UCHAR(lex.pos)
-#define GETC() EXTRACT_UCHAR(lex.pos++)
-#define SKIP() lex.pos++
-#define SKIPN(N) (lex.pos += (N))
+#define LOOK() EXTRACT_UCHAR(lex->pos)
+#define GETC() EXTRACT_UCHAR(lex->pos++)
+#define SKIP() lex->pos++
+#define SKIPN(N) (lex->pos += (N))
 
 #define READBUF(X) do {				\
   register int C;				\
-  buf = lex.pos;				\
+  buf = lex->pos;				\
   while((C = LOOK()) && (X))			\
-    lex.pos++;					\
-  len = (size_t)(lex.pos - buf);		\
+    lex->pos++;					\
+  len = (size_t)(lex->pos - buf);		\
 } while(0)
 
 #define TWO_CHAR(X,Y) ((X)<<8)+(Y)
@@ -60,17 +60,17 @@
 
 #else /* SHIFT != 0 */
 
-#define LOOK() INDEX_CHARP(lex.pos,0,SHIFT)
-#define SKIP() (lex.pos += (1<<SHIFT))
-#define SKIPN(N) (lex.pos += ((N)<<SHIFT))
-#define GETC() (SKIP(),INDEX_CHARP(lex.pos-(1<<SHIFT),0,SHIFT))
+#define LOOK() INDEX_CHARP(lex->pos,0,SHIFT)
+#define SKIP() (lex->pos += (1<<SHIFT))
+#define SKIPN(N) (lex->pos += ((N)<<SHIFT))
+#define GETC() (SKIP(),INDEX_CHARP(lex->pos-(1<<SHIFT),0,SHIFT))
 
 #define READBUF(X) do {				\
   register int C;				\
-  buf = lex.pos;				\
+  buf = lex->pos;				\
   while((C = LOOK()) && (X))			\
     SKIP();					\
-  len = (size_t)((lex.pos - buf) >> SHIFT);	\
+  len = (size_t)((lex->pos - buf) >> SHIFT);	\
 } while(0)
 
 #define TWO_CHAR(X,Y) ((X)<<8)+(Y)
@@ -314,11 +314,11 @@ int parse_esc_seq (WCHAR *buf, int *chr, ptrdiff_t *len)
   return 0;
 }
 
-static int char_const(void)
+static int char_const(struct lex *lex)
 {
   int c;
   ptrdiff_t l;
-  switch (parse_esc_seq ((WCHAR *)lex.pos, &c, &l)) {
+  switch (parse_esc_seq ((WCHAR *)lex->pos, &c, &l)) {
     case 0:
       break;
     case 1:
@@ -326,11 +326,11 @@ static int char_const(void)
       return '\r';
     case 2:
       SKIP();
-      lex.current_line++;
+      lex->current_line++;
       return '\n';
     case 3:
       yyerror("Unexpected end of file.");
-      lex.pos -= (1<<SHIFT);
+      lex->pos -= (1<<SHIFT);
       return 0;
     case 4: case 5: case 6:
       yywarning ("Too large character value in escape.");
@@ -347,7 +347,7 @@ static int char_const(void)
   return c;
 }
 
-static struct pike_string *readstring(void)
+static struct pike_string *readstring(struct lex *lex)
 {
   int c;
   struct string_builder tmp;
@@ -374,17 +374,17 @@ static struct pike_string *readstring(void)
     switch(c=GETC())
     {
     case 0:
-      lex.pos -= (1<<SHIFT);
+      lex->pos -= (1<<SHIFT);
       yyerror("End of file in string.");
       break;
       
     case '\n':
-      lex.current_line++;
+      lex->current_line++;
       yyerror("Newline in string.");
       break;
       
     case '\\':
-      string_builder_putchar(&tmp,char_const());
+      string_builder_putchar(&tmp, char_const(lex));
       continue;
       
     case '"':
@@ -403,8 +403,8 @@ static struct pike_string *readstring(void)
 
 
 
-static int low_yylex(YYSTYPE *);
-int yylex(YYSTYPE *yylval)
+static int low_yylex(struct lex *lex, YYSTYPE *);
+int yylex(struct lex *lex, YYSTYPE *yylval)
 #if LEXDEBUG>4
 {
   int t;
@@ -412,7 +412,7 @@ int yylex(YYSTYPE *yylval)
   fprintf(stderr, "YYLEX:\n");
 #endif /* LEXDEBUG>8 */
 
-  t=low_yylex(yylval);
+  t=low_yylex(lex, yylval);
   if(t<256)
   {
     fprintf(stderr,"YYLEX: '%c' (%d) at %s:%d\n",t,t,lex.current_file->str,lex.current_line);
@@ -422,7 +422,7 @@ int yylex(YYSTYPE *yylval)
   return t;
 }
 
-static int low_yylex(YYSTYPE *yylval)
+static int low_yylex(struct lex *lex, YYSTYPE *yylval)
 #endif /* LEXDEBUG>4 */
 {
   INT32 c;
@@ -442,7 +442,7 @@ static int low_yylex(YYSTYPE *yylval)
 
     if((c>'9') && lex_isidchar(c))
     {
-      lex.pos -= (1<<SHIFT);
+      lex->pos -= (1<<SHIFT);
       READBUF(lex_isidchar(C));
 
       PIKE_MEM_WO_RANGE (yylval, sizeof (YYSTYPE));
@@ -609,8 +609,8 @@ static int low_yylex(YYSTYPE *yylval)
     switch(c)
     {
     case 0:
-      lex.pos -= (1<<SHIFT);
-      if(lex.end != lex.pos)
+      lex->pos -= (1<<SHIFT);
+      if(lex->end != lex->pos)
 	yyerror("Illegal character (NUL)");
 
 #ifdef TOK_LEX_EOF
@@ -620,7 +620,7 @@ static int low_yylex(YYSTYPE *yylval)
 #endif /* TOK_LEX_EOF */
 
     case '\n':
-      lex.current_line++;
+      lex->current_line++;
       continue;
 
     case 0x1b: case 0x9b:	/* ESC or CSI */
@@ -648,22 +648,22 @@ static int low_yylex(YYSTYPE *yylval)
       {
       case '0': case '1': case '2': case '3': case '4':
       case '5': case '6': case '7': case '8': case '9':
-	lex.current_line=lex_atoi(buf)-1;
+	lex->current_line=lex_atoi(buf)-1;
 	SKIPSPACE();
 	if(GOBBLE('"'))
 	{
-	  struct pike_string *tmp=readstring();
-	  free_string(lex.current_file);
-	  lex.current_file = dmalloc_touch(struct pike_string *, tmp);
+	  struct pike_string *tmp=readstring(lex);
+	  free_string(lex->current_file);
+	  lex->current_file = dmalloc_touch(struct pike_string *, tmp);
 	}
 	if (Pike_compiler->compiler_pass == 1 &&
 	    !Pike_compiler->new_program->num_linenumbers) {
 	  /* A nested program will always get an entry right away in
 	   * language.yacc. */
-	  store_linenumber(0, lex.current_file);
+	  store_linenumber(0, lex->current_file);
 #ifdef DEBUG_MALLOC
-	  if(strcmp(lex.current_file->str,"-"))
-	    debug_malloc_name(Pike_compiler->new_program, lex.current_file->str, 0);
+	  if(strcmp(lex->current_file->str,"-"))
+	    debug_malloc_name(Pike_compiler->new_program, lex->current_file->str, 0);
 #endif
 	}
 	break;
@@ -675,23 +675,23 @@ static int low_yylex(YYSTYPE *yylval)
 	  READBUF(C!='\n');
 	  if (ISWORD("all_inline"))
 	  {
-	    lex.pragmas |= ID_INLINE;
+	    lex->pragmas |= ID_INLINE;
 	  }
 	  else if (ISWORD("all_final") || ISWORD("all_nomask"))
 	  {
-	    lex.pragmas |= ID_FINAL;
+	    lex->pragmas |= ID_FINAL;
 	  }
 	  else if (ISWORD("strict_types"))
 	  {
-	    lex.pragmas |= ID_STRICT_TYPES;
+	    lex->pragmas |= ID_STRICT_TYPES;
 	  }
 	  else if (ISWORD("save_parent"))
 	  {
-	    lex.pragmas |= ID_SAVE_PARENT;
+	    lex->pragmas |= ID_SAVE_PARENT;
 	  }
 	  else if (ISWORD("dont_save_parent"))
 	  {
-	    lex.pragmas |= ID_DONT_SAVE_PARENT;
+	    lex->pragmas |= ID_DONT_SAVE_PARENT;
 	  }
 	  break;
 	}
@@ -763,12 +763,12 @@ static int low_yylex(YYSTYPE *yylval)
       switch(c=GETC())
       {
       case 0:
-	lex.pos -= (1<<SHIFT);
+	lex->pos -= (1<<SHIFT);
 	yyerror("Unexpected end of file\n");
 	break;
 
       case '\\':
-	c = char_const();
+	c = char_const(lex);
 	break;
 
       case '\'':
@@ -783,7 +783,7 @@ static int low_yylex(YYSTYPE *yylval)
 	
     case '"':
     {
-      struct pike_string *s=readstring();
+      struct pike_string *s=readstring(lex);
       yylval->n=mkstrnode(s);
       free_string(s);
       return TOK_STRING;
@@ -799,10 +799,10 @@ static int low_yylex(YYSTYPE *yylval)
 	if(GOBBLE('.')) return TOK_DOT_DOT_DOT;
 	return TOK_DOT_DOT;
       }
-      if (((c = INDEX_CHARP(lex.pos, 0, SHIFT)) <= '9') &&
+      if (((c = INDEX_CHARP(lex->pos, 0, SHIFT)) <= '9') &&
 	  (c >= '0')) {
 	/* FIXME: Only in Pike 7.7 and later mode? */
-	lex.pos -= (1<<SHIFT);
+	lex->pos -= (1<<SHIFT);
 	goto read_float;
       }
       return '.';
@@ -825,8 +825,8 @@ static int low_yylex(YYSTYPE *yylval)
 	sval.subtype = NUMBER_NUMBER;
 	sval.u.integer = 0;
 	wide_string_to_svalue_inumber(&sval,
-				      lex.pos,
-				      (void **)&lex.pos,
+				      lex->pos,
+				      (void **)&lex->pos,
 				      base,
 				      0,
 				      SHIFT);
@@ -845,23 +845,23 @@ static int low_yylex(YYSTYPE *yylval)
       long l = 0;
       struct svalue sval;
 
-      lex.pos -= (1<<SHIFT);
-      if(INDEX_CHARP(lex.pos, 0, SHIFT)=='0')
-	for(l=1;INDEX_CHARP(lex.pos, l, SHIFT)<='9' &&
-	      INDEX_CHARP(lex.pos, l, SHIFT)>='0';l++)
-	  if(INDEX_CHARP(lex.pos, l, SHIFT)>='8')
+      lex->pos -= (1<<SHIFT);
+      if(INDEX_CHARP(lex->pos, 0, SHIFT)=='0')
+	for(l=1;INDEX_CHARP(lex->pos, l, SHIFT)<='9' &&
+	      INDEX_CHARP(lex->pos, l, SHIFT)>='0';l++)
+	  if(INDEX_CHARP(lex->pos, l, SHIFT)>='8')
 	    my_yyerror("Illegal octal digit '%c'.",
-		       INDEX_CHARP(lex.pos, l, SHIFT));
+		       INDEX_CHARP(lex->pos, l, SHIFT));
 
     read_float:
-      f=lex_strtod(lex.pos, &p1);
+      f=lex_strtod(lex->pos, &p1);
 
       sval.type = PIKE_T_INT;
       sval.subtype = NUMBER_NUMBER;
       sval.u.integer = 0;      
 
       wide_string_to_svalue_inumber(&sval,
-				    lex.pos,
+				    lex->pos,
 				    &p2,
 				    0,
 				    0,
@@ -890,7 +890,7 @@ static int low_yylex(YYSTYPE *yylval)
 	    if ((INDEX_CHARP(p3, l, SHIFT) == ':') &&
 		(INDEX_CHARP(p3, l+1, SHIFT) == ':')) {
 	      /* Version prefix. */
-	      lex.pos = p3;
+	      lex->pos = p3;
 	      yylval->n = mkversionnode(major, sval.u.integer);
 	      return TOK_VERSION;
 	    }
@@ -900,12 +900,12 @@ static int low_yylex(YYSTYPE *yylval)
 	yylval->fnum=(FLOAT_TYPE)f;
 #if 0
 	fprintf(stderr, "LEX: \"%.8s\" => %f, %f\n",
-		(char *)lex.pos, f, yylval->fnum);
+		(char *)lex->pos, f, yylval->fnum);
 #endif /* 0 */
-	lex.pos=p1;
+	lex->pos=p1;
 	if (lex_isidchar (LOOK())) {
 	  my_yyerror ("Invalid char '%c' in constant.",
-		      INDEX_CHARP (lex.pos, l, SHIFT));
+		      INDEX_CHARP (lex->pos, l, SHIFT));
 	  do SKIP(); while (lex_isidchar (LOOK()));
 	}
 	return TOK_FLOAT;
@@ -914,10 +914,10 @@ static int low_yylex(YYSTYPE *yylval)
 	yylval->n = mksvaluenode(&sval);
 	free_svalue(&sval);
 	debug_malloc_touch(yylval->n);
-	lex.pos=p2;
+	lex->pos=p2;
 	if (lex_isidchar (LOOK())) {
 	  my_yyerror ("Invalid char '%c' in constant.",
-		      INDEX_CHARP (lex.pos, l, SHIFT));
+		      INDEX_CHARP (lex->pos, l, SHIFT));
 	  do SKIP(); while (lex_isidchar (LOOK()));
 	}
 	return TOK_NUMBER;
@@ -1142,7 +1142,7 @@ static int low_yylex(YYSTYPE *yylval)
 	    return TOK_IDENTIFIER;
 	  }
 	yyerror("Illegal ` identifier.");
-	lex.pos -= (1<<SHIFT);
+	lex->pos -= (1<<SHIFT);
 	tmp="```";
 	break;
       }
diff --git a/src/module.c b/src/module.c
index e9f31857ef56f91df1119538c28e78077e236fbd..019de7a0110e9fc9f265922e23d47320bc22abb5 100644
--- a/src/module.c
+++ b/src/module.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: module.c,v 1.51 2008/03/30 01:24:10 mast Exp $
+|| $Id: module.c,v 1.52 2008/04/14 10:14:40 grubba Exp $
 */
 
 #include "global.h"
@@ -383,11 +383,8 @@ void init_modules(void)
 {
   struct program *p = NULL;
   volatile unsigned int e;
-  struct lex save_lex;
 
-  save_lex = lex;
-  lex.current_line=1;
-  lex.current_file=make_shared_string("-");
+  enter_compiler(NULL, 1);
 
   start_new_program();
   Pike_compiler->new_program->id=PROG___BUILTIN_ID;
@@ -428,8 +425,8 @@ void init_modules(void)
   push_object(low_clone(p=end_program()));
   f_add_constant(2);
   free_program(p);
-  free_string(lex.current_file);
-  lex = save_lex;
+
+  exit_compiler();
 }
 
 void exit_modules(void)
diff --git a/src/object.c b/src/object.c
index d2678f7bbcb743323b5198a93a105af33a5a0e31..19961a646261dc52cf59d084cd10df55a82e6781 100644
--- a/src/object.c
+++ b/src/object.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: object.c,v 1.283 2008/03/29 02:55:42 mast Exp $
+|| $Id: object.c,v 1.284 2008/04/14 10:14:40 grubba Exp $
 */
 
 #include "global.h"
@@ -2505,6 +2505,8 @@ void init_object(void)
 {
   ptrdiff_t offset;
 
+  enter_compiler(NULL, 0);
+
   init_destroy_called_mark_hash();
   start_new_program();
   offset=ADD_STORAGE(struct magic_index_struct);
@@ -2534,6 +2536,8 @@ void init_object(void)
 	       offset + OFFSETOF(magic_index_struct, o), T_OBJECT);
   ADD_FUNCTION("`()",f_magic_values,tFunc(tOr(tVoid,tInt),tArray),0);
   magic_values_program=end_program();
+
+  exit_compiler();
 }
 
 void exit_object(void)
diff --git a/src/operators.c b/src/operators.c
index c36ed12084ea1cc0146a1e50595c5ec6bae33138..b1eee0939ce69b6f22bac87906975d5352d3d5c0 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: operators.c,v 1.229 2008/03/29 02:04:40 mast Exp $
+|| $Id: operators.c,v 1.230 2008/04/14 10:14:40 grubba Exp $
 */
 
 #include "global.h"
@@ -30,6 +30,7 @@
 #include "builtin_functions.h"
 #include "cyclic.h"
 #include "pike_security.h"
+#include "pike_compiler.h"
 
 #define sp Pike_sp
 
@@ -1737,6 +1738,7 @@ PMOD_EXPORT void f_add(INT32 args)
 
 static int generate_sum(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   node **first_arg, **second_arg, **third_arg;
   int num_args;
   switch(count_args(CDR(n)))
@@ -2046,6 +2048,7 @@ static int generate_comparison(node *n)
 {
   if(count_args(CDR(n))==2)
   {
+    struct compilation *c = THIS_COMPILATION;
     if(do_docode(CDR(n),DO_NOT_COPY) != 2)
       Pike_fatal("Count args was wrong in generate_comparison.\n");
 
@@ -2366,6 +2369,7 @@ PMOD_EXPORT void f_minus(INT32 args)
 
 static int generate_minus(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   switch(count_args(CDR(n)))
   {
   case 1:
@@ -2703,6 +2707,7 @@ PMOD_EXPORT void f_and(INT32 args)
 
 static int generate_and(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   switch(count_args(CDR(n)))
   {
   case 1:
@@ -2937,6 +2942,7 @@ PMOD_EXPORT void f_or(INT32 args)
 
 static int generate_or(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   switch(count_args(CDR(n)))
   {
   case 1:
@@ -3176,6 +3182,7 @@ PMOD_EXPORT void f_xor(INT32 args)
 
 static int generate_xor(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   switch(count_args(CDR(n)))
   {
   case 1:
@@ -3259,6 +3266,7 @@ PMOD_EXPORT void f_lsh(INT32 args)
 
 static int generate_lsh(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   if(count_args(CDR(n))==2)
   {
     do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL);
@@ -3342,6 +3350,7 @@ static int generate_rsh(node *n)
 {
   if(count_args(CDR(n))==2)
   {
+    struct compilation *c = THIS_COMPILATION;
     do_docode(CDR(n),DO_NOT_COPY);
     emit0(F_RSH);
     return 1;
@@ -3623,6 +3632,7 @@ PMOD_EXPORT void f_multiply(INT32 args)
 
 static int generate_multiply(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   switch(count_args(CDR(n)))
   {
   case 1:
@@ -3993,6 +4003,7 @@ static int generate_divide(node *n)
 {
   if(count_args(CDR(n))==2)
   {
+    struct compilation *c = THIS_COMPILATION;
     do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL);
     emit0(F_DIVIDE);
     return 1;
@@ -4173,6 +4184,7 @@ static int generate_mod(node *n)
 {
   if(count_args(CDR(n))==2)
   {
+    struct compilation *c = THIS_COMPILATION;
     do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL);
     emit0(F_MOD);
     return 1;
@@ -4252,6 +4264,7 @@ static int generate_not(node *n)
 {
   if(count_args(CDR(n))==1)
   {
+    struct compilation *c = THIS_COMPILATION;
     do_docode(CDR(n),DO_NOT_COPY);
     emit0(F_NOT);
     return 1;
@@ -4373,6 +4386,7 @@ static int generate_compl(node *n)
 {
   if(count_args(CDR(n))==1)
   {
+    struct compilation *c = THIS_COMPILATION;
     do_docode(CDR(n),DO_NOT_COPY);
     emit0(F_COMPL);
     return 1;
@@ -5293,6 +5307,7 @@ static node *optimize_sizeof(node *n)
 
 static int generate_sizeof(node *n)
 {
+  struct compilation *c = THIS_COMPILATION;
   if(count_args(CDR(n)) != 1) return 0;
   if(do_docode(CDR(n),DO_NOT_COPY) != 1)
     Pike_fatal("Count args was wrong in sizeof().\n");
diff --git a/src/pike_compiler.h b/src/pike_compiler.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd0b7b6d3ffb32644cfcc59edb9581d77fc74af9
--- /dev/null
+++ b/src/pike_compiler.h
@@ -0,0 +1,55 @@
+/*
+|| This file is part of Pike. For copyright information see COPYRIGHT.
+|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
+|| for more information.
+|| $Id: pike_compiler.h,v 1.1 2008/04/14 10:14:41 grubba Exp $
+*/
+
+#ifndef PIKE_COMPILER_H
+#define PIKE_COMPILER_H
+
+#include "lex.h"
+#include "program.h"
+
+struct compilation
+{
+  struct Supporter supporter;
+  struct pike_string *prog;		/* String to compile. */
+  struct object *handler;		/* error_handler */
+  struct object *compat_handler;	/* compat_handler */
+  int major, minor;			/* compat version */
+  struct program *target;		/* Program being compiled. */
+  struct object *placeholder;
+  
+  struct program *p;			/* Compiled program or NULL. */
+  struct lex lex;
+  int compilation_inherit;		/* Inherit in supporter->self containing
+					 * compilation_program. */
+  int save_depth;
+  int saved_threads_disabled;
+  dynamic_buffer used_modules_save;
+  INT32 num_used_modules_save;
+  struct mapping *resolve_cache_save;
+
+  struct svalue default_module;
+};
+
+#ifdef PIKE_DEBUG
+#define CHECK_COMPILER()	do {				\
+    if (!Pike_fp || !compilation_program ||			\
+	Pike_fp->context->prog != compilation_program) {	\
+      Pike_fatal("Invalid compilation context!\n");		\
+    }								\
+  } while(0)
+#else
+#define CHECK_COMPILER()
+#endif
+#define THIS_COMPILATION  ((struct compilation *)(Pike_fp->current_storage))
+#define MAYBE_THIS_COMPILATION  ((Pike_fp && compilation_program && (Pike_fp->context->prog == compilation_program))?THIS_COMPILATION:NULL)
+
+/* Function numbers. */
+#define CE_REPORT_FUN_NUM		0
+#define CE_PIKE_COMPILER_FUN_NUM	1
+#define CE_COMPILE_FUN_NUM		2
+
+#endif	/* !PIKE_COMPILER_H */
diff --git a/src/pike_types.c b/src/pike_types.c
index 336553f33972617ec0d42bc2cf83c1c1ddd71ca5..f830ab95fe69351b6c2cdc2fa1e1282915ea59dd 100644
--- a/src/pike_types.c
+++ b/src/pike_types.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: pike_types.c,v 1.320 2008/04/01 13:20:07 mast Exp $
+|| $Id: pike_types.c,v 1.321 2008/04/14 10:14:41 grubba Exp $
 */
 
 #include "global.h"
@@ -27,6 +27,7 @@
 #include "opcodes.h"
 #include "cyclic.h"
 #include "gc.h"
+#include "pike_compiler.h"
 #include "block_alloc.h"
 
 #ifdef PIKE_DEBUG
@@ -55,6 +56,7 @@
 				 * Perform weaker checking for OR-nodes. */
 #define LE_A_B_GROUPED	0/*12*/	/* Both the above two flags. */
 #endif
+#define LE_USE_HANDLERS	16	/* Call handlers if appropriate. */
 
 /*
  * Flags used by low_get_first_arg_type()
@@ -1871,10 +1873,18 @@ void simple_describe_type(struct pike_type *s)
 	break;
 
       case PIKE_T_ATTRIBUTE:
-	fprintf(stderr, "__attribute__(\"%s\", ",
-		((struct pike_string *)s->car)->str);
-	simple_describe_type(s->cdr);
-	fprintf(stderr, ")");
+	{
+	  struct pike_string *deprecated;
+	  MAKE_CONST_STRING(deprecated, "deprecated");
+	  if (((struct pike_string *)s->car) == deprecated) {
+	    fprintf(stderr, "__deprecated__(");
+	  } else {
+	    fprintf(stderr, "__attribute__(\"%s\", ",
+		    ((struct pike_string *)s->car)->str);
+	  }
+	  simple_describe_type(s->cdr);
+	  fprintf(stderr, ")");
+	}
 	break;
 
       case T_SCOPE:
@@ -2214,10 +2224,16 @@ static void low_describe_type(struct pike_type *t)
       
     case PIKE_T_ATTRIBUTE:
       if (!((struct pike_string *)t->car)->size_shift) {
-	my_strcat("__attribute__(\"");
-	my_binary_strcat(((struct pike_string *)t->car)->str,
-			 ((struct pike_string *)t->car)->len);
-	my_strcat("\", ");
+	struct pike_string *deprecated;
+	MAKE_CONST_STRING(deprecated, "deprecated");
+	if (((struct pike_string *)t->car) == deprecated) {
+	  my_strcat("__deprecated__(");
+	} else {
+	  my_strcat("__attribute__(\"");
+	  my_binary_strcat(((struct pike_string *)t->car)->str,
+			   ((struct pike_string *)t->car)->len);
+	  my_strcat("\", ");
+	}
 	my_describe_type(t->cdr);
 	my_strcat(")");
       } else {
@@ -3727,9 +3743,38 @@ static int low_pike_types_le2(struct pike_type *a, struct pike_type *b,
 #endif
     /* FALL_THROUGH */
   case PIKE_T_NAME:
-  case PIKE_T_ATTRIBUTE:
     a = a->cdr;
     goto recurse;
+  case PIKE_T_ATTRIBUTE:
+    if ((b->type == PIKE_T_ATTRIBUTE) && (a->car == b->car)) {
+      a = a->cdr;
+      b = b->cdr;
+      goto recurse;
+    }
+#if 0
+    if (!flags & LE_USE_HANDLERS) {
+      a = a->cdr;
+      goto recurse;
+    }
+#endif /* 0 */
+    if (!low_pike_types_le(a->cdr, b, array_cnt, flags)) return 0;
+#if 0
+    ref_push_string((struct pike_string *)a->car);
+    ref_push_type_value(a->cdr);
+    ref_push_type_value(b);
+    push_int(1);
+    if (safe_apply_handler("handle_attribute", error_handler, compat_handler,
+			   4, 0)) {
+      if ((Pike_sp[-1].type == T_INT) &&
+	  (Pike_sp[-1].subtype == NUMBER_NUMBER) &&
+	  (!Pike_sp[-1].u.integer)) {
+	pop_stack();
+	return 0;
+      }
+      pop_stack();
+    }
+#endif /* 0 */
+    return 1;
 
   case T_NOT:
     if (b->type == T_NOT) {
@@ -3863,13 +3908,37 @@ static int low_pike_types_le2(struct pike_type *a, struct pike_type *b,
     b = b->car;
     goto recurse;
 
+  case PIKE_T_ATTRIBUTE:
+#if 0
+    if (!flags & LE_USE_HANDLERS) {
+      b = b->cdr;
+      goto recurse;
+    }
+#endif /* 0 */
+    if (!low_pike_types_le(a, b->cdr, array_cnt, flags)) return 0;
+#if 0
+    ref_push_string((struct pike_string *)b->car);
+    ref_push_type_value(a);
+    ref_push_type_value(b->cdr);
+    push_int(2);
+    if (safe_apply_handler("handle_attribute", error_handler, compat_handler,
+			   4, 0)) {
+      if ((Pike_sp[-1].type == T_INT) &&
+	  (Pike_sp[-1].subtype == NUMBER_NUMBER) &&
+	  (!Pike_sp[-1].u.integer)) {
+	pop_stack();
+	return 0;
+      }
+      pop_stack();
+    }
+#endif /* 0 */
+    return 1;
   case PIKE_T_SCOPE:
 #ifdef TYPE_GROUPING
     flags |= LE_B_GROUPED;
 #endif
     /* FALL_THROUGH */
   case PIKE_T_NAME:
-  case PIKE_T_ATTRIBUTE:
     b = b->cdr;
     goto recurse;
 
@@ -4318,7 +4387,9 @@ int check_soft_cast(struct pike_type *to, struct pike_type *from)
  */
 static int low_get_return_type(struct pike_type *a, struct pike_type *b)
 {
+  struct compilation *c = THIS_COMPILATION;
   int tmp;
+  CHECK_COMPILER();
   switch(a->type)
   {
   case T_OR:
@@ -4380,7 +4451,7 @@ static int low_get_return_type(struct pike_type *a, struct pike_type *b)
   if(a)
   {
 #if 0
-    if ((lex.pragmas & ID_STRICT_TYPES) &&
+    if ((c->lex.pragmas & ID_STRICT_TYPES) &&
 	!low_pike_types_le(a, b, 0, 0)) {
       yywarning("Type mismatch");
     }
@@ -4441,6 +4512,13 @@ static struct pike_type *debug_low_index_type(struct pike_type *t,
 {
   struct pike_type *tmp;
   struct program *p;
+  int pragmas = 0;
+
+  if (n) {
+    struct compilation *c = THIS_COMPILATION;
+    CHECK_COMPILER();
+    pragmas = c->lex.pragmas;
+  }
 
   switch(low_check_indexing(t, index_type, n))
   {
@@ -4519,7 +4597,7 @@ static struct pike_type *debug_low_index_type(struct pike_type *t,
     return mixed_type_string;
 
   case T_MIXED:
-    if (lex.pragmas & ID_STRICT_TYPES) {
+    if (pragmas & ID_STRICT_TYPES) {
       yywarning("Indexing mixed.");
     }
     add_ref(mixed_type_string);
@@ -4633,9 +4711,12 @@ static struct pike_type *debug_low_range_type(struct pike_type *t,
 					      struct pike_type *index1_type,
 					      struct pike_type *index2_type)
 {
+  struct compilation *c = THIS_COMPILATION;
   struct pike_type *tmp;
   struct program *p;
 
+  CHECK_COMPILER();
+
   while((t->type == PIKE_T_NAME) ||
 	(t->type == PIKE_T_ATTRIBUTE)) {
     t = t->cdr;
@@ -4736,7 +4817,7 @@ static struct pike_type *debug_low_range_type(struct pike_type *t,
       yywarning("Ranging object without index operator.");
       return 0;
     }
-    if (lex.pragmas & ID_STRICT_TYPES) {
+    if (c->lex.pragmas & ID_STRICT_TYPES) {
       yywarning("Ranging generic object.");
     }
     add_ref(mixed_type_string);
@@ -4744,7 +4825,7 @@ static struct pike_type *debug_low_range_type(struct pike_type *t,
   }
 
   case T_MIXED:
-    if (lex.pragmas & ID_STRICT_TYPES) {
+    if (c->lex.pragmas & ID_STRICT_TYPES) {
       yywarning("Ranging mixed.");
     }
     add_ref(mixed_type_string);
@@ -5892,14 +5973,16 @@ static struct pike_type *lower_new_check_call(struct pike_type *fun_type,
       }
 
       if (tmp2->type == PIKE_T_ATTRIBUTE) {
+	struct compilation *c = MAYBE_THIS_COMPILATION;
 	/* Perform extra argument checking based on the attribute. */
 	/* FIXME: Support multiple attributes. */
 	ref_push_string((struct pike_string *)tmp2->car);
 	push_svalue(sval);
 	ref_push_type_value(tmp2->cdr);
 	ref_push_type_value(res);
-	if (safe_apply_handler("handle_attribute_constant", error_handler,
-			       compat_handler, 4, 0)) {
+	if (safe_apply_handler("handle_attribute_constant",
+			       c?c->handler:NULL,
+			       c?c->compat_handler:NULL, 4, 0)) {
 	  if ((Pike_sp[-1].type == PIKE_T_TYPE)) {
 	    type_stack_mark();
 	    push_finished_type(Pike_sp[-1].u.type);
@@ -6454,11 +6537,14 @@ struct pike_type *new_check_call(struct pike_string *fun_name,
 				 struct pike_type *fun_type,
 				 node *args, INT32 *argno)
 {
+  struct compilation *c = THIS_COMPILATION;
   struct pike_type *tmp = NULL;
   struct pike_type *res = NULL;
   struct svalue *sval = NULL;
   int flags = 0;
 
+  CHECK_COMPILER();
+
   debug_malloc_touch(fun_type);
 
   while (args && (args->token == F_ARG_LIST) && fun_type) {
@@ -6549,7 +6635,7 @@ struct pike_type *new_check_call(struct pike_string *fun_name,
       if (cnt == 256) {
 	yywarning("In argument %d to %S: The @-operator argument must be an empty array.",
 		  *argno, fun_name);
-      } else if (lex.pragmas & ID_STRICT_TYPES) {
+      } else if (c->lex.pragmas & ID_STRICT_TYPES) {
 	yywarning("In argument %d to %S: The @-operator argument has a max length of %d.",
 		  *argno, fun_name, 256-cnt);
       }
@@ -6571,7 +6657,7 @@ struct pike_type *new_check_call(struct pike_string *fun_name,
       fprintf(stderr, " OK.\n");
     }
 #endif /* PIKE_DEBUG */
-    if (lex.pragmas & ID_STRICT_TYPES) {
+    if (c->lex.pragmas & ID_STRICT_TYPES) {
       if (!(tmp = low_new_check_call(fun_type, args->type,
 				     flags|CALL_STRICT, sval))) {
 	yywarning("Type mismatch in argument %d to %S.",
diff --git a/src/program.c b/src/program.c
index 8d23c11f61d23866ee68fc2d9be6f4ccbe1e4d09..d058c74dbdb1d18682163e01049e08c472aa3a11 100644
--- a/src/program.c
+++ b/src/program.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: program.c,v 1.659 2008/04/07 01:45:53 mbaehr Exp $
+|| $Id: program.c,v 1.660 2008/04/14 10:14:41 grubba Exp $
 */
 
 #include "global.h"
@@ -35,6 +35,7 @@
 #include "version.h"
 #include "block_alloc.h"
 #include "pikecode.h"
+#include "pike_compiler.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -44,6 +45,7 @@
 #undef ATTRIBUTE
 #define ATTRIBUTE(X)
 
+static void low_enter_compiler(struct object *ce, int inherit);
 static void exit_program_struct(struct program *);
 static size_t add_xstorage(size_t size,
 			   size_t alignment,
@@ -1218,9 +1220,6 @@ struct program *null_program=0;
 
 struct program *compilation_program = 0;
 
-struct object *error_handler=0;
-struct object *compat_handler=0;
-
 struct program *gc_internal_program = 0;
 static struct program *gc_mark_program_pos = 0;
 
@@ -1616,23 +1615,24 @@ struct node_s *resolve_identifier(struct pike_string *ident)
 
   if(get_master())
   {
+    struct compilation *c = THIS_COMPILATION;
     DECLARE_CYCLIC();
     node *ret=0;
-    if(BEGIN_CYCLIC(ident, lex.current_file))
+    if(BEGIN_CYCLIC(ident, c->lex.current_file))
     {
       my_yyerror("Recursive module dependency in %S.", ident);
     }else{
       SET_CYCLIC_RET(1);
 
       ref_push_string(ident);
-      ref_push_string(lex.current_file);
-      if (error_handler) {
-	ref_push_object(error_handler);
+      ref_push_string(c->lex.current_file);
+      if (c->handler) {
+	ref_push_object(c->handler);
       } else {
 	push_int(0);
       }
 
-      if (safe_apply_handler("resolv", error_handler, compat_handler, 3, 0)) {
+      if (safe_apply_handler("resolv", c->handler, c->compat_handler, 3, 0)) {
 	if (Pike_compiler->compiler_pass == 2 &&
 	    ((Pike_sp[-1].type == T_OBJECT &&
 	      Pike_sp[-1].u.object == placeholder_object) ||
@@ -1977,6 +1977,7 @@ struct pike_string *find_program_name(struct program *p, INT32 *line)
 
 int override_identifier (struct reference *new_ref, struct pike_string *name)
 {
+  struct compilation *c = THIS_COMPILATION;
   int id = -1, cur_id = 0, is_used = 0;
 
   int new_is_variable =
@@ -1989,6 +1990,8 @@ int override_identifier (struct reference *new_ref, struct pike_string *name)
    * /Hubbe
    */
 
+  CHECK_COMPILER();
+
   for(;cur_id<Pike_compiler->new_program->num_identifier_references;cur_id++)
   {
     struct reference *ref =
@@ -2040,7 +2043,7 @@ int override_identifier (struct reference *new_ref, struct pike_string *name)
       sub_ref = PTR_FROM_INT(inh->prog, cur_id - inh->identifier_level);
 
       /* Check if the symbol was used before it was inherited. */
-      if ((lex.pragmas & ID_STRICT_TYPES) &&
+      if ((c->lex.pragmas & ID_STRICT_TYPES) &&
 	  (sub_ref->id_flags & ID_USED)) {
 	struct identifier *sub_id = ID_FROM_PTR(inh->prog, sub_ref);
 	if (IDENTIFIER_IS_FUNCTION(sub_id->identifier_flags)) {
@@ -2085,9 +2088,12 @@ int override_identifier (struct reference *new_ref, struct pike_string *name)
 
 void fixate_program(void)
 {
+  struct compilation *c = THIS_COMPILATION;
   INT32 i,e,t;
   struct program *p=Pike_compiler->new_program;
 
+  CHECK_COMPILER();
+
   if(p->flags & PROGRAM_FIXED) return;
 #ifdef PIKE_DEBUG
   if(p->flags & PROGRAM_OPTIMIZED)
@@ -2161,7 +2167,7 @@ void fixate_program(void)
 	  if(funa_is_prototype && (funb->func.offset != -1) &&
 	     !(funp->id_flags & ID_INLINE))
 	  {
-	    if ((lex.pragmas & ID_STRICT_TYPES) &&
+	    if ((c->lex.pragmas & ID_STRICT_TYPES) &&
 		(funp->id_flags & ID_USED)) {
 	      /* Verify that the types are compatible. */
 	      if (!pike_types_le(funb->type, fun->type)) {
@@ -2175,7 +2181,7 @@ void fixate_program(void)
 	  }
 	  if(!funa_is_prototype && funb->func.offset == -1)
 	  {
-	    if ((lex.pragmas & ID_STRICT_TYPES) &&
+	    if ((c->lex.pragmas & ID_STRICT_TYPES) &&
 		(funpb->id_flags & ID_USED)) {
 	      /* Verify that the types are compatible. */
 	      if (!pike_types_le(fun->type, funb->type)) {
@@ -2267,12 +2273,12 @@ void fixate_program(void)
     INT32 line;
     struct pike_string *tmp;
     struct memory_map *m=0;;
-    if(lex.current_file && 
-       lex.current_file->str &&
-       lex.current_file->len &&
-       !strcmp(lex.current_file->str,"-"))
+    if(c->lex.current_file && 
+       c->lex.current_file->str &&
+       c->lex.current_file->len &&
+       !strcmp(c->lex.current_file->str,"-"))
     {
-      m=dmalloc_alloc_mmap( DBSTR(lex.current_file), lex.current_line);
+      m=dmalloc_alloc_mmap( DBSTR(c->lex.current_file), c->lex.current_line);
     }
     else if( (tmp=find_program_name(Pike_compiler->new_program, &line)) )
     {
@@ -2353,9 +2359,12 @@ void low_start_new_program(struct program *p,
 			   int flags,
 			   int *idp)
 {
+  struct compilation *c = THIS_COMPILATION;
   int id=0;
   struct svalue tmp;
 
+  CHECK_COMPILER();
+
 #ifdef WITH_FACETS
   if(Pike_compiler->compiler_pass == 1 && p) {
     p->facet_class = 0;
@@ -2387,7 +2396,7 @@ void low_start_new_program(struct program *p,
       fprintf(stderr,"Compiling class %s, depth=%d\n",name->str,compilation_depth);
     }else{
       fprintf(stderr,"Compiling file %s, depth=%d\n",
-	      lex.current_file ? lex.current_file->str : "-",
+	      c->lex.current_file ? c->lex.current_file->str : "-",
 	      compilation_depth);
 #endif
     }
@@ -2499,10 +2508,10 @@ void low_start_new_program(struct program *p,
 #endif
 
   if (compilation_depth >= 1) {
-    if(TEST_COMPAT(7,2) || (lex.pragmas & ID_SAVE_PARENT))
+    if(TEST_COMPAT(7,2) || (c->lex.pragmas & ID_SAVE_PARENT))
     {
       p->flags |= PROGRAM_USES_PARENT;
-    }else if (!(lex.pragmas & ID_DONT_SAVE_PARENT)) {
+    }else if (!(c->lex.pragmas & ID_DONT_SAVE_PARENT)) {
       struct pike_string *tmp=findstring("__pragma_save_parent__");
       if(tmp)
       {
@@ -2613,17 +2622,23 @@ void low_start_new_program(struct program *p,
 
 PMOD_EXPORT void debug_start_new_program(int line, const char *file)
 {
-  struct pike_string *save_file =
-    dmalloc_touch(struct pike_string *, lex.current_file);
-  int save_line = lex.current_line;
+  struct pike_string *save_file;
+  int save_line;
+  struct compilation *c;
+
+  CHECK_COMPILER();
+  c = THIS_COMPILATION;
+
+  save_file = dmalloc_touch(struct pike_string *, c->lex.current_file);
+  save_line = c->lex.current_line;
 
   { /* Trim off the leading path of the compilation environment. */
     const char *p = DEFINETOSTR(PIKE_SRC_ROOT), *f = file;
     while (*p && *p == *f) p++, f++;
     while (*f == '/' || *f == '\\') f++;
 
-    lex.current_file = make_shared_string(f);
-    lex.current_line = line;
+    c->lex.current_file = make_shared_string(f);
+    c->lex.current_line = line;
   }
 
   CDFPRINTF((stderr,
@@ -2632,12 +2647,12 @@ PMOD_EXPORT void debug_start_new_program(int line, const char *file)
 	     (long)th_self(), line, file, threads_disabled, compilation_depth));
 
   low_start_new_program(0,1,0,0,0);
-  store_linenumber(line,lex.current_file);
+  store_linenumber(line,c->lex.current_file);
   debug_malloc_name(Pike_compiler->new_program, file, line);
 
-  free_string(lex.current_file);
-  lex.current_file = dmalloc_touch(struct pike_string *, save_file);
-  lex.current_line = save_line;
+  free_string(c->lex.current_file);
+  c->lex.current_file = dmalloc_touch(struct pike_string *, save_file);
+  c->lex.current_line = save_line;
 }
 
 
@@ -3044,6 +3059,17 @@ void dump_program_tables (struct program *p, int indent)
 #endif /* 0 */
   }
 
+  fprintf(stderr, "\n"
+	  "%*sLFUN table:\n"
+	  "%*s  LFUN  Ref# Name\n",
+	  indent, "", indent, "");
+  for (d = 0; d < NUM_LFUNS; d++) {
+    if (p->lfuns[d] != -1) {
+      fprintf(stderr, "%*s  %4d: %04d %s\n",
+	      indent, "", d, p->lfuns[d], lfun_names[d]);
+    }
+  }
+
   fprintf(stderr, "\n"
 	  "%*sLinenumber table:\n",
 	  indent, "");
@@ -4445,8 +4471,11 @@ void compiler_do_inherit(node *n,
 
 int call_handle_inherit(struct pike_string *s)
 {
+  struct compilation *c = THIS_COMPILATION;
   int args;
 
+  CHECK_COMPILER();
+
   reference_shared_string(s);
   push_string(s);
   if (!TEST_COMPAT(7,6)) {
@@ -4455,14 +4484,14 @@ int call_handle_inherit(struct pike_string *s)
      */
     f_string_to_utf8(1);
   }
-  ref_push_string(lex.current_file);
-  if (error_handler && error_handler->prog) {
-    ref_push_object(error_handler);
+  ref_push_string(c->lex.current_file);
+  if (c->handler && c->handler->prog) {
+    ref_push_object(c->handler);
     args = 3;
   }
   else args = 2;
 
-  if (safe_apply_handler("handle_inherit", error_handler, compat_handler,
+  if (safe_apply_handler("handle_inherit", c->handler, c->compat_handler,
 			 args, BIT_PROGRAM|BIT_FUNCTION|BIT_ZERO))
     if (Pike_sp[-1].type != T_INT)
       return 1;
@@ -5314,6 +5343,7 @@ INT32 define_function(struct pike_string *name,
 		      union idptr *func,
 		      unsigned opt_flags)
 {
+  struct compilation *c = THIS_COMPILATION;
   struct identifier *funp,fun;
   struct reference ref;
   struct svalue *lfun_type;
@@ -5321,6 +5351,8 @@ INT32 define_function(struct pike_string *name,
   INT32 i;
   INT32 getter_setter_offset = -1;
 
+  CHECK_COMPILER();
+
 #ifdef PROGRAM_BUILD_DEBUG
   {
     struct pike_string *d = describe_type (type);
@@ -5351,7 +5383,7 @@ INT32 define_function(struct pike_string *name,
 	my_yyerror("Type mismatch for callback function %S:", name);
 	yytype_error(NULL, lfun_type->u.type, type, 0);
 	Pike_fatal("Type mismatch!\n");
-      } else if (lex.pragmas & ID_STRICT_TYPES) {
+      } else if (c->lex.pragmas & ID_STRICT_TYPES) {
 	yywarning("Type mismatch for callback function %S:", name);
 	yytype_error(NULL, lfun_type->u.type, type,
 		     YYTE_IS_WARNING);
@@ -5396,7 +5428,7 @@ INT32 define_function(struct pike_string *name,
 	if (!match_types(type, gs_type)) {
 	  my_yyerror("Type mismatch for callback function %S:", name);
 	  yytype_error(NULL, gs_type, type, 0);
-	} else if (lex.pragmas & ID_STRICT_TYPES) {
+	} else if (c->lex.pragmas & ID_STRICT_TYPES) {
 	  yywarning("Type mismatch for callback function %S:", name);
 	  yytype_error(NULL, gs_type, type, YYTE_IS_WARNING);
 	}
@@ -6791,6 +6823,10 @@ struct pike_string *format_exception_for_error_msg (struct svalue *thrown)
 void handle_compile_exception (const char *yyerror_fmt, ...)
 {
   struct svalue thrown;
+  struct compilation *c = THIS_COMPILATION;
+
+  CHECK_COMPILER();
+
   move_svalue (&thrown, &throw_value);
   mark_free_svalue (&throw_value);
 
@@ -6802,7 +6838,7 @@ void handle_compile_exception (const char *yyerror_fmt, ...)
   }
 
   push_svalue(&thrown);
-  low_safe_apply_handler("compile_exception", error_handler, compat_handler, 1);
+  low_safe_apply_handler("compile_exception", c->handler, c->compat_handler, 1);
 
   if (SAFE_IS_ZERO(sp-1)) {
     struct pike_string *s = format_exception_for_error_msg (&thrown);
@@ -6960,6 +6996,8 @@ void init_supporter(struct Supporter *s,
 		    supporter_callback *fun,
 		    void *data)
 {
+  CDFPRINTF((stderr, "th(%ld) init_supporter() supporter=%p data=%p.\n",
+	     (long) th_self(), s, data));
   verify_supporters();
 #ifdef PIKE_DEBUG
   s->magic = 0x500b0127;
@@ -6995,6 +7033,9 @@ int unlink_current_supporter(struct Supporter *c)
     ret++;
     c->next_dependant = c->depends_on->dependants;
     c->depends_on->dependants=c;
+    add_ref(c->self);
+    CDFPRINTF((stderr, "th(%ld) unlink_current_supporter() supporter=%p depends on %p.\n",
+	       (long) th_self(), c, c->depends_on));
   }
   current_supporter=c->previous;
   verify_supporters();
@@ -7017,9 +7058,13 @@ int call_dependants(struct Supporter *s, int finish)
 {
   int ok = 1;
   struct Supporter *tmp;
+  CDFPRINTF((stderr, "th(%ld) call_dependants() supporter=%p finish=%d.\n",
+	     (long) th_self(), s, finish));
   verify_supporters();
   while((tmp=s->dependants))
   {
+    CDFPRINTF((stderr, "th(%ld) dependant: %p (data:%p).\n",
+	       (long) th_self(), tmp, tmp->data));
     s->dependants=tmp->next_dependant;
 #ifdef PIKE_DEBUG
     tmp->next_dependant=0;
@@ -7027,6 +7072,7 @@ int call_dependants(struct Supporter *s, int finish)
     verify_supporters();
     if (!tmp->fun(tmp->data, finish)) ok = 0;
     verify_supporters();
+    free_object(tmp->self);
   }
   return ok;
 }
@@ -7040,6 +7086,10 @@ int report_compiler_dependency(struct program *p)
     /* Depends on self... */
     return 0;
   }
+
+  CDFPRINTF((stderr, "th(%ld) %p depends on %p\n",
+	     (long)th_self(), Pike_compiler->new_program, p));
+
   verify_supporters();
   if (Pike_compiler->flags & COMPILATION_FORCE_RESOLVE)
     return 0;
@@ -7066,40 +7116,20 @@ int report_compiler_dependency(struct program *p)
 }
 
 
-/*! @class PikeCompiler
+/*! @class CompilerEnviroment
  *!
- *!   The Pike compiler.
+ *!   The compiler environment.
  */
 
-struct compilation
-{
-  struct Supporter supporter;
-  struct pike_string *prog;
-  struct object *handler;
-  int major, minor;
-  struct program *target;
-  struct object *placeholder;
-  
-  struct program *p;
-  struct lex save_lex;
-  int save_depth;
-  int saved_threads_disabled;
-  struct object *saved_handler;
-  struct object *saved_compat_handler;
-  dynamic_buffer used_modules_save;
-  INT32 num_used_modules_save;
-  struct mapping *resolve_cache_save;
-
-  struct svalue default_module;
-};
-
 static void free_compilation(struct compilation *c)
 {
   debug_malloc_touch(c);
-  free_string(c->prog);
+  if (c->prog) free_string(c->prog);
   if(c->handler) free_object(c->handler);
+  if(c->compat_handler) free_object(c->compat_handler);
   if(c->target) free_program(c->target);
   if(c->placeholder) free_object(c->placeholder);
+  if(c->lex.current_file) free_string(c->lex.current_file);
   free_svalue(& c->default_module);
   free_supporter(&c->supporter);
   verify_supporters();
@@ -7111,12 +7141,8 @@ static void run_init(struct compilation *c)
   c->save_depth=compilation_depth;
   compilation_depth=-1;
 
-  c->saved_handler = error_handler;
-  if((error_handler = c->handler))
-    add_ref(error_handler);
-
-  c->saved_compat_handler = compat_handler;
-  compat_handler=0;
+  if (c->compat_handler) free_object(c->compat_handler);
+  c->compat_handler=0;
 
   c->used_modules_save = used_modules;
   c->num_used_modules_save = Pike_compiler->num_used_modules;
@@ -7125,31 +7151,30 @@ static void run_init(struct compilation *c)
   c->resolve_cache_save = resolve_cache;
   resolve_cache = 0;
 
-  c->save_lex=lex;
-
-  lex.current_line=1;
-  lex.current_file=make_shared_string("-");
+  c->lex.current_line=1;
+  free_string(c->lex.current_file);
+  c->lex.current_file=make_shared_string("-");
 
   if (runtime_options & RUNTIME_STRICT_TYPES)
   {
-    lex.pragmas = ID_STRICT_TYPES;
+    c->lex.pragmas = ID_STRICT_TYPES;
   } else {
-    lex.pragmas = 0;
+    c->lex.pragmas = 0;
   }
 
-  lex.end = c->prog->str + (c->prog->len << c->prog->size_shift);
+  c->lex.end = c->prog->str + (c->prog->len << c->prog->size_shift);
 
   switch(c->prog->size_shift)
   {
-    case 0: lex.current_lexer = yylex0; break;
-    case 1: lex.current_lexer = yylex1; break;
-    case 2: lex.current_lexer = yylex2; break;
+    case 0: c->lex.current_lexer = yylex0; break;
+    case 1: c->lex.current_lexer = yylex1; break;
+    case 2: c->lex.current_lexer = yylex2; break;
     default:
       Pike_fatal("Program has bad shift %d!\n", c->prog->size_shift);
       break;
   }
 
-  lex.pos=c->prog->str;
+  c->lex.pos=c->prog->str;
 }
 
 static void run_init2(struct compilation *c)
@@ -7191,14 +7216,6 @@ static void run_exit(struct compilation *c)
     free_mapping(resolve_cache);
   resolve_cache = c->resolve_cache_save;
 
-  if (error_handler) free_object(error_handler);
-  error_handler = c->saved_handler;
-
-  if (compat_handler)  free_object(compat_handler);
-  compat_handler = c->saved_compat_handler;
-
-  free_string(lex.current_file);
-  lex=c->save_lex;
   verify_supporters();
 }
 
@@ -7286,15 +7303,16 @@ static int run_pass1(struct compilation *c)
 
   if (!Pike_compiler->new_program->num_linenumbers) {
     /* The lexer didn't write an initial entry. */
-    store_linenumber(0, lex.current_file);
+    store_linenumber(0, c->lex.current_file);
 #ifdef DEBUG_MALLOC
-    if(strcmp(lex.current_file->str,"-"))
-      debug_malloc_name(Pike_compiler->new_program, lex.current_file->str, 0);
+    if(strcmp(c->lex.current_file->str,"-"))
+      debug_malloc_name(Pike_compiler->new_program, c->lex.current_file->str, 0);
 #endif
   }
 
   CDFPRINTF((stderr, "th(%ld) %p run_pass1() done for %s\n",
-	     (long)th_self(), Pike_compiler->new_program, lex.current_file->str));
+	     (long)th_self(), Pike_compiler->new_program,
+	     c->lex.current_file->str));
 
   ret=unlink_current_supporter(& c->supporter);
 
@@ -7343,12 +7361,20 @@ void run_pass2(struct compilation *c)
 	     (long)th_self(), Pike_compiler->new_program,
 	     threads_disabled, compilation_depth));
 
+  CDFPRINTF((stderr,
+	     "th(%ld) %p:\n"
+	     "%s\n"
+	     "---\n"
+	     "%s\n", (long)th_self(), Pike_compiler->new_program,
+	     c->prog->str, c->lex.pos));
+
   verify_supporters();
 
   do_yyparse();  /* Parse da program */
 
   CDFPRINTF((stderr, "th(%ld) %p run_pass2() done for %s\n",
-	     (long)th_self(), Pike_compiler->new_program, lex.current_file->str));
+	     (long)th_self(), Pike_compiler->new_program,
+	     c->lex.current_file->str));
 
   verify_supporters();
 
@@ -7458,11 +7484,19 @@ static int call_delayed_pass2(struct compilation *cc, int finish)
   int ok = 0;
   debug_malloc_touch(cc);
 
+  debug_malloc_touch(cc->p);
+
   CDFPRINTF((stderr, "th(%ld) %p %s delayed compile.\n",
 	     (long) th_self(), cc->p, finish ? "continuing" : "cleaning up"));
 
+  /* Reenter the delayed compilation. */
+  add_ref(cc->supporter.self);
+  low_enter_compiler(cc->supporter.self, cc->compilation_inherit);
+
   if(finish && cc->p) run_pass2(cc);
   run_cleanup(cc,1);
+
+  exit_compiler();
   
   debug_malloc_touch(cc);
 
@@ -7478,48 +7512,46 @@ static int call_delayed_pass2(struct compilation *cc, int finish)
   CDFPRINTF((stderr, "th(%ld) %p delayed compile %s.\n",
 	     (long) th_self(), cc->target, ok ? "done" : "failed"));
 
-  free_compilation(cc);
-  free(cc);
   verify_supporters();
 
   return ok;
 }
 
-#define THIS_COMPILATION  ((struct compilation *)(Pike_fp->current_storage))
-
 static void compilation_event_handler(int e)
 {
   struct compilation *c = THIS_COMPILATION;
+
   switch (e) {
   case PROG_EVENT_INIT:
+    CDFPRINTF((stderr, "th(%ld) compilation: INIT(%p).\n",
+	       (long) th_self(), c));
+    MEMSET(c, 0, sizeof(*c));
+    c->supporter.self = Pike_fp->current_object; /* NOTE: Not ref-counted! */
+    c->compilation_inherit =
+      Pike_fp->context - Pike_fp->current_object->prog->inherits;
     c->default_module.type = T_INT;
     c->default_module.subtype = NUMBER_NUMBER;
+    c->lex.current_line = 1;
+    c->lex.current_file = make_shared_string("-");
     break;
   case PROG_EVENT_EXIT:
+    CDFPRINTF((stderr, "th(%ld) compilation: EXIT(%p).\n",
+	       (long) th_self(), c));
     free_compilation(c);
     break;
   }
 }
 
-/*! @decl void compile(string code)
- *!
- *!   Compile a segment of Pike code.
- */
-static void f_compilation_compile(INT32 args)
-{
-  pop_n_elems(args);
-  push_int(0);
-}
-
 /*! @decl void report(SeverityLevel severity, @
- *!              string filename, int linenumber, @
- *!              string subsystem, @
- *!              string message, mixed ... extra_args)
+ *!                   string filename, int linenumber, @
+ *!                   string subsystem, @
+ *!                   string message, mixed ... extra_args)
  *!
  *!   Report a diagnostic from the compiler.
  */
 static void f_compilation_report(INT32 args)
 {
+  struct compilation *c = THIS_COMPILATION;
   int level;
   struct pike_string *filename;
   INT_TYPE linenumber;
@@ -7529,30 +7561,355 @@ static void f_compilation_report(INT32 args)
     f_sprintf(args - 4);
     args = 5;
   }
-  get_all_args("report", args, "%d%S%i%S%S",
+  get_all_args("report", args, "%d%W%i%W%W",
 	       &level, &filename, &linenumber, &subsystem, &message);
-  fprintf(stderr, "%s:%ld: %s\n", filename->str, linenumber, message->str);
+
+  /* Ignore informational level messages */
+  if (level) {
+    if ((c->handler && c->handler->prog) ||
+	(c->compat_handler && c->compat_handler->prog) ||
+	get_master()) {
+      ref_push_string(filename);
+      push_int(linenumber);
+      ref_push_string(message);
+      if (level >= 2) {
+	low_safe_apply_handler("compile_error",
+			       c->handler, c->compat_handler, 3);
+	args++;
+      } else {
+	low_safe_apply_handler("compile_warning",
+			       c->handler, c->compat_handler, 3);
+	args++;
+      }
+    } else {
+      if (level >= 2) {
+	fprintf(stderr, "%s:%ld: %s\n",
+		filename->str, linenumber, message->str);
+      } else {
+	fprintf(stderr, "%s:%ld: Warning: %s\n",
+		filename->str, linenumber, message->str);
+      }
+      fflush(stderr);
+    }
+  }
   pop_n_elems(args);
   push_int(0);
 }
 
+/*! @decl program compile(string source, CompilationHandler|void handler, @
+ *!                       int|void major, int|void minor,@
+ *!                       program|void target, object|void placeholder)
+ *!
+ *!   Compile a string to a program.
+ *!
+ *!   This function takes a piece of Pike code as a string and
+ *!   compiles it into a clonable program.
+ *!
+ *!   The optional argument @[handler] is used to specify an alternative
+ *!   error handler. If it is not specified the current master object will
+ *!   be used.
+ *!
+ *!   The optional arguments @[major] and @[minor] are used to tell the
+ *!   compiler to attempt to be compatible with Pike @[major].@[minor].
+ *!
+ *! @note
+ *!   Note that @[source] must contain the complete source for a program.
+ *!   It is not possible to compile a single expression or statement.
+ *!
+ *!   Also note that @[compile()] does not preprocess the program.
+ *!   To preprocess the program you can use @[compile_string()] or
+ *!   call the preprocessor manually by calling @[cpp()].
+ *!
+ *! @seealso
+ *!   @[compile_string()], @[compile_file()], @[cpp()], @[master()],
+ *!   @[CompilationHandler]
+ */
+static void f_compilation_compile(INT32 args)
+{
+  struct pike_string *aprog;
+  struct object *ahandler = NULL;/* error handler */
+  int amajor = -1;
+  int aminor = -1;
+  struct program *atarget = NULL;
+  struct object *aplaceholder = NULL;
+  int delay, dependants_ok = 1;
+  struct program *ret;
+#ifdef PIKE_DEBUG
+  ONERROR tmp;
+#endif
+  struct compilation *c = THIS_COMPILATION;
+
+  if (c->target) {
+    Pike_error("CompilationEnvironment in use.\n");
+  }
+
+  STACK_LEVEL_START(args);
+
+  get_all_args("compile", args, "%W.%O%d%d%P%O",
+	       &aprog, &ahandler,
+	       &amajor, &aminor,
+	       &atarget, &aplaceholder);
+
+  if (args == 3) {
+    SIMPLE_BAD_ARG_ERROR("compile", 4, "int");
+  }
+
+  check_c_stack(65536);
+
+  CDFPRINTF((stderr, "th(%ld) %p compile() enter, placeholder=%p\n",
+	     (long) th_self(), atarget, aplaceholder));
+
+  debug_malloc_touch(c);
+
+  verify_supporters();
+
+  if (c->p) free_program(c->p);
+  c->p = NULL;
+  if (c->prog) free_string(c->prog);
+  add_ref(c->prog=aprog);
+  if (ahandler) {
+    if (c->handler) free_object(c->handler);
+    add_ref(c->handler = ahandler);
+  }
+  c->major=amajor;
+  c->minor=aminor;
+
+  if((c->target=atarget)) add_ref(atarget);
+  else c->target = low_allocate_program();
+
+  if (c->placeholder) free_object(c->placeholder);
+  if ((c->placeholder=aplaceholder)) add_ref(aplaceholder);
+
+  if (c->handler)
+  {
+    if (safe_apply_handler ("get_default_module", c->handler, NULL,
+			    0, BIT_MAPPING|BIT_OBJECT|BIT_ZERO)) {
+      if(SAFE_IS_ZERO(Pike_sp-1))
+      {
+	pop_stack();
+	ref_push_mapping(get_builtin_constants());
+      }
+    } else {
+      ref_push_mapping(get_builtin_constants());
+    }
+  }else{
+    ref_push_mapping(get_builtin_constants());
+  }
+  free_svalue(& c->default_module);
+  c->default_module=Pike_sp[-1];
+  dmalloc_touch_svalue(Pike_sp-1);
+  Pike_sp--;
+
+#ifdef PIKE_DEBUG
+  SET_ONERROR(tmp, fatal_on_error,"Compiler exited with longjump!\n");
+#endif
+
+  low_init_threads_disable();
+  c->saved_threads_disabled = threads_disabled;
+
+  init_supporter(& c->supporter,
+		 (supporter_callback *) call_delayed_pass2,
+		 (void *)c);
+
+  delay=run_pass1(c) && c->p;
+  dependants_ok = call_dependants(& c->supporter, !!c->p );
+#ifdef PIKE_DEBUG
+  /* FIXME */
+  UNSET_ONERROR(tmp);
+#endif
+
+  if(delay)
+  {
+    CDFPRINTF((stderr, "th(%ld) %p compile() finish later, placeholder=%p.\n",
+	       (long) th_self(), c->target, c->placeholder));
+    /* finish later */
+    add_ref(c->p);
+    verify_supporters();
+    /* We're hanging in the supporter. */
+    ret = c->p;
+  }else{
+    /* finish now */
+    if(c->p) run_pass2(c);
+    debug_malloc_touch(c);
+    run_cleanup(c,0);
+    
+    ret=c->p;
+    c->p = NULL;
+
+    debug_malloc_touch(c);
+
+    if (!dependants_ok) {
+      CDFPRINTF((stderr, "th(%ld) %p compile() reporting failure "
+		 "since a dependant failed.\n",
+		 (long) th_self(), c->target));
+      if (ret) free_program(ret);
+      throw_error_object(low_clone(compilation_error_program), 0, 0, 0,
+			 "Compilation failed.\n");
+    }
+    if(!ret) {
+      CDFPRINTF((stderr, "th(%ld) %p compile() failed.\n",
+		 (long) th_self(), c->target));
+      throw_error_object(low_clone(compilation_error_program), 0, 0, 0,
+			 "Compilation failed.\n");
+    }
+    debug_malloc_touch(ret);
+#ifdef PIKE_DEBUG
+    if (a_flag > 2) {
+      dump_program_tables(ret, 0);
+    }
+#endif /* PIKE_DEBUG */
+    verify_supporters();
+  }
+  STACK_LEVEL_DONE(args);
+  pop_n_elems(args);
+  if (ret)
+    push_program(ret);
+  else
+    push_int(0);
+}
+
+/* Fake being called via CompilationEnvironment()->compile()
+ *
+ * This function is used to set up the environment for
+ * compiling C efuns and modules.
+ *
+ * Note: Since this is a stack frame, it will be cleaned up
+ *       automatically on error, so no need to use ONERROR().
+ *
+ * Note: Steals a reference from ce.
+ */
+static void low_enter_compiler(struct object *ce, int inherit)
+{
+  struct pike_frame *new_frame = alloc_pike_frame();
+#ifdef PROFILING
+  new_frame->children_base = Pike_interpreter.accounted_time;
+  new_frame->start_time = get_cpu_time() - Pike_interpreter.unlocked_time;
+  new_frame->ident = CE_COMPILE_FUN_NUM;	/* Fake call of compile(). */
+#endif /* PROFILING */
+  new_frame->next = Pike_fp;
+  new_frame->current_object = ce;
+  /* Note: The compilation environment object hangs on this frame,
+   *       so that it will be freed when the frame dies.
+   */
+  new_frame->current_program = ce->prog;
+  add_ref(new_frame->current_program);
+  new_frame->context = compilation_program->inherits + inherit;
+  new_frame->current_storage = ce->storage + new_frame->context->storage_offset;
+#ifdef PIKE_DEBUG
+  if (new_frame->context->prog != compilation_program) {
+    Pike_fatal("Invalid inherit for compilation context (%p != %p).\n",
+	       new_frame->context->prog, compilation_program);
+  }
+#endif /* PIKE_DEBUG */
+  new_frame->fun = new_frame->context->identifier_level + CE_COMPILE_FUN_NUM;
+  new_frame->expendible = Pike_sp;
+  new_frame->locals = Pike_sp;
+  new_frame->save_sp = Pike_sp;
+  new_frame->save_mark_sp = Pike_mark_sp;
+  new_frame->mark_sp_base = Pike_mark_sp;
+  new_frame->args = 0;
+  new_frame->num_locals = 0;
+  new_frame->pc = 0;
+  new_frame->return_addr = 0;
+  new_frame->scope = 0;
+  new_frame->save_sp = Pike_sp;
+  Pike_fp = new_frame;
+}
+
+void enter_compiler(struct pike_string *filename, int linenumber)
+{
+  struct object *ce = clone_object(compilation_program, 0);
+  struct compilation *c;
+
+  low_enter_compiler(ce, 0);
+
+  c = THIS_COMPILATION;
+  if (filename) {
+    free_string(c->lex.current_file);
+    copy_shared_string(c->lex.current_file, filename);
+  }
+  if (linenumber) {
+    c->lex.current_line = linenumber;
+  }
+}
+
+/* Reverse the effect of enter_compiler().
+ */
+void exit_compiler(void)
+{
+#ifdef PIKE_DEBUG
+  if ((Pike_fp->current_program != compilation_program) ||
+      (Pike_fp->fun != 2)) {
+    Pike_fatal("exit_compiler(): Frame stack out of whack!\n");
+  }
+#endif /* PIKE_DEBUG */
+  POP_PIKE_FRAME();
+}
+
+/*! @class PikeCompiler
+ *!
+ *!   The Pike compiler.
+ */
+
+/*! @decl void report(SeverityLevel severity, @
+ *!                   string filename, int linenumber, @
+ *!                   string subsystem, @
+ *!                   string message, mixed ... extra_args)
+ *!
+ *!   Report a diagnostic from the compiler.
+ *!
+ *!   The default implementation calls @[CompilerEnvironment::report()]
+ *!   with the same arguments.
+ */
+
+#define THIS_PROGRAM_STATE  ((struct program_state *)(Pike_fp->current_storage))
+
+static void program_state_event_handler(int event)
+{
+#if 0
+  struct program_state *c = THIS_PROGRAM_STATE;
+  switch (event) {
+  case PROG_EVENT_INIT:
+#define INIT
+#include "compilation.h"
+    break;
+  case PROG_EVENT_EXIT:
+#define EXIT
+#include "compilation.h"
+    break;
+  }
+#endif /* 0 */
+
+  fprintf(stderr, "program_state_event_handler(%d) obj:%p prog:%p\n",
+	  event, Pike_fp->current_object, Pike_fp->current_program);
+}
+
+/*! @endclass
+ */
+
+/*! @endclass
+ */
+
 /* Strap the compiler by creating the compilation program by hand. */
 static void compile_compiler(void)
 {
-  struct program *p = compilation_program = low_allocate_program();
-  struct reference *ref;
-  struct identifier *i;
-  struct inherit *inh;
-  unsigned INT16 *ix;
+  struct program *p = compilation_program = low_allocate_program(), *p2;
+  struct program_constant *pc;
+  struct reference *ref, *ref2;
+  struct identifier *i, *i2;
+  struct inherit *inh, *inh2;
+  unsigned INT16 *ix, *ix2;
+  int e;
 
   p->parent_info_storage = -1;
   p->event_handler = compilation_event_handler;
   p->flags |= PROGRAM_HAS_C_METHODS;
 
-  p->inherits = inh = malloc(sizeof(struct inherit));
-  p->identifier_references = ref = malloc(sizeof(struct reference) * 2);
-  p->identifiers = i = malloc(sizeof(struct identifier) * 2);
-  p->identifier_index = ix = malloc(sizeof(unsigned INT16) * 2);
+  p->inherits = inh = xalloc(sizeof(struct inherit));
+  p->identifier_references = ref = xalloc(sizeof(struct reference) * 3);
+  p->identifiers = i = xalloc(sizeof(struct identifier) * 3);
+  p->identifier_index = ix = xalloc(sizeof(unsigned INT16) * 3);
+  p->constants = pc = xalloc(sizeof(struct program_constant) * 1);
 
   inh->prog = p;
   inh->inherit_level = 0;
@@ -7570,13 +7927,19 @@ static void compile_compiler(void)
   p->inherits->storage_offset = 0;
   p->storage_needed = sizeof(struct compilation);
 
-  /* ADD_FUNCTION("compile", f_compilation_compile, ...); */
-  i->name = make_shared_string("compile");
-  i->type = make_pike_type(tFunc(tStr, tPrg(tObj)));
+  /* ADD_FUNCTION("report", f_compilation_report, ...); */
+  i->name = make_shared_string("report");
+  i->type = make_pike_type(tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
+				  tStr tStr, tMix, tVoid));
   i->run_time_type = T_FUNCTION;
   i->identifier_flags = IDENTIFIER_C_FUNCTION;
-  i->func.c_fun = f_compilation_compile;
+  i->func.c_fun = f_compilation_report;
   i->opt_flags = 0;
+#ifdef PROFILING
+  i->self_time = 0;
+  i->num_calls = 0;
+  i->total_time = 0;
+#endif
   i++;
   *(ix++) = ref->identifier_offset = compilation_program->num_identifiers++;
   p->num_identifier_index++;
@@ -7585,14 +7948,108 @@ static void compile_compiler(void)
   ref++;
   p->num_identifier_references++;
 
-  /* ADD_FUNCTION("report", f_compilation_report, ...); */
-  i->name = make_shared_string("report");
-  i->type = make_pike_type(tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
-				  tStr tStr, tMix, tVoid));
+  p2 = low_allocate_program();
+
+  pc->sval.u.program = p2;
+  pc->sval.type = T_PROGRAM;
+  pc->sval.subtype = 0;
+  pc->offset = -1;
+  i->name = make_shared_string("PikeCompiler");
+  i->type = get_type_of_svalue(&pc->sval);
+  i->run_time_type = T_PROGRAM;
+  i->identifier_flags = IDENTIFIER_CONSTANT;
+  i->func.offset = p->num_constants++;
+  pc++;
+  i->opt_flags = 0;
+#ifdef PROFILING
+  i->self_time = 0;
+  i->num_calls = 0;
+  i->total_time = 0;
+#endif
+  i++;
+  *(ix++) = ref->identifier_offset = compilation_program->num_identifiers++;
+  p->num_identifier_index++;
+  ref->id_flags = 0;
+  ref->inherit_offset = 0;
+  ref++;
+  p->num_identifier_references++;
+
+  /* FIXME: Parent info. */
+  p2->event_handler = program_state_event_handler;
+  p2->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT|PROGRAM_HAS_C_METHODS;
+  p2->parent_info_storage = 0;
+  p2->xstorage = sizeof(struct parent_info);
+
+  p2->inherits = inh2 = malloc(sizeof(struct inherit));
+  p2->identifier_references = ref2 = malloc(sizeof(struct reference) * 2);
+  p2->identifiers = i2 = malloc(sizeof(struct identifier) * 2);
+  p2->identifier_index = ix2 = malloc(sizeof(unsigned INT16) * 2);
+
+  inh2->prog = p2;
+  inh2->inherit_level = 0;
+  inh2->identifier_level = 0;
+  inh2->parent_identifier = -1;
+  inh2->parent_offset = OBJECT_PARENT;
+  inh2->identifier_ref_offset = 0;
+  inh2->storage_offset = p2->xstorage;
+  inh2->parent = NULL;
+  inh2->name = NULL;
+  p2->num_inherits = 1;
+
+  /* ADD_STORAGE(struct program_state); */
+  p2->alignment_needed = ALIGNOF(struct program_state);
+  p2->inherits->storage_offset = p2->xstorage;
+  p2->storage_needed = p2->xstorage + sizeof(struct program_state);
+
+  /* low_define_alias(NULL, NULL, 0, 1, 0); */
+  i2->name = make_shared_string("report");
+  i2->type = make_pike_type(tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
+				   tStr tStr, tMix, tVoid));
+  i2->run_time_type = T_FUNCTION;
+  i2->identifier_flags = IDENTIFIER_C_FUNCTION | IDENTIFIER_ALIAS;
+  i2->func.ext_ref.depth = 1;
+  i2->func.ext_ref.id = 0;
+  i2->opt_flags = 0;
+#ifdef PROFILING
+  i2->self_time = 0;
+  i2->num_calls = 0;
+  i2->total_time = 0;
+#endif
+  i2++;
+  *(ix2++) = ref2->identifier_offset = p2->num_identifiers++;
+  p2->num_identifier_index++;
+  ref2->id_flags = 0;
+  ref2->inherit_offset = 0;
+  ref2++;
+  p2->num_identifier_references++;
+  
+
+  p2->flags |= PROGRAM_PASS_1_DONE;
+
+  fsort_program_identifier_index(p2->identifier_index, ix2-1, p2);
+  p2->flags |= PROGRAM_FIXED;
+
+  /* Yes, it is supposed to start at 0  /Grubba */
+  for(e=0;e<NUM_LFUNS;e++) {
+    int id = p2->lfuns[e] = low_find_lfun(p2, e);
+  }
+
+  optimize_program(p2);
+  p2->flags |= PROGRAM_FINISHED;
+
+
+  /* ADD_FUNCTION("compile", f_compilation_compile, ...); */
+  i->name = make_shared_string("compile");
+  i->type = make_pike_type(tFunc(tStr, tPrg(tObj)));
   i->run_time_type = T_FUNCTION;
   i->identifier_flags = IDENTIFIER_C_FUNCTION;
-  i->func.c_fun = f_compilation_report;
+  i->func.c_fun = f_compilation_compile;
   i->opt_flags = 0;
+#ifdef PROFILING
+  i->self_time = 0;
+  i->num_calls = 0;
+  i->total_time = 0;
+#endif
   i++;
   *(ix++) = ref->identifier_offset = compilation_program->num_identifiers++;
   p->num_identifier_index++;
@@ -7606,12 +8063,16 @@ static void compile_compiler(void)
   fsort_program_identifier_index(p->identifier_index, ix-1, p);
   p->flags |= PROGRAM_FIXED;
 
+  /* Yes, it is supposed to start at 0  /Grubba */
+  for(e=0;e<NUM_LFUNS;e++) {
+    int id = p->lfuns[e] = low_find_lfun(p, e);
+  }
+
   optimize_program(p);
   p->flags |= PROGRAM_FINISHED;
-}
 
-/*! @endclass
- */
+  add_global_program("CompilerEnvironment", p);
+}
 
 struct program *compile(struct pike_string *aprog,
 			struct object *ahandler,/* error handler */
@@ -7624,14 +8085,23 @@ struct program *compile(struct pike_string *aprog,
 #ifdef PIKE_DEBUG
   ONERROR tmp;
 #endif
-  struct compilation *c=ALLOC_STRUCT(compilation);
+  struct object *ce;
+  struct compilation *c;
 
-  verify_supporters();
+  /* FIXME! */
+
+  Pike_fatal("Old C-level compile() function called!\n");
 
   CDFPRINTF((stderr, "th(%ld) %p compile() enter, placeholder=%p\n",
 	     (long) th_self(), atarget, aplaceholder));
 
+  ce = clone_object(compilation_program, 0);
+  c = (struct compilation *)ce->storage;
+
   debug_malloc_touch(c);
+
+  verify_supporters();
+
   c->p = NULL;
   add_ref(c->prog=aprog);
   if((c->handler=ahandler)) add_ref(ahandler);
@@ -7697,8 +8167,7 @@ struct program *compile(struct pike_string *aprog,
     ret=c->p;
 
     debug_malloc_touch(c);
-    free_compilation(c);
-    free(c);
+    free_object(ce);
 
     if (!dependants_ok) {
       CDFPRINTF((stderr, "th(%ld) %p compile() reporting failure "
@@ -7955,6 +8424,8 @@ void init_program(void)
 
   compile_compiler();
 
+  enter_compiler(NULL, 0);
+
   MAKE_CONST_STRING(this_program_string,"this_program");
   MAKE_CONST_STRING(this_string,"this");
   MAKE_CONST_STRING(UNDEFINED_string,"UNDEFINED");
@@ -8036,6 +8507,8 @@ void init_program(void)
     low_add_constant("__placeholder_object",&s);
     debug_malloc_touch(placeholder_object);
   }
+
+  exit_compiler();
 }
 
 void cleanup_program(void)
@@ -8395,6 +8868,7 @@ void push_compiler_frame(int lexical_scope)
 
 void low_pop_local_variables(int level)
 {
+  struct compilation *c = THIS_COMPILATION;
   while(Pike_compiler->compiler_frame->current_number_of_locals > level)
   {
     int e;
@@ -8402,14 +8876,14 @@ void low_pop_local_variables(int level)
     if ((Pike_compiler->compiler_pass == 2) &&
 	!(Pike_compiler->compiler_frame->variable[e].flags &
 	  LOCAL_VAR_IS_USED)) {
-      struct pike_string *save_file = lex.current_file;
-      int save_line = lex.current_line;
-      lex.current_file = Pike_compiler->compiler_frame->variable[e].file;
-      lex.current_line = Pike_compiler->compiler_frame->variable[e].line;
+      struct pike_string *save_file = c->lex.current_file;
+      int save_line = c->lex.current_line;
+      c->lex.current_file = Pike_compiler->compiler_frame->variable[e].file;
+      c->lex.current_line = Pike_compiler->compiler_frame->variable[e].line;
       yywarning("Unused local variable %S.",
 		Pike_compiler->compiler_frame->variable[e].name);
-      lex.current_file = save_file;
-      lex.current_line = save_line;
+      c->lex.current_file = save_file;
+      c->lex.current_line = save_line;
     }
     free_string(Pike_compiler->compiler_frame->variable[e].name);
     free_type(Pike_compiler->compiler_frame->variable[e].type);
@@ -8423,6 +8897,7 @@ void low_pop_local_variables(int level)
 void pop_local_variables(int level)
 {
 #if 1
+  struct compilation *c = THIS_COMPILATION;
   /* We need to save the variables Kuppo (but not their names) */
   if(level < Pike_compiler->compiler_frame->min_number_of_locals)
   {
@@ -8433,14 +8908,16 @@ void pop_local_variables(int level)
       if ((Pike_compiler->compiler_pass == 2) &&
 	  !(Pike_compiler->compiler_frame->variable[level].flags &
 	    LOCAL_VAR_IS_USED)) {
-	struct pike_string *save_file = lex.current_file;
-	int save_line = lex.current_line;
-	lex.current_file = Pike_compiler->compiler_frame->variable[level].file;
-	lex.current_line = Pike_compiler->compiler_frame->variable[level].line;
+	struct pike_string *save_file = c->lex.current_file;
+	int save_line = c->lex.current_line;
+	c->lex.current_file =
+	  Pike_compiler->compiler_frame->variable[level].file;
+	c->lex.current_line =
+	  Pike_compiler->compiler_frame->variable[level].line;
 	yywarning("Unused local variable %S.",
 		Pike_compiler->compiler_frame->variable[level].name);
-	lex.current_file = save_file;
-	lex.current_line = save_line;
+	c->lex.current_file = save_file;
+	c->lex.current_line = save_line;
 	/* Make sure we only warn once... */
 	Pike_compiler->compiler_frame->variable[level].flags |=
 	  LOCAL_VAR_IS_USED;
@@ -8649,10 +9126,13 @@ int find_child(struct program *parent, struct program *child)
 
 void yywarning(char *fmt, ...)
 {
+  struct compilation *c = THIS_COMPILATION;
   struct string_builder s;
   struct pike_string *msg;
   va_list args;
 
+  CHECK_COMPILER();
+
   /* If we have parse errors we might get erroneous warnings,
    * so don't print them.
    * This has the additional benefit of making it easier to
@@ -8667,21 +9147,17 @@ void yywarning(char *fmt, ...)
   msg = finish_string_builder(&s);
 
   if (master_object) {
-    if (lex.current_file) {
-      ref_push_string(lex.current_file);
-    } else {
-      push_empty_string();
-    }
-    push_int(lex.current_line);
+    ref_push_string(c->lex.current_file);
+    push_int(c->lex.current_line);
     push_string(msg);
 
     low_safe_apply_handler("compile_warning",
-			   error_handler, compat_handler, 3);
+			   c->handler, c->compat_handler, 3);
     pop_stack();
   } else {
     if (!msg->size_shift) {
       fprintf(stderr, "%s:%d: Warning: %s\n",
-	      lex.current_file->str, lex.current_line, msg->str);
+	      c->lex.current_file->str, c->lex.current_line, msg->str);
     }
     free_string(msg);
   }
@@ -9001,6 +9477,10 @@ PMOD_EXPORT void *parent_storage(int depth)
 
 PMOD_EXPORT void change_compiler_compatibility(int major, int minor)
 {
+  struct compilation *c = THIS_COMPILATION;
+
+  CHECK_COMPILER();
+
   STACK_LEVEL_START(0);
 
   if(major == PIKE_MAJOR_VERSION && minor == PIKE_MINOR_VERSION)
@@ -9010,8 +9490,8 @@ PMOD_EXPORT void change_compiler_compatibility(int major, int minor)
     if(major == Pike_compiler->compat_major &&
        minor == Pike_compiler->compat_minor) {
       /* Optimization -- reuse the current compat handler. */
-      if (compat_handler) {
-	ref_push_object(compat_handler);
+      if (c->compat_handler) {
+	ref_push_object(c->compat_handler);
       } else {
 	push_int(0);
       }
@@ -9024,10 +9504,10 @@ PMOD_EXPORT void change_compiler_compatibility(int major, int minor)
 
   STACK_LEVEL_CHECK(1);
 
-  if(compat_handler)
+  if(c->compat_handler)
   {
-    free_object(compat_handler);
-    compat_handler = NULL;
+    free_object(c->compat_handler);
+    c->compat_handler = NULL;
   }
   
   if((Pike_sp[-1].type == T_OBJECT) && (Pike_sp[-1].u.object->prog))
@@ -9036,14 +9516,15 @@ PMOD_EXPORT void change_compiler_compatibility(int major, int minor)
       /* FIXME: */
       Pike_error("Subtyped compat handlers are not supported yet.\n");
     }
-    compat_handler = dmalloc_touch(struct object *, Pike_sp[-1].u.object);
+    c->compat_handler = dmalloc_touch(struct object *, Pike_sp[-1].u.object);
     dmalloc_touch_svalue(Pike_sp-1);
     Pike_sp--;
   } else {
     pop_stack();
   }
 
-  if (safe_apply_handler ("get_default_module", error_handler, compat_handler,
+  if (safe_apply_handler ("get_default_module",
+			  c->handler, c->compat_handler,
 			  0, BIT_MAPPING|BIT_OBJECT|BIT_ZERO)) {
     if(Pike_sp[-1].type == T_INT)
     {
diff --git a/src/program.h b/src/program.h
index 03ea246d943f4b11b59bce6e2ead4eb4fe3a5e8d..32c41e269379fe3a6b366778cc78adb69b36df3e 100644
--- a/src/program.h
+++ b/src/program.h
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: program.h,v 1.236 2007/12/28 13:38:16 nilsson Exp $
+|| $Id: program.h,v 1.237 2008/04/14 10:14:41 grubba Exp $
 */
 
 #ifndef PROGRAM_H
@@ -659,11 +659,9 @@ PMOD_EXPORT void gc_check_zapped (void *a, TYPE_T type, const char *file, int li
 BLOCK_ALLOC_FILL_PAGES(program, n/a);
 
 
-extern struct object *error_handler;
-extern struct object *compat_handler;
-
 extern struct program *first_program;
 extern struct program *null_program;
+extern struct program *compilation_program;
 extern struct program *pike_trampoline_program;
 extern struct program *gc_internal_program;
 extern struct program *placeholder_program;
@@ -695,13 +693,12 @@ struct Supporter
   struct Supporter *depends_on;
   struct Supporter *dependants;
   struct Supporter *next_dependant;
+  struct object *self;
   supporter_callback *fun;
   void *data;
   struct program *prog;
 };
 
-
-
 /* Prototypes begin here */
 PMOD_EXPORT void do_free_program (struct program *p);
 void ins_int(INT32 i, void (*func)(char tmp));
@@ -887,6 +884,8 @@ int call_dependants(struct Supporter *s, int finish);
 int report_compiler_dependency(struct program *p);
 struct compilation;
 void run_pass2(struct compilation *c);
+void enter_compiler(struct pike_string *filename, int linenumber);
+void exit_compiler(void);
 struct program *compile(struct pike_string *aprog,
 			struct object *ahandler,
 			int amajor, int aminor,