diff --git a/bin/mktestsuite b/bin/mktestsuite
index d1a6ed108923dc4dd3b9dd6d5fc79bdc15141f83..0d0cdab03b82e307f220370a1975250d91a3db86 100755
--- a/bin/mktestsuite
+++ b/bin/mktestsuite
@@ -53,7 +53,7 @@ define(test_eval_error,[[DOTEST(EVAL_ERROR,dnl
 mixed a() { [[$1]]; })]])
 
 define(test_define_program,[[DOTEST(RUN,dnl
-void a() { add_constant("[[$1]]",class {
+void a() { add_constant("[[$1]]",class c {
   [[$2]]
 });})]])
 
diff --git a/lib/master.pike b/lib/master.pike
index 5aad3438d461d977c42cf596940dbd5bc9035410..25f788cb2d8ab67e4451707c3244c28f0a6c5139 100644
--- a/lib/master.pike
+++ b/lib/master.pike
@@ -11,6 +11,16 @@ string *pike_program_path=({});
 
 int want_warnings;
 
+program compile_string(string data, void|string name)
+{
+  return compile(cpp(data,name||"-"));
+}
+
+program compile_file(string file)
+{
+  return compile(cpp(_static_modules.files()->file(file,"r")->read(),file));
+}
+
 mapping (string:string) environment=([]);
 
 varargs mixed getenv(string s)
@@ -185,6 +195,8 @@ object new(mixed prog, mixed ... args)
 void create()
 {
   /* make ourselves known */
+  add_constant("compile_string",compile_string);
+  add_constant("compile_file",compile_file);
   add_constant("add_include_path",add_include_path);
   add_constant("remove_include_path",remove_include_path);
   add_constant("add_module_path",add_module_path);
@@ -517,6 +529,11 @@ void compile_warning(string file,int line,string err)
   }
 }
 
+string read_include(string f)
+{
+  return _static_modules->files()->file(f,"r")->read();
+}
+
 /* This function is called whenever an #include directive is encountered
  * it receives the argument for #include and should return the file name
  * of the file to include
diff --git a/src/ChangeLog b/src/ChangeLog
index bdb237e4335f182a0a02cb89b0270855c264e2fd..702df0c80c53300850c2d047607fb0a96528c864 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,10 @@
+Wed Jun 25 15:33:23 1997  Fredrik Hubinette  <hubbe@cytocin.hubbe.net>
+
+	* Compiler is now two-pass -> no more prototypes
+	* New efun: cpp()
+	* you can now access a class name from inside itself
+	* objects now have parents
+
 Sat May 10 06:20:51 1997  Fredrik Hubinette  <hubbe@cytocin.hubbe.net>
 
 	* fork() now returns an object
diff --git a/src/Makefile.in b/src/Makefile.in
index fcd4fe18450d751ae6941cd70d78e331670864f4..51d95c13da73fe0fa74c15f2081d00fedc5c391a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -65,6 +65,7 @@ MAKE_FLAGS = "prefix=$(prefix)" "exec_prefix=$(exec_prefix)" "CC=$(CC)" "OTHERFL
 # Add ualarm.o if you don't have ualarm() on your machine.
 #
 OBJ= \
+ cpp.o \
  language.o \
  constants.o \
  array.o \
diff --git a/src/backend.c b/src/backend.c
index e0754176b8f284b761f339dca39ab8b990df3cea..842a49ade23c3a8762ccc00502adfdf531273414 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: backend.c,v 1.10.2.2 1997/05/19 09:04:55 hubbe Exp $");
+RCSID("$Id: backend.c,v 1.10.2.3 1997/06/25 22:46:34 hubbe Exp $");
 #include "backend.h"
 #include <errno.h>
 #ifdef HAVE_SYS_TYPES_H
@@ -119,6 +119,7 @@ void set_read_callback(int fd,file_callback cb,void *data)
 
   if(cb)
   {
+    wake_up_backend();
     FD_SET(fd, &selectors.read);
     if(max_fd < fd) max_fd = fd;
   }else{
@@ -148,6 +149,7 @@ void set_write_callback(int fd,file_callback cb,void *data)
 
   if(cb)
   {
+    wake_up_backend();
     FD_SET(fd, &selectors.write);
     if(max_fd < fd) max_fd = fd;
   }else{
diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 2279f3ee24c176fe73f50d674515cf6a94757cca..2b0ce84c7cf4e2e4637430a7e4c4cf8d69ebd46f 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: builtin_functions.c,v 1.36 1997/05/07 06:27:32 per Exp $");
+RCSID("$Id: builtin_functions.c,v 1.36.2.1 1997/06/25 22:46:35 hubbe Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "pike_macros.h"
@@ -281,6 +281,28 @@ void f_call_function(INT32 args)
   }
 }
 
+void f_parent(INT32 args)
+{
+  struct object *o;
+  if(!args)
+  {
+    o=fp->current_object;
+  }else{
+    if(sp[-args].type!=T_OBJECT)
+      error("Bad argument 1 to parent()\n");
+    o=sp[-args].u.object;
+  }
+  o->refs++;
+  pop_n_elems(args);
+  if(o->parent)
+  {
+    ref_push_object(o->parent);
+  }else{
+    push_int(0);
+  }
+  free_object(o);
+}
+
 void f_backtrace(INT32 args)
 {
   INT32 frames;
@@ -364,20 +386,6 @@ void f_add_constant(INT32 args)
   pop_n_elems(args);
 }
 
-void f_compile_file(INT32 args)
-{
-  struct program *p;
-  if(args<1)
-    error("Too few arguments to compile_file.\n");
-
-  if(sp[-args].type!=T_STRING)
-    error("Bad argument 1 to compile_file.\n");
-
-  p=compile_file(sp[-args].u.string);
-  pop_n_elems(args);
-  push_program(p);
-}
-
 static char *combine_path(char *cwd,char *file)
 {
   /* cwd is supposed to be combined already */
@@ -839,24 +847,38 @@ void f_next_object(INT32 args)
 
 void f_object_program(INT32 args)
 {
-  struct program *p;
   if(args < 1)
     error("Too few argumenets to object_program()\n");
 
   if(sp[-args].type == T_OBJECT)
-    p=sp[-args].u.object->prog;
-  else
-    p=0;
-
-  pop_n_elems(args);
-
-  if(!p)
   {
-    push_int(0);
-  }else{
-    p->refs++;
-    push_program(p);
+    struct object *o=sp[-args].u.object;
+    struct program *p;
+    if((p=o->prog))
+    {
+      if(o->parent && o->parent->prog)
+      {
+	INT32 i=find_child(o->parent->prog, p);
+	if(i!=-1)
+	{
+	  o->refs++;
+	  pop_n_elems(args);
+	  push_object(o->parent);
+	  sp[-1].subtype=i;
+	  sp[-1].type=T_FUNCTION;
+	  return;
+	}
+      }else{
+	p->refs++;
+	pop_n_elems(args);
+	push_program(p);
+	return;
+      }
+    }
   }
+
+  pop_n_elems(args);
+  push_int(0);
 }
 
 void f_reverse(INT32 args)
@@ -1068,26 +1090,17 @@ void f_replace(INT32 args)
   }
 }
 
-void f_compile_string(INT32 args)
+void f_compile(INT32 args)
 {
   
   struct program *p;
   if(args < 1)
-    error("Too few arguments to compile_string()\n");
+    error("Too few arguments to compile()\n");
 
   if(sp[-args].type != T_STRING)
-    error("Bad argument 1 to compile_string()\n");
-
-  if(args < 2)
-  {
-    push_string(make_shared_string("-"));
-    args++;
-  }
-
-  if(sp[1-args].type != T_STRING)
-    error("Bad argument 2 to compile_string()\n");
+    error("Bad argument 1 to compile()\n");
 
-  p=compile_string(sp[-args].u.string,sp[1-args].u.string);
+  p=compile(sp[-args].u.string);
   pop_n_elems(args);
   push_program(p);
 }
@@ -1206,7 +1219,6 @@ void ID(INT32 args) \
   push_int(t); \
 }
 
-TYPEP(f_programp, "programp", T_PROGRAM)
 TYPEP(f_intp, "intpp", T_INT)
 TYPEP(f_mappingp, "mappingp", T_MAPPING)
 TYPEP(f_arrayp, "arrayp", T_ARRAY)
@@ -1214,6 +1226,31 @@ TYPEP(f_multisetp, "multisetp", T_MULTISET)
 TYPEP(f_stringp, "stringp", T_STRING)
 TYPEP(f_floatp, "floatp", T_FLOAT)
 
+void f_programp(INT32 args)
+{
+  if(args<1)
+    error("Too few arguments to programp()\n");
+  switch(sp[-args].type)
+  {
+  case T_PROGRAM:
+    pop_n_elems(args);
+    push_int(1);
+    return;
+
+  case T_FUNCTION:
+    if(program_from_function(sp-args))
+    {
+      pop_n_elems(args);
+      push_int(1);
+      return;
+    }
+
+  default:
+    pop_n_elems(args);
+    push_int(0);
+  }
+}
+
 void f_sort(INT32 args)
 {
   INT32 e,*order;
@@ -1702,8 +1739,7 @@ void init_builtin_efuns()
 
   add_efun("column",f_column,"function(array,mixed:array)",0);
   add_efun("combine_path",f_combine_path,"function(string,string:string)",0);
-  add_efun("compile_file",f_compile_file,"function(string:program)",OPT_EXTERNAL_DEPEND);
-  add_efun("compile_string",f_compile_string,"function(string,string|void:program)",OPT_EXTERNAL_DEPEND);
+  add_efun("compile",f_compile,"function(string:program)",OPT_EXTERNAL_DEPEND);
   add_efun("copy_value",f_copy_value,"function(mixed:mixed)",0);
   add_efun("crypt",f_crypt,"function(string:string)|function(string,string:int)",OPT_EXTERNAL_DEPEND);
   add_efun("ctime",f_ctime,"function(int:string)",OPT_TRY_OPTIMIZE);
@@ -1768,5 +1804,6 @@ void init_builtin_efuns()
 
   add_efun("encode_value", f_encode_value, "function(mixed:string)", OPT_TRY_OPTIMIZE);
   add_efun("decode_value", f_decode_value, "function(string:mixed)", OPT_TRY_OPTIMIZE);
+  add_efun("parent", f_parent, "function(object|void:object)", OPT_EXTERNAL_DEPEND);
 }
 
diff --git a/src/builtin_functions.h b/src/builtin_functions.h
index eb2b465b0d8efb4b3e1aa845741ea59d50ae08cf..83f9da886633eeb9e5a34dab0b1fada9e5f2d7d5 100644
--- a/src/builtin_functions.h
+++ b/src/builtin_functions.h
@@ -57,7 +57,6 @@ void f_objectp(INT32 args);
 void f_functionp(INT32 args);
 void f_sleep(INT32 args);
 void f_gc(INT32 args);
-TYPEP(f_programp, "programp", T_PROGRAM)
 TYPEP(f_intp, "intpp", T_INT)
 TYPEP(f_mappingp, "mappingp", T_MAPPING)
 TYPEP(f_arrayp, "arrayp", T_ARRAY)
diff --git a/src/compilation.h b/src/compilation.h
index 6c614ed7fecbf76ff2adc8dc149654a8f480b07b..4be9a7a69013b7af80d03762370a0c15e2aa5028 100644
--- a/src/compilation.h
+++ b/src/compilation.h
@@ -14,7 +14,6 @@
  * defining PUSH pushes the selected state(s) on the stack(s)
  * defining POP pops the selected state(s) from the stack(s)
  *
- * define FILE_STATE to select the file state
  * define PROGRAM_STATE to select the program state
  */
 
@@ -75,35 +74,19 @@
   ZMEMBER(struct pike_string *,X)
 #endif
 
-#ifdef PROGRAM_STATE
   SNAME(program_state,previous_program_state)
   ZMEMBER(INT32,last_line)
   STRMEMBER(last_file,"last_file")
-  ZMEMBER(struct program,fake_program)
+  ZMEMBER(struct program *,new_program)
+  ZMEMBER(struct program *,malloc_size_program)
   ZMEMBER(node *,init_node)
   ZMEMBER(INT32,last_pc)
   ZMEMBER(int,num_parse_error)
-  ZMEMBER(struct locals *,local_variables)
-  ZMEMBER(dynamic_buffer,inherit_names)
+  ZMEMBER(struct compiler_frame *,compiler_frame)
   ZMEMBER(dynamic_buffer,used_modules)
-  ZMEMBER2(dynamic_buffer,areas,[NUM_AREAS])
   IMEMBER(int,comp_stackp)
+  IMEMBER(int,compiler_pass)
   SEND
-#endif
-
-#ifdef FILE_STATE
-  SNAME(file_state,previous_file_state)
-  ZMEMBER(INT32,old_line)
-  ZMEMBER(INT32,current_line)
-  ZMEMBER(INT32,nexpands)
-  ZMEMBER(int,pragma_all_inline)
-  ZMEMBER(struct inputstate *,istate)
-  ZMEMBER(struct hash_table *,defines)
-  ZMEMBER(struct program_state *,previous_program_state)
-  STRMEMBER(current_file,"current_file")
-  SEND
-#endif
-
 
 #undef PCODE
 #undef STRMEMBER
@@ -113,3 +96,8 @@
 #undef ZMEMBER2
 #undef SNAME
 #undef SEND
+
+#undef STRUCT
+#undef PUSH
+#undef POP
+#undef DECLARE
diff --git a/src/cpp.c b/src/cpp.c
new file mode 100644
index 0000000000000000000000000000000000000000..0b6f8d0224a9b40a161da3b7b1979960f13631aa
--- /dev/null
+++ b/src/cpp.c
@@ -0,0 +1,1878 @@
+/*\
+||| This file a part of Pike, and is copyright by Fredrik Hubinette
+||| Pike is distributed as GPL (General Public License)
+||| See the files COPYING and DISCLAIMER for more information.
+\*/
+#include "global.h"
+#include "dynamic_buffer.h"
+#include "lex.h"
+#include "language.h"
+#include "stralloc.h"
+#include "module_support.h"
+#include "interpret.h"
+#include "svalue.h"
+#include "pike_macros.h"
+#include "hashtable.h"
+#include "program.h"
+#include "object.h"
+#include "error.h"
+#include "array.h"
+#include "mapping.h"
+#include "builtin_functions.h"
+#include "operators.h"
+#include "opcodes.h"
+#include "constants.h"
+#include "time.h"
+#include "stuff.h"
+#include <ctype.h>
+
+#define CPP_NO_OUTPUT 1
+#define CPP_EXPECT_ELSE 2
+#define CPP_EXPECT_ENDIF 4
+#define CPP_REALLY_NO_OUTPUT 8
+#define CPP_END_AT_NEWLINE 16
+#define CPP_DO_IF 32
+
+#define OUTP() (!(flags & (CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT)))
+#define PUTNL() low_my_putchar('\n', &this->buf)
+#define GOBBLE(X) (data[pos]==(X)?++pos,1:0)
+#define PUTC(C) do { \
+ int c_=(C); if(OUTP() || c_=='\n') low_my_putchar(c_, &this->buf); }while(0)
+
+#define STRCAT(STR,LEN) do {				\
+  INT32 x_,len_=(LEN);					\
+  char *str_=(STR);					\
+  if(OUTP())						\
+    low_my_binary_strcat(str_,len_, &this->buf);	\
+  else							\
+    for(x_=0;x_<len_;x_++)				\
+      if(str_[x_]=='\n')				\
+        low_my_putchar('\n',&this->buf);		\
+}while(0)
+
+#define CHECKWORD(X) \
+ (!strncmp(X,data+pos,strlen(X)) && !isidchar(data[pos+strlen(X)]))
+#define WGOBBLE(X) (CHECKWORD(X) ? (pos+=strlen(X)),1 : 0)
+#define GOBBLEOP(X) \
+ ((!strncmp(X,data+pos,strlen(X))) ? (pos+=strlen(X)),1 : 0)
+
+#define MAX_ARGS            255
+#define DEF_ARG_STRINGIFY   0x100000
+#define DEF_ARG_NOPRESPACE  0x200000
+#define DEF_ARG_NOPOSTSPACE 0x400000
+#define DEF_ARG_MASK        0x0fffff
+
+
+struct pike_predef_s
+{
+  struct pike_predef_s *next;
+  char *name;
+  char *value;
+};
+
+struct pike_predef_s *pike_predefs=0;
+struct define_part
+{
+  int argument;
+  struct pike_string *postfix;
+};
+
+struct define_argument {
+  char *arg;
+  INT32 len;
+};
+
+
+struct cpp;
+struct define;
+typedef void (*magic_define_fun)(struct cpp *,
+				 struct define *,
+				 struct define_argument *,
+				 dynamic_buffer *);
+
+
+struct define
+{
+  struct hash_entry link; /* must be first */
+  magic_define_fun magic;
+  int args;
+  int num_parts;
+  int inside;
+  struct pike_string *first;
+  struct define_part parts[1];
+};
+
+#define find_define(N) \
+  (this->defines?BASEOF(hash_lookup(this->defines, N), define, link):0)
+
+struct cpp
+{
+  struct hash_table *defines;
+  INT32 current_line;
+  INT32 compile_errors;
+  struct pike_string *current_file;
+  dynamic_buffer buf;
+};
+
+struct define *defined_macro =0;
+struct define *constant_macro =0;
+
+static INT32 calc(struct cpp *,char*,INT32,INT32);
+static INT32 calc1(struct cpp *,char*,INT32,INT32);
+
+void cpp_error(struct cpp *this,char *err)
+{
+  this->compile_errors++;
+  if(this->compile_errors > 10) return;
+  if(get_master())
+  {
+    ref_push_string(this->current_file);
+    push_int(this->current_line);
+    push_text(err);
+    SAFE_APPLY_MASTER("compile_error",3);
+    pop_stack();
+  }else{
+    (void)fprintf(stderr, "%s:%ld: %s",
+		  this->current_file->str,
+		  (long)this->current_line,
+		  err);
+    fflush(stderr);
+  }
+}
+
+/* devours one reference to 'name'! */
+static struct define *alloc_empty_define(struct pike_string *name, INT32 parts)
+{
+  struct define *def;
+  def=(struct define *)xalloc(sizeof(struct define)+
+			      sizeof(struct define_part) * (parts -1));
+  def->magic=0;
+  def->args=-1;
+  def->inside=0;
+  def->num_parts=parts;
+  def->first=0;
+  def->link.s=name;
+  return def;
+}
+
+static void undefine(struct cpp *this,
+		     struct pike_string *name)
+{
+  INT32 e;
+  struct define *d;
+
+  d=find_define(name);
+
+  if(!d) return;
+
+  this->defines=hash_unlink(this->defines, & d->link);
+
+  for(e=0;e<d->num_parts;e++)
+    free_string(d->parts[e].postfix);
+  free_string(d->link.s);
+  if(d->first)
+    free_string(d->first);
+  free((char *)d);
+}
+
+static void do_magic_define(struct cpp *this,
+			    char *name,
+			    magic_define_fun fun)
+{
+  struct define* def=alloc_empty_define(make_shared_string(name),0);
+  def->magic=fun;
+  this->defines=hash_insert(this->defines, & def->link);
+}
+
+static void simple_add_define(struct cpp *this,
+			    char *name,
+			    char *what)
+{
+  struct define* def=alloc_empty_define(make_shared_string(name),0);
+  def->first=make_shared_string(what);
+  this->defines=hash_insert(this->defines, & def->link);
+}
+
+
+/* Who needs inline functions anyway? /Hubbe */
+
+#define FIND_END_OF_STRING() do {					\
+  while(1)								\
+  {									\
+    if(pos>=len)							\
+    {									\
+      cpp_error(this,"End of file in string.");				\
+      break;								\
+    }									\
+    switch(data[pos++])							\
+    {									\
+    case '\n':								\
+      cpp_error(this,"Newline in string.");				\
+      this->current_line++;						\
+      break;								\
+    case '"': break;							\
+    case '\\': if(data[++pos]=='\n') this->current_line++;		\
+    default: continue;							\
+    }									\
+   break;								\
+  } } while(0)
+
+
+#define FIND_END_OF_CHAR() do {					\
+  int e=0;							\
+  while(1)							\
+  {								\
+    if(pos+1>=len)						\
+    {								\
+      cpp_error(this,"End of file in character constant.");	\
+      break;							\
+    }								\
+								\
+    if(e++>16)							\
+    {								\
+      cpp_error(this,"Too long character constant.");		\
+      break;							\
+    }								\
+								\
+    switch(data[pos++])						\
+    {								\
+    case '\n':							\
+      cpp_error(this,"Newline in char.");			\
+      this->current_line++;					\
+      break;							\
+    case '\'': break;						\
+    case '\\': if(data[++pos]=='\n') this->current_line++;	\
+    default: continue;						\
+    }								\
+    break;							\
+  } } while(0)
+
+#define DUMPPOS(X)					\
+		  fprintf(stderr,"\nPOS(%s):",X);	\
+		  fflush(stderr);			\
+		  write(2,data+pos,20);			\
+		  fprintf(stderr,"\n");			\
+		  fflush(stderr)
+
+#define FIND_EOL() do {				\
+    this->current_line++;			\
+    while(pos < len && data[pos]!='\n') pos++;	\
+  } while(0)
+
+#define SKIPWHITE() do {			\
+    if(!isspace(data[pos])) break;		\
+    PUTNL();					\
+    pos++;					\
+  } while(0)
+
+#define SKIPSPACE() \
+  do { while(isspace(data[pos]) && data[pos]!='\n') pos++; }while (0)
+
+#define SKIPCOMMENT()	do{				\
+  	pos++;						\
+	while(data[pos]!='*' || data[pos+1]!='/')	\
+	{						\
+	  if(pos+2>=len)				\
+	  {						\
+	    cpp_error(this,"End of file in comment.");	\
+	    break;					\
+	  }						\
+							\
+	  if(data[pos]=='\n')				\
+	  {						\
+	    this->current_line++;			\
+	    PUTNL();					\
+	  }						\
+							\
+	  pos++;					\
+	}						\
+	pos+=2;						\
+  }while(0)
+
+#define READCHAR(C) do {			\
+  switch(data[++pos])				\
+  {						\
+  case 'n': C='\n'; break;			\
+  case 'r': C='\r'; break;			\
+  case 'b': C='\b'; break;			\
+  case 't': C='\t'; break;			\
+    						\
+  case '0': case '1': case '2': case '3':	\
+  case '4': case '5': case '6': case '7':	\
+    C=data[pos]-'0';				\
+    if(data[pos+1]>='0' && data[pos+1]<='8')	\
+    {						\
+      C*=8;					\
+      C+=data[++pos]-'0';			\
+      						\
+      if(data[pos+1]>='0' && data[pos+1]<='8')	\
+      {						\
+	C*=8;					\
+	C+=data[++pos]-'0';			\
+      }						\
+    }						\
+    break;					\
+    						\
+  case '\n':					\
+    this->current_line++;			\
+    C='\n';					\
+    break;					\
+    						\
+  default:					\
+    C=data[pos];				\
+  }						\
+}while (0)
+
+
+#define READSTRING(nf)				\
+while(1)					\
+{						\
+  pos++;					\
+  if(pos>=len)					\
+  {						\
+    cpp_error(this,"End of file in string.");	\
+    break;					\
+  }						\
+						\
+  switch(data[pos])				\
+  {						\
+  case '\n':					\
+    cpp_error(this,"Newline in string.");	\
+    this->current_line++;			\
+    break;					\
+  case '"':  break;				\
+  case '\\':					\
+  {						\
+    int tmp;					\
+    READCHAR(tmp);				\
+    low_my_putchar(tmp, &nf);			\
+    continue;					\
+  }						\
+						\
+  default:					\
+    low_my_putchar(data[pos], &nf);		\
+    continue;					\
+  }						\
+  pos++;					\
+  break;					\
+}
+
+void PUSH_STRING(char *str,
+		 INT32 len,
+		 dynamic_buffer *buf)
+{
+  INT32 p2;
+  low_my_putchar('"', buf);
+  for(p2=0;p2<len;p2++)
+  {
+    switch(str[p2])
+    {
+    case '\n':
+      low_my_putchar('\\', buf);
+      low_my_putchar('n', buf);
+      break;
+      
+    case '\t':
+      low_my_putchar('\\', buf);
+      low_my_putchar('t', buf);
+      break;
+      
+    case '\r':
+      low_my_putchar('\\', buf);
+      low_my_putchar('r', buf);
+      break;
+      
+    case '\b':
+      low_my_putchar('\\', buf);
+      low_my_putchar('b', buf);
+      break;
+      
+    case '\\':
+    case '"':
+      low_my_putchar('\\', buf);
+      low_my_putchar(str[p2], buf);
+      break;
+      
+    default:
+      if(isprint(EXTRACT_UCHAR(str+p2)))
+      {
+	low_my_putchar(str[p2], buf);
+      }
+      else
+      {
+	int c=EXTRACT_UCHAR(str+p2);
+	low_my_putchar('\\', buf);
+	low_my_putchar(((c>>6)&7)+'0', buf);
+	low_my_putchar(((c>>3)&7)+'0', buf);
+	low_my_putchar((c&7)+'0', buf);
+      }
+      break;
+    }
+  }
+  low_my_putchar('"', buf);
+}
+
+#define FINDTOK() 				\
+  do {						\
+  SKIPSPACE();					\
+  if(data[pos]=='/')				\
+  {						\
+    INT32 tmp;					\
+    switch(data[pos+1])				\
+    {						\
+    case '/':					\
+      FIND_EOL();				\
+      break;					\
+      						\
+    case '*':					\
+      tmp=pos+2;				\
+      while(1)					\
+      {						\
+        if(data[tmp]=='*')			\
+	{					\
+	  if(data[tmp+1] == '/')		\
+	  {					\
+	    pos=tmp+2;				\
+	    break;				\
+	  }					\
+	  break;				\
+	}					\
+						\
+	if(data[tmp]=='\n')			\
+	  break;				\
+        tmp++;					\
+      }						\
+    }						\
+  }						\
+  break;					\
+  }while(1)
+
+static INLINE int find_end_parenthesis(struct cpp *this,
+				       char *data,
+				       INT32 len,
+				       INT32 pos) /* position of first " */
+{
+  while(1)
+  {
+    if(pos+1>=len)
+    {
+      cpp_error(this,"End of file while looking for end parenthesis.");
+      return pos;
+    }
+
+    switch(data[pos++])
+    {
+    case '\n': this->current_line++; break;
+    case '\'': FIND_END_OF_CHAR();  break;
+    case '"':  FIND_END_OF_STRING();  break;
+    case '(':  pos=find_end_parenthesis(this, data, len, pos); break;
+    case ')':  return pos;
+    }
+  }
+}
+
+static INT32 low_cpp(struct cpp *this,
+		    char *data,
+		    INT32 len,
+		    int flags)
+{
+  INT32 pos, tmp, e;
+  
+  for(pos=0;pos<len;)
+  {
+/*    fprintf(stderr,"%c",data[pos]);
+    fflush(stderr); */
+
+    switch(data[pos++])
+    {
+    case '\n':
+      if(flags & CPP_END_AT_NEWLINE) return pos-1;
+
+/*      fprintf(stderr,"CURRENT LINE: %d\n",this->current_line); */
+      this->current_line++;
+      PUTNL();
+      goto do_skipwhite;
+
+    case '\t':
+    case ' ':
+    case '\r':
+      PUTC(' ');
+      
+    do_skipwhite:
+      while(data[pos]==' ' || data[pos]=='\r' || data[pos]=='\t')
+	pos++;
+      break;
+
+      /* Minor optimization */
+    case '!': case '@': case '$': case '%': case '^': case '&':
+    case '*': case '(': case ')': case '-': case '=': case '+':
+    case '{': case '}': case ':': case '?': case '`': case ';':
+    case '<': case '>': case ',': case '.': case '~': case '[':
+    case ']': case '|':
+      PUTC(data[pos-1]);
+      break;
+      
+    default:
+      if(OUTP() && isidchar(data[pos-1]))
+      {
+	struct pike_string *s=0;
+	struct define *d=0;
+	tmp=pos-1;
+	while(isidchar(data[pos])) pos++;
+
+	if(flags & CPP_DO_IF)
+	{
+	  if(pos-tmp == 7 && !strncmp("defined",data+tmp, 7))
+	  {
+	    d=defined_macro;
+	  }
+	  else if((pos-tmp == 4 && !strncmp("efun",data+tmp, 4)) ||
+		  (pos-tmp == 8 && !strncmp("constant",data+tmp,8)))
+	  {
+	    d=constant_macro;
+	  }
+	  else
+	  {
+	    goto do_find_define;
+	  }
+	}else{
+	do_find_define:
+	  if((s=binary_findstring(data+tmp, pos-tmp)))
+	  {
+	    d=find_define(s);
+	  }
+	}
+	  
+	if(d && !d->inside)
+	{
+	  int arg=0;
+	  dynamic_buffer tmp;
+	  struct define_argument arguments [MAX_ARGS];
+	  
+	  if(s) s->refs++;
+	  
+	  if(d->args>=0)
+	  {
+	    SKIPWHITE();
+	    
+	    if(!GOBBLE('('))
+	    {
+	      cpp_error(this,"Missing '(' in macro call.");
+	      break;
+	    }
+	    
+	    for(arg=0;arg<d->args;arg++)
+	    {
+	      SKIPWHITE();
+	      arguments[arg].arg=data + pos;
+	      if(data[pos]==')')
+	      {
+		cpp_error(this,"Too few arguments to macro.");
+		break;
+	      }
+	      
+	      while(1)
+	      {
+		if(pos+1>len)
+		{
+		  cpp_error(this,"End of file in macro call.");
+		  break;
+		}
+		
+		switch(data[pos++])
+		{
+		case '\n':
+		  this->current_line++;
+		  PUTNL();
+		default: continue;
+		  
+		case '"':
+		  FIND_END_OF_STRING();
+		  continue;
+		  
+		case '\'':
+		  FIND_END_OF_CHAR();
+		  continue;
+		  
+		case '(':
+		  pos=find_end_parenthesis(this, data, len, pos);
+		  continue;
+		  
+		case ')': pos--;
+		case ',': 
+		  break;
+		}
+		break;
+	      }
+	      arguments[arg].len=data+pos-arguments[arg].arg;
+	    }
+	    SKIPWHITE();
+	    if(!GOBBLE(')'))
+	      cpp_error(this,"Missing ) in macro call.");
+	  }
+	  
+	  if(d->args >= 0 && arg != d->args)
+	    cpp_error(this,"Wrong number of arguments to macro.");
+	  
+	  initialize_buf(&tmp);
+	  if(d->magic)
+	  {
+	    d->magic(this, d, arguments, &tmp);
+	  }else{
+	    low_my_binary_strcat(d->first->str, d->first->len, &tmp);
+	    for(e=0;e<d->num_parts;e++)
+	    {
+	      char *a;
+	      INT32 l;
+	      
+	      if((d->parts[e].argument & DEF_ARG_MASK) < 0 || 
+		 (d->parts[e].argument & DEF_ARG_MASK) >= arg)
+	      {
+		cpp_error(this,"Macro not expanded correctly.");
+		continue;
+	      }
+	      
+	      a=arguments[d->parts[e].argument&DEF_ARG_MASK].arg;
+	      l=arguments[d->parts[e].argument&DEF_ARG_MASK].len;
+	      
+	      if(!(d->parts[e].argument & DEF_ARG_NOPRESPACE))
+		low_my_putchar(' ', &tmp);
+	      
+	      if(d->parts[e].argument & DEF_ARG_STRINGIFY)
+	      {
+		PUSH_STRING(a,l,&tmp);
+	      }else{
+		low_my_binary_strcat(a, l, &tmp);
+	      }
+	      
+	      if(!(d->parts[e].argument & DEF_ARG_NOPOSTSPACE))
+		low_my_putchar(' ', &tmp);
+	      
+	      low_my_binary_strcat(d->parts[e].postfix->str,
+				   d->parts[e].postfix->len,
+				   &tmp);
+	    }
+	  }
+	  
+	  /* FIXME */
+	  for(e=0;e<(long)tmp.s.len;e++)
+	    if(tmp.s.str[e]=='\n')
+	      tmp.s.str[e]=' ';
+
+	  if(s) d->inside=1;
+	  
+	  low_my_putchar(0, &tmp);
+	  tmp.s.len--;
+	  
+	  low_cpp(this, tmp.s.str, tmp.s.len, 
+		  flags & ~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE));
+	  
+	  if(s)
+	  {
+	    if((d=find_define(s)))
+	      d->inside=0;
+	    
+	    free_string(s);
+	  }
+
+	  toss_buffer(&tmp);
+	  break;
+	}else{
+	  if(flags & CPP_DO_IF)
+	  {
+	    STRCAT(" 0 ", 3);
+	  }else{
+	    STRCAT(data+tmp, pos-tmp);
+	  }
+	}
+      }else{
+	PUTC(data[pos-1]);
+      }
+      break;
+      
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      PUTC(data[pos-1]);
+      while(data[pos]>='0' && data[pos]<='9') PUTC(data[pos++]);
+      break;
+
+    case '"':
+      tmp=pos-1;
+      FIND_END_OF_STRING();
+      STRCAT(data+tmp, pos-tmp);
+      break;
+
+    case '\'':
+      tmp=pos-1;
+      FIND_END_OF_CHAR();
+      STRCAT(data+tmp, pos-tmp);
+      break;
+
+    case '/':
+      if(data[pos]=='/')
+      {
+	FIND_EOL();
+	break;
+      }
+
+      if(data[pos]=='*')
+      {
+	PUTC(' ');
+	SKIPCOMMENT();
+	break;
+      }
+
+      PUTC(data[pos-1]);
+      break;
+
+  case '#':
+    if(GOBBLE('!'))
+    {
+      FIND_EOL();
+      break;
+    }
+    SKIPSPACE();
+
+    switch(data[pos])
+    {
+    case 'l':
+      if(WGOBBLE("line"))
+	{
+	  while(data[pos]==' ' || data[pos]=='\t') pos++;
+	}else{
+	  goto unknown_preprocessor_directive;
+	}
+      /* Fall through */
+      
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    {
+      char *foo=data+pos;
+      this->current_line=STRTOL(foo, &foo, 10)-1;
+      pos=foo-data;
+      SKIPSPACE();
+      
+      if(data[pos]=='"')
+      {
+	dynamic_buffer nf;
+	initialize_buf(&nf);
+	
+	READSTRING(nf);
+
+	free_string(this->current_file);
+	this->current_file=low_free_buf(&nf);
+      }
+      
+      FIND_EOL();
+      break;
+    }
+
+    case 'i': /* include, if, ifdef */
+      if(WGOBBLE("include"))
+	{
+	  struct svalue *save_sp=sp;
+	  SKIPSPACE();
+
+	  check_stack(3);
+
+	  switch(data[pos++])
+	    {
+	    case '"':
+	      {
+		dynamic_buffer nf;
+		initialize_buf(&nf);
+		pos--;
+		READSTRING(nf);
+		push_string(low_free_buf(&nf));
+		ref_push_string(this->current_file);
+		push_int(1);
+		break;
+	      }
+
+	    case '<':
+	      {
+		INT32 tmp=pos;
+		while(data[pos]!='>')
+		{
+		  if(data[pos]=='\n')
+		  {
+		    cpp_error(this,"Expecting '>' in include.");
+		    break;
+		  }
+		      
+		  pos++;
+		}
+		push_string(make_shared_binary_string(data+tmp, pos-tmp));
+		ref_push_string(this->current_file);
+		pos++;
+		push_int(0);
+		break;
+	      }
+
+	    default:
+	      cpp_error(this,"Expected file to include.");
+	      break;
+	    }
+
+	  if(sp==save_sp) break;
+
+	  if(OUTP())
+	  {
+	    struct pike_string *new_file;
+
+	    SAFE_APPLY_MASTER("handle_include",3);
+	  
+	    if(sp[-1].type != T_STRING)
+	    {
+	      cpp_error(this,"Couldn't include file.");
+	      pop_n_elems(sp-save_sp);
+	      break;
+	    }
+	    
+	    new_file=sp[-1].u.string;
+	    
+	    assign_svalue_no_free(sp,sp-1);
+	    sp++;
+	    
+	    SAFE_APPLY_MASTER("read_include",1);
+	    
+	    if(sp[-1].type != T_STRING)
+	    {
+	      cpp_error(this,"Couldn't read include file.");
+	      pop_n_elems(sp-save_sp);
+	      break;
+	    }
+	    
+	    
+	    {
+	      char buffer[47];
+	      struct pike_string *save_current_file;
+	      INT32 save_current_line;
+
+	      save_current_file=this->current_file;
+	      save_current_line=this->current_line;
+	      copy_shared_string(this->current_file,new_file);
+	      
+	      low_my_binary_strcat("# 1 ",4,&this->buf);
+	      PUSH_STRING(new_file->str,new_file->len, & this->buf);
+	      low_my_putchar('\n',&this->buf);
+	      
+	      
+	      low_cpp(this,
+		      sp[-1].u.string->str,
+		      sp[-1].u.string->len,
+		      flags&~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE));
+	      
+	      free_string(this->current_file);
+	      this->current_file=save_current_file;
+	      this->current_line=save_current_line;
+	      
+	      sprintf(buffer,"# %d ",this->current_line);
+	      low_my_binary_strcat(buffer,strlen(buffer),&this->buf);
+	      PUSH_STRING(this->current_file->str,this->current_file->len,& this->buf);
+	      low_my_putchar('\n',&this->buf);
+	    }
+	  }
+
+	  pop_n_elems(sp-save_sp);
+	  
+	  break;
+	}
+
+      if(WGOBBLE("if"))
+      {
+	dynamic_buffer save,tmp;
+	INT32 nflags=CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF;
+	
+	if(!OUTP())
+	  nflags|=CPP_REALLY_NO_OUTPUT;
+	
+	save=this->buf;
+	initialize_buf(& this->buf);
+	pos+=low_cpp(this,data+pos,len-pos,CPP_END_AT_NEWLINE|CPP_DO_IF);
+	tmp=this->buf;
+	this->buf=save;
+	
+	low_my_putchar(0, &tmp);
+	tmp.s.len--;
+	
+	calc(this,tmp.s.str,tmp.s.len,0);
+	toss_buffer(&tmp);
+	if(IS_ZERO(sp-1)) nflags|=CPP_NO_OUTPUT;
+	pop_stack();
+	pos+=low_cpp(this,data+pos,len-pos,nflags);
+	break;
+      }
+
+      if(WGOBBLE("ifdef"))
+	{
+	  INT32 namestart,nflags;
+	  struct pike_string *s;
+	  SKIPSPACE();
+
+	  if(!isidchar(data[pos]))
+	    cpp_error(this,"#ifdef what?\n");
+
+	  namestart=pos;
+	  while(isidchar(data[pos])) pos++;
+	  nflags=CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF | CPP_NO_OUTPUT;
+
+	  if(!OUTP())
+	    nflags|=CPP_REALLY_NO_OUTPUT;
+
+	  if((s=binary_findstring(data+namestart,pos-namestart)))
+	    if(find_define(s))
+	      nflags&=~CPP_NO_OUTPUT;
+
+	  pos+=low_cpp(this,data+pos,len-pos,nflags);
+	  break;
+	}
+
+      if(WGOBBLE("ifndef"))
+	{
+	  INT32 namestart,nflags;
+	  struct pike_string *s;
+	  SKIPSPACE();
+
+	  if(!isidchar(data[pos]))
+	    cpp_error(this,"#ifndef what?");
+
+	  namestart=pos;
+	  while(isidchar(data[pos])) pos++;
+	  nflags=CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF;
+
+	  if(!OUTP())
+	    nflags|=CPP_REALLY_NO_OUTPUT;
+
+	  if((s=binary_findstring(data+namestart,pos-namestart)))
+	    if(find_define(s))
+	      nflags|=CPP_NO_OUTPUT;
+
+	  pos+=low_cpp(this,data+pos,len-pos,nflags);
+	  break;
+	}
+
+      goto unknown_preprocessor_directive;
+
+    case 'e': /* endif, else, elif, error */
+      if(WGOBBLE("endif"))
+      {
+	if(!(flags & CPP_EXPECT_ENDIF))
+	  cpp_error(this,"Unmatched #endif");
+
+	return pos;
+      }
+
+      if(WGOBBLE("else"))
+	{
+	  if(!(flags & CPP_EXPECT_ELSE))
+	    cpp_error(this,"Unmatched #else");
+
+	  flags&=~CPP_EXPECT_ELSE;
+	  flags|=CPP_EXPECT_ENDIF;
+
+	  if(flags & CPP_NO_OUTPUT)
+	    flags&=~CPP_NO_OUTPUT;
+	  else
+	    flags|=CPP_NO_OUTPUT;
+
+	  break;
+	}
+
+      if(WGOBBLE("elif") || WGOBBLE("elseif"))
+      {
+	if(!(flags & CPP_EXPECT_ELSE))
+	  cpp_error(this,"Unmatched #elif");
+	
+	flags|=CPP_EXPECT_ENDIF;
+	
+	if(flags & CPP_NO_OUTPUT)
+	{
+	  dynamic_buffer save,tmp;
+	  save=this->buf;
+	  initialize_buf(& this->buf);
+	  pos+=low_cpp(this,data+pos,len-pos,CPP_END_AT_NEWLINE|CPP_DO_IF);
+	  tmp=this->buf;
+	  this->buf=save;
+	  
+	  low_my_putchar(0, &tmp);
+	  tmp.s.len--;
+	  
+	  calc(this,tmp.s.str,tmp.s.len,0);
+	  toss_buffer(&tmp);
+	  if(!IS_ZERO(sp-1)) flags&=~CPP_NO_OUTPUT;
+	  pop_stack();
+	}else{
+	  FIND_EOL();
+	  flags|= CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT;
+	}
+	break;
+      }
+
+      if(WGOBBLE("error"))
+	{
+          INT32 foo;
+          SKIPSPACE();
+          foo=pos;
+          FIND_EOL();
+	  pos++;
+	  if(OUTP())
+	  {
+	    push_string(make_shared_binary_string(data+foo,pos-foo));
+	    cpp_error(this,sp[-1].u.string->str);
+	  }
+	  break;
+	}
+      
+      goto unknown_preprocessor_directive;
+
+    case 'd': /* define */
+      if(WGOBBLE("define"))
+	{
+	  dynamic_buffer str;
+	  INT32 namestart, tmp3, nameend, argno=-1;
+	  struct define *def;
+	  struct svalue *partbase,*argbase=sp;
+
+	  SKIPSPACE();
+
+	  namestart=pos;
+	  if(!isidchar(data[pos]))
+	    cpp_error(this,"Define what?");
+
+	  while(isidchar(data[pos])) pos++;
+	  nameend=pos;
+
+	  if(GOBBLE('('))
+	    {
+	      argno=0;
+	      SKIPWHITE();
+
+	      while(data[pos]!=')')
+		{
+		  INT32 tmp2;
+		  if(argno)
+		    {
+		      if(!GOBBLE(','))
+			cpp_error(this,"Expecting comma in macro definition.");
+		      SKIPWHITE();
+		    }
+		  tmp2=pos;
+
+		  if(!isidchar(data[pos]))
+		  {
+		    cpp_error(this,"Expected argument for macro.");
+		    break;
+		  }
+
+		  while(isidchar(data[pos])) pos++;
+		  check_stack(1);
+		  push_string(make_shared_binary_string(data+tmp2, pos-tmp2));
+
+		  SKIPWHITE();
+		  argno++;
+		  if(argno>=MAX_ARGS)
+		  {
+		    cpp_error(this,"Too many arguments in macro definition.");
+		    pop_stack();
+		    argno--;
+		  }
+		}
+
+	      if(!GOBBLE(')'))
+		cpp_error(this,"Missing ) in macro definition.");
+	    }
+
+	  SKIPSPACE();
+
+	  partbase=sp;
+	  initialize_buf(&str);
+	  
+	  while(1)
+	  {
+	    INT32 extra=0;
+
+/*	    fprintf(stderr,"%c",data[pos]);
+	    fflush(stderr); */
+
+	    switch(data[pos++])
+	    {
+	    case '/':
+	      if(data[pos]=='/')
+	      {
+		low_my_putchar(' ',&str);
+		FIND_EOL();
+		continue;
+	      }
+	      
+	      if(data[pos]=='*')
+	      {
+		PUTC(' ');
+		SKIPCOMMENT();
+		continue;
+	      }
+	      
+	      low_my_putchar('/',&str);
+	      continue;
+	      
+	    case '0': case '1': case '2': case '3':	case '4':
+	    case '5': case '6': case '7': case '8':	case '9':
+	      low_my_putchar(data[pos-1],&str);
+	      while(data[pos]>='0' && data[pos]<='9')
+		low_my_putchar(data[pos++],&str);
+	      continue;
+	      
+	    case '#':
+	      if(GOBBLE('#'))
+	      {
+		extra=DEF_ARG_NOPRESPACE;
+		while(str.s.len && isspace(str.s.str[str.s.len-1]))
+		  str.s.len--;
+	      }else{
+		extra=DEF_ARG_STRINGIFY;
+	      }
+	      SKIPSPACE();
+	      
+	      /* fall through */
+	      
+	    default:
+	      if(isidchar(data[pos-1]))
+	      {
+		struct pike_string *s;
+		tmp3=pos-1;
+		while(isidchar(data[pos])) pos++;
+		if(argno>0)
+		{
+		  if((s=binary_findstring(data+tmp3,pos-tmp3)))
+		  {
+		    for(e=0;e<argno;e++)
+		    {
+		      if(argbase[e].u.string == s)
+		      {
+			check_stack(2);
+			push_string(low_free_buf(&str));
+			initialize_buf(&str);
+			push_int(e | extra);
+			extra=0;
+			break;
+		      }
+		    }
+		    if(e!=argno) continue;
+		  }
+		}
+		low_my_binary_strcat(data+tmp3,pos-tmp3, &str);
+	      }else{
+		low_my_putchar(data[pos-1],&str);
+	      }
+	      extra=0;
+	      continue;
+	      
+	    case '"':
+	      tmp3=pos-1;
+	      FIND_END_OF_STRING();
+	      low_my_binary_strcat(data+tmp3, pos-tmp3, &str);
+	      continue;
+	      
+	    case '\'':
+	      tmp3=pos-1;
+	      FIND_END_OF_CHAR();
+	      low_my_binary_strcat(data+tmp3, pos-tmp3, &str);
+	      continue;
+	      
+	    case '\\':
+	      if(GOBBLE('\n'))
+	      { 
+		this->current_line++;
+		PUTNL();
+	      }
+	      continue;
+	      
+	    case '\n':
+		PUTNL();
+		this->current_line++;
+	    case 0:
+		break;
+	    }
+	    push_string(low_free_buf(&str));
+	    break;
+	  }
+
+	  if(OUTP())
+	  {
+	    def=alloc_empty_define(make_shared_binary_string(data+namestart,
+						  nameend-namestart),
+				   (sp-partbase)/2);
+	    copy_shared_string(def->first, partbase->u.string);
+	    def->args=argno;
+	    
+	    for(e=0;e<def->num_parts;e++)
+	    {
+#if 1
+	      if(partbase[e*2+1].type != T_INT)
+		fatal("Cpp internal error, expected integer!\n");
+	      
+	      if(partbase[e*2+2].type != T_STRING)
+		fatal("Cpp internal error, expected string!\n");
+#endif
+	      def->parts[e].argument=partbase[e*2+1].u.integer;
+	      copy_shared_string(def->parts[e].postfix,
+				 partbase[e*2+2].u.string);
+	    }
+	    
+#ifdef DEBUG
+	    if(def->num_parts==1 &&
+	       (def->parts[0].argument & DEF_ARG_MASK) > MAX_ARGS)
+	      fatal("Internal error in define\n");
+#endif	  
+	    
+	    this->defines=hash_insert(this->defines, & def->link);
+	    
+	  }
+	  pop_n_elems(sp-argbase);
+	  break;
+	}
+      
+      goto unknown_preprocessor_directive;
+      
+    case 'u': /* undefine */
+      if(WGOBBLE("undefine") || WGOBBLE("undef"))
+	{
+	  INT32 tmp;
+	  struct pike_string *s;
+
+	  SKIPSPACE();
+
+	  tmp=pos;
+	  if(!isidchar(data[pos]))
+	    cpp_error(this,"Undefine what?");
+
+	  while(isidchar(data[pos])) pos++;
+
+	  if(OUTP())
+	  {
+	    if((s=binary_findstring(data+pos, pos-tmp)))
+	      undefine(this,s);
+	  }
+
+	  break;
+	}
+
+      goto unknown_preprocessor_directive;
+
+    case 'p': /* pragma */
+      if(WGOBBLE("pragma"))
+	{
+	  if(OUTP())
+	    STRCAT("#pragma", 7);
+	  else
+	    FIND_EOL();
+	  break;
+	}
+
+    default:
+    unknown_preprocessor_directive:
+      {
+      char buffer[180];
+      int i;
+      for(i=0;i<(long)sizeof(buffer)-1;i++)
+      {
+	if(!isidchar(data[pos])) break;
+	buffer[i]=data[pos++];
+      }
+      buffer[i]=0;
+	
+      cpp_error(this,"Unknown preprocessor directive.");
+      }
+    }
+    }
+  }
+
+  if(flags & CPP_EXPECT_ENDIF)
+    error("End of file while searching for #endif\n");
+
+  return pos;
+}
+
+static INT32 calcC(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  FINDTOK();
+
+/*  DUMPPOS("calcC"); */
+
+  switch(data[pos])
+  {
+  case '(':
+    pos=calc1(this,data,len,pos+1);
+    FINDTOK();
+    if(!GOBBLE(')'))
+      error("Missing ')'\n");
+    break;
+    
+  case '0':
+    if(data[pos+1]=='x' || data[pos+1]=='X')
+    {
+      char *p;
+      push_int(STRTOL(data+pos+2, &p, 16));
+      pos=p-data;
+      break;
+    }
+    
+  case '1': case '2': case '3': case '4':
+  case '5': case '6': case '7': case '8': case '9':
+  {
+    char *p1,*p2;
+    double f;
+    long l;
+    
+    f=my_strtod(data+pos, &p1);
+    l=STRTOL(data+pos, &p2, 0);
+    if(p1 > p2)
+    {
+      push_float(f);
+      pos=p1-data;
+    }else{
+      push_int(l);
+      pos=p2-data;
+    }
+    break;
+  }
+
+  case '\'':
+  {
+    int tmp;
+    READCHAR(tmp);
+    pos++;
+    if(!GOBBLE('\''))
+      error("Missing end quote in character constant.\n");
+    push_int(tmp);
+    break;
+  }
+
+  case '"':
+  {
+    dynamic_buffer s;
+    initialize_buf(&s);
+    READSTRING(s);
+    push_string(low_free_buf(&s));
+    break;
+  }
+  
+  default:
+#ifdef DEBUG
+    if(isidchar(data[pos]))
+      error("Syntax error in #if (should not happen)\n");
+#endif
+
+    error("Syntax error in #if.\n");
+  }
+  
+
+  FINDTOK();
+
+  while(GOBBLE('['))
+  {
+    pos=calc1(this,data,len,pos);
+    f_index(2);
+
+    FINDTOK();
+    if(!GOBBLE(']'))
+      error("Missing ']'");
+  }
+/*   DUMPPOS("after calcC"); */
+  return pos;
+}
+
+static INT32 calcB(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  FINDTOK();
+  switch(data[pos])
+  {
+    case '-': pos++; pos=calcB(this,data,len,pos); o_negate(); break;
+    case '!': pos++; pos=calcB(this,data,len,pos); o_not(); break;
+    case '~': pos++; pos=calcB(this,data,len,pos); o_compl(); break;
+    default: pos=calcC(this,data,len,pos);
+  }
+/*   DUMPPOS("after calcB"); */
+  return pos;
+}
+
+static INT32 calcA(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calcB(this,data,len,pos);
+  while(1)
+  {
+/*     DUMPPOS("inside calcA"); */
+    FINDTOK();
+    switch(data[pos])
+    {
+      case '/':
+	if(data[1]=='/' || data[1]=='*') return pos;
+	pos++;
+	pos=calcB(this,data,len,pos);
+	o_divide();
+	continue;
+
+      case '*':
+	pos++;
+	pos=calcB(this,data,len,pos);
+	o_multiply();
+	continue;
+
+      case '%':
+	pos++;
+	pos=calcB(this,data,len,pos);
+	o_mod();
+	continue;
+    }
+    break;
+  }
+/*   DUMPPOS("after calcA"); */
+  return pos;
+}
+
+static INT32 calc9(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calcA(this,data,len,pos);
+
+  while(1)
+  {
+    FINDTOK();
+    switch(data[pos])
+    {
+      case '+':
+	pos++;
+	pos=calcA(this,data,len,pos);
+	f_add(2);
+	continue;
+
+      case '-':
+	pos++;
+	pos=calcA(this,data,len,pos);
+	o_subtract();
+	continue;
+    }
+    break;
+  }
+
+/*   DUMPPOS("after calc9"); */
+  return pos;
+}
+
+static INT32 calc8(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc9(this,data,len,pos);
+
+  while(1)
+  {
+    FINDTOK();
+    if(GOBBLEOP("<<"))
+    {
+      pos=calc9(this,data,len,pos);
+      o_lsh();
+      break;
+    }
+
+    if(GOBBLEOP(">>"))
+    {
+      pos=calc9(this,data,len,pos);
+      o_rsh();
+      break;
+    }
+
+    break;
+  }
+  return pos;
+}
+
+static INT32 calc7b(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc8(this,data,len,pos);
+
+  while(1)
+  {
+    FINDTOK();
+    
+    switch(data[pos])
+    {
+      case '<':
+	if(data[pos]+1 == '<') break;
+	pos++;
+	if(GOBBLE('='))
+	{
+	   pos=calc8(this,data,len,pos);
+	   f_le(2);
+	}else{
+	   pos=calc8(this,data,len,pos);
+	   f_lt(2);
+	}
+	continue;
+
+      case '>':
+	if(data[pos]+1 == '>') break;
+	pos++;
+	if(GOBBLE('='))
+	{
+	   pos=calc8(this,data,len,pos);
+	   f_ge(2);
+	}else{
+	   pos=calc8(this,data,len,pos);
+	   f_gt(2);
+	}
+	continue;
+    }
+    break;
+  }
+  return pos;
+}
+
+static INT32 calc7(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc7b(this,data,len,pos);
+
+  while(1)
+  {
+    FINDTOK();
+    if(GOBBLEOP("=="))
+    {
+      pos=calc7b(this,data,len,pos);
+      f_eq(2);
+      continue;
+    }
+
+    if(GOBBLEOP("!="))
+    {
+      pos=calc7b(this,data,len,pos);
+      f_ne(2);
+      continue;
+    }
+
+    break;
+  }
+  return pos;
+}
+
+static INT32 calc6(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc7(this,data,len,pos);
+
+  FINDTOK();
+  while(data[pos] == '&' && data[pos+1]!='&')
+  {
+    pos++;
+    pos=calc7(this,data,len,pos);
+    o_and();
+  }
+  return pos;
+}
+
+static INT32 calc5(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc6(this,data,len,pos);
+
+  FINDTOK();
+  while(GOBBLE('^'))
+  {
+    pos=calc6(this,data,len,pos);
+    o_xor();
+  }
+  return pos;
+}
+
+static INT32 calc4(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc5(this,data,len,pos);
+
+  FINDTOK();
+  while(data[pos] == '|' && data[pos+1]!='|')
+  {
+    pos++;
+    pos=calc5(this,data,len,pos);
+    o_or();
+  }
+  return pos;
+}
+
+static INT32 calc3(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc4(this,data,len,pos);
+
+  FINDTOK();
+  while(GOBBLEOP("&&"))
+  {
+    check_destructed(sp-1);
+    if(IS_ZERO(sp-1))
+    {
+      pos=calc4(this,data,len,pos);
+      pop_stack();
+    }else{
+      pop_stack();
+      pos=calc4(this,data,len,pos);
+    }
+  }
+  return pos;
+}
+
+static INT32 calc2(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc3(this,data,len,pos);
+
+  FINDTOK();
+  while(GOBBLEOP("||"))
+  {
+    check_destructed(sp-1);
+    if(!IS_ZERO(sp-1))
+    {
+      pos=calc3(this,data,len,pos);
+      pop_stack();
+    }else{
+      pop_stack();
+      pos=calc3(this,data,len,pos);
+    }
+  }
+  return pos;
+}
+
+static INT32 calc1(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc2(this,data,len,pos);
+
+  FINDTOK();
+
+  if(GOBBLE('?'))
+  {
+    pos=calc1(this,data,len,pos);
+    if(!GOBBLE(':'))
+      error("Colon expected");
+    pos=calc1(this,data,len,pos);
+
+    check_destructed(sp-3);
+    assign_svalue(sp-3,IS_ZERO(sp-3)?sp-1:sp-2);
+    pop_n_elems(2);
+  }
+  return pos;
+}
+
+static int calc(struct cpp *this,char *data,INT32 len,INT32 tmp)
+{
+  JMP_BUF recovery;
+  INT32 pos;
+
+/*  fprintf(stderr,"Calculating\n"); */
+
+  if (SETJMP(recovery))
+  {
+    pos=tmp;
+    if(throw_value.type == T_ARRAY && throw_value.u.array->size)
+    {
+      union anything *a;
+      a=low_array_get_item_ptr(throw_value.u.array, 0, T_STRING);
+      if(a)
+      {
+	cpp_error(this,a->string->str);
+      }else{
+	cpp_error(this,"Nonstandard error format.");
+      }
+    }else{
+      cpp_error(this,"Nonstandard error format.");
+    }
+    FIND_EOL();
+    push_int(0);
+  }else{
+    pos=calc1(this,data,len,tmp);
+    check_destructed(sp-1);
+  }
+  UNSETJMP(recovery);
+
+/*  fprintf(stderr,"Done\n"); */
+
+  return pos;
+}
+
+void free_one_define(struct hash_entry *h)
+{
+  int e;
+  struct define *d=BASEOF(h, define, link);
+
+  for(e=0;e<d->num_parts;e++)
+    free_string(d->parts[e].postfix);
+  if(d->first)
+    free_string(d->first);
+  free((char *)d);
+}
+
+/*** Magic defines ***/
+static void insert_current_line(struct cpp *this,
+				struct define *def,
+				struct define_argument *args,
+				dynamic_buffer *tmp)
+{
+  char buf[20];
+  sprintf(buf," %ld ",(long)this->current_line);
+  low_my_binary_strcat(buf, strlen(buf),tmp);
+}
+
+static void insert_current_file_as_string(struct cpp *this,
+					  struct define *def,
+					  struct define_argument *args,
+					  dynamic_buffer *tmp)
+{
+  PUSH_STRING(this->current_file->str, this->current_file->len, tmp);
+}
+
+static void insert_current_time_as_string(struct cpp *this,
+					  struct define *def,
+					  struct define_argument *args,
+					  dynamic_buffer *tmp)
+{
+  time_t tmp2;
+  char *buf;
+  time(&tmp2);
+  buf=ctime(&tmp2);
+
+  PUSH_STRING(buf+11, 8, tmp);
+}
+
+static void insert_current_date_as_string(struct cpp *this,
+					  struct define *def,
+					  struct define_argument *args,
+					  dynamic_buffer *tmp)
+{
+  time_t tmp2;
+  char *buf;
+  time(&tmp2);
+  buf=ctime(&tmp2);
+
+  PUSH_STRING(buf+19, 5, tmp);
+  PUSH_STRING(buf+4, 6, tmp);
+}
+
+static void check_defined(struct cpp *this,
+			  struct define *def,
+			  struct define_argument *args,
+			  dynamic_buffer *tmp)
+{
+  struct pike_string *s;
+  s=binary_findstring(args[0].arg, args[0].len);
+  if(s && find_define(s))
+  {
+    low_my_binary_strcat(" 1 ", 3,tmp);
+  }else{
+    low_my_binary_strcat(" 0 ", 3,tmp);
+  }
+}
+
+static void check_constant(struct cpp *this,
+			  struct define *def,
+			  struct define_argument *args,
+			  dynamic_buffer *tmp)
+{
+  struct pike_string *s;
+  s=binary_findstring(args[0].arg, args[0].len);
+  if(s && low_mapping_string_lookup(get_builtin_constants(), s))
+  {
+    low_my_binary_strcat(" 1 ", 3,tmp);
+  }else{
+    low_my_binary_strcat(" 0 ", 3,tmp);
+  }
+}
+
+
+
+void f_cpp(INT32 args)
+{
+  struct pike_predef_s *tmpf;
+  struct cpp this;
+  if(args<1)
+    error("Too few arguments to cpp()\n");
+
+  if(sp[-args].type != T_STRING)
+    error("Bad argument 1 to cpp()\n");
+
+  if(args>1)
+  {
+    if(sp[1-args].type != T_STRING)
+      error("Bad argument 2 to cpp()\n");
+    copy_shared_string(this.current_file, sp[1-args].u.string);
+  }else{
+    this.current_file=make_shared_string("-");
+  }
+  
+  initialize_buf(&this.buf);
+  this.current_line=1;
+  this.compile_errors=0;
+  this.defines=0;
+  do_magic_define(&this,"__LINE__",insert_current_line);
+  do_magic_define(&this,"__FILE__",insert_current_file_as_string);
+  do_magic_define(&this,"__DATE__",insert_current_date_as_string);
+  do_magic_define(&this,"__TIME__",insert_current_time_as_string);
+  simple_add_define(&this,"__PIKE__"," 1 ");
+
+  for (tmpf=pike_predefs; tmpf; tmpf=tmpf->next)
+    simple_add_define(&this, tmpf->name, tmpf->value);
+
+  low_my_binary_strcat("# 1 ",4,&this.buf);
+  PUSH_STRING(this.current_file->str,this.current_file->len,&this.buf);
+  low_my_putchar('\n',&this.buf);
+
+  low_cpp(&this, sp[-args].u.string->str, sp[-args].u.string->len,0);
+  if(this.defines)
+    free_hashtable(this.defines, free_one_define);
+
+  if(this.compile_errors)
+  {
+    error("Cpp() failed\n");
+  }else{
+    pop_n_elems(args);
+    free_string(this.current_file);
+    push_string(low_free_buf(&this.buf));
+  }
+}
+
+void init_cpp()
+{
+  defined_macro=alloc_empty_define(make_shared_string("defined"),0);
+  defined_macro->magic=check_defined;
+  defined_macro->args=1;
+
+  constant_macro=alloc_empty_define(make_shared_string("constant"),0);
+  constant_macro->magic=check_constant;
+  constant_macro->args=1;
+
+  add_efun("cpp",f_cpp,"function(string,string|void:string)",OPT_EXTERNAL_DEPEND);
+}
+
+
+void add_predefine(char *s)
+{
+  struct pike_predef_s *tmp=ALLOC_STRUCT(pike_predef_s);
+  char * pos=STRCHR(s,'=');
+  if(pos)
+  {
+    tmp->name=(char *)xalloc(pos-s+1);
+    MEMCPY(tmp->name,s,pos-s);
+    tmp->name[pos-s]=0;
+
+    tmp->value=(char *)xalloc(s+strlen(s)-pos);
+    MEMCPY(tmp->value,pos+1,s+strlen(s)-pos);
+  }else{
+    tmp->name=(char *)xalloc(strlen(s)+1);
+    MEMCPY(tmp->name,s,strlen(s)+1);
+
+    tmp->value=(char *)xalloc(4);
+    MEMCPY(tmp->value," 1 ",4);
+  }
+  tmp->next=pike_predefs;
+  pike_predefs=tmp;
+}
+
+void exit_cpp()
+{
+  struct pike_predef_s *tmp;
+  while((tmp=pike_predefs))
+  {
+    free(tmp->name);
+    free(tmp->value);
+    pike_predefs=tmp->next;
+    free((char *)tmp);
+  }
+}
diff --git a/src/docode.c b/src/docode.c
index c6a3bcb7a92fc76979b30ad1e87996b17c64a906..2d1d1b35243574d36b4866834cb5f8074e808ccc 100644
--- a/src/docode.c
+++ b/src/docode.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: docode.c,v 1.16 1997/04/17 22:47:06 hubbe Exp $");
+RCSID("$Id: docode.c,v 1.16.2.1 1997/06/25 22:46:36 hubbe Exp $");
 #include "las.h"
 #include "program.h"
 #include "language.h"
@@ -32,47 +32,14 @@ static INT32 current_switch_default;
 static INT32 current_switch_values_on_stack;
 static INT32 *current_switch_jumptable =0;
 
-void ins_byte(unsigned char b,int area)
-{
-  add_to_mem_block(area, (char *)&b, 1);
-}
-
-void ins_signed_byte(char b,int area)
-{
-  add_to_mem_block(area, (char *)&b, 1);
-}
-
-void ins_short(INT16 l,int area)
-{
-  add_to_mem_block(area, (char *)&l, sizeof(INT16));
-}
-
-/*
- * Store an INT32.
- */
-void ins_int(INT32 l,int area)
-{
-  add_to_mem_block(area, (char *)&l+0, sizeof(INT32));
-}
-
 void upd_int(int offset, INT32 tmp)
 {
-#ifdef HANDLES_UNALIGNED_MEMORY_ACCESS
-  *((int *)(areas[A_PROGRAM].s.str+offset))=tmp;
-#else
-  MEMCPY(areas[A_PROGRAM].s.str+offset, (char *)&tmp,sizeof(tmp));
-#endif
+  MEMCPY(new_program->program+offset, (char *)&tmp,sizeof(tmp));
 }
 
 INT32 read_int(int offset)
 {
-  INT32 tmp;
-#ifdef HANDLES_UNALIGNED_MEMORY_ACCESS
-  tmp=*((int *)(areas[A_PROGRAM].s.str+offset));
-#else
-  MEMCPY((char *)&tmp, areas[A_PROGRAM].s.str+offset,sizeof(tmp));
-#endif
-  return tmp;
+  return EXTRACT_INT(new_program->program+offset);
 }
 
 int store_linenumbers=1;
@@ -148,12 +115,12 @@ void do_pop(int x)
 int do_docode(node *n,INT16 flags)
 {
   int i;
-  int save_current_line=current_line;
+  int save_current_line=lex.current_line;
   if(!n) return 0;
-  current_line=n->line_number;
+  lex.current_line=n->line_number;
   i=do_docode2(n, flags);
 
-  current_line=save_current_line;
+  lex.current_line=save_current_line;
   return i;
 }
 
@@ -174,8 +141,8 @@ static void code_expression(node *n, int flags, char *err)
   case 2:
     fatal("Internal compiler error (%s), line %ld, file %s\n",
 	  err,
-	  (long)current_line,
-	  current_file?current_file->str:"Unknown");
+	  (long)lex.current_line,
+	  lex.current_file?lex.current_file->str:"Unknown");
   }
 }
 
@@ -294,6 +261,11 @@ static int do_docode2(node *n,int flags)
 
   switch(n->token)
   {
+  case F_UNDEFINED:
+    yyerror("Undefined identifier");
+    emit(F_NUMBER,0);
+    return 1;
+
   case F_PUSH_ARRAY:
     code_expression(CAR(n), 0, "`@");
     emit2(F_PUSH_ARRAY);
@@ -440,7 +412,7 @@ static int do_docode2(node *n,int flags)
       switch(CDR(n)->token)
       {
       case F_LOCAL:
-	if(CDR(n)->u.number >= local_variables->max_number_of_locals)
+	if(CDR(n)->u.number >= compiler_frame->max_number_of_locals)
 	  yyerror("Illegal to use local variable here.");
 
 	code_expression(CAR(n), 0, "RHS");
@@ -449,7 +421,7 @@ static int do_docode2(node *n,int flags)
 	break;
 
       case F_IDENTIFIER:
-	if(!IDENTIFIER_IS_VARIABLE( ID_FROM_INT(& fake_program, CDR(n)->u.number)->flags))
+	if(!IDENTIFIER_IS_VARIABLE( ID_FROM_INT(new_program, CDR(n)->u.number)->flags))
 	{
 	  yyerror("Cannot assign functions or constants.\n");
 	}else{
@@ -500,7 +472,7 @@ static int do_docode2(node *n,int flags)
   case F_RANGE:
     tmp1=do_docode(CAR(n),DO_NOT_COPY);
     if(do_docode(CDR(n),DO_NOT_COPY)!=2)
-      fatal("Compiler internal error (at %ld).\n",(long)current_line);
+      fatal("Compiler internal error (at %ld).\n",(long)lex.current_line);
     emit2(n->token);
     return tmp1;
 
@@ -702,7 +674,7 @@ static int do_docode2(node *n,int flags)
       return 1;
     }
     else if(CAR(n)->token == F_IDENTIFIER &&
-	    IDENTIFIER_IS_FUNCTION(ID_FROM_INT(& fake_program, CAR(n)->u.number)->flags))
+	    IDENTIFIER_IS_FUNCTION(ID_FROM_INT(new_program, CAR(n)->u.number)->flags))
     {
       emit2(F_MARK);
       do_docode(CDR(n),0);
@@ -1034,7 +1006,7 @@ static int do_docode2(node *n,int flags)
     }
 
   case F_LOCAL:
-    if(n->u.number >= local_variables->max_number_of_locals)
+    if(n->u.number >= compiler_frame->max_number_of_locals)
       yyerror("Illegal to use local variable here.");
     if(flags & DO_LVALUE)
     {
@@ -1046,7 +1018,7 @@ static int do_docode2(node *n,int flags)
     }
 
   case F_IDENTIFIER:
-    if(IDENTIFIER_IS_FUNCTION(ID_FROM_INT(& fake_program, n->u.number)->flags))
+    if(IDENTIFIER_IS_FUNCTION(ID_FROM_INT(new_program, n->u.number)->flags))
     {
       if(flags & DO_LVALUE)
       {
diff --git a/src/docode.h b/src/docode.h
index b197c0cde4dfe53f46689972342448f281a28a67..7eb6130bc6e0c01b16eac47cdf8b8b74d48523a5 100644
--- a/src/docode.h
+++ b/src/docode.h
@@ -21,20 +21,20 @@ extern int store_linenumbers;
 extern int comp_stackp;
 extern INT32 comp_stack[COMPILER_STACK_SIZE];
 
-#define emit(X,Y) insert_opcode((X),(Y),current_line, current_file)
-#define emit2(X) insert_opcode2((X),current_line, current_file)
+#define emit(X,Y) insert_opcode((X),(Y),lex.current_line, lex.current_file)
+#define emit2(X) insert_opcode2((X),lex.current_line, lex.current_file)
 
 /* Prototypes begin here */
-void ins_byte(unsigned char b,int area);
-void ins_signed_byte(char b,int area);
-void ins_short(INT16 l,int area);
-void ins_int(INT32 l,int area);
 void upd_int(int offset, INT32 tmp);
 INT32 read_int(int offset);
 void push_address();
 void push_explicit(INT32 address);
 INT32 pop_address();
+int alloc_label();
+int do_jump(int token,INT32 lbl);
+void do_pop(int x);
 int do_docode(node *n,INT16 flags);
+void do_cond_jump(node *n, int label, int iftrue, int flags);
 void do_code_block(node *n);
 int docode(node *n);
 /* Prototypes end here */
diff --git a/src/interpret.c b/src/interpret.c
index 5c6d7a6f3c267d843cb8473afe1ef32da9fc9d9d..28b4730238625e7b8cfc6840f7e4d4c9361a7315 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: interpret.c,v 1.42 1997/04/16 03:09:11 hubbe Exp $");
+RCSID("$Id: interpret.c,v 1.42.2.1 1997/06/25 22:46:37 hubbe Exp $");
 #include "interpret.h"
 #include "object.h"
 #include "program.h"
@@ -614,6 +614,7 @@ static void eval_instruction(unsigned char *pc)
       print_return_value();
       break;
 
+
       CASE(F_MARK_AND_LOCAL); *(mark_sp++)=sp;
       CASE(F_LOCAL);
       assign_svalue_no_free(sp++,fp->locals+GET_ARG());
@@ -1340,12 +1341,29 @@ void apply_low(struct object *o, int fun, int args)
   if(function->func.offset == -1)
     error("Calling undefined function '%s'.\n",function->name->str);
 
-  if(function->flags & IDENTIFIER_C_FUNCTION)
+  switch(function->flags & (IDENTIFIER_FUNCTION | IDENTIFIER_CONSTANT))
   {
+  case IDENTIFIER_C_FUNCTION:
     fp->num_args=args;
     new_frame.num_locals=args;
     (*function->func.c_fun)(args);
-  }else{
+    break;
+
+  case IDENTIFIER_CONSTANT:
+  {
+    struct svalue *s=fp->context.prog->constants+function->func.offset;
+    if(s->type == T_PROGRAM)
+    {
+      struct object *tmp=parent_clone_object(s->u.program,o,args);
+      push_object(tmp);
+    }else{
+      error("Calling strange value!\n");
+    }
+    break;
+  }
+
+  case IDENTIFIER_PIKE_FUNCTION:
+  {
     int num_args;
     int num_locals;
     unsigned char *pc;
@@ -1388,6 +1406,9 @@ void apply_low(struct object *o, int fun, int args)
     if(sp<evaluator_stack)
       fatal("Stack error (also simple).\n");
 #endif
+    break;
+  }
+
   }
 
   if(sp - new_frame.locals > 1)
@@ -1495,7 +1516,7 @@ void apply_lfun(struct object *o, int fun, int args)
   if(!o->prog)
     error("Apply on destructed object.\n");
 
-  apply_low(o, o->prog->lfuns[fun], args);
+  apply_low(o, FIND_LFUN(o->prog,fun), args);
 }
 
 void apply_shared(struct object *o,
diff --git a/src/interpret.h b/src/interpret.h
index c9a47e19c18d3db1282aabfcca60ac8d03c31cf8..3768ed054655eea924e81a5c968d0f2e2922fc80 100644
--- a/src/interpret.h
+++ b/src/interpret.h
@@ -43,6 +43,7 @@ struct frame
 #define push_object(O) do{ struct object  *_=(O); sp->u.object=_; sp++->type=T_OBJECT; }while(0)
 #define push_float(F) do{ float _=(F); sp->u.float_number=_; sp++->type=T_FLOAT; }while(0)
 #define push_text(T) push_string(make_shared_string((T)))
+#define push_constant_text(T) do{ sp->subtype=0; MAKE_CONSTANT_SHARED_STRING(sp->u.string,T); sp++->type=T_STRING; }while(0)
 
 #define ref_push_program(P) do{ struct program *_=(P); _->refs++; sp->u.program=_; sp++->type=T_PROGRAM; }while(0)
 #define ref_push_mapping(M) do{ struct mapping *_=(M); _->refs++; sp->u.mapping=_; sp++->type=T_MAPPING; }while(0)
diff --git a/src/language.yacc b/src/language.yacc
index cf53c114e44b0bb4edc6160e44d14e7cdf1de5a5..7c194632eb026a1d546a0f92ff3b7128fcd6e131 100644
--- a/src/language.yacc
+++ b/src/language.yacc
@@ -129,6 +129,7 @@
 %token F_WHILE
 %token F_XOR_EQ
 %token F_NOP
+%token F_UNDEFINED
 
 %token F_ALIGN
 %token F_POINTER
@@ -156,7 +157,7 @@
 /* This is the grammar definition of Pike. */
 
 #include "global.h"
-RCSID("$Id: language.yacc,v 1.42.2.1 1997/05/10 12:56:55 hubbe Exp $");
+RCSID("$Id: language.yacc,v 1.42.2.2 1997/06/25 22:46:38 hubbe Exp $");
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
@@ -176,19 +177,14 @@ RCSID("$Id: language.yacc,v 1.42.2.1 1997/05/10 12:56:55 hubbe Exp $");
 #include "docode.h"
 #include "machine.h"
 
-#define YYMAXDEPTH	600
+#define YYMAXDEPTH	1000
 
 #ifdef DEBUG
 #define YYDEBUG 1
 #endif
 
-void free_all_local_names();
-void add_local_name(struct pike_string *,struct pike_string *);
 
-/*
- * The names and types of arguments and auto variables.
- */
-struct locals *local_variables = 0;
+void add_local_name(struct pike_string *,struct pike_string *);
 
 static int varargs;
 static INT32  current_modifiers;
@@ -205,16 +201,6 @@ void fix_comp_stack(int sp)
   }
 }
 
-void pop_local_variables(int level)
-{
-  while(local_variables->current_number_of_locals > level)
-  {
-    int e;
-    e=--(local_variables->current_number_of_locals);
-    free_string(local_variables->variable[e].name);
-    free_string(local_variables->variable[e].type);
-  }
-}
 
 %}
 
@@ -359,9 +345,7 @@ optional_semi_colon: /* empty */
 string_constant: low_string
   | string_constant '+' low_string
   {
-    $$=add_shared_strings($1,$3);
-    free_string($1);
-    free_string($3);
+    $$=add_and_free_shared_strings($1,$3);
   }
   ;
 
@@ -371,11 +355,9 @@ optional_rename_inherit: ':' F_IDENTIFIER { $$=$2; }
 
 program_ref: string_constant
   {
-    reference_shared_string($1);
-    push_string($1);
+    ref_push_string($1);
     push_string($1);
-    reference_shared_string(current_file);
-    push_string(current_file);
+    ref_push_string(lex.current_file);
     SAFE_APPLY_MASTER("handle_inherit", 2);
 
     if(sp[-1].type != T_PROGRAM)
@@ -388,43 +370,60 @@ program_ref: string_constant
       push_string(last_identifier);
       last_identifier->refs++;
     }else{
-      push_text("");
+      push_constant_text("");
     }
     
     resolv_constant($1);
-    if(sp[-1].type == T_OBJECT)
+    switch(sp[-1].type)
     {
-      struct program *p=sp[-1].u.object->prog;
-      if(!p)
+    case T_OBJECT:
+      if(!sp[-1].u.object->prog)
       {
 	pop_stack();
 	push_int(0);
       }else{
+	struct program *p=sp[-1].u.object->prog;
 	p->refs++;
 	pop_stack();
 	push_program(p);
       }
-    }
-    if(sp[-1].type != T_PROGRAM)
+      break;
+
+    case T_FUNCTION:
     {
+      struct program *p=program_from_function(sp-1);
+      if(p)
+      {
+	p->refs++;
+	pop_stack();
+	push_program(p);
+	break;
+      }
+    }
+
+    default:
       yyerror("Illegal program identifier");
       pop_stack();
       push_int(0);
+      
+    case T_PROGRAM:
+      break;
     }
+
     free_node($1);
   }
   ;
           
 inheritance: modifiers F_INHERIT program_ref optional_rename_inherit ';'
   {
-    struct pike_string *s;
-    if(sp[-1].type == T_PROGRAM)
+    if(sp[-1].type == T_PROGRAM &&
+       !(new_program->flags & PROGRAM_PASS_1_DONE))
     {
-      s=sp[-2].u.string;
+      struct pike_string *s=sp[-2].u.string;
       if($4) s=$4;
       do_inherit(sp[-1].u.program,$1,s);
-      if($4) free_string($4);
     }
+    if($4) free_string($4);
     pop_n_elems(2);
   }
   ;
@@ -441,19 +440,20 @@ import: modifiers F_IMPORT idents ';'
 constant_name: F_IDENTIFIER '=' expr0
   {
     int tmp;
-    node *n;
     /* This can be made more lenient in the future */
-    n=mknode(F_ARG_LIST,$3,0); /* Make sure it is optimized */
-    if(!is_const(n))
+
+    /* Ugly hack to make sure that $3 is optimized */
+    tmp=compiler_pass;
+    $3=mknode(F_ARG_LIST,$3,0);
+    compiler_pass=tmp;
+
+    if(!is_const($3))
     {
-      struct svalue tmp;
-      yyerror("Constant definition is not constant.");
-      tmp.type=T_INT;
-      tmp.u.integer=0;
-      add_constant($1,&tmp, current_modifiers);
+      if(compiler_pass==2)
+	yyerror("Constant definition is not constant.");
+      add_constant($1,0, current_modifiers); /* Prototype */
     } else {
-      tmp=eval_low(n);
-      free_node(n);
+      tmp=eval_low($3);
       if(tmp < 1)
       {
 	yyerror("Error in constant definition.");
@@ -462,8 +462,9 @@ constant_name: F_IDENTIFIER '=' expr0
 	add_constant($1,sp-1,current_modifiers);
 	pop_stack();
       }
-      free_string($1);
     }
+    if($3) free_node($3);
+    free_string($1);
   }
   ;
 
@@ -484,35 +485,49 @@ block_or_semi: block
 
 type_or_error: simple_type
   {
-    if(local_variables->current_type)
-      free_string(local_variables->current_type); 
-    local_variables->current_type=$1;
+    if(compiler_frame->current_type)
+      free_string(compiler_frame->current_type); 
+    compiler_frame->current_type=$1;
   }
   | /* empty */
   {
     yyerror("Missing type.");
-    copy_shared_string(local_variables->current_type,
+    copy_shared_string(compiler_frame->current_type,
 		       mixed_type_string);
   }
   
 
-def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
+def: modifiers type_or_error optional_stars F_IDENTIFIER 
+  {
+    push_compiler_frame();
+    if(!compiler_frame->previous ||
+       !compiler_frame->previous->current_type)
+    {
+      yyerror("Internal compiler fault");
+      copy_shared_string(compiler_frame->current_type,
+			 mixed_type_string);
+    }else{
+      copy_shared_string(compiler_frame->current_type,
+			 compiler_frame->previous->current_type);
+    }
+  }
+  '(' arguments ')'
   {
     int e;
     /* construct the function type */
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while(--$3>=0) push_type(T_ARRAY);
     
-    if(local_variables->current_return_type)
-      free_string(local_variables->current_return_type);
-    local_variables->current_return_type=pop_type();
+    if(compiler_frame->current_return_type)
+      free_string(compiler_frame->current_return_type);
+    compiler_frame->current_return_type=pop_type();
     
-    push_finished_type(local_variables->current_return_type);
+    push_finished_type(compiler_frame->current_return_type);
     
-    e=$6-1;
+    e=$7-1;
     if(varargs)
     {
-      push_finished_type(local_variables->variable[e].type);
+      push_finished_type(compiler_frame->variable[e].type);
       e--;
       varargs=0;
       pop_type_stack();
@@ -522,7 +537,7 @@ def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
     push_type(T_MANY);
     for(; e>=0; e--)
     {
-      push_finished_type(local_variables->variable[e].type);
+      push_finished_type(compiler_frame->variable[e].type);
       if($1 & ID_VARARGS)
       {
 	push_type(T_VOID);
@@ -532,36 +547,35 @@ def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
     push_type(T_FUNCTION);
     
     $<string>$=pop_type();
-    define_function($4,
-		    $<string>$,
-		    $1,
-		    IDENTIFIER_PIKE_FUNCTION,
-		    0);
+
+    if(compiler_pass==1)
+    {
+      define_function($4,
+		      $<string>$,
+		      $1,
+		      IDENTIFIER_PIKE_FUNCTION,
+		      0);
+    }
   }
   block_or_semi
   {
     int e;
-    if($9)
+    if($10)
     {
-      for(e=0; e<$6; e++)
+      for(e=0; e<$7; e++)
       {
-	if(!local_variables->variable[e].name ||
-	   !local_variables->variable[e].name->len)
-	{
-	  my_yyerror("Missing name for argument %d",e);
-	}
+	if(!compiler_frame->variable[e].name ||
+	   !compiler_frame->variable[e].name->len)
+	  {
+	    my_yyerror("Missing name for argument %d",e);
+	  }
       }
 
-      dooptcode($4, $9, $<string>8, $1);
+      dooptcode($4, $10, $<string>9, $1);
     }
-    if(local_variables->current_return_type)
-    {
-      free_string(local_variables->current_return_type);
-      local_variables->current_return_type=0;
-    }
-    free_all_local_names();
+    pop_compiler_frame();
     free_string($4);
-    free_string($<string>8);
+    free_string($<string>9);
   }
   | modifiers type_or_error name_list ';' {}
   | inheritance {}
@@ -575,7 +589,6 @@ def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
   }
   ;
 
-
 optional_dot_dot_dot: F_DOT_DOT_DOT { $$=1; }
   | /* empty */ { $$=0; }
   ;
@@ -584,7 +597,6 @@ optional_identifier: F_IDENTIFIER
   | /* empty */ { $$=0; }
   ;
 
-
 new_arg_name: type optional_dot_dot_dot optional_identifier
   {
     if(varargs) yyerror("Can't define more arguments after ...");
@@ -594,7 +606,9 @@ new_arg_name: type optional_dot_dot_dot optional_identifier
       push_type(T_ARRAY);
       varargs=1;
     }
-    if(!$3) $3=make_shared_string("");
+    if(!$3)
+      MAKE_CONSTANT_SHARED_STRING($3,"");
+
     if(islocal($3) >= 0)
       my_yyerror("Variable '%s' appears twice in argument list.",
 		 $3->str);
@@ -756,7 +770,7 @@ name_list: new_name
 new_name: optional_stars F_IDENTIFIER
   {
     struct pike_string *type;
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while($1--) push_type(T_ARRAY);
     type=pop_type();
     define_variable($2, type, current_modifiers);
@@ -766,7 +780,7 @@ new_name: optional_stars F_IDENTIFIER
   | optional_stars F_IDENTIFIER '='
   {
     struct pike_string *type;
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while($1--) push_type(T_ARRAY);
     type=pop_type();
     $<number>$=define_variable($2, type, current_modifiers);
@@ -785,14 +799,14 @@ new_name: optional_stars F_IDENTIFIER
 
 new_local_name: optional_stars F_IDENTIFIER
   {
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while($1--) push_type(T_ARRAY);
     add_local_name($2, pop_type());
     $$=mknode(F_ASSIGN,mkintnode(0), mklocalnode(islocal($2)));
   }
   | optional_stars F_IDENTIFIER '=' expr0
   {
-    push_finished_type(local_variables->current_type);
+    push_finished_type(compiler_frame->current_type);
     while($1--) push_type(T_ARRAY);
     add_local_name($2, pop_type());
     $$=mknode(F_ASSIGN,$4,mklocalnode(islocal($2)));
@@ -802,7 +816,7 @@ new_local_name: optional_stars F_IDENTIFIER
 
 block:'{'
   {
-    $<number>$=local_variables->current_number_of_locals;
+    $<number>$=compiler_frame->current_number_of_locals;
   } 
   statements '}'
   {
@@ -851,12 +865,12 @@ continue: F_CONTINUE { $$=mknode(F_CONTINUE,0,0); } ;
 
 lambda: F_LAMBDA
   {
-    push_locals();
+    push_compiler_frame();
     $<number>$=comp_stackp;
     
-    if(local_variables->current_return_type)
-      free_string(local_variables->current_return_type);
-    copy_shared_string(local_variables->current_return_type,any_type_string);
+    if(compiler_frame->current_return_type)
+      free_string(compiler_frame->current_return_type);
+    copy_shared_string(compiler_frame->current_return_type,any_type_string);
   }
   func_args failsafe_block
   {
@@ -865,7 +879,6 @@ lambda: F_LAMBDA
     int f,e;
     struct pike_string *name;
     
-    setup_fake_program();
     fix_comp_stack($<number>2);
     
     push_type(T_MIXED);
@@ -873,7 +886,7 @@ lambda: F_LAMBDA
     e=$3-1;
     if(varargs)
     {
-      push_finished_type(local_variables->variable[e].type);
+      push_finished_type(compiler_frame->variable[e].type);
       e--;
       varargs=0;
       pop_type_stack();
@@ -882,24 +895,27 @@ lambda: F_LAMBDA
     }
     push_type(T_MANY);
     for(; e>=0; e--)
-      push_finished_type(local_variables->variable[e].type);
+      push_finished_type(compiler_frame->variable[e].type);
     
     push_type(T_FUNCTION);
     
     type=pop_type();
-    
-    sprintf(buf,"__lambda_%ld",
-	    (long)fake_program.num_identifier_references);
-    name=make_shared_string(buf);
-
-    f=dooptcode(name,
-	      mknode(F_ARG_LIST,$4,mknode(F_RETURN,mkintnode(0),0)),
-	      type,
-	      0);
+
+    if(new_program->flags | PROGRAM_PASS_1_DONE)
+    {
+      sprintf(buf,"__lambda_%ld",
+	      (long)new_program->num_identifier_references);
+      name=make_shared_string(buf);
+      
+      f=dooptcode(name,
+		  mknode(F_ARG_LIST,$4,mknode(F_RETURN,mkintnode(0),0)),
+		  type,
+		  0);
+    }
     free_string(name);
     free_string(type);
     comp_stackp=$<number>2;
-    pop_locals();
+    pop_compiler_frame();
     $$=mkidentifiernode(f);
   }
   ;
@@ -908,16 +924,48 @@ failsafe_program: '{' program '}'
                 | error { yyerrok; }
                 ;
 
-class: modifiers F_CLASS optional_identifier
+class: modifiers F_CLASS F_IDENTIFIER
   {
-    start_new_program();
-    /* write(2, "start\n", 6); */
+    if(compiler_pass==1)
+    {
+      low_start_new_program(0, $3, $1);
+    }else{
+      int i;
+      struct program *p;
+      struct identifier *id;
+      i=isidentifier($3);
+      if(i<0)
+      {
+	low_start_new_program(new_program,0,0);
+	yyerror("Pass 2: program not defined!");
+      }else{
+	id=ID_FROM_INT(new_program, i);
+	if(IDENTIFIER_IS_CONSTANT(id->flags))
+	{
+	  struct svalue *s;
+	  s=PROG_FROM_INT(new_program,i)->constants+id->func.offset;
+	  if(s->type==T_PROGRAM)
+	  {
+	    low_start_new_program(s->u.program, $3, $1);
+	  }else{
+	    yyerror("Pass 2: constant redefined!");
+	    low_start_new_program(new_program, 0,0);
+	  }
+	}else{
+	  yyerror("Pass 2: class constant no longer constant!");
+	  low_start_new_program(new_program, 0,0);
+	}
+      }
+    }
   }
   failsafe_program
   {
     struct svalue s;
-    /* write(2, "end\n", 4); */
-    s.u.program=end_program();
+    if(compiler_pass == 1)
+      s.u.program=end_first_pass(0);
+    else
+      s.u.program=end_program();
+
     if(!s.u.program)
     {
       yyerror("Class definition failed.");
@@ -927,11 +975,8 @@ class: modifiers F_CLASS optional_identifier
       s.type=T_PROGRAM;
       s.subtype=0;
     }
-    if($3)
-    { 
-      add_constant($3, &s, $1);
-      free_string($3);
-    }
+
+    free_string($3);
     $$=mksvaluenode(&s);
     free_svalue(&s);
   }
@@ -939,7 +984,7 @@ class: modifiers F_CLASS optional_identifier
 
 cond: F_IF
   {
-    $<number>$=local_variables->current_number_of_locals;
+    $<number>$=compiler_frame->current_number_of_locals;
   }
   '(' comma_expr ')' statement optional_else_part
   {
@@ -957,7 +1002,7 @@ optional_else_part: { $$=0; }
 
 foreach: F_FOREACH
   {
-    $<number>$=local_variables->current_number_of_locals;
+    $<number>$=compiler_frame->current_number_of_locals;
   }
   '(' expr0 ',' lvalue ')' statement
   {
@@ -976,14 +1021,14 @@ do: F_DO statement F_WHILE '(' comma_expr ')' ';'
 
 for: F_FOR
   {
-    $<number>$=local_variables->current_number_of_locals;
+    $<number>$=compiler_frame->current_number_of_locals;
   }
   '(' unused  ';' for_expr ';' unused ')' statement
   {
-    int i=current_line;
-    current_line=$1;
+    int i=lex.current_line;
+    lex.current_line=$1;
     $$=mknode(F_ARG_LIST,mkcastnode(void_type_string,$4),mknode(F_FOR,$6,mknode(':',$10,$8)));
-    current_line=i;
+    lex.current_line=i;
     pop_local_variables($<number>2);
   }
   ;
@@ -991,14 +1036,14 @@ for: F_FOR
 
 while:  F_WHILE
   {
-    $<number>$=local_variables->current_number_of_locals;
+    $<number>$=compiler_frame->current_number_of_locals;
   }
   '(' comma_expr ')' statement
   {
-    int i=current_line;
-    current_line=$1;
+    int i=lex.current_line;
+    lex.current_line=$1;
     $$=mknode(F_FOR,$4,mknode(':',$6,NULL));
-    current_line=i;
+    lex.current_line=i;
     pop_local_variables($<number>2);
   }
   ;
@@ -1009,7 +1054,7 @@ for_expr: /* EMPTY */ { $$=mkintnode(1); }
 
 switch:	F_SWITCH
   {
-    $<number>$=local_variables->current_number_of_locals;
+    $<number>$=compiler_frame->current_number_of_locals;
   }
   '(' comma_expr ')' statement
   {
@@ -1031,7 +1076,7 @@ case: F_CASE comma_expr ':'
 
 return: F_RETURN
   {
-    if(!match_types(local_variables->current_return_type,
+    if(!match_types(compiler_frame->current_return_type,
 		    void_type_string))
     {
       yyerror("Must return a value for a non-void function.");
@@ -1053,9 +1098,9 @@ unused2: comma_expr { $$=mkcastnode(void_type_string,$1);  } ;
 comma_expr: comma_expr2
   | type2
   {
-    if(local_variables->current_type)
-      free_string(local_variables->current_type);
-    local_variables->current_type=pop_type();
+    if(compiler_frame->current_type)
+      free_string(compiler_frame->current_type);
+    compiler_frame->current_type=pop_type();
   } local_name_list { $$=$3; }
   ;
           
@@ -1213,8 +1258,7 @@ low_idents: F_IDENTIFIER
       {
 	reference_shared_string($1);
 	push_string($1);
-	reference_shared_string(current_file);
-	push_string(current_file);
+	ref_push_string(lex.current_file);
 	SAFE_APPLY_MASTER("resolv", 2);
 	
 	if(throw_value.type == T_STRING)
@@ -1229,7 +1273,12 @@ low_idents: F_IDENTIFIER
 	}
 	pop_stack();
       }else{
-	my_yyerror("'%s' undefined.", $1->str);
+	if(compiler_pass==2)
+	{
+	  my_yyerror("'%s' undefined.", $1->str);
+	}else{
+	  $$=mknode(F_UNDEFINED,0,0);
+	}
       }
     }
     free_string($1);
@@ -1253,10 +1302,9 @@ low_idents: F_IDENTIFIER
     int f;
     struct reference *idp;
 
-    setup_fake_program();
     f=reference_inherited_identifier($1,$3);
-    idp=fake_program.identifier_references+f;
-    if (f<0 || ID_FROM_PTR(&fake_program,idp)->func.offset == -1)
+    idp=new_program->identifier_references+f;
+    if (f<0 || ID_FROM_PTR(new_program,idp)->func.offset == -1)
     {
       my_yyerror("Undefined identifier %s::%s", $1->str,$3->str);
       $$=mkintnode(0);
@@ -1272,10 +1320,9 @@ low_idents: F_IDENTIFIER
     int e,i;
 
     $$=0;
-    setup_fake_program();
-    for(e=1;e<(int)fake_program.num_inherits;e++)
+    for(e=1;e<(int)new_program->num_inherits;e++)
     {
-      if(fake_program.inherits[e].inherit_level!=1) continue;
+      if(new_program->inherits[e].inherit_level!=1) continue;
       i=low_reference_inherited_identifier(e,$2);
       if(i==-1) continue;
       if($$)
@@ -1357,9 +1404,7 @@ lvalue_list: /* empty */ { $$ = 0; }
 low_string: F_STRING 
   | low_string F_STRING
   {
-    $$=add_shared_strings($1,$2);
-    free_string($1);
-    free_string($2);
+    $$=add_and_free_shared_strings($1,$2);
   }
   ;
 
@@ -1380,10 +1425,10 @@ void yyerror(char *str)
   if ( get_master() )
   {
     sp->type = T_STRING;
-    copy_shared_string(sp->u.string, current_file);
+    copy_shared_string(sp->u.string, lex.current_file);
     sp++;
     sp->type = T_INT;
-    sp->u.integer = current_line;
+    sp->u.integer = lex.current_line;
     sp++;
     sp->type = T_STRING;
     sp->u.string = make_shared_string(str);
@@ -1392,8 +1437,8 @@ void yyerror(char *str)
     pop_stack();
   }else{
     (void)fprintf(stderr, "%s:%ld: %s\n",
-		  current_file->str,
-		  (long)current_line,
+		  lex.current_file->str,
+		  (long)lex.current_line,
 		  str);
     fflush(stderr);
   }
@@ -1403,18 +1448,18 @@ void yyerror(char *str)
 void add_local_name(struct pike_string *str,
 		    struct pike_string *type)
 {
-  if (local_variables->current_number_of_locals == MAX_LOCAL)
+  if (compiler_frame->current_number_of_locals == MAX_LOCAL)
   {
     yyerror("Too many local variables");
   }else {
-    local_variables->variable[local_variables->current_number_of_locals].type = type;
-    local_variables->variable[local_variables->current_number_of_locals].name = str;
-    local_variables->current_number_of_locals++;
-    if(local_variables->current_number_of_locals > 
-       local_variables->max_number_of_locals)
+    compiler_frame->variable[compiler_frame->current_number_of_locals].type = type;
+    compiler_frame->variable[compiler_frame->current_number_of_locals].name = str;
+    compiler_frame->current_number_of_locals++;
+    if(compiler_frame->current_number_of_locals > 
+       compiler_frame->max_number_of_locals)
     {
-      local_variables->max_number_of_locals=
-	local_variables->current_number_of_locals;
+      compiler_frame->max_number_of_locals=
+	compiler_frame->current_number_of_locals;
     }
   }
 }
@@ -1423,27 +1468,8 @@ void add_local_name(struct pike_string *str,
 int islocal(struct pike_string *str)
 {
   int e;
-  for(e=local_variables->current_number_of_locals-1;e>=0;e--)
-    if(local_variables->variable[e].name==str)
+  for(e=compiler_frame->current_number_of_locals-1;e>=0;e--)
+    if(compiler_frame->variable[e].name==str)
       return e;
   return -1;
 }
-
-void free_all_local_names()
-{
-  int e;
-
-  for (e=0; e<local_variables->current_number_of_locals; e++)
-  {
-    if(local_variables->variable[e].name)
-    {
-      free_string(local_variables->variable[e].name);
-      free_string(local_variables->variable[e].type);
-    }
-    local_variables->variable[e].name=0;
-    local_variables->variable[e].type=0;
-  }
-  local_variables->current_number_of_locals = 0;
-  local_variables->max_number_of_locals = 0;
-}
-
diff --git a/src/las.c b/src/las.c
index 23c9066cee738b20a39d1cc9fd3bad6b2c080b8d..abf41900f6c514d54a9c2ee3ea20494e6605dd23 100644
--- a/src/las.c
+++ b/src/las.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: las.c,v 1.32 1997/04/18 01:17:40 hubbe Exp $");
+RCSID("$Id: las.c,v 1.32.2.1 1997/06/25 22:46:39 hubbe Exp $");
 
 #include "language.h"
 #include "interpret.h"
@@ -34,7 +34,6 @@ int lasdebug=0;
 static node *eval(node *);
 static void optimize(node *n);
 
-dynamic_buffer areas[NUM_AREAS];
 node *init_node = 0;
 int num_parse_error;
 int cumulative_parse_error=0;
@@ -137,7 +136,7 @@ static node *free_nodes=0;
 
 void free_all_nodes()
 {
-  if(!local_variables)
+  if(!compiler_frame)
   {
     node *tmp;
     struct node_chunk *tmp2;
@@ -240,7 +239,7 @@ static node *mkemptynode()
   res=free_nodes;
   free_nodes=CAR(res);
   res->token=0;
-  res->line_number=current_line;
+  res->line_number=lex.current_line;
   res->type=0;
   res->node_info=0;
   res->tree_info=0;
@@ -273,6 +272,10 @@ node *mknode(short token,node *a,node *b)
     }
     break;
 
+  case F_UNDEFINED:
+    res->node_info |= OPT_EXTERNAL_DEPEND | OPT_SIDE_EFFECT;
+    break;
+
   case F_RETURN:
     res->node_info |= OPT_RETURN;
     break;
@@ -310,7 +313,9 @@ node *mknode(short token,node *a,node *b)
 
   if(a) a->parent = res;
   if(b) b->parent = res;
-  if(!num_parse_error) optimize(res);
+
+  if(!num_parse_error && compiler_pass==2)
+    optimize(res);
 
 #ifdef DEBUG
   if(d_flag > 3)
@@ -394,7 +399,7 @@ node *mklocalnode(int var)
 {
   node *res = mkemptynode();
   res->token = F_LOCAL;
-  copy_shared_string(res->type, local_variables->variable[var].type);
+  copy_shared_string(res->type, compiler_frame->variable[var].type);
   res->node_info = OPT_NOT_CONST;
   res->tree_info=res->node_info;
 #ifdef __CHECKER__
@@ -408,11 +413,10 @@ node *mkidentifiernode(int i)
 {
   node *res = mkemptynode();
   res->token = F_IDENTIFIER;
-  setup_fake_program();
-  copy_shared_string(res->type, ID_FROM_INT(&fake_program, i)->type);
+  copy_shared_string(res->type, ID_FROM_INT(new_program, i)->type);
 
   /* FIXME */
-  if(IDENTIFIER_IS_CONSTANT(ID_FROM_INT(&fake_program, i)->flags))
+  if(IDENTIFIER_IS_CONSTANT(ID_FROM_INT(new_program, i)->flags))
   {
     res->node_info = OPT_EXTERNAL_DEPEND;
   }else{
@@ -462,12 +466,11 @@ void resolv_constant(node *n)
       break;
 
     case F_IDENTIFIER:
-      setup_fake_program();
-      i=ID_FROM_INT(& fake_program, n->u.number);
+      i=ID_FROM_INT(new_program, n->u.number);
 	
       if(IDENTIFIER_IS_CONSTANT(i->flags))
       {
-	push_svalue(PROG_FROM_INT(&fake_program, n->u.number)->constants +
+	push_svalue(PROG_FROM_INT(new_program, n->u.number)->constants +
 		    i->func.offset);
       }else{
 	yyerror("Identifier is not a constant");
@@ -799,8 +802,7 @@ static void low_print_tree(node *foo,int needlval)
 
   case F_IDENTIFIER:
     if(needlval) putchar('&');
-    setup_fake_program();
-    printf("%s",ID_FROM_INT(&fake_program, foo->u.number)->name->str);
+    printf("%s",ID_FROM_INT(new_program, foo->u.number)->name->str);
     break;
 
   case F_ASSIGN:
@@ -1236,8 +1238,7 @@ void fix_type_field(node *n)
       switch(CAR(n)->token)
       {
       case F_IDENTIFIER:
-	setup_fake_program();
-	name=ID_FROM_INT(&fake_program, CAR(n)->u.number)->name->str;
+	name=ID_FROM_INT(new_program, CAR(n)->u.number)->name->str;
 	break;
 	
       case F_CONSTANT:
@@ -1278,11 +1279,11 @@ void fix_type_field(node *n)
     break;
 
   case F_RETURN:
-    if(local_variables &&
-       local_variables->current_return_type &&
-       !match_types(local_variables->current_return_type,CAR(n)->type) &&
+    if(compiler_frame &&
+       compiler_frame->current_return_type &&
+       !match_types(compiler_frame->current_return_type,CAR(n)->type) &&
        !(
-	 local_variables->current_return_type==void_type_string &&
+	 compiler_frame->current_return_type==void_type_string &&
 	 CAR(n)->token == F_CONSTANT &&
 	 IS_ZERO(& CAR(n)->u.sval)
 	 )
@@ -1361,7 +1362,7 @@ static void zapp_try_optimize(node *n)
 static void optimize(node *n)
 {
   node *tmp1, *tmp2, *tmp3;
-  INT32 save_line = current_line;
+  INT32 save_line = lex.current_line;
   do
   {
     if(car_is_node(n) && !(CAR(n)->node_info & OPT_OPTIMIZED))
@@ -1374,7 +1375,7 @@ static void optimize(node *n)
       n=CDR(n);
       continue;
     }
-    current_line = n->line_number;
+    lex.current_line = n->line_number;
 
 
     n->tree_info = n->node_info;
@@ -1804,7 +1805,7 @@ static void optimize(node *n)
     n->node_info |= OPT_OPTIMIZED;
     n=n->parent;
   }while(n);
-  current_line = save_line;
+  lex.current_line = save_line;
 }
 
 struct timer_oflo
@@ -1839,10 +1840,9 @@ int eval_low(node *n)
 #endif
 
   if(num_parse_error) return -1;
-  setup_fake_program();
 
-  num_strings=fake_program.num_strings;
-  num_constants=fake_program.num_constants;
+  num_strings=new_program->num_strings;
+  num_constants=new_program->num_constants;
   jump=PC;
 
   store_linenumbers=0;
@@ -1850,7 +1850,6 @@ int eval_low(node *n)
   ins_f_byte(F_DUMB_RETURN);
   store_linenumbers=1;
 
-  setup_fake_program();
   ret=-1;
   if(!num_parse_error)
   {
@@ -1893,21 +1892,19 @@ int eval_low(node *n)
     remove_callback(tmp_callback);
   }
 
-  while(fake_program.num_strings > num_strings)
+  while(new_program->num_strings > num_strings)
   {
-    fake_program.num_strings--;
-    free_string(fake_program.strings[fake_program.num_strings]);
-    areas[A_STRINGS].s.len-=sizeof(struct pike_string *);
+    new_program->num_strings--;
+    free_string(new_program->strings[new_program->num_strings]);
   }
 
-  while(fake_program.num_constants > num_constants)
+  while(new_program->num_constants > num_constants)
   {
-    fake_program.num_constants--;
-    free_svalue(fake_program.constants + fake_program.num_constants);
-    areas[A_CONSTANTS].s.len-=sizeof(struct svalue);
+    new_program->num_constants--;
+    free_svalue(new_program->constants + new_program->num_constants);
   }
 
-  areas[A_PROGRAM].s.len=jump;
+  new_program->num_program=jump;
 
   return ret;
 }
@@ -2037,7 +2034,6 @@ int dooptcode(struct pike_string *name,
   if(a_flag > 1)
     fprintf(stderr,"Doing function '%s' at %x\n",name->str,PC);
 #endif
-  last_function_opt_info=OPT_SIDE_EFFECT;
 
   args=count_arguments(type);
   if(args < 0) 
@@ -2047,37 +2043,42 @@ int dooptcode(struct pike_string *name,
   }else{
     vargs=0;
   }
-  n=mknode(F_ARG_LIST,n,0);
-
-  if((foo=is_stupid_func(n, args, vargs)))
+  if(compiler_pass==1)
   {
-    if(foo->type == T_FUNCTION && foo->subtype==FUNCTION_BUILTIN)
+    tmp.offset=-1;
+  }else{
+    n=mknode(F_ARG_LIST,n,0);
+    
+    if((foo=is_stupid_func(n, args, vargs)))
     {
-      tmp.c_fun=foo->u.efun->function;
-      ret=define_function(name,
-			  type,
-			  modifiers,
-			  IDENTIFIER_C_FUNCTION | vargs,
-			  &tmp);
-      free_node(n);
-      return ret;
+      if(foo->type == T_FUNCTION && foo->subtype==FUNCTION_BUILTIN)
+      {
+	tmp.c_fun=foo->u.efun->function;
+	ret=define_function(name,
+			    type,
+			    modifiers,
+			    IDENTIFIER_C_FUNCTION | vargs,
+			    &tmp);
+	free_node(n);
+	return ret;
+      }
     }
-  }
-  
-  tmp.offset=PC;
-  ins_byte(local_variables->max_number_of_locals, A_PROGRAM);
-  ins_byte(args, A_PROGRAM);
+
+    tmp.offset=PC;
+    add_to_program(compiler_frame->max_number_of_locals);
+    add_to_program(args);
   
 #ifdef DEBUG
-  if(a_flag > 2)
-  {
-    fprintf(stderr,"Coding: ");
-    print_tree(n);
-  }
+    if(a_flag > 2)
+    {
+      fprintf(stderr,"Coding: ");
+      print_tree(n);
+    }
 #endif
-  if(!num_parse_error)
-  {
-    do_code_block(n);
+    if(!num_parse_error)
+    {
+      do_code_block(n);
+    }
   }
   
   ret=define_function(name,
@@ -2090,6 +2091,4 @@ int dooptcode(struct pike_string *name,
   return ret;
 }
 
-INT32 get_opt_info() { return last_function_opt_info; }
-
 
diff --git a/src/las.h b/src/las.h
index 078670474766d8fde6c66d094b511c50d5441205..7b750e149a10fba4cd8018547fae8352d0459251 100644
--- a/src/las.h
+++ b/src/las.h
@@ -14,21 +14,6 @@
 
 #define MAX_GLOBAL_VARIABLES 1000
 
-struct local_variable
-{
-  struct pike_string *name;
-  struct pike_string *type;
-};
-
-struct locals
-{
-  struct locals *next;
-  struct pike_string *current_type;
-  struct pike_string *current_return_type;
-  int current_number_of_locals;
-  int max_number_of_locals;
-  struct local_variable variable[MAX_LOCAL];
-};
 
 void yyerror(char *s);
 int islocal(struct pike_string *str);
@@ -55,10 +40,27 @@ struct node_s
 
 typedef struct node_s node;
 
-extern struct locals *local_variables;
 extern node *init_node;
 extern int num_parse_error;
 extern int cumulative_parse_error;
+extern struct compiler_frame *compiler_frame;
+
+struct local_variable
+{
+  struct pike_string *name;
+  struct pike_string *type;
+};
+
+struct compiler_frame
+{
+  struct compiler_frame *previous;
+
+  struct pike_string *current_type;
+  struct pike_string *current_return_type;
+  int current_number_of_locals;
+  int max_number_of_locals;
+  struct local_variable variable[MAX_LOCAL];
+};
 
 #define OPT_OPTIMIZED       0x1    /* has been processed by optimize(),
 				    * only used in node_info
@@ -126,20 +128,9 @@ INT32 get_opt_info();
 
 #define GAUGE_RUSAGE_INDEX 0
 
-#define A_PROGRAM 0
-#define A_STRINGS 1
-#define A_INHERITS 2
-#define A_IDENTIFIERS 3
-#define A_IDENTIFIER_REFERENCES 4
-#define A_CONSTANTS 5
-#define A_LINENUMBERS 6
-#define NUM_AREAS 7
-
 #define add_to_mem_block(N,Data,Size) low_my_binary_strcat(Data,Size,areas+N)
-#define IDENTIFIERP(i) (((struct reference *)areas[A_IDENTIFIER_REFERENCES].s.str)+i)
-#define INHERIT(i) (((struct inherit *)areas[A_INHERITS].s.str)+i)
-#define PC (areas[A_PROGRAM].s.len)
-
-extern dynamic_buffer areas[NUM_AREAS];
+#define IDENTIFIERP(i) (new_program->identifier_references+(i))
+#define INHERIT(i) (new_program->inherits+(i))
+#define PC (new_program->num_program)
 
 #endif
diff --git a/src/lex.c b/src/lex.c
index a5a99a7f3e59e90cbddec3f08575fbe53a1da954..507d5e682c3f1b818f59ecd07c67d3931532a880 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: lex.c,v 1.21.2.1 1997/05/19 09:04:55 hubbe Exp $");
+RCSID("$Id: lex.c,v 1.21.2.2 1997/06/25 22:46:39 hubbe Exp $");
 #include "language.h"
 #include "array.h"
 #include "lex.h"
@@ -33,29 +33,8 @@ RCSID("$Id: lex.c,v 1.21.2.1 1997/05/19 09:04:55 hubbe Exp $");
 #include "time_stuff.h"
 
 #define LEXDEBUG 0
-#define EXPANDMAX 500000
 
-struct pike_string *current_file;
-
-INT32 current_line;
-INT32 old_line;
-INT32 total_lines;
-INT32 nexpands;
-int pragma_all_inline;          /* inline all possible inlines */
-
-struct pike_predef_s
-{
-  char *name;
-  char *value;
-  struct pike_predef_s *next;
-};
-
-struct pike_predef_s *pike_predefs=0;
-
-static int calc();
-static void calc1();
-
-void exit_lex()
+void exit_lex(void)
 {
 #ifdef DEBUG
   if(p_flag)
@@ -71,74 +50,8 @@ void exit_lex()
     }
   }
 #endif
-
-
-  while(local_variables)
-  {
-    int e;
-    struct locals *l;
-    for(e=0;e<local_variables->current_number_of_locals;e++)
-    {
-      free_string(local_variables->variable[e].name);
-      free_string(local_variables->variable[e].type);
-    }
-    if(local_variables->current_type)
-      free_string(local_variables->current_type);
-    if(local_variables->current_return_type)
-      free_string(local_variables->current_return_type);
-    l=local_variables->next;
-    free((char *)local_variables);
-    local_variables=l;
-  }
-
-  if(current_file) free_string(current_file);
-  free_reswords();
 }
 
-struct keyword reserved_words[] =
-{
-{ "array",	F_ARRAY_ID, },
-{ "break",	F_BREAK, },
-{ "case",	F_CASE, },
-{ "catch",	F_CATCH, },
-{ "class",	F_CLASS, },
-{ "constant",	F_CONSTANT, },
-{ "continue",	F_CONTINUE, },
-{ "default",	F_DEFAULT, },
-{ "do",		F_DO, },
-{ "else",	F_ELSE, },
-{ "float",	F_FLOAT_ID, },
-{ "for",	F_FOR, },
-{ "foreach",	F_FOREACH, },
-{ "function",	F_FUNCTION_ID, },
-{ "gauge",	F_GAUGE, },
-{ "if",		F_IF, },
-{ "import",	F_IMPORT, },
-{ "inherit",	F_INHERIT, },
-{ "inline",	F_INLINE, },
-{ "int",	F_INT_ID, },
-{ "lambda",	F_LAMBDA, },
-{ "mapping",	F_MAPPING_ID, },
-{ "mixed",	F_MIXED_ID, },
-{ "multiset",	F_MULTISET_ID, },
-{ "nomask",	F_NO_MASK, },
-{ "object",	F_OBJECT_ID, },
-{ "predef",	F_PREDEF, },
-{ "private",	F_PRIVATE, },
-{ "program",	F_PROGRAM_ID, },
-{ "protected",	F_PROTECTED, },
-{ "public",	F_PUBLIC, },
-{ "return",	F_RETURN, },
-{ "sscanf",	F_SSCANF, },
-{ "static",	F_STATIC, },
-{ "string",	F_STRING_ID, },
-{ "switch",	F_SWITCH, },
-{ "typeof",	F_TYPEOF, },
-{ "varargs",	F_VARARGS, },
-{ "void",	F_VOID_ID, },
-{ "while",	F_WHILE, },
-};
-
 struct keyword instr_names[]=
 {
 { "!",			F_NOT },	
@@ -293,8 +206,6 @@ struct reserved
   int token;
 };
 
-struct hash_table *reswords;
-
 void init_lex()
 {
   unsigned int i;
@@ -309,24 +220,6 @@ void init_lex()
     instrs[instr_names[i].token - F_OFFSET].name = instr_names[i].word;
     instrs[instr_names[i].token - F_OFFSET].flags=instr_names[i].flags;
   }
-
-  reswords=create_hash_table();
-
-  for(i=0; i<NELEM(reserved_words); i++)
-  {
-    struct reserved *r=ALLOC_STRUCT(reserved);
-    r->token = reserved_words[i].token;
-    r->link.s = make_shared_string(reserved_words[i].word);
-    reswords=hash_insert(reswords, &r->link);
-  }
-
-  /* Enlarge this hashtable heruetically */
-  reswords = hash_rehash(reswords, 2<<my_log2(NELEM(reserved_words)));
-}
-
-void free_reswords()
-{
-  free_hashtable(reswords,0);
 }
 
 char *low_get_f_name(int n,struct program *p)
@@ -390,1068 +283,210 @@ char *get_token_name(int n)
   }
 }
 
-/* foo must be a shared string */
-static int lookup_resword(struct pike_string *s)
-{
-  struct hash_entry *h;
-  h=hash_lookup(reswords, s);
-  if(!h) return -1;
-  return BASEOF(h, reserved, link)->token;
-}
-
-
-
-/*** input routines ***/
-struct inputstate
-{
-  struct inputstate *next;
-  int fd;
-  unsigned char *data;
-  INT32 buflen;
-  INT32 pos;
-  int dont_free_data;
-
-  int (*my_getc)();
-  int (*gobble)(int);
-  int (*look)();
-  void (*my_ungetc)(int);
-  void (*ungetstr)(char *,INT32);
-};
-
-#define MY_EOF 4711
+struct lex lex;
 
-struct inputstate *istate=NULL;
+#define LOOK() (*(lex.pos))
+#define GETC() (*(lex.pos++))
+#define GOBBLE(c) (LOOK()==c?(lex.pos++,1):0)
+#define SKIPSPACE() do { while(ISSPACE(LOOK()) && LOOK()!='\n') lex.pos++; }while(0)
+#define SKIPWHITE() do { while(ISSPACE(LOOK())) lex.pos++; }while(0)
+#define SKIPUPTO(X) do { while(LOOK()!=(X) && LOOK()) lex.pos++; }while(0)
 
-static void link_inputstate(struct inputstate *i)
-{
-  i->next=istate;
-  istate=i;
+#define READBUF(X) {				\
+  register int C;				\
+  buf=lex.pos;					\
+  while((C=LOOK()) && (X)) lex.pos++;		\
+  len=lex.pos - buf;				\
 }
 
-static void free_inputstate(struct inputstate *i)
-{
-  if(!i) return;
-  if(i->fd>=0)
-  {
-  retry:
-    if(close(i->fd)< 0)
-      if(errno == EINTR)
-	goto retry;
-  }
-  if(i->data && !i->dont_free_data) free(i->data);
-  free_inputstate(i->next);
-  free((char *)i);
-}
+#define TWO_CHAR(X,Y) ((X)<<8)+(Y)
+#define ISWORD(X) (len==(long)strlen(X) && !MEMCMP(buf,X,strlen(X)))
 
-static struct inputstate *new_inputstate();
-static struct inputstate *memory_inputstate(INT32 size);
+/*** Lexical analyzing ***/
 
-static int default_gobble(int c)
+static int char_const(void)
 {
-  if(istate->look()==c)
+  int c;
+  switch(c=GETC())
   {
-    istate->my_getc();
-    return 1;
-  }else{
+  case 0:
+    lex.pos--;
+    yyerror("Unexpected end of file\n");
     return 0;
+    
+  case '0': case '1': case '2': case '3':
+  case '4': case '5': case '6': case '7':
+    c-='0';
+      if(LOOK()<'0' || LOOK()>'8') return c;
+      c=c*8+(GETC()-'0');
+      if(LOOK()<'0' || LOOK()>'8') return c;
+      c=c*8+(GETC()-'0');
+      return c;
+      
+  case 'r': return '\r';
+  case 'n': return '\n';
+  case 't': return '\t';
+  case 'b': return '\b';
+
+  case '\n':
+    lex.current_line++;
+    return '\n';
+    
   }
-}
-
-static void default_ungetstr(char *s,INT32 len)
-{
-  link_inputstate(memory_inputstate(len+1000));
-  istate->ungetstr(s,len);
-}
-
-static void default_ungetc(int s)
-{
-  char c=s;
-  istate->ungetstr(&c,1);
-}
-
-static int default_look()
-{
-  int c;
-  c=istate->my_getc();
-  istate->my_ungetc(c);
   return c;
 }
 
-static struct inputstate *new_inputstate()
-{
-  struct inputstate *i;
-  i=(struct inputstate *)xalloc(sizeof(struct inputstate));
-  i->fd=-1;
-  i->data=NULL;
-  i->next=NULL;
-  i->dont_free_data=0;
-  i->gobble=default_gobble;
-  i->ungetstr=default_ungetstr;
-  i->my_ungetc=default_ungetc;
-  i->look=default_look;
-  return i;
-}
-
-/*** end of file input ***/
-static int end_getc() { return MY_EOF; }
-static int end_gobble(int c) { return c==MY_EOF; }
-static void end_ungetc(int c)
-{
-  if(c==MY_EOF) return;
-  default_ungetc(c);
-}
-
-static struct inputstate *end_inputstate()
-{
-  struct inputstate *i;
-  i=new_inputstate();
-  i->gobble=end_gobble;
-  i->look=end_getc;
-  i->my_getc=end_getc;
-  i->my_ungetc=end_ungetc;
-  return i;
-}
-
-/*** MEMORY input ***/
-static void memory_ungetstr(char *s,INT32 len)
-{
-  INT32 tmp;
-  tmp=MINIMUM(len,istate->pos);
-  if(tmp)
-  {
-    istate->pos -= tmp;
-    MEMCPY(istate->data + istate->pos , s+len-tmp , tmp);
-    len-=tmp;
-  }
-  if(len) default_ungetstr(s,len);
-}
-
-static void memory_ungetc(int s)
-{
-  if(istate->pos)
-  {
-    istate->pos --;
-    istate->data[istate->pos]=s;
-  }else{
-    default_ungetc(s);
-  }
-}
-
-static int memory_getc()
-{
-  if(istate->pos<istate->buflen)
-  {
-#if LEXDEBUG>9
-    fprintf(stderr,"lex: reading from memory '%c' (%d).\n",istate->data[istate->pos],istate->data[istate->pos]);
-#endif
-    return istate->data[(istate->pos)++];
-  }else{
-    struct inputstate *i;
-    i=istate;
-    istate=i->next;
-    if(!i->dont_free_data) free(i->data);
-    free((char *)i);
-    return istate->my_getc();
-  }
-}
-
-static int memory_look()
-{
-  if(istate->pos<istate->buflen)
-  {
-    return istate->data[istate->pos];
-  }else{
-    struct inputstate *i;
-    i=istate;
-    istate=i->next;
-    if(!i->dont_free_data) free(i->data);
-    free((char *)i);
-    return istate->look();
-  }
-}
-
-/* allocate an empty memory state */
-static struct inputstate *memory_inputstate(INT32 size)
-{
-  struct inputstate *i;
-  if(!size) size=10000;
-  i=new_inputstate();
-  i->data=(unsigned char *)xalloc(size);
-  i->buflen=size;
-  i->pos=size;
-  i->ungetstr=memory_ungetstr;
-  i->my_getc=memory_getc;
-  i->look=memory_look;
-  i->my_ungetc=memory_ungetc;
-  return i;
-}
-
-static void prot_memory_ungetstr(char *s,INT32 len)
+static struct pike_string *readstring(void)
 {
-  INT32 tmp;
-  tmp=MINIMUM(len,istate->pos);
-  if(tmp)
+  int c;
+  dynamic_buffer tmp;
+  initialize_buf(&tmp);
+  
+  while(1)
   {
-    if(!MEMCMP(istate->data + istate->pos - tmp, s+len-tmp , tmp))
+    switch(c=GETC())
     {
-      istate->pos-=tmp;
-      len-=tmp;
+    case 0:
+      lex.pos--;
+      yyerror("End of file in string.");
+      break;
+      
+    case '\n':
+      lex.current_line++;
+      yyerror("Newline in string.");
+      break;
+      
+    case '\\':
+      low_my_putchar(char_const(),&tmp);
+      continue;
+      
+    case '"':
+      break;
+      
+    default:
+      low_my_putchar(c,&tmp);
+      continue;
     }
+    break;
   }
-  if(len) default_ungetstr(s,len);
-}
-
-static void prot_memory_ungetc(int s)
-{
-  if(istate->pos && istate->data[istate->pos-1] == s)
-  {
-    istate->pos--;
-  }else{
-    default_ungetc(s);
-  }
-}
-
-/* allocate a memory, read-only, inputstate */
-static struct inputstate *prot_memory_inputstate(char *data,INT32 len)
-{
-  struct inputstate *i;
-  i=new_inputstate();
-  i->data=(unsigned char *)data;
-  i->buflen=len;
-  i->dont_free_data=1;
-  i->pos=0;
-  i->my_getc=memory_getc;
-  i->look=memory_look;
-  i->ungetstr=prot_memory_ungetstr;
-  i->my_ungetc=prot_memory_ungetc;
-  return i;
+  return low_free_buf(&tmp);
 }
 
-/*** FILE input ***/
-
-#define READAHEAD 8192
-static int file_getc()
-{
-  unsigned char buf[READAHEAD];
-  int got;
-  do {
-    got=read(istate->fd, buf, READAHEAD);
-    if(got > 0)
-    {
-      default_ungetstr((char *)buf, got);
-      return istate->my_getc();
-    }
-    else if(got==0 || errno != EINTR)
-    {
-      struct inputstate *i;
-      if(got<0 && errno != EINTR)
-	my_yyerror("Lex: Read failed with error %d\n",errno);
-
-      i=istate->next;
-      close(istate->fd);
-      free((char *)istate);
-      istate=i;
-      return istate->my_getc();
-    }
-  }while(1);
-}
-
-static struct inputstate *file_inputstate(int fd)
-{
-  struct inputstate *i;
-  i=new_inputstate();
-  i->fd=fd;
-  i->my_getc=file_getc;
-  return i;
-}
-
-static int GETC()
-{
-  int c;
-  c=istate->my_getc();
-  if(c=='\n') current_line++;
-  return c;
-}
-
-static void UNGETC(int c)
-{
-  if(c=='\n') current_line--;
-  istate->my_ungetc(c);
-}
-
-static void UNGETSTR(char *s,INT32 len)
-{
-  INT32 e;
-  for(e=0;e<len;e++) if(s[e]=='\n') current_line--;
-  istate->ungetstr(s,len);
-}
-
-static int GOBBLE(char c)
+int yylex(YYSTYPE *yylval)
+#if LEXDEBUG>4
 {
-  if(istate->gobble(c))
+  int t;
+  int yylex2(YYSTYPE *);
+  t=yylex2(yylval);
+  if(t<256)
   {
-    if(c=='\n') current_line++;
-    return 1;
+    fprintf(stderr,"yylex() -> '%c' (%d)\n",t,t);
   }else{
-    return 0;
+    fprintf(stderr,"yylex() -> %s (%d)\n",get_f_name(t),t);
   }
+  return t;
 }
 
-#define LOOK() (istate->look())
-#define SKIPWHITE() { int c; while(ISSPACE(c=GETC())); UNGETC(c); }
-#define SKIPTO(X) { int c; while((c=GETC())!=(X) && (c!=MY_EOF)); }
-#define SKIPUPTO(X) { int c; while((c=GETC())!=(X) && (c!=MY_EOF)); UNGETC(c); }
-#define READBUF(X) { \
-  register unsigned INT32 p; \
-  register int C; \
-  for(p=0;(C=GETC())!=MY_EOF && p<sizeof(buf) && (X);p++) \
-  buf[p]=C; \
-  if(p==sizeof(buf)) { \
-    yyerror("Internal buffer overflow.\n"); p--; \
-  } \
-  UNGETC(C); \
-  buf[p]=0; \
-}
-
-static char buf[1024];
-
-/*** Define handling ***/
-
-struct define
-{
-  struct hash_entry link; /* must be first */
-  void (*magic)();
-  int args;
-  struct array *parts;
-};
-
-struct hash_table *defines = 0;
-
-#define find_define(N) (defines?BASEOF(hash_lookup(defines, N), define, link):0)
-
-/* argument must be shared string */
-static void undefine(struct pike_string *name)
-{
-  struct define *d;
-
-  d=find_define(name);
-
-  if(!d) return;
-
-  defines=hash_unlink(defines, & d->link);
-  free_string(d->link.s);
-  free_array(d->parts);
-  free((char *)d);
-}
-
-/* name and as are supposed to be SHARED strings */
-static void add_define(struct pike_string *name,
-		       int args,
-		       int parts_on_stack,
-		       void (*magic)())
-{
-  struct define *d;
-
-  f_aggregate(parts_on_stack);
-  if(sp[-1].type != T_ARRAY)
-  {
-    yyerror("Define failed for unknown reason.\n");
-    free_string(name);
-    pop_stack();
-    return;
-  }
-
-#if 0
-  if(find_define(name))
-  {
-    my_yyerror("Redefining '%s'",name->str);
-    free_string(name);
-    pop_stack();
-    return;
-  }
-#else
-  undefine(name);
+static int yylex2(YYSTYPE *yylval)
 #endif
-
-  d=(struct define *)xalloc(sizeof(struct define));
-  d->link.s=name;
-  d->args=args;
-  d->magic=magic;
-  d->parts=sp[-1].u.array;
-  sp--;
-
-  defines=hash_insert(defines, & d->link);
-}
-
-static void simple_add_define(char *name,char *as,void (*magic)())
-{
-  if(magic)
-  {
-    add_define(make_shared_string(name),-1,0,magic);
-  }else{
-    push_string(make_shared_string(as));
-    add_define(make_shared_string(name),-1,1,magic);
-  }
-}
-
-void free_one_define(struct hash_entry *h)
-{
-  struct define *d;
-  d=BASEOF(h, define, link);
-  if(d->parts) free_array(d->parts);
-  free((void *)d);
-}
-
-static void free_all_defines()
 {
-  if(defines)
-    free_hashtable(defines, free_one_define);
-  defines=0;
-}
-
-static void do_define()
-{
-  int c,e,t,argc;
-  struct svalue *save_sp=sp;
-  struct svalue *args_sp;
-  struct pike_string *s, *s2;
-
-  SKIPWHITE();
-  READBUF(isidchar(C));
+  INT32 c,len;
+  char *buf;
 
-  s=make_shared_string(buf);
+#ifdef __CHECKER__
+  MEMSET((char *)yylval,0,sizeof(YYSTYPE));
+#endif
+#ifdef MALLOC_DEBUG
+  check_sfltable();
+#endif
 
-  if(GOBBLE('('))
+  while(1)
   {
-    argc=0;
-
-    SKIPWHITE();
-    READBUF(isidchar(C));
-    if(buf[0])
+    switch(c=GETC())
     {
-      push_string(make_shared_string(buf));
-      argc++;
-      SKIPWHITE();
-      while(GOBBLE(','))
-      {
-        SKIPWHITE();
-        READBUF(isidchar(C));
-        push_string(make_shared_string(buf));
-        argc++;
-      }
-    }
-    SKIPWHITE();
-
-    if(!GOBBLE(')'))
-      yyerror("Missing ')'");
-  }else{
-    argc=-1;
-  }
-
-  args_sp=sp;
+    case 0:
+      lex.pos--;
+      return 0;
 
-  init_buf();
-  t=0;
-  sp->type=T_STRING;
-  sp->u.string=make_shared_string("");
-  sp++;
+    case '\n':
+      lex.current_line++;
+      continue;
 
-  while(1)
-  {
-    int tmp;
+    case '#':
+      SKIPSPACE();
+      READBUF(C!=' ' && C!='\t' && C!='\n');
 
-    c=GETC();
-    if(c=='\\') if(GOBBLE('\n')) continue;
-    if( (t!=!!isidchar(c) && argc>0) || c=='\n' || c==MY_EOF)
-    {
-      s2=free_buf();
-      tmp=0;
-      for(e=0;e<argc;e++)
+      switch(len>0?buf[0]:0)
       {
-	if(save_sp[e].u.string==s2)
+	char *p;
+	
+      case 'l':
+	if(!ISWORD("line")) goto badhash;
+	READBUF(C!=' ' && C!='\t' && C!='\n');
+	
+      case '0': case '1': case '2': case '3': case '4':
+      case '5': case '6': case '7': case '8': case '9':
+	lex.current_line=atoi(buf)-1;
+	SKIPSPACE();
+	if(GOBBLE('"'))
 	{
-	  free_string(s2);
-	  push_int(e);
-	  tmp=1;
-	  break;
+	  struct pike_string *tmp=readstring();
+	  free_string(lex.current_file);
+	  lex.current_file=tmp;
 	}
-      }
-      if(!tmp)
-      {
-	push_string(s2);
-	if(sp[-2].type==T_STRING) f_add(2);
-      }
-      if(c=='\n' || c==MY_EOF)
-      {
-	push_string(make_shared_string(" "));
-	if(sp[-2].type==T_STRING) f_add(2);
 	break;
-      }
-      t=!!isidchar(c);
-      init_buf();
-    }
-    my_putchar(c);
-  }
-  UNGETC(c);
-  add_define(s,argc,sp-args_sp,0);
-  while(sp>save_sp) pop_stack();
-}
-
-/* s is a shared string */
-static int expand_define(struct pike_string *s, int save_newline)
-{
-  struct svalue *save_sp=sp;
-  struct define *d;
-  int len,e,tmp,args;
-  d=find_define(s);
-  if(!d) return 0;
-
-  if(nexpands>EXPANDMAX)
-  {
-    yyerror("Macro limit exceeded.");
-    return 0;
-  }
-
-  if(d->magic)
-  {
-    d->magic();
-    return 1;
-  }
-
-  if(d->args >= 0)
-  {
-    if(!save_newline)
-    {
-      SKIPWHITE();
-    }else{
-      do { e=GETC(); }while(ISSPACE(e) && e!='\n');
-      UNGETC(e);
-    }
-
-    if(GOBBLE('('))
-    {
-      int parlvl,quote;
-      int c;
-      args=0;
+	
+      case 'e':
+	if(ISWORD("error"))
+	{
+	  SKIPSPACE();
+	  READBUF(C!='\n');
+	  yyerror(buf);
+	  break;
+	}
+	goto badhash;
 
-      SKIPWHITE();
-      init_buf();
-      parlvl=1;
-      quote=0;
-      while(parlvl)
-      {
-	switch(c=GETC())
+      case 'p':
+	if(ISWORD("pragma"))
 	{
-	case MY_EOF:
-	  yyerror("Unexpected end of file.");
-	  while(sp>save_sp) pop_stack();
-	  return 0;
-	case '"': if(!(quote&2)) quote^=1; break;
-	case '\'': if(!(quote&1)) quote^=2; break;
-	case '(': if(!quote) parlvl++; break;
-	case ')': if(!quote) parlvl--; break;
-	case '\\': my_putchar(c); c=GETC(); break;
-	case ',':
-	  if(!quote && parlvl==1)
+	  SKIPSPACE();
+	  READBUF(C!='\n');
+	  if (strcmp(buf, "all_inline") == 0)
 	  {
-	    push_string(free_buf());
-	    init_buf();
-	    args++;
-	    continue;
+	    lex.pragmas |= PRAGMA_ALL_INLINE;
 	  }
+	  break;
 	}
-	if(parlvl) my_putchar(c);
-      }
-      push_string(free_buf());
-      if(args==0 && !d->args && !sp[-1].u.string->len)
-      {
-	pop_stack();
-      }else{
-	args++;
-      }
-    }else{
-      args=0;
-    }
-  } else {
-    args=-1;
-  }
-  
-  if(args>d->args)
-  {
-    my_yyerror("Too many arguments to macro '%s'.\n",s->str);
-    while(sp>save_sp) pop_stack();
-    return 0;
-  }
-
-  if(args<d->args)
-  {
-    my_yyerror("Too few arguments to macro '%s'.\n",s->str);
-    while(sp>save_sp) pop_stack();
-    return 0;
-  }
-  len=0;
-  for(e=d->parts->size-1;e>=0;e--)
-  {
-    switch(ITEM(d->parts)[e].type)
-    {
-    case T_STRING:
-      tmp=ITEM(d->parts)[e].u.string->len;
-      UNGETSTR(ITEM(d->parts)[e].u.string->str,tmp);
-      break;
-
-    case T_INT:
-      tmp=save_sp[ITEM(d->parts)[e].u.integer].u.string->len;
-      UNGETSTR(save_sp[ITEM(d->parts)[e].u.integer].u.string->str,tmp);
-      break;
-
-    default: tmp=0;
-    }
-    len+=tmp;
-  }
-  while(sp>save_sp) pop_stack();
-  nexpands+=len;
-  return 1;
-}
-
-/*** Handle include ****/
-
-static void handle_include(char *name, int local_include)
-{
-  int fd;
-  char buf[400];
-  struct pike_string *s;
-
-  s=make_shared_string(name);
-  push_string(s);
-  reference_shared_string(s);
-  push_string(current_file);
-  reference_shared_string(current_file);
-  push_int(local_include);
-  
-  SAFE_APPLY_MASTER("handle_include",3);
-  
-  if(sp[-1].type != T_STRING)
-  {
-    my_yyerror("Couldn't include file '%s'.",s->str);
-    return;
-  }
-  free_string(s);
-  
- retry:
-  fd=open(sp[-1].u.string->str,O_RDONLY);
-  if(fd < 0)
-  {
-    if(errno == EINTR) goto retry;
-
-#ifdef HAVE_STRERROR    
-    my_yyerror("Couldn't open file to include '%s'. (%s)",sp[-1].u.string->str,strerror(errno));
-#else
-    my_yyerror("Couldn't open file to include '%s'. (ERRNO=%d)",sp[-1].u.string->str,errno);
-#endif
-    return;
-  }
-
-  UNGETSTR("\" 2",3);
-  UNGETSTR(current_file->str,current_file->len);
-  sprintf(buf,"\n# %ld \"",(long)current_line+1);
-  UNGETSTR(buf,strlen(buf));
-
-  total_lines+=current_line-old_line;
-  old_line=current_line=1;
-  free_string(current_file);
-  current_file=sp[-1].u.string;
-  sp--;
-  link_inputstate(file_inputstate(fd));
-  UNGETSTR("\n",1);
-}
-
-/*** Lexical analyzing ***/
-
-static int char_const()
-{
-  int c;
-  switch(c=GETC())
-  {
-  case '0': case '1': case '2': case '3':
-  case '4': case '5': case '6': case '7':
-      c-='0';
-      if(LOOK()<'0' || LOOK()>'8') return c;
-      c=c*8+(GETC()-'0');
-      if(LOOK()<'0' || LOOK()>'8') return c;
-      c=c*8+(GETC()-'0');
-      return c;
-
-    case 'r': return '\r';
-    case 'n': return '\n';
-    case 't': return '\t';
-    case 'b': return '\b';
-  }
-  return c;
-}
-
-#define SKIPTO_ENDIF 1
-#define SKIPTO_ELSE 2
-
-static void do_skip(int to)
-{
-  int lvl;
-#if LEXDEBUG>3
-  fprintf(stderr,"Skipping from %ld to ",(long)current_line);
-#endif
-  lvl=1;
-  while(lvl)
-  {
-    switch(GETC())
-    {
-    case '/':
-      if(GOBBLE('*'))
-      {
-	do{
-	  SKIPTO('*');
-	  if(LOOK()==MY_EOF)
-	  {
-	    yyerror("Unexpected end of file while skipping comment.");
-	    return;
-	  }
-	}while(!GOBBLE('/'));
-      }
-      continue;
-
-    case MY_EOF:
-      yyerror("Unexpected end of file while skipping.");
-      return;
-
-    case '\\':
-      GETC();
-      continue;
 	
-    case '\n':
-      if(GOBBLE('#'))
-      {
-	SKIPWHITE();
-	READBUF(C!=' ' && C!='\t' && C!='\n');
-    
-	switch(buf[0])
-	{
-	case 'l':
-	  if(strcmp("line",buf)) break;
-	  READBUF(C!=' ' && C!='\t' && C!='\n');
-
-	case '0': case '1': case '2': case '3': case '4':
-	case '5': case '6': case '7': case '8': case '9':
-	  SKIPWHITE();
-	  READBUF(C!='\n');
-	  if(buf[0]=='"' &&
-	     buf[strlen(buf)-1]=='2' &&
-	     ISSPACE(buf[strlen(buf)-2]))
-	  {
-	    if(lvl)
-	    {
-	      yyerror("Unterminated '#if' conditional.");
-	      num_parse_error+=1000;
-	    }
-	  }
-	  continue;
-
-	case 'i':
-	  if(!strcmp("include",buf)) continue;
-	  if(!strcmp("if",buf) || !strcmp("ifdef",buf) || !strcmp("ifndef",buf))
-	  {
-	    lvl++;
-	    continue;
-	  }
-	  break;
-
-	case 'e':
-	  if(!strcmp("endif",buf))
-	  { 
-	    lvl--;
-	    if(lvl<0)
-	    {
-	      yyerror("Unbalanced '#endif'\n");
-	      lvl=0;
-	    }
-	    continue;
-	  }
-	  if(!strcmp("else",buf))
-	  {
-	    if(lvl==1 && to==SKIPTO_ELSE) lvl=0;
-	    continue;
-	  }
-	  if(!strcmp("elif",buf) || !strcmp("elseif",buf))
-	  {
-	    if(lvl==1 && to==SKIPTO_ELSE && calc()) lvl--;
-	    continue;
-	  }
-	  if(!strcmp("error",buf)) continue;
-	  break;
-
-	case 'd':
-	  if(!strcmp("define",buf)) continue;
-	  break;
-
-	case 'u':
-	  if(!strcmp("undef",buf)) continue;
-	  break;
-
-	case 'p':
-	  if(!strcmp("pragma",buf)) continue;
-	  break;
-	}
-    
+      badhash:
 	my_yyerror("Unknown directive #%s.",buf);
 	SKIPUPTO('\n');
 	continue;
       }
-    }
-  }
-#if LEXDEBUG>3
-  fprintf(stderr,"%ld in %s.\n",(long)current_line,current_file->str);
-#endif
-}
-
-static int do_lex(int literal, YYSTYPE *yylval)
-#if LEXDEBUG>4
-{
-  int t;
-  int do_lex2(int literal, YYSTYPE *yylval);
-  t=do_lex2(literal, yylval);
-  if(t<256)
-  {
-    fprintf(stderr,"do_lex(%d) -> '%c' (%d)\n",literal,t,t);
-  }else{
-    fprintf(stderr,"do_lex(%d) -> %s (%d)\n",literal,get_f_name(t),t);
-  }
-  return t;
-}
-
-static int do_lex2(int literal, YYSTYPE *yylval)
-#endif
-{
-  int c;
-#ifdef MALLOC_DEBUG
-  check_sfltable();
-#endif
-  while(1)
-  {
-    switch(c=GETC())
-    {
-    case '\n':
-      if(literal)
-      {
-	UNGETC('\n');
-	return '\n';
-      }
-      if(GOBBLE('#'))
-      {
-	if(GOBBLE('!'))
-	{
-	  SKIPUPTO('\n');
-	  continue;
-	}
-            
-	SKIPWHITE();
-	READBUF(C!=' ' && C!='\t' && C!='\n');
-
-	switch(buf[0])
-	{
-	  char *p;
-
-	case 'l':
-	  if(strcmp("line",buf)) goto badhash;
-	  READBUF(C!=' ' && C!='\t' && C!='\n');
-
-	case '0': case '1': case '2': case '3': case '4':
-	case '5': case '6': case '7': case '8': case '9':
-	  total_lines+=current_line-old_line;
-	  old_line=current_line=atoi(buf)-1;
-	  SKIPWHITE();
-	  READBUF(C!='\n');
-
-	  p=buf;
-	  if(*p=='"' && STRCHR(p+1,'"'))
-	  {
-	    char *p2;
-	    p++;
-	    if((p2=STRCHR(p+1,'"')))
-	    {
-	      *p2=0;
-	      free_string(current_file);
-	      current_file=make_shared_string(p);
-	    }
-	  }
-	  break;
-
-	case 'i':
-	  if(!strcmp("include",buf))
-	  {
-	    SKIPWHITE();
-	    c=do_lex(1, yylval);
-	    if(c=='<')
-	    {
-	      READBUF(C!='>' && C!='\n');
-	      if(!GOBBLE('>'))
-	      {
-		yyerror("Missing `>`");
-		SKIPUPTO('\n');
-		continue;
-	      }
-	    }else{
-	      if(c!=F_STRING)
-	      {
-		yyerror("Couldn't find include filename.\n");
-		SKIPUPTO('\n');
-		continue;
-	      }
-	    }
-	    handle_include(buf, c==F_STRING);
-	    break;
-	  }
-
-	  if(!strcmp("if",buf))
-	  {
-	    if(!calc()) do_skip(SKIPTO_ELSE);
-	    break;
-	  }
-
-	  if(!strcmp("ifdef",buf))
-	  {
-	    struct pike_string *s;
-	    SKIPWHITE();
-	    READBUF(isidchar(C));
-	    s=findstring(buf);
-	    if(!s || !find_define(s)) do_skip(SKIPTO_ELSE);
-	    break;
-	  }
-
-	  if(!strcmp("ifndef",buf))
-	  {
-	    struct pike_string *s;
-	    SKIPWHITE();
-	    READBUF(isidchar(C));
-	    s=findstring(buf);
-	    if(s && find_define(s)) do_skip(SKIPTO_ELSE);
-	    break;
-	  }
-	  goto badhash;
-
-	case 'e':
-	  if(!strcmp("endif",buf)) break;
-	  if(!strcmp("else",buf))
-	  {
-	    SKIPUPTO('\n');
-	    do_skip(SKIPTO_ENDIF);
-	    break;
-	  }
-	  if(!strcmp("elif",buf) || !strcmp("elseif",buf))
-	  {
-	    SKIPUPTO('\n');
-	    do_skip(SKIPTO_ENDIF);
-	    break;
-	  }
-	  if(!strcmp("error",buf))
-	  {
-	    SKIPWHITE();
-	    READBUF(C!='\n');
-	    yyerror(buf);
-	    break;
-	  }
-	  goto badhash;
-
-	case 'u':
-	  if(!strcmp("undef",buf))
-	  {
-	    struct pike_string *s;
-	    SKIPWHITE();
-	    READBUF(isidchar(C));
-	    if((s=findstring(buf))) undefine(s);
-	    break;
-	  }
-	  goto badhash;
-
-	case 'd':
-	  if(!strcmp("define",buf))
-	  {
-	    do_define();
-	    break;
-	  }
-	  goto badhash;
-
-	case 'p':
-	  if(!strcmp("pragma",buf))
-	  {
-	    SKIPWHITE();
-	    READBUF(C!='\n');
-	    if (strcmp(buf, "all_inline") == 0)
-	    {
-	      pragma_all_inline = 1;
-	    }
-	    break;
-	  }
-
-	badhash:
-	  my_yyerror("Unknown directive #%s.",buf);
-	  SKIPUPTO('\n');
-	  continue;
-	  
-	}
-      }
       continue;
 
     case ' ':
     case '\t':
       continue;
 
-    case MY_EOF:
-      return 0;
-  
     case '\'':
-      c=GETC();
-      if(c=='\\') c=char_const();
-      if(GETC()!='\'')
+      switch(c=GETC())
+      {
+      case 0:
+	lex.pos--;
+	yyerror("Unexpected end of file\n");
+	break;
+
+	case '\\':
+	  c=char_const();
+      }
+      if(!GOBBLE('\''))
 	yyerror("Unterminated character constant.");
       yylval->number=c;
       return F_NUMBER;
 	
     case '"':
-      init_buf();
-      while(1)
-      {
-	c=GETC();
-
-	switch(c)
-	{
-	case MY_EOF:
-	  yyerror("End of file in string.");
-	  free(simple_free_buf());
-	  return 0;
-
-	case '\n':
-	  yyerror("Newline in string.");
-	  free(simple_free_buf());
-	  return 0;
-
-	case '\\':
-	  my_putchar(char_const());
-	  continue;
-	  
-	case '"':
-	  break;
-
-	default:
-	  my_putchar(c);
-	  continue;
-	}
-	break;
-      }
-      if(literal)
-      {
-	strncpy(buf,return_buf(),sizeof(buf));
-	buf[sizeof(buf)-1]=0;
-	yylval->str=buf;
-      }else{
-	yylval->string=free_buf();
-      }
+      yylval->string=readstring();
       return F_STRING;
   
     case ':':
@@ -1467,75 +502,32 @@ static int do_lex2(int literal, YYSTYPE *yylval)
       return c;
   
     case '0':
-      if(GOBBLE('x'))
+      if(GOBBLE('x') || GOBBLE('X'))
       {
-	READBUF(isxdigit(C));
-	yylval->number=STRTOL(buf,NULL,16);
+	yylval->number=STRTOL(lex.pos, &lex.pos, 16);
 	return F_NUMBER;
       }
   
     case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9':
     {
-      char *p, *p2;
-      int isfloat=0;
-      double d;
-
-      UNGETC(c);
-      READBUF(isdigit(C) || C=='.');
-
-      p=STRCHR(buf,'.');
-      
-      if(p)
-      {
-	if(p[1]=='.')
-	{
-	  UNGETSTR(p,strlen(p));
-	  *p=0;
-	  p=NULL;
-	}else if((p=STRCHR(p+1,'.')))
-	{
-	  UNGETSTR(p,strlen(p));
-	  *p=0;
-	}
-
-	if((p=STRCHR(buf,'.')))
-	{
-	  isfloat=1;
-	}
-      }
-
-      d=STRTOD(buf, NULL);
-
-      if(GOBBLE('e') || GOBBLE('E'))
+      char *p1, *p2;
+      double f;
+      long l;
+      lex.pos--;
+      f=my_strtod(lex.pos, &p1);
+      l=STRTOL(lex.pos, &p2, 0);
+
+      if(p1>p2)
       {
-	int neg;
-	if(GOBBLE('-'))
-	  neg=1;
-	else if(GOBBLE('+'))
-	  neg=0;
-	else
-	  neg=0;
-	
-	READBUF(isdigit(C));
-        if(neg)
-	  d /= pow(10.0,STRTOD(buf,NULL));
-        else
-	  d *= pow(10.0,STRTOD(buf,NULL));
-	isfloat=1;
-      }
-      if(isfloat)
-      {
-	yylval->fnum=(float)d;
+	lex.pos=p1;
+	yylval->fnum=(float)f;
 	return F_FLOAT;
+      }else{
+	lex.pos=p2;
+	yylval->number=l;
+	return F_NUMBER;
       }
-
-      if(buf[0]=='0')
-	yylval->number=STRTOL(buf,NULL,8);
-      else
-	yylval->number=STRTOL(buf,NULL,10);
-      return F_NUMBER;
-    }
   
     case '-':
       if(GOBBLE('=')) return F_SUB_EQ;
@@ -1571,23 +563,6 @@ static int do_lex2(int literal, YYSTYPE *yylval)
       return '%';
   
     case '/':
-      if(GOBBLE('*'))
-      {
-	do{
-	  SKIPTO('*');
-	  if(LOOK()==MY_EOF)
-	  {
-	    yyerror("Unexpected end of file while skipping comment.");
-	    return 0;
-	  }
-	} while(!GOBBLE('/'));
-	continue;
-      }else if(GOBBLE('/'))
-      {
-	SKIPUPTO('\n');
-	continue;
-      }
-       /* Fallthrough */
       if(GOBBLE('=')) return F_DIV_EQ;
       return '/';
   
@@ -1698,17 +673,12 @@ static int do_lex2(int literal, YYSTYPE *yylval)
 
       default:
 	yyerror("Illegal ` identifier.");
-	tmp="";
+	lex.pos--;
+	tmp="`";
 	break;
-
       }
 
-      if(literal)
-      {
-	yylval->str=buf;
-      }else{
-	yylval->string=make_shared_string(tmp);
-      }
+      yylval->string=make_shared_string(tmp);
       return F_IDENTIFIER;
     }
 
@@ -1717,38 +687,121 @@ static int do_lex2(int literal, YYSTYPE *yylval)
       if(isidchar(c))
       {
 	struct pike_string *s;
-	UNGETC(c);
+	lex.pos--;
 	READBUF(isidchar(C));
 
-	if(!literal)
-	{
-	  /* identify identifier, if it is not a shared string,
-	   * then it is neither a define, reserved word, local variable
-	   * or efun, at least not yet.
-	   */
+	yylval->number=lex.current_line;
 
-	  s=findstring(buf);
-	  if(s)
+	if(len>1 && len<10)
+	{
+	  switch(TWO_CHAR(buf[0],buf[1]))
 	  {
-	    int i;
-	    if(expand_define(s,0)) continue;
-
-	    i=lookup_resword(s);
-	    if(i >= 0)
-	    {
-	      yylval->number=current_line;
-	      return i;
-	    }
-
-	    reference_shared_string(s);
-	  }else{
-	    s=make_shared_string(buf);
+	  case TWO_CHAR('a','r'):
+	    if(ISWORD("array")) return F_ARRAY_ID;
+	  break;
+	  case TWO_CHAR('b','r'):
+	    if(ISWORD("break")) return F_BREAK;
+	  break;
+	  case TWO_CHAR('c','a'):
+	    if(ISWORD("case")) return F_CASE;
+	    if(ISWORD("catch")) return F_CATCH;
+	  break;
+	  case TWO_CHAR('c','l'):
+	    if(ISWORD("class")) return F_CLASS;
+	  break;
+	  case TWO_CHAR('c','o'):
+	    if(ISWORD("constant")) return F_CONSTANT;
+	    if(ISWORD("continue")) return F_CONTINUE;
+	  break;
+	  case TWO_CHAR('d','e'):
+	    if(ISWORD("default")) return F_DEFAULT;
+	  break;
+	  case TWO_CHAR('d','o'):
+	    if(ISWORD("do")) return F_DO;
+	  break;
+	  case TWO_CHAR('e','l'):
+	    if(ISWORD("else")) return F_ELSE;
+	  break;
+	  case TWO_CHAR('f','l'):
+	    if(ISWORD("float")) return F_FLOAT_ID;
+	  break;
+	  case TWO_CHAR('f','o'):
+	    if(ISWORD("for")) return F_FOR;
+	    if(ISWORD("foreach")) return F_FOREACH;
+	  break;
+	  case TWO_CHAR('f','u'):
+	    if(ISWORD("function")) return F_FUNCTION_ID;
+	  break;
+	  case TWO_CHAR('g','a'):
+	    if(ISWORD("gauge")) return F_GAUGE;
+	  break;
+	  case TWO_CHAR('i','f'):
+	    if(ISWORD("if")) return F_IF;
+	  break;
+	  case TWO_CHAR('i','m'):
+	    if(ISWORD("import")) return F_IMPORT;
+	  break;
+	  case TWO_CHAR('i','n'):
+	    if(ISWORD("int")) return F_INT_ID;
+	    if(ISWORD("inherit")) return F_INHERIT;
+	    if(ISWORD("inline")) return F_INLINE;
+	  break;
+	  case TWO_CHAR('l','a'):
+	    if(ISWORD("lambda")) return F_LAMBDA;
+	  break;
+	  case TWO_CHAR('m','a'):
+	    if(ISWORD("mapping")) return F_MAPPING_ID;
+	  break;
+	  case TWO_CHAR('m','i'):
+	    if(ISWORD("mixed")) return F_MIXED_ID;
+	  break;
+	  case TWO_CHAR('m','u'):
+	    if(ISWORD("multiset")) return F_MULTISET_ID;
+	  break;
+	  case TWO_CHAR('n','o'):
+	    if(ISWORD("nomask")) return F_NO_MASK;
+	  break;
+	  case TWO_CHAR('o','b'):
+	    if(ISWORD("object")) return F_OBJECT_ID;
+	  break;
+	  case TWO_CHAR('p','r'):
+	    if(ISWORD("predef")) return F_PREDEF;
+	    if(ISWORD("program")) return F_PROGRAM_ID;
+	    if(ISWORD("private")) return F_PRIVATE;
+	    if(ISWORD("protected")) return F_PROTECTED;
+	    break;
+	  break;
+	  case TWO_CHAR('p','u'):
+	    if(ISWORD("public")) return F_PUBLIC;
+	  break;
+	  case TWO_CHAR('r','e'):
+	    if(ISWORD("return")) return F_RETURN;
+	  break;
+	  case TWO_CHAR('s','s'):
+	    if(ISWORD("sscanf")) return F_SSCANF;
+	  break;
+	  case TWO_CHAR('s','t'):
+	    if(ISWORD("static")) return F_STATIC;
+	    if(ISWORD("string")) return F_STRING_ID;
+	  break;
+	  case TWO_CHAR('s','w'):
+	    if(ISWORD("switch")) return F_SWITCH;
+	  break;
+	  case TWO_CHAR('t','y'):
+	    if(ISWORD("typeof")) return F_TYPEOF;
+	  break;
+	  case TWO_CHAR('v','a'):
+	    if(ISWORD("varargs")) return F_VARARGS;
+	  break;
+	  case TWO_CHAR('v','o'):
+	    if(ISWORD("void")) return F_VOID_ID;
+	  break;
+	  case TWO_CHAR('w','h'):
+	    if(ISWORD("while")) return F_WHILE;
+	  break;
 	  }
-	  yylval->string=s;
-	  return F_IDENTIFIER;
 	}
-  
-	yylval->str=buf;
+	yylval->string=make_shared_binary_string(buf,len);
 	return F_IDENTIFIER;
       }else{
 	char buff[100];
@@ -1757,469 +810,7 @@ static int do_lex2(int literal, YYSTYPE *yylval)
 	return ' ';
       }
     }
-  }
-}
-
-int yylex(YYSTYPE *yylval)
-{
-#ifdef __CHECKER__
-  MEMSET((char *)yylval,0,sizeof(YYSTYPE));
-#endif
-  return do_lex(0, yylval);
-}
-
-static YYSTYPE my_yylval;
-static int lookahead;
-
-static void low_lex()
-{
-  while(1)
-  {
-    struct pike_string *s;
-
-    lookahead=do_lex(1, &my_yylval);
-    if(lookahead == F_IDENTIFIER)
-    {
-      if(!strcmp("defined",my_yylval.str))
-      {
-	SKIPWHITE();
-	if(!GOBBLE('('))
-	{
-	  yyerror("Missing '(' in defined.\n");
-	  return;
-	}
-	READBUF(isidchar(C));
-	if(!GOBBLE(')'))
-	{
-	  yyerror("Missing ')' in defined.\n");
-	  return;
-	}
-	s=findstring(buf);
-
-	if(s && find_define(s))
-	  UNGETSTR(" 1 ",3);
-	else
-	  UNGETSTR(" 0 ",3);
-
-	continue;
-      }
-
-      if(!strcmp("efun",my_yylval.str) || !strcmp("constant",my_yylval.str))
-      {
-	SKIPWHITE();
-	if(!GOBBLE('('))
-	{
-	  yyerror("Missing '(' in #if constant().\n");
-	  return;
-	}
-	READBUF(isidchar(C));
-	if(!GOBBLE(')'))
-	{
-	  yyerror("Missing ')' in #if constant().\n");
-	  return;
-	}
-	s=findstring(buf);
-
-	if(s && low_mapping_string_lookup(get_builtin_constants(), s))
-	  UNGETSTR(" 1 ",3);
-	else
-	  UNGETSTR(" 0 ",3);
-
-	continue;
-      }
-
-      s=findstring(my_yylval.str);
-      if(!s || !expand_define(s,1))
-	UNGETSTR(" 0 ",3);
-      continue;
-    }
-
-    break;
-  }
-}
-
-static void calcC()
-{
-  switch(lookahead)
-  {
-    case '(':
-      low_lex();
-      calc1();
-      if(lookahead != ')')
-	error("Missing ')'\n");
-      break;
-
-    case F_FLOAT:
-      push_float(my_yylval.fnum);
-      break;
-
-    case F_STRING:
-      push_string(make_shared_string(my_yylval.str));
-      break;
-
-    case F_NUMBER:
-      push_int(my_yylval.number);
-      break;
-
-    default:
-      yyerror("Syntax error in #if.");
-      return;
-  }
-
-  low_lex();
-
-  while(lookahead=='[')
-  {
-    low_lex();
-    calc1();
-    f_index(2);
-    if(lookahead!=']')
-      error("Missing ']'\n");
-    else
-      low_lex();
-  }
-}
-
-static void calcB()
-{
-  switch(lookahead)
-  {
-    case '-': low_lex(); calcB(); o_negate(); break;
-    case F_NOT: low_lex(); calcB(); o_not(); break;
-    case '~': low_lex(); calcB(); o_compl(); break;
-    default: calcC();
-  }
-}
-
-static void calcA()
-{
-  calcB();
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case '/': low_lex(); calcB(); o_divide(); continue;
-      case '*': low_lex(); calcB(); o_multiply(); continue;
-      case '%': low_lex(); calcB(); o_mod(); continue;
-    }
-    break;
-  }
-}
-
-static void calc9()
-{
-  calcA();
-
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case '+': low_lex(); calcA(); f_add(2); continue;
-      case '-': low_lex(); calcA(); o_subtract(); continue;
     }
-    break;
   }
 }
 
-static void calc8()
-{
-  calc9();
-
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case F_LSH: low_lex(); calc9(); o_lsh(); continue;
-      case F_RSH: low_lex(); calc9(); o_rsh(); continue;
-    }
-    break;
-  }
-}
-
-static void calc7b()
-{
-  calc8();
-
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case '<': low_lex(); calc8(); f_lt(2); continue;
-      case '>': low_lex(); calc8(); f_gt(2); continue;
-      case F_GE: low_lex(); calc8(); f_ge(2); continue;
-      case F_LE: low_lex(); calc8(); f_le(2); continue;
-    }
-    break;
-  }
-}
-
-static void calc7()
-{
-  calc7b();
-
-  while(1)
-  {
-    switch(lookahead)
-    {
-      case F_EQ: low_lex(); calc7b(); f_eq(2); continue;
-      case F_NE: low_lex(); calc7b(); f_ne(2); continue;
-    }
-    break;
-  }
-}
-
-static void calc6()
-{
-  calc7();
-
-  while(lookahead=='&')
-  {
-    low_lex();
-    calc7();
-    o_and();
-  }
-}
-
-static void calc5()
-{
-  calc6();
-
-  while(lookahead=='^')
-  {
-    low_lex();
-    calc6();
-    o_xor();
-  }
-}
-
-static void calc4()
-{
-  calc5();
-
-  while(lookahead=='|')
-  {
-    low_lex();
-    calc5();
-    o_or();
-  }
-}
-
-static void calc3()
-{
-  calc4();
-
-  while(lookahead==F_LAND)
-  {
-    low_lex();
-    check_destructed(sp-1);
-    if(IS_ZERO(sp-1))
-    {
-      calc4();
-      pop_stack();
-    }else{
-      pop_stack();
-      calc4();
-    }
-  }
-}
-
-static void calc2()
-{
-  calc3();
-
-  while(lookahead==F_LOR)
-  {
-    low_lex();
-    check_destructed(sp-1);
-    if(!IS_ZERO(sp-1))
-    {
-      calc3();
-      pop_stack();
-    }else{
-      pop_stack();
-      calc3();
-    }
-  }
-}
-
-static void calc1()
-{
-  calc2();
-
-  if(lookahead=='?')
-  {
-    low_lex();
-    calc1();
-    if(lookahead!=':')
-      error("Colon expected.\n");
-    low_lex();
-    calc1();
-
-    check_destructed(sp-3);
-    assign_svalue(sp-3,IS_ZERO(sp-3)?sp-1:sp-2);
-    pop_n_elems(2);
-  }
-
-}
-
-static int calc()
-{
-  JMP_BUF recovery;
-  int ret;
-
-  ret=0;
-  if (SETJMP(recovery))
-  {
-    if(throw_value.type == T_ARRAY && throw_value.u.array->size)
-    {
-      union anything *a;
-      a=low_array_get_item_ptr(throw_value.u.array, 0, T_STRING);
-      if(a)
-      {
-	yyerror(a->string->str);
-      }else{
-	yyerror("Nonstandard error format.\n");
-      }
-    }else{
-      yyerror("Nonstandard error format.\n");
-    }
-    ret=-1;
-  }else{
-    low_lex();
-    calc1();
-    if(lookahead!='\n')
-    {
-      SKIPUPTO('\n');
-      yyerror("Extra characters after #if expression.");
-    }else{
-      UNGETC('\n');
-    }
-    check_destructed(sp-1);
-    ret=!IS_ZERO(sp-1);
-    pop_stack();
-  }
-  UNSETJMP(recovery);
-
-  return ret;
-}
-
-/*** Magic defines ***/
-void insert_current_line()
-{
-  char buf[20];
-  sprintf(buf," %ld ",(long)current_line);
-  UNGETSTR(buf,strlen(buf));
-}
-
-void insert_current_file_as_string()
-{
-  UNGETSTR("\"",1);
-  UNGETSTR(current_file->str, current_file->len);
-  UNGETSTR("\"",1);
-}
-
-void insert_current_time_as_string()
-{
-  time_t tmp;
-  char *buf;
-  time(&tmp);
-  buf=ctime(&tmp);
-
-  UNGETSTR("\"",1);
-  UNGETSTR(buf+11, 8);
-  UNGETSTR("\"",1);
-}
-
-void insert_current_date_as_string()
-{
-  time_t tmp;
-  char *buf;
-  time(&tmp);
-  buf=ctime(&tmp);
-
-  UNGETSTR("\"",1);
-  UNGETSTR(buf+19, 5);
-  UNGETSTR(buf+4, 6);
-  UNGETSTR("\"",1);
-}
-
-/*** ***/
-
-static void start_new()
-{
-  struct pike_predef_s *tmpf;
-
-  free_all_defines();
-
-  simple_add_define("__PIKE__", "1",0);
-  
-  for (tmpf=pike_predefs; tmpf; tmpf=tmpf->next)
-    simple_add_define(tmpf->name, tmpf->value,0);
-
-  simple_add_define("__LINE__",0,insert_current_line);
-  simple_add_define("__FILE__",0,insert_current_file_as_string);
-  simple_add_define("__DATE__",0,insert_current_date_as_string);
-  simple_add_define("__TIME__",0,insert_current_time_as_string);
-
-  free_inputstate(istate);
-  istate=NULL;
-  link_inputstate(end_inputstate());
-  old_line=current_line = 1;
-  pragma_all_inline=0;
-  nexpands=0;
-  if(current_file) free_string(current_file);
-  current_file=0;
-}
-
-void start_new_file(int fd,struct pike_string *filename)
-{
-  start_new();
-  copy_shared_string(current_file,filename);
-  
-  link_inputstate(file_inputstate(fd));
-  UNGETSTR("\n",1);
-}
-
-void start_new_string(char *s,INT32 len,struct pike_string *name)
-{
-  start_new();
-  copy_shared_string(current_file,name);
-  link_inputstate(prot_memory_inputstate(s,len));
-  UNGETSTR("\n",1);
-}
-
-void end_new_file()
-{
-  if(current_file)
-  {
-    free_string(current_file);
-    current_file=0;
-  }
-
-  free_inputstate(istate);
-  istate=NULL;
-  free_all_defines();
-  total_lines+=current_line-old_line;
-}
-
-
-void add_predefine(char *s)
-{
-  char buffer1[100],buffer2[10000];
-  struct pike_predef_s *tmp;
-
-  if(sscanf(s,"%[^=]=%[ -~=]",buffer1,buffer2) ==2)
-  {
-    s=buffer1;
-  }else{
-    buffer2[0]='1';
-    buffer2[1]=0;
-  }
-  tmp=ALLOC_STRUCT(pike_predef_s);
-  tmp->name=(char *)xalloc(strlen(s)+1);
-  strcpy(tmp->name,s);
-  tmp->value=(char *)xalloc(strlen(buffer2)+1);
-  strcpy(tmp->value,buffer2);
-  tmp->next=pike_predefs;
-  pike_predefs=tmp;
-}
diff --git a/src/lex.h b/src/lex.h
index e5d0f5ba7649e8436dce6e286e7e02d75ee85454..bf9424d3062d4a46d1de70529832d8c32a2ec84c 100644
--- a/src/lex.h
+++ b/src/lex.h
@@ -54,38 +54,27 @@ struct inputstate;
 struct hash_table;
 #endif
 
-extern struct instr instrs[];
-extern struct hash_table *defines;
-extern struct pike_string *current_file;
-extern INT32 current_line;
-extern INT32 old_line;
-extern INT32 total_lines;
-extern INT32 nexpands;
-extern int pragma_all_inline;          /* inline all possible inlines */
-extern struct inputstate *istate;
+#define PRAGMA_ALL_INLINE 1
+
+struct lex
+{
+  char *pos;
+  char *end;
+  INT32 current_line;
+  INT32 pragmas;
+  struct pike_string *current_file;
+};
 
-extern struct pike_predef_s * pike_predefs;
+extern struct lex lex;
+extern struct instr instrs[];
 
 /* Prototypes begin here */
-struct pike_predef_s;
-void exit_lex();
+void exit_lex(void);
 struct reserved;
 void init_lex();
-void free_reswords();
 char *low_get_f_name(int n,struct program *p);
 char *get_f_name(int n);
 char *get_token_name(int n);
-struct inputstate;
-struct define;
-void free_one_define(struct hash_entry *h);
-void insert_current_line();
-void insert_current_file_as_string();
-void insert_current_time_as_string();
-void insert_current_date_as_string();
-void start_new_file(int fd,struct pike_string *filename);
-void start_new_string(char *s,INT32 len,struct pike_string *name);
-void end_new_file();
-void add_predefine(char *s);
 /* Prototypes end here */
 
 #endif
diff --git a/src/main.c b/src/main.c
index c780f60a94ede77cd1c75b2b7472fc38781d4a77..15b253193a4029969bdc9478e93f47aa061c7100 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: main.c,v 1.21 1997/04/16 03:09:13 hubbe Exp $");
+RCSID("$Id: main.c,v 1.21.2.1 1997/06/25 22:46:40 hubbe Exp $");
 #include "types.h"
 #include "backend.h"
 #include "module.h"
@@ -259,7 +259,10 @@ void main(int argc, char **argv, char **env)
 
 void init_main(void)
 {
+  void init_cpp(void);
+
   th_init();
+  init_cpp();
   init_builtin_efuns();
   init_signals();
   init_dynamic_load();
diff --git a/src/modules/files/file.c b/src/modules/files/file.c
index 9ae0b999862deb9e89b540dd4a134fd4ecaa1b9a..6d763cc3428919a945057c16829f15215befb2a6 100644
--- a/src/modules/files/file.c
+++ b/src/modules/files/file.c
@@ -6,7 +6,7 @@
 #define READ_BUFFER 8192
 
 #include "global.h"
-RCSID("$Id: file.c,v 1.37.2.2 1997/05/19 09:07:32 hubbe Exp $");
+RCSID("$Id: file.c,v 1.37.2.3 1997/06/25 22:47:56 hubbe Exp $");
 #include "types.h"
 #include "interpret.h"
 #include "svalue.h"
@@ -785,6 +785,7 @@ static void file_set_nonblocking(INT32 args)
   case 3: file_set_close_callback(1);
   case 2: file_set_write_callback(1);
   case 1: file_set_read_callback(1);
+  case 0: break;
   }
   set_nonblocking(FD,1);
   THIS->open_mode |= FILE_NONBLOCKING;
@@ -1497,7 +1498,7 @@ void pike_module_init()
   add_function("open_socket",file_open_socket,"function(int|void,string|void:int)",0);
   add_function("connect",file_connect,"function(string,int:int)",0);
   add_function("query_address",file_query_address,"function(int|void:string)",0);
-  add_function("create",file_create,"function(void|string:void)",0);
+  add_function("create",file_create,"function(void|string,void|string:void)",0);
   add_function("`<<",file_lsh,"function(mixed:object)",0);
 
   set_init_callback(init_file_struct);
diff --git a/src/object.c b/src/object.c
index af163ae754418492a33e788880e356dcb2b1b0d7..5b9aa08600e7434a577e7d8e7977011f51246301 100644
--- a/src/object.c
+++ b/src/object.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: object.c,v 1.17.2.1 1997/05/10 12:56:56 hubbe Exp $");
+RCSID("$Id: object.c,v 1.17.2.2 1997/06/25 22:46:41 hubbe Exp $");
 #include "object.h"
 #include "dynamic_buffer.h"
 #include "interpret.h"
@@ -28,22 +28,27 @@ struct object fake_object = { 1 }; /* start with one reference */
 
 void setup_fake_object()
 {
-  fake_object.prog=&fake_program;
+  fake_object.prog=new_program;
   fake_object.next=0;
   fake_object.refs=0xffffff;
 }
 
-struct object *low_clone(struct program *p)
+struct object *low_clone(struct program *p,
+			 struct object *parent)
 {
   int e;
   struct object *o;
   struct frame frame;
 
+  if(!(p->flags & PROGRAM_FINISHED))
+    error("Attempting to clone an unfinished program\n");
+
   GC_ALLOC();
 
   o=(struct object *)xalloc(sizeof(struct object)-1+p->storage_needed);
 
   o->prog=p;
+  if((o->parent=parent)) parent->refs++;
   p->refs++;
   o->next=first_object;
   o->prev=0;
@@ -113,7 +118,16 @@ static void init_object(struct object *o, int args)
 
 struct object *clone_object(struct program *p, int args)
 {
-  struct object *o=low_clone(p);
+  struct object *o=low_clone(p,0);
+  init_object(o,args);
+  return o;
+}
+
+struct object *parent_clone_object(struct program *p,
+				   struct object *parent,
+				   int args)
+{
+  struct object *o=low_clone(p,parent);
   init_object(o,args);
   return o;
 }
@@ -139,17 +153,33 @@ struct object *get_master()
 
   if(!master_program)
   {
-    master_name=make_shared_string(master_file);
-    master_program=compile_file(master_name);
-    free_string(master_name);
-    if(!master_program) return 0;
+    INT32 len;
+    struct pike_string *s;
+
+
+    FILE *f=fopen(master_file,"r");
+    fseek(f,0,SEEK_END);
+    len=ftell(f);
+    fseek(f,0,SEEK_SET);
+    s=begin_shared_string(len);
+    fread(s->str,1,len,f);
+    fclose(f);
+    push_string(end_shared_string(s));
+    push_text(master_file);
+    f_cpp(2);
+    f_compile(1);
+
+    if(sp[-1].type != T_PROGRAM)
+    {
+      pop_stack();
+      return 0;
+    }
+    master_program=sp[-1].u.program;
+    sp--;
   }
-  master_object=clone_object(master_program,0);
+  master_object=low_clone(master_program,0);
 
-  apply_lfun(master_object,LFUN___INIT,0);
-  pop_stack();
-  apply_lfun(master_object,LFUN_CREATE,0);
-  pop_stack();
+  init_object(master_object,0);
   
   inside = 0;
   return master_object;
@@ -177,6 +207,12 @@ void destruct(struct object *o)
 
   o->refs++;
 
+  if(o->parent)
+  {
+    free_object(o->parent);
+    o->parent=0;
+  }
+
   if(o->prog->lfuns[LFUN_DESTROY] != -1)
   {
     safe_apply_low(o, o->prog->lfuns[LFUN_DESTROY], 0);
@@ -338,8 +374,16 @@ void low_object_index_no_free(struct svalue *to,
     {
       struct svalue *s;
       s=PROG_FROM_INT(p,f)->constants + i->func.offset;
-      check_destructed(s);
-      assign_svalue_no_free(to, s);
+      if(s->type==T_PROGRAM)
+      {
+	to->type=T_FUNCTION;
+	to->subtype=f;
+	to->u.object=o;
+	o->refs++;
+      }else{
+	check_destructed(s);
+	assign_svalue_no_free(to, s);
+      }
       break;
     }
 
@@ -715,8 +759,8 @@ struct array *object_indices(struct object *o)
 
   if(p->lfuns[LFUN__INDICES]==-1)
   {
-    a=allocate_array_no_init(p->num_identifier_indexes,0);
-    for(e=0;e<(int)p->num_identifier_indexes;e++)
+    a=allocate_array_no_init(p->num_identifier_index,0);
+    for(e=0;e<(int)p->num_identifier_index;e++)
     {
       copy_shared_string(ITEM(a)[e].u.string,
 			 ID_FROM_INT(p,p->identifier_index[e])->name);
@@ -744,8 +788,8 @@ struct array *object_values(struct object *o)
 
   if(p->lfuns[LFUN__INDICES]==-1)
   {
-    a=allocate_array_no_init(p->num_identifier_indexes,0);
-    for(e=0;e<(int)p->num_identifier_indexes;e++)
+    a=allocate_array_no_init(p->num_identifier_index,0);
+    for(e=0;e<(int)p->num_identifier_index;e++)
     {
       low_object_index_no_free(ITEM(a)+e, o, p->identifier_index[e]);
     }
@@ -770,7 +814,7 @@ void gc_mark_object_as_referenced(struct object *o)
     {
       INT32 e;
       
-      for(e=0;e<(int)o->prog->num_identifier_indexes;e++)
+      for(e=0;e<(int)o->prog->num_identifier_index;e++)
       {
 	struct identifier *i;
 	
@@ -799,7 +843,7 @@ void gc_check_all_objects()
     {
       INT32 e;
 
-      for(e=0;e<(int)o->prog->num_identifier_indexes;e++)
+      for(e=0;e<(int)o->prog->num_identifier_index;e++)
       {
 	struct identifier *i;
 	
diff --git a/src/object.h b/src/object.h
index 5ac6bae0121bd5e9d1ae9b5b0e1625b04ef45cb6..4d39c455fd32e47ad87613068ea1ab59d9139923 100644
--- a/src/object.h
+++ b/src/object.h
@@ -18,6 +18,7 @@ struct object
 {
   INT32 refs;                    /* Reference count, must be first. */
   struct program *prog;
+  struct object *parent;
   struct object *next;
   struct object *prev;
   char storage[1];
@@ -38,8 +39,12 @@ extern struct program *master_program;
 
 /* Prototypes begin here */
 void setup_fake_object();
-struct object *low_clone(struct program *p);
+struct object *low_clone(struct program *p,
+			 struct object *parent);
 struct object *clone_object(struct program *p, int args);
+struct object *parent_clone_object(struct program *p,
+				   struct object *parent,
+				   int args);
 struct object *get_master();
 struct object *master();
 void destruct(struct object *o);
diff --git a/src/peep.c b/src/peep.c
index 49e19ea939253f05c3a322ae526ffa8d75af270b..b8f2643265e6ae36a2e07b216290397bb86e8810 100644
--- a/src/peep.c
+++ b/src/peep.c
@@ -109,7 +109,7 @@ void ins_f_byte(unsigned int b)
   if(b>255)
     error("Instruction too big %d\n",b);
 #endif
-  ins_byte((unsigned char)b,A_PROGRAM);
+  add_to_program((unsigned char)b);
 }
 
 static void ins_f_byte_with_arg(unsigned int a,unsigned INT32 b)
@@ -125,20 +125,20 @@ static void ins_f_byte_with_arg(unsigned int a,unsigned INT32 b)
     if( b < 256*256)
     {
       ins_f_byte(F_PREFIX_CHARX256);
-      ins_byte(b>>8, A_PROGRAM);
+      add_to_program(b>>8);
     }else if(b < 256*256*256) {
       ins_f_byte(F_PREFIX_WORDX256);
-      ins_byte(b >> 16, A_PROGRAM);
-      ins_byte(b >> 8, A_PROGRAM);
+      add_to_program(b >> 16);
+      add_to_program(b >> 8);
     }else{
       ins_f_byte(F_PREFIX_24BITX256);
-      ins_byte(b >> 24, A_PROGRAM);
-      ins_byte(b >> 16, A_PROGRAM);
-      ins_byte(b >> 8, A_PROGRAM);
+      add_to_program(b >> 24);
+      add_to_program(b >> 16);
+      add_to_program(b >> 8);
     }
   }
   ins_f_byte(a);
-  ins_byte(b, A_PROGRAM);
+  add_to_program(b);
 }
 
 void assemble(void)
@@ -244,11 +244,11 @@ void assemble(void)
     {
     case F_NOP: break;
     case F_ALIGN:
-      while(PC % c->arg) ins_byte(0, A_PROGRAM);
+      while(PC % c->arg) add_to_program(0);
       break;
 
     case F_BYTE:
-      ins_byte(c->arg, A_PROGRAM);
+      add_to_program(c->arg);
       break;
 
     case F_LABEL:
@@ -272,7 +272,7 @@ void assemble(void)
 	if(c->arg > max_label || c->arg < 0) fatal("Jump to unknown label?\n");
 #endif
 	tmp=PC;
-	ins_int(jumps[c->arg],A_PROGRAM);
+	ins_int(jumps[c->arg],(void(*)(char))add_to_program);
 	jumps[c->arg]=tmp;
 	break;
 
@@ -348,7 +348,7 @@ int insopt(int f, INT32 b, int cl, struct pike_string *cf)
 
   p->opcode=f;
   p->line=cl;
-  copy_shared_string(p->file, current_file);
+  copy_shared_string(p->file, lex.current_file);
   p->arg=b;
 
   return p - (p_instr *)instrbuf.s.str;
diff --git a/src/pike_types.c b/src/pike_types.c
index 92c102e6bffc616153fcf80684721db1c6d8018b..cfba782560a21964803481e946d99a3865aa45a4 100644
--- a/src/pike_types.c
+++ b/src/pike_types.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: pike_types.c,v 1.21 1997/04/16 03:09:15 hubbe Exp $");
+RCSID("$Id: pike_types.c,v 1.21.2.1 1997/06/25 22:46:42 hubbe Exp $");
 #include <ctype.h>
 #include "svalue.h"
 #include "pike_types.h"
@@ -1164,7 +1164,7 @@ struct pike_string *get_type_of_svalue(struct svalue *s)
   case T_PROGRAM:
   {
     char *a;
-    int id=s->u.program->lfuns[LFUN_CREATE];
+    int id=FIND_LFUN(s->u.program,LFUN_CREATE);
     if(id>=0)
     {
       a=ID_FROM_INT(s->u.program, id)->type->str;
diff --git a/src/program.c b/src/program.c
index edb83e8c18e2427bcfa678ce7ae04069ff93afd2..a23b69b9222db6fa229e8ca1f6eeff7084dda4ef 100644
--- a/src/program.c
+++ b/src/program.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: program.c,v 1.33.2.1 1997/05/10 12:56:56 hubbe Exp $");
+RCSID("$Id: program.c,v 1.33.2.2 1997/06/25 22:46:43 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -39,19 +39,11 @@ RCSID("$Id: program.c,v 1.33.2.1 1997/05/10 12:56:56 hubbe Exp $");
 #define FIND_FUNCTION_HASHSIZE 4711
 
 
-#define FILE_STATE
-#define PROGRAM_STATE
-
 #define STRUCT
 #include "compilation.h"
-#undef STRUCT
 
 #define DECLARE
 #include "compilation.h"
-#undef DECLARE
-
-#undef FILE_STATE
-#undef PROGRAM_STATE
 
 
 char *lfun_names[] = {
@@ -86,17 +78,61 @@ char *lfun_names[] = {
 };
 
 struct program *first_program = 0;
+static int current_program_id=0;
 
-struct program fake_program;
+struct program *new_program=0;
+struct program *malloc_size_program=0;
 
-static int current_program_id=0;
+int compiler_pass;
+int compilation_depth;
+struct compiler_frame *compiler_frame=0;
 static INT32 last_line = 0;
 static INT32 last_pc = 0;
 static struct pike_string *last_file = 0;
-dynamic_buffer inherit_names;
 dynamic_buffer used_modules;
 
-void free_all_local_names(void);
+/* So what if we don't have templates? / Hubbe */
+
+#ifdef DEBUG
+#define CHECK_FOO(NUMTYPE,TYPE,NAME)				\
+  if(malloc_size_program->num_##NAME < new_program->num_##NAME)	\
+    fatal("new_program->num_" #NAME " is out of order\n");	\
+  if(new_program->flags & PROGRAM_OPTIMIZED)			\
+    fatal("Tried to reallocate fixed program.\n")
+
+#else
+#define CHECK_FOO(NUMTYPE,TYPE,NAME)
+#endif
+
+#define FOO(NUMTYPE,TYPE,NAME)						\
+void add_to_##NAME(TYPE ARG) {						\
+  CHECK_FOO(NUMTYPE,TYPE,NAME);						\
+  if(malloc_size_program->num_##NAME == new_program->num_##NAME) {	\
+    void *tmp;								\
+    malloc_size_program->num_##NAME *= 2;				\
+    malloc_size_program->num_##NAME++;					\
+    tmp=realloc((char *)new_program->NAME,				\
+                sizeof(TYPE) *						\
+		malloc_size_program->num_##NAME);			\
+    if(!tmp) fatal("Out of memory.\n");					\
+    new_program->NAME=tmp;						\
+  }									\
+  new_program->NAME[new_program->num_##NAME++]=(ARG);                   \
+}
+
+#include "program_areas.h"
+
+void ins_int(INT32 i, void (*func)(char tmp))
+{
+  int e;
+  for(e=0;e<(long)sizeof(i);e++) func(EXTRACT_UCHAR(((char *)&i)+e));
+}
+
+void ins_short(INT16 i, void (*func)(char tmp))
+{
+  int e;
+  for(e=0;e<(long)sizeof(i);e++) func(EXTRACT_UCHAR(((char *)&i)+e));
+}
 
 void use_module(struct svalue *s)
 {
@@ -150,22 +186,18 @@ int find_module_identifier(struct pike_string *ident)
   UNSETJMP(tmp);
 
   {
-    struct program_state *p;
-    for(p=previous_program_state;p;p=p->previous)
+    struct program_state *p=previous_program_state;
+    int n;
+    for(n=0;n<compilation_depth;n++,p=p->previous)
     {
-      INT32 i;
-      if(previous_file_state &&
-	 previous_file_state->previous_program_state==p->previous)
-	break;
-
-      i=low_find_shared_string_identifier(ident, &p->fake_program);
+      int i=low_find_shared_string_identifier(ident, p->new_program);
       if(i!=-1)
       {
 	struct identifier *id;
-	id=ID_FROM_INT(&p->fake_program, i);
+	id=ID_FROM_INT(p->new_program, i);
 	if(IDENTIFIER_IS_CONSTANT(id->flags))
 	{
-	  push_svalue(PROG_FROM_INT(&p->fake_program, i)->constants+
+	  push_svalue(PROG_FROM_INT(p->new_program, i)->constants+
 		      id->func.offset);
 	  return 1;
 	}else{
@@ -179,89 +211,204 @@ int find_module_identifier(struct pike_string *ident)
   return 0;
 }
 
-/* This should be optimized */
+#define ID_TO_PROGRAM_CACHE_SIZE 512
+struct program *id_to_program_cache[ID_TO_PROGRAM_CACHE_SIZE];
+
 struct program *id_to_program(INT32 id)
 {
   struct program *p;
+  INT32 h;
+  if(!id) return 0;
+  h=id & (ID_TO_PROGRAM_CACHE_SIZE-1);
+
+  if((p=id_to_program_cache[h]))
+    if(p->id==id) return p;
+  
   if(id) 
-    for(p=first_program;p;p=p->next)
-      if(id==p->id)
-	return p;
+    {
+      for(p=first_program;p;p=p->next)
+	{
+	  if(id==p->id)
+	    {
+	      if(id_to_program_cache[h])
+		free_program(id_to_program_cache[h]);
+	      
+	      id_to_program_cache[h]=p;
+	      p->refs++;
+	      return p;
+	    }
+	}
+    }
   return 0;
 }
 
-#define SETUP(X,Y,TYPE,AREA) \
-   fake_program.X=(TYPE *)areas[AREA].s.str; \
-   fake_program.Y=areas[AREA].s.len/sizeof(TYPE)
+/* Here starts routines which are used to build new programs */
 
-/*
- * This routine sets up the struct fake_program to work almost like a
- * normal program, but all pointers points to the program we are currently
- * compiling
+/* Re-allocate all the memory in the program in one chunk. because:
+ * 1) The individual blocks are munch bigger than they need to be
+ * 2) cuts down on malloc overhead (maybe)
+ * 3) localizes memory access (decreases paging)
  */
-void setup_fake_program()
-{
-  fake_program.refs=0xffffff;
-  SETUP(program, program_size, unsigned char, A_PROGRAM);
-  SETUP(strings, num_strings, struct pike_string *, A_STRINGS);
-  SETUP(inherits, num_inherits, struct inherit, A_INHERITS);
-  SETUP(identifiers, num_identifiers, struct identifier, A_IDENTIFIERS);
-  SETUP(identifier_references, num_identifier_references, struct reference, A_IDENTIFIER_REFERENCES);
-  SETUP(constants, num_constants, struct svalue, A_CONSTANTS);
-  SETUP(linenumbers, num_linenumbers, char, A_LINENUMBERS);
-
-  fake_program.inherits[0].prog=&fake_program;
-  fake_program.next=0;
-  fake_program.prev=0;
-/*
-  fake_program.lfuns=0;
-  fake_prog.num_lfuns=0;
-*/
-  fake_object.prog=&fake_program;
+void optimize_program(struct program *p)
+{
+  SIZE_T size=0;
+  char *data;
+
+  /* Already done (shouldn't happen, but who knows?) */
+  if(p->flags & PROGRAM_OPTIMIZED) return;
+
+#define FOO(NUMTYPE,TYPE,NAME) \
+  size+=MY_ALIGN(p->num_##NAME*sizeof(p->NAME[0]));
+#include "program_areas.h"
+
+  data=malloc(size);
+  if(!data) return; /* We are out of memory, but we don't care! */
+
+  size=0;
+
+#define FOO(NUMTYPE,TYPE,NAME) \
+  MEMCPY(data+size,p->NAME,p->num_##NAME*sizeof(p->NAME[0])); \
+  free((char *)p->NAME); \
+  p->NAME=(TYPE *)(data+size); \
+  size+=MY_ALIGN(p->num_##NAME*sizeof(p->NAME[0]));
+#include "program_areas.h"
+
+  p->total_size=size + sizeof(struct program);
+
+  p->flags |= PROGRAM_OPTIMIZED;
 }
 
-/* Here starts routines which are used to build new programs */
+/* internal function to make the index-table */
+static int funcmp(const void *a,const void *b)
+{
+  return
+    my_order_strcmp(ID_FROM_INT(new_program, *(unsigned short *)a)->name,
+		    ID_FROM_INT(new_program, *(unsigned short *)b)->name);
+}
+
+void fixate_program(void)
+{
+  INT32 i,e,t;
+  if(new_program->flags & PROGRAM_FIXED) return;
+#ifdef DEBUG
+  if(new_program->flags & PROGRAM_OPTIMIZED)
+    fatal("Cannot fixate optimized program\n");
+#endif
+
+  /* Ok, sort for binsearch */
+  for(e=i=0;i<(int)new_program->num_identifier_references;i++)
+  {
+    struct reference *funp;
+    struct identifier *fun;
+    funp=new_program->identifier_references+i;
+    if(funp->flags & (ID_HIDDEN|ID_STATIC)) continue;
+    if(funp->flags & ID_INHERITED)
+    {
+      if(funp->flags & ID_PRIVATE) continue;
+      fun=ID_FROM_PTR(new_program, funp);
+/*	  if(fun->func.offset == -1) continue; * prototype */
+      
+      /* check for multiple definitions */
+      for(t=0;t>=0 && t<(int)new_program->num_identifier_references;t++)
+      {
+	struct reference *funpb;
+	struct identifier *funb;
+	
+	if(t==i) continue;
+	funpb=new_program->identifier_references+t;
+	if(funpb->flags & (ID_HIDDEN|ID_STATIC)) continue;
+	if((funpb->flags & ID_INHERITED) && t<i) continue;
+	funb=ID_FROM_PTR(new_program,funpb);
+	/* if(funb->func.offset == -1) continue; * prototype */
+	if(fun->name==funb->name) t=-10;
+      }
+      if(t<0) continue;
+    }
+    add_to_identifier_index(i);
+  }
+  fsort((void *)new_program->identifier_index,
+	new_program->num_identifier_index,
+	sizeof(unsigned short),(fsortfun)funcmp);
+  
+  
+  for(i=0;i<NUM_LFUNS;i++)
+    new_program->lfuns[i]=find_identifier(lfun_names[i],new_program);
+  
+  new_program->flags |= PROGRAM_FIXED;
+}
 
 /*
  * Start building a new program
  */
-void start_new_program()
+void low_start_new_program(struct program *p,
+			   struct pike_string *name,
+			   int flags)
 {
   int e;
 
   threads_disabled++;
-  if(local_variables)
-    setup_fake_program();
-#define PROGRAM_STATE
+  compilation_depth++;
+
+  if(!p)
+  {
+    p=ALLOC_STRUCT(program);
+    MEMSET(p, 0, sizeof(struct program));
+    
+    p->refs=1;
+    p->id=++current_program_id;
+    
+    if((p->next=first_program)) first_program->prev=p;
+    first_program=p;
+  }else{
+    p->refs++;
+  }
+
+  if(name)
+  {
+    struct svalue s;
+    s.type=T_PROGRAM;
+    s.u.program=p;
+    add_constant(name, &s, flags);
+  }
+
 #define PUSH
 #include "compilation.h"
-#undef PUSH
-#undef PROGRAM_STATE
-
-  if(previous_program_state->fake_program.num_inherits)
-    previous_program_state->fake_program.inherits[0].prog=
-      &previous_program_state->fake_program;
 
   init_type_stack();
 
-  for(e=0; e<NUM_AREAS; e++) low_reinit_buf(areas + e);
-  low_reinit_buf(& inherit_names);
   low_reinit_buf(& used_modules);
-  fake_program.id = ++current_program_id;
 
+  if(p && (p->flags & PROGRAM_FINISHED))
   {
-    struct inherit inherit;
-    struct pike_string *name;
-    
-    inherit.prog=&fake_program;
-    inherit.inherit_level=0;
-    inherit.identifier_level=0;
-    inherit.storage_offset=0;
-    add_to_mem_block(A_INHERITS,(char *)&inherit,sizeof inherit);
-    name=make_shared_string("this");
-    low_my_binary_strcat((char *)&name,sizeof(name), &inherit_names);
+    yyerror("Pass2: Program already done");
+    p=0;
+  }
+
+  malloc_size_program = ALLOC_STRUCT(program);
+  new_program=p;
+
+  if(new_program->program)
+  {
+#define FOO(NUMTYPE,TYPE,NAME) \
+    malloc_size_program->num_##NAME=new_program->num_##NAME;
+#include "program_areas.h"
+  }else{
+    static struct pike_string *s;
+    struct inherit i;
+
+#define START_SIZE 64
+#define FOO(NUMTYPE,TYPE,NAME) \
+    malloc_size_program->num_##NAME=START_SIZE; \
+    new_program->NAME=(TYPE *)xalloc(sizeof(TYPE) * START_SIZE);
+#include "program_areas.h"
+
+    i.prog=new_program;
+    i.identifier_level=0;
+    i.storage_offset=0;
+    i.inherit_level=0;
+    i.name=0;
+    add_to_inherits(i);
   }
- 
 
   {
     struct svalue tmp;
@@ -273,18 +420,25 @@ void start_new_program()
     use_module(& tmp);
   }
 
+  init_node=0;
   num_parse_error=0;
-  local_variables=ALLOC_STRUCT(locals);
-  local_variables->next=0;
-  local_variables->current_number_of_locals=0;
-  local_variables->max_number_of_locals=0;
-  local_variables->current_type=0;
-  local_variables->current_return_type=0;
+
+  push_compiler_frame();
 }
 
-static void low_free_program(struct program *p)
+void start_new_program(void)
+{
+  low_start_new_program(0,0,0);
+}
+
+
+void really_free_program(struct program *p)
 {
   unsigned INT16 e;
+
+  if(id_to_program_cache[p->id & (ID_TO_PROGRAM_CACHE_SIZE-1)]==p)
+    id_to_program_cache[p->id & (ID_TO_PROGRAM_CACHE_SIZE-1)]=0;
+
   for(e=0; e<p->num_strings; e++)
     free_string(p->strings[e]);
 
@@ -299,11 +453,6 @@ static void low_free_program(struct program *p)
 
   for(e=1; e<p->num_inherits; e++)
     free_program(p->inherits[e].prog);
-}
-
-void really_free_program(struct program *p)
-{
-  low_free_program(p);
 
   if(p->prev)
     p->prev->next=p->next;
@@ -313,6 +462,18 @@ void really_free_program(struct program *p)
   if(p->next)
     p->next->prev=p->prev;
 
+  if(p->flags & PROGRAM_OPTIMIZED)
+    {
+      if(p->program)
+	  free(p->program);
+#define FOO(NUMTYPE,TYPE,NAME) p->NAME=0;
+#include "program_areas.h"
+    }else{
+#define FOO(NUMTYPE,TYPE,NAME) \
+  if(p->NAME) { free((char *)p->NAME); p->NAME=0; }
+#include "program_areas.h"
+    }
+
   free((char *)p);
 
   GC_FREE();
@@ -342,7 +503,7 @@ void dump_program_desc(struct program *p)
     fprintf(stderr,"%s;\n",ID_FROM_INT(p,e)->name->str);
   }
   fprintf(stderr,"All sorted identifiers:\n");
-  for(q=0;q<(int)p->num_identifier_indexes;q++)
+  for(q=0;q<(int)p->num_identifier_index;q++)
   {
     e=p->identifier_index[q];
     fprintf(stderr,"%3d (%3d):",e,q);
@@ -352,61 +513,36 @@ void dump_program_desc(struct program *p)
 }
 #endif
 
-static void toss_compilation_resources()
+static void toss_compilation_resources(void)
 {
-  struct pike_string **names;
-  struct svalue *modules;
-  int e;
+  free_program(new_program);
+  new_program=0;
 
-  for (e=0; e<NUM_AREAS; e++) toss_buffer(areas+e);
-
-  names=(struct pike_string **)inherit_names.s.str;
-  e=inherit_names.s.len / sizeof(struct pike_string *);
-  while(--e>=0) if(names[e]) free_string(names[e]);
-  toss_buffer(& inherit_names);
-
-  modules=(struct svalue *)used_modules.s.str;
-  e=used_modules.s.len / sizeof(struct svalue);
-  while(--e>=0) free_svalue(modules+e);
-  toss_buffer(& used_modules);
-
-  /* Clean up */
-  while(local_variables)
-  {
-    struct locals *l;
-    for(e=0;e<local_variables->current_number_of_locals;e++)
+  if(malloc_size_program)
     {
-      free_string(local_variables->variable[e].name);
-      free_string(local_variables->variable[e].type);
+      free((char *)malloc_size_program);
+      malloc_size_program=0;
     }
   
-    if(local_variables->current_type)
-      free_string(local_variables->current_type);
-
-    if(local_variables->current_return_type)
-      free_string(local_variables->current_return_type);
-
-    l=local_variables->next;
-    free((char *)local_variables);
-    local_variables=l;
-  }
+  while(compiler_frame)
+    pop_compiler_frame();
 
   if(last_file)
   {
     free_string(last_file);
     last_file=0;
   }
-}
+  
+  {
+    struct svalue *modules=(struct svalue *)used_modules.s.str;
+    INT32 e;
 
-/*
- * Something went wrong.
- * toss resources of program we were building
- */
-void toss_current_program()
-{
-  setup_fake_program();
-  low_free_program(&fake_program);
-  toss_compilation_resources();
+    for(e=0;e<(long)(used_modules.s.len / sizeof(struct svalue));e++)
+      free_svalue(modules+e);
+
+    toss_buffer(&used_modules);
+  }
+  
 }
 
 #ifdef DEBUG
@@ -436,6 +572,10 @@ void check_program(struct program *p)
   if(p->storage_needed < 0)
     fatal("Program->storage_needed < 0.\n");
 
+  if(p->num_identifier_index > p->num_identifier_references)
+    fatal("Too many identifier index entries in program!\n");
+
+#if 0
   size=MY_ALIGN(sizeof(struct program));
   size+=MY_ALIGN(p->num_linenumbers);
   size+=MY_ALIGN(p->program_size);
@@ -456,8 +596,8 @@ void check_program(struct program *p)
   if(size < (INT32)p->total_size)
     fatal("Program size is in error.\n");
 
-
-#define CHECKRANGE(X,Y) if((char *)(p->X) < (char *)p || (char *)(p->X)> ((char *)p)+size) fatal("Program->%s is wrong.\n",Y)
+#define CHECKRANGE(X,Y) \
+if((char *)(p->X) < (char *)p || (char *)(p->X)> ((char *)p)+size) fatal("Program->%s is wrong.\n",Y)
 
   CHECKRANGE(program,"program");
   CHECKRANGE(strings,"strings");
@@ -480,11 +620,10 @@ void check_program(struct program *p)
     if(p->checksum != checksum)
       fatal("Someone changed a program!!!\n");
   }
+#endif
 
   for(e=0;e<(int)p->num_constants;e++)
-  {
     check_svalue(p->constants + e);
-  }
 
   for(e=0;e<(int)p->num_strings;e++)
     check_string(p->strings[e]);
@@ -511,7 +650,7 @@ void check_program(struct program *p)
       fatal("Identifier offset is wrong!\n");
   }
 
-  for(e=0;e<(int)p->num_identifier_indexes;e++)
+  for(e=0;e<(int)p->num_identifier_index;e++)
   {
     if(p->identifier_index[e] > p->num_identifier_references)
       fatal("Program->identifier_indexes[%ld] is wrong\n",(long)e);
@@ -525,128 +664,38 @@ void check_program(struct program *p)
 }
 #endif
 
-/* internal function to make the index-table */
-static int funcmp(const void *a,const void *b)
-{
-  return
-    my_order_strcmp(ID_FROM_INT(&fake_program, *(unsigned short *)a)->name,
-		    ID_FROM_INT(&fake_program, *(unsigned short *)b)->name);
-}
-
-/*
- * Finish this program, returning the newly built program
- */
-
-#define INS_BLOCK(PTR,PTRS,TYPE,AREA) \
-prog->PTR=(TYPE *)p; \
-if((prog->PTRS = areas[AREA].s.len/sizeof(TYPE))) \
-{ \
-  MEMCPY(p,areas[AREA].s.str, areas[AREA].s.len); \
-  p+=MY_ALIGN(areas[AREA].s.len); \
-}
-
-struct program *end_program()
+struct program *end_first_pass(int finish)
 {
-  struct pike_string **names;
-  int size, i,e,t;
-  char *p;
   struct program *prog;
 
   /*
    * Define the __INIT function, but only if there was any code
    * to initialize.
    */
-  if (init_node)
+  if(init_node)
   {
     union idptr tmp;
     struct pike_string *s;
-    push_locals();
     s=make_shared_string("__INIT");
     dooptcode(s,
 	      mknode(F_ARG_LIST,
 		     init_node,mknode(F_RETURN,mkintnode(0),0)),
 	      function_type_string,
 	      0);
-    pop_locals();
     free_string(s);
     init_node=0;
   }
 
+  pop_compiler_frame(); /* Pop __INIT local variables */
+
   exit_type_stack();
 
-  if (num_parse_error > 0)
+  if(num_parse_error > 0)
   {
-    toss_current_program();
     prog=0;
   }else{
-    setup_fake_program();
-    size = MY_ALIGN(sizeof (struct program));
-    for (i=0; i<NUM_AREAS; i++) size += MY_ALIGN(areas[i].s.len);
-    size+=MY_ALIGN(fake_program.num_identifier_references * sizeof(unsigned short));
-
-    p = (char *)xalloc(size);
-    prog = (struct program *)p;
-    *prog = fake_program;
-    prog->total_size = size;
-    prog->refs = 1;
-    p += MY_ALIGN(sizeof (struct program));
-
-    INS_BLOCK(program,program_size,unsigned char,A_PROGRAM);
-    INS_BLOCK(linenumbers,num_linenumbers,char,A_LINENUMBERS);
-    INS_BLOCK(identifiers,num_identifiers,struct identifier,A_IDENTIFIERS);
-    INS_BLOCK(identifier_references,num_identifier_references,struct reference,A_IDENTIFIER_REFERENCES);
-    INS_BLOCK(strings,num_strings,struct pike_string *,A_STRINGS);
-    INS_BLOCK(inherits,num_inherits,struct inherit,A_INHERITS);
-    INS_BLOCK(constants,num_constants,struct svalue,A_CONSTANTS);
-
-    /* Ok, sort for binsearch */
-    prog->identifier_index=(unsigned short *)p;
-    for(e=i=0;i<(int)prog->num_identifier_references;i++)
-    {
-      struct reference *funp;
-      struct identifier *fun;
-      funp=prog->identifier_references+i;
-      if(funp->flags & (ID_HIDDEN|ID_STATIC)) continue;
-      if(funp->flags & ID_INHERITED)
-      {
-	if(funp->flags & ID_PRIVATE) continue;
-	fun=ID_FROM_PTR(prog, funp);
-	if(fun->func.offset == -1) continue; /* prototype */
-
-	/* check for multiple definitions */
-	for(t=0;t>=0 && t<(int)prog->num_identifier_references;t++)
-	{
-	  struct reference *funpb;
-	  struct identifier *funb;
-
-	  if(t==i) continue;
-	  funpb=prog->identifier_references+t;
-	  if(funpb->flags & (ID_HIDDEN|ID_STATIC)) continue;
-	  if((funpb->flags & ID_INHERITED) && t<i) continue;
-	  funb=ID_FROM_PTR(prog,funpb);
-	  if(funb->func.offset == -1) continue; /* prototype */
-	  if(fun->name==funb->name) t=-10;
-	}
-	if(t<0) continue;
-      }
-      prog->identifier_index[e]=i;
-      e++;
-    }
-    prog->num_identifier_indexes=e;
-    fsort((void *)prog->identifier_index, e,sizeof(unsigned short),(fsortfun)funcmp);
-
-    p+=MY_ALIGN(prog->num_identifier_indexes*sizeof(unsigned short));
-
-    toss_compilation_resources();
-
-    prog->inherits[0].prog=prog;
-    prog->prev=0;
-    if((prog->next=first_program))
-      first_program->prev=prog;
-    first_program=prog;
-
-    for(i=0;i<NUM_LFUNS;i++)
-      prog->lfuns[i]=find_identifier(lfun_names[i],prog);
+    prog=new_program;
+    prog->refs++;
 
 #ifdef DEBUG
     check_program(prog);
@@ -654,21 +703,37 @@ struct program *end_program()
       dump_program_desc(prog);
 #endif
 
+    new_program->flags |= PROGRAM_PASS_1_DONE;
+
+    if(finish)
+    {
+      fixate_program();
+      optimize_program(new_program);
+      new_program->flags |= PROGRAM_FINISHED;
+    }
+
     GC_ALLOC();
   }
+  toss_compilation_resources();
 
-#define PROGRAM_STATE
 #define POP
 #include "compilation.h"
-#undef POP
-#undef PROGRAM_STATE
-  if(fake_program.num_inherits)
-    fake_program.inherits[0].prog=&fake_program;
+
+  compilation_depth--;
   threads_disabled--;
   free_all_nodes();
   return prog;
 }
 
+/*
+ * Finish this program, returning the newly built program
+ */
+struct program *end_program(void)
+{
+  return end_first_pass(1);
+}
+
+
 /*
  * Allocate needed for this program in the object structure.
  * An offset to the data is returned.
@@ -676,9 +741,9 @@ struct program *end_program()
 SIZE_T add_storage(SIZE_T size)
 {
   SIZE_T offset;
-  offset=fake_program.storage_needed;
+  offset=new_program->storage_needed;
   size=MY_ALIGN(size);
-  fake_program.storage_needed += size;
+  new_program->storage_needed += size;
   return offset;
 }
 
@@ -688,7 +753,7 @@ SIZE_T add_storage(SIZE_T size)
  */
 void set_init_callback(void (*init)(struct object *))
 {
-  fake_program.init=init;
+  new_program->init=init;
 }
 
 /*
@@ -697,17 +762,18 @@ void set_init_callback(void (*init)(struct object *))
  */
 void set_exit_callback(void (*exit)(struct object *))
 {
-  fake_program.exit=exit;
+  new_program->exit=exit;
 }
 
 
-int low_reference_inherited_identifier(int e,struct pike_string *name)
+int low_reference_inherited_identifier(int e,
+				       struct pike_string *name)
 {
   struct reference funp;
   struct program *p;
   int i,d;
 
-  p=fake_program.inherits[e].prog;
+  p=new_program->inherits[e].prog;
   i=find_shared_string_identifier(name,p);
   if(i==-1) return i;
 
@@ -721,24 +787,21 @@ int low_reference_inherited_identifier(int e,struct pike_string *name)
   funp.inherit_offset+=e;
   funp.flags|=ID_HIDDEN;
 
-  for(d=0;d<(int)fake_program.num_identifier_references;d++)
+  for(d=0;d<(int)new_program->num_identifier_references;d++)
   {
     struct reference *fp;
-    fp=fake_program.identifier_references+d;
+    fp=new_program->identifier_references+d;
 
     if(!MEMCMP((char *)fp,(char *)&funp,sizeof funp)) return d;
   }
 
-  add_to_mem_block(A_IDENTIFIER_REFERENCES,(char *)&funp,sizeof funp);
-  return fake_program.num_identifier_references;
+  add_to_identifier_references(funp);
+  return new_program->num_identifier_references -1;
 }
 
-
-
 int reference_inherited_identifier(struct pike_string *super_name,
 				   struct pike_string *function_name)
 {
-  struct pike_string **names;
   int e,i;
 
 #ifdef DEBUG
@@ -746,21 +809,18 @@ int reference_inherited_identifier(struct pike_string *super_name,
     fatal("reference_inherited_function on nonshared string.\n");
 #endif
 
-  names=(struct pike_string **)inherit_names.s.str;
-  setup_fake_program();
-
-  for(e=fake_program.num_inherits-1;e>0;e--)
+  for(e=new_program->num_inherits-1;e>0;e--)
   {
-    if(fake_program.inherits[e].inherit_level!=1) continue;
-    if(!names[e]) continue;
+    if(new_program->inherits[e].inherit_level!=1) continue;
+    if(!new_program->inherits[e].name) continue;
 
     if(super_name)
     {
       int l;
-      l=names[e]->len;
+      l=new_program->inherits[e].name->len;
       if(l<super_name->len) continue;
       if(strncmp(super_name->str,
-		 names[e]->str+l-super_name->len,
+		 new_program->inherits[e].name->str+l-super_name->len,
 		 super_name->len))
 	continue;
     }
@@ -774,12 +834,10 @@ int reference_inherited_identifier(struct pike_string *super_name,
 
 void rename_last_inherit(struct pike_string *n)
 {
-  struct pike_string **names;
-  int e;
-  names=(struct pike_string **)inherit_names.s.str;
-  e=inherit_names.s.len / sizeof(struct pike_string *);
-  free_string(names[e-1]);
-  copy_shared_string(names[e-1],n);
+  if(new_program->inherits[new_program->num_inherits].name)
+    free_string(new_program->inherits[new_program->num_inherits].name);
+  copy_shared_string(new_program->inherits[new_program->num_inherits].name,
+		     n);
 }
 
 /*
@@ -791,28 +849,44 @@ void do_inherit(struct program *p,INT32 flags, struct pike_string *name)
   struct inherit inherit;
   struct pike_string *s;
 
-  setup_fake_program();
-
-  inherit_offset = fake_program.num_inherits;
+  inherit_offset = new_program->num_inherits;
 
-  storage_offset=fake_program.storage_needed;
+  storage_offset=new_program->storage_needed;
   add_storage(p->storage_needed);
 
   for(e=0; e<(int)p->num_inherits; e++)
   {
     inherit=p->inherits[e];
     inherit.prog->refs++;
-    inherit.identifier_level += fake_program.num_identifier_references;
+    inherit.identifier_level += new_program->num_identifier_references;
     inherit.storage_offset += storage_offset;
     inherit.inherit_level ++;
-    add_to_mem_block(A_INHERITS,(char *)&inherit,sizeof inherit);
-    
-    low_my_binary_strcat((char *)&name,sizeof(name),&inherit_names);
+
+
     if(name)
     {
-      reference_shared_string(name);
-      name=0;
+      if(e==0)
+      {
+	inherit.name=name;
+	reference_shared_string(name);
+      }
+      else if(inherit.name)
+      {
+	struct pike_string *s;
+	s=begin_shared_string(inherit.name->len + name->len + 2);
+	MEMCPY(s->str,name->str,name->len);
+	MEMCPY(s->str+name->len,"::",2);
+	MEMCPY(s->str+name->len+2,inherit.name->str,inherit.name->len);
+	inherit.name=end_shared_string(s);
+      }
+      else
+      {
+	inherit.name=0;
+      }
+    }else{
+      inherit.name=0;
     }
+    add_to_inherits(inherit);
   }
 
   for (e=0; e < (int)p->num_identifier_references; e++)
@@ -829,7 +903,7 @@ void do_inherit(struct program *p,INT32 flags, struct pike_string *name)
     {
       int n;
       n = isidentifier(name);
-      if (n != -1 && ID_FROM_INT(&fake_program,n)->func.offset != -1)
+      if (n != -1 && ID_FROM_INT(new_program,n)->func.offset != -1)
 	my_yyerror("Illegal to redefine 'nomask' function/variable \"%s\"",name->str);
     }
 
@@ -841,7 +915,7 @@ void do_inherit(struct program *p,INT32 flags, struct pike_string *name)
       fun.flags |= flags;
 
     fun.flags |= ID_INHERITED;
-    add_to_mem_block(A_IDENTIFIER_REFERENCES, (char *)&fun, sizeof fun);
+    add_to_identifier_references(fun);
   }
 
   /* Ska det h{r vara s} h{r? */
@@ -863,8 +937,7 @@ void simple_do_inherit(struct pike_string *s, INT32 flags,struct pike_string *na
 {
   reference_shared_string(s);
   push_string(s);
-  reference_shared_string(current_file);
-  push_string(current_file);
+  ref_push_string(lex.current_file);
   SAFE_APPLY_MASTER("handle_inherit", 2);
 
   if(sp[-1].type != T_PROGRAM)
@@ -890,12 +963,11 @@ void simple_do_inherit(struct pike_string *s, INT32 flags,struct pike_string *na
 int isidentifier(struct pike_string *s)
 {
   INT32 e;
-  setup_fake_program();
-  for(e=0;e<(int)fake_program.num_identifier_references;e++)
+  for(e=0;e<(int)new_program->num_identifier_references;e++)
   {
-    if(fake_program.identifier_references[e].flags & ID_HIDDEN) continue;
+    if(new_program->identifier_references[e].flags & ID_HIDDEN) continue;
     
-    if(ID_FROM_INT(& fake_program, e)->name == s)
+    if(ID_FROM_INT(new_program, e)->name == s)
       return e;
   }
   return -1;
@@ -916,23 +988,34 @@ int define_variable(struct pike_string *name,
   if(type == void_type_string)
     yyerror("Variables can't be of type void");
   
-  setup_fake_program();
   n = isidentifier(name);
 
+  if(new_program->flags & PROGRAM_PASS_1_DONE)
+  {
+    if(n==-1)
+      yyerror("Pass2: Variable disappeared!");
+    else
+      return n;
+  }
+
+#ifdef DEBUG
+  if(new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))
+    fatal("Attempting to add variable to fixed program\n");
+#endif
+
   if(n != -1)
   {
-    setup_fake_program();
 
     if (IDENTIFIERP(n)->flags & ID_NOMASK)
       my_yyerror("Illegal to redefine 'nomask' variable/functions \"%s\"", name->str);
 
-    if(PROG_FROM_INT(& fake_program, n) == &fake_program)
+    if(PROG_FROM_INT(new_program, n) == new_program)
       my_yyerror("Variable '%s' defined twice.",name->str);
 
-    if(ID_FROM_INT(& fake_program, n)->type != type)
+    if(ID_FROM_INT(new_program, n)->type != type)
       my_yyerror("Illegal to redefine inherited variable with different type.");
 
-    if(ID_FROM_INT(& fake_program, n)->flags != flags)
+    if(ID_FROM_INT(new_program, n)->flags != flags)
       my_yyerror("Illegal to redefine inherited variable with different type.");
 
   } else {
@@ -952,16 +1035,13 @@ int define_variable(struct pike_string *name,
 				  sizeof(union anything));
 
     ref.flags=flags;
-    ref.identifier_offset=areas[A_IDENTIFIERS].s.len / sizeof dummy;
+    ref.identifier_offset=new_program->num_identifiers;
     ref.inherit_offset=0;
 
-    add_to_mem_block(A_IDENTIFIERS, (char *)&dummy, sizeof dummy);
-    fake_program.num_identifiers ++;
-
-    n=areas[A_IDENTIFIER_REFERENCES].s.len / sizeof ref;
-    add_to_mem_block(A_IDENTIFIER_REFERENCES, (char *)&ref, sizeof ref);
-    fake_program.num_identifier_references ++;
+    add_to_identifiers(dummy);
 
+    n=new_program->num_identifier_references;
+    add_to_identifier_references(ref);
   }
 
   return n;
@@ -982,6 +1062,7 @@ int simple_add_variable(char *name,
   return ret;
 }
 
+/* FIXME: add_constant with c==0 means declaration */
 int add_constant(struct pike_string *name,
 		 struct svalue *c,
 		 INT32 flags)
@@ -995,9 +1076,37 @@ int add_constant(struct pike_string *name,
     fatal("define_constant on nonshared string.\n");
 #endif
 
-  setup_fake_program();
   n = isidentifier(name);
 
+
+  if(new_program->flags & PROGRAM_PASS_1_DONE)
+  {
+    if(n==-1)
+    {
+      yyerror("Pass2: Constant disappeared!");
+    }else{
+#if 1
+      struct identifier *id;
+      id=ID_FROM_INT(new_program,n);
+      if(id->func.offset>=0)
+      {
+	struct pike_string *s;
+	struct svalue *c=PROG_FROM_INT(new_program,n)->constants+
+	  id->func.offset;
+	s=get_type_of_svalue(c);
+	free_string(id->type);
+	id->type=s;
+      }
+#endif
+      return n;
+    }
+  }
+
+#ifdef DEBUG
+  if(new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))
+    fatal("Attempting to add constant to fixed program\n");
+#endif
+
   copy_shared_string(dummy.name, name);
   dummy.type = get_type_of_svalue(c);
   
@@ -1007,25 +1116,23 @@ int add_constant(struct pike_string *name,
   dummy.func.offset=store_constant(c, 0);
 
   ref.flags=flags;
-  ref.identifier_offset=fake_program.num_identifiers;
+  ref.identifier_offset=new_program->num_identifiers;
   ref.inherit_offset=0;
 
-  add_to_mem_block(A_IDENTIFIERS, (char *)&dummy, sizeof dummy);
-  fake_program.num_identifiers ++;
+  add_to_identifiers(dummy);
 
   if(n != -1)
   {
-    if (IDENTIFIERP(n)->flags & ID_NOMASK)
+    if(IDENTIFIERP(n)->flags & ID_NOMASK)
       my_yyerror("Illegal to redefine 'nomask' identifier \"%s\"", name->str);
 
-    if(PROG_FROM_INT(& fake_program, n) == &fake_program)
+    if(PROG_FROM_INT(new_program, n) == new_program)
       my_yyerror("Identifier '%s' defined twice.",name->str);
 
-    fake_program.identifier_references[n]=ref;
+    new_program->identifier_references[n]=ref;
   } else {
-    n=areas[A_IDENTIFIER_REFERENCES].s.len / sizeof ref;
-    add_to_mem_block(A_IDENTIFIER_REFERENCES, (char *)&ref, sizeof ref);
-    fake_program.num_identifier_references ++;
+    n=new_program->num_identifier_references;
+    add_to_identifier_references(ref);
   }
 
   return n;
@@ -1137,14 +1244,13 @@ INT32 define_function(struct pike_string *name,
 
   i=isidentifier(name);
 
-  setup_fake_program();
 
   if(i >= 0)
   {
     /* already defined */
 
-    funp=ID_FROM_INT(&fake_program, i);
-    ref=fake_program.identifier_references[i];
+    funp=ID_FROM_INT(new_program, i);
+    ref=new_program->identifier_references[i];
 
     if(ref.inherit_offset == 0) /* not inherited */
     {
@@ -1161,11 +1267,7 @@ INT32 define_function(struct pike_string *name,
       }
     }
 
-    /* it's just another prototype, don't define anything */
-    if(!func || func->offset == -1) return i;
-
-    if((ref.flags & ID_NOMASK) &&
-       !(funp->func.offset == -1))
+    if((ref.flags & ID_NOMASK) && !(funp->func.offset == -1))
     {
       my_yyerror("Illegal to redefine 'nomask' function %s.",name->str);
     }
@@ -1193,13 +1295,13 @@ INT32 define_function(struct pike_string *name,
       else
 	fun.func.offset = -1;
 
-      ref.identifier_offset=fake_program.num_identifiers;
-      add_to_mem_block(A_IDENTIFIERS, (char *)&fun, sizeof(fun));
+      ref.identifier_offset=new_program->num_identifiers;
+      add_to_identifiers(fun);
     }
 
     ref.inherit_offset = 0;
     ref.flags = flags;
-    fake_program.identifier_references[i]=ref;
+    new_program->identifier_references[i]=ref;
   }else{
     /* define it */
 
@@ -1215,16 +1317,15 @@ INT32 define_function(struct pike_string *name,
     else
       fun.func.offset = -1;
 
-    i=fake_program.num_identifiers;
-    add_to_mem_block(A_IDENTIFIERS, (char *)&fun, sizeof(fun));
+    i=new_program->num_identifiers;
+    add_to_identifiers(fun);
 
     ref.flags = flags;
     ref.identifier_offset = i;
     ref.inherit_offset = 0;
 
-    i=fake_program.num_identifier_references;
-    add_to_mem_block(A_IDENTIFIER_REFERENCES, (char *)&ref, sizeof ref);
-
+    i=new_program->num_identifier_references;
+    add_to_identifier_references(ref);
   }
   return i;
 }
@@ -1240,12 +1341,17 @@ static int low_find_shared_string_identifier(struct pike_string *name,
   int max,min,tst;
   struct reference *funp;
   struct identifier *fun;
-  unsigned short *funindex;
 
-  funindex = prog->identifier_index;
-  if(funindex)
+  if(prog->flags & PROGRAM_FIXED)
   {
-    max = prog->num_identifier_indexes;
+    unsigned short *funindex = prog->identifier_index;
+
+#ifdef DEBUG
+    if(!funindex)
+      fatal("No funindex in fixed program\n");
+#endif
+  
+    max = prog->num_identifier_index;
     min = 0;
     while(max != min)
     {
@@ -1264,17 +1370,23 @@ static int low_find_shared_string_identifier(struct pike_string *name,
       funp = prog->identifier_references + i;
       if(funp->flags & ID_HIDDEN) continue;
       fun = ID_FROM_PTR(prog, funp);
-      if(fun->func.offset == -1) continue; /* Prototype */
+      /* if(fun->func.offset == -1) continue; * Prototype */
       if(!is_same_string(fun->name,name)) continue;
       if(funp->flags & ID_INHERITED)
       {
         if(funp->flags & ID_PRIVATE) continue;
 	for(t=0; t>=0 && t<(int)prog->num_identifier_references; t++)
 	{
-	  if(t == i) continue;
-
-	  if(is_same_string(fun->name, ID_FROM_INT(prog, i)->name))
-	    t=-10;
+	  struct reference *funpb;
+	  struct identifier *funb;
+	  
+	  if(t==i) continue;
+	  funpb=prog->identifier_references+t;
+	  if(funpb->flags & (ID_HIDDEN|ID_STATIC)) continue;
+	  if((funpb->flags & ID_INHERITED) && t<i) continue;
+	  funb=ID_FROM_PTR(prog,funpb);
+	  /* if(funb->func.offset == -1) continue; * prototype */
+	  if(fun->name==funb->name) t=-10;
 	}
 	if(t < 0) continue;
       }
@@ -1305,7 +1417,7 @@ int find_shared_string_identifier(struct pike_string *name,
 				  struct program *prog)
 {
 #ifdef FIND_FUNCTION_HASHSIZE
-  if(prog!=&fake_program)
+  if(prog -> flags & PROGRAM_FIXED)
   {
     unsigned int hashval;
     hashval=my_hash_string(name);
@@ -1340,31 +1452,30 @@ int find_identifier(char *name,struct program *prog)
 int store_prog_string(struct pike_string *str)
 {
   unsigned int i;
-  struct pike_string **p;
 
-  p = (struct pike_string **)areas[A_STRINGS].s.str;
-
-  for (i=0;i<areas[A_STRINGS].s.len / sizeof str;i++)
-    if (p[i] == str)
+  for (i=0;i<new_program->num_strings;i++)
+    if (new_program->strings[i] == str)
       return i;
 
   reference_shared_string(str);
-  add_to_mem_block(A_STRINGS, (char *)&str, sizeof str);
+  add_to_strings(str);
   return i;
 }
 
 int store_constant(struct svalue *foo, int equal)
 {
-  struct svalue *s,tmp;
+  struct svalue tmp;
   unsigned int e;
-  s=(struct svalue *)areas[A_CONSTANTS].s.str;
 
-  for(e=0;e<areas[A_CONSTANTS].s.len / sizeof(struct svalue);e++)
-    if(equal ? is_equal(s+e,foo) : is_eq(s+e,foo))
+  for(e=0;e<new_program->num_constants;e++)
+  {
+    struct svalue *s=new_program->constants + e;
+    if(equal ? is_equal(s,foo) : is_eq(s,foo))
       return e;
+  }
 
   assign_svalue_no_free(&tmp,foo);
-  add_to_mem_block(A_CONSTANTS,(char *)&tmp,sizeof(struct svalue));
+  add_to_constants(tmp);
   return e;
 }
 
@@ -1393,21 +1504,25 @@ static int get_small_number(char **q)
 
 void start_line_numbering(void)
 {
-  if(last_file) { free_string(last_file); last_file=0; }
+  if(last_file)
+    {
+      free_string(last_file);
+      last_file=0;
+    }
   last_pc=last_line=0;
 }
 
-static void insert_small_number(int a,int area)
+static void insert_small_number(INT32 a)
 {
   if(a>-127 && a<127)
   {
-    ins_byte(a,area);
+    add_to_linenumbers(a);
   }else if(a>=-32768 && a<32768){
-    ins_signed_byte(-127,area);
-    ins_short(a,area);
+    add_to_linenumbers(a);
+    ins_short(a, add_to_linenumbers);
   }else{
-    ins_signed_byte(-128,area);
-    ins_int(a,area);
+    add_to_linenumbers(-128);
+    ins_int(a, add_to_linenumbers);
   }	
 }
 
@@ -1419,13 +1534,14 @@ void store_linenumber(INT32 current_line, struct pike_string *current_file)
     {
       char *tmp;
       if(last_file) free_string(last_file);
-      ins_byte(127,A_LINENUMBERS);
-      for(tmp=current_file->str; *tmp; tmp++) ins_byte(*tmp,A_LINENUMBERS);
-      ins_byte(0,A_LINENUMBERS);
+      add_to_linenumbers(127);
+      for(tmp=current_file->str; *tmp; tmp++)
+	add_to_linenumbers(*tmp);
+      add_to_linenumbers(0);
       copy_shared_string(last_file, current_file);
     }
-    insert_small_number(PC-last_pc,A_LINENUMBERS);
-    insert_small_number(current_line-last_line,A_LINENUMBERS);
+    insert_small_number(PC-last_pc);
+    insert_small_number(current_line-last_line);
     last_line=current_line;
     last_pc=PC;
   }
@@ -1446,20 +1562,18 @@ char *get_line(unsigned char *pc,struct program *prog,INT32 *linep)
   if (prog == 0) return "Unkown program";
   offset = pc - prog->program;
 
-  if(prog == & fake_program)
+  if(prog == new_program)
   {
     linep[0]=0;
     return "Optimizer";
   }
 
-#ifdef DEBUG
-  if (offset > (INT32)prog->program_size || offset<0)
-    fatal("Illegal offset %ld in program.\n", (long)offset);
-#endif
-
   cnt=prog->linenumbers;
   off=line=0;
   file="Line not found";
+  if (offset > (INT32)prog->num_program || offset<0)
+    return file;
+
   while(cnt < prog->linenumbers + prog->num_linenumbers)
   {
     if(*cnt == 127)
@@ -1489,81 +1603,45 @@ void my_yyerror(char *fmt,...)  ATTRIBUTE((format(printf,1,2)))
   va_end(args);
 }
 
-/*
- * Compile an PIKE file. Input is supposed to be initalized already.
- */
-void compile()
+struct program *compile(struct pike_string *prog)
 {
-  int yyparse();
-
-  start_line_numbering();
-
-  num_parse_error = 0;
-  init_node=0;
-
-  yyparse();  /* Parse da program */
-  free_all_local_names();
-}
-
-struct program *compile_file(struct pike_string *file_name)
-{
-  int fd;
   struct program *p;
+  struct lex save_lex;
+  int save_depth=compilation_depth;
+  void yyparse(void);
 
-  while(1)
-  {
-    fd=open(file_name->str,O_RDONLY);
-    if(fd >= 0) break;
-    if(errno != EINTR)
-    {
-#ifdef HAVE_STRERROR
-      error("Couldn't open file '%s'. (%s)\n",file_name->str,strerror(errno));
-#else
-      error("Couldn't open file '%s'. (ERRNO=%d)\n",file_name->str,errno);
-#endif
-    }
-  }
+  save_lex=lex;
 
-#define FILE_STATE
-#define PUSH
-#include "compilation.h"
-#undef PUSH
+  lex.end=prog->str+prog->len;
+  lex.current_line=1;
+  lex.current_file=make_shared_string("-");
+  lex.pragmas=0;
 
-  start_new_file(fd,file_name);
   start_new_program();
-  compile();
-  p=end_program();
-  end_new_file();
+  compilation_depth=0;
 
-#define POP
-#include "compilation.h"
-#undef POP
-#undef FILE_STATE
+  start_line_numbering();
 
-  if(!p) error("Failed to compile %s.\n",file_name->str);
-  return p;
-}
+  compiler_pass=1;
+  lex.pos=prog->str;
+  yyparse();  /* Parse da program */
 
-struct program *compile_string(struct pike_string *prog,
-			       struct pike_string *name)
-{
-  struct program *p;
+  p=end_first_pass(0);
+  
+  if(p && !num_parse_error)
+  {
+    low_start_new_program(p,0,0);
+    compiler_pass=2;
+    lex.pos=prog->str;
+    yyparse();  /* Parse da program again */
+    p=end_program();
+  }
 
-#define FILE_STATE
-#define PUSH
-#include "compilation.h"
-#undef PUSH
 
-  start_new_string(prog->str,prog->len,name);
-  start_new_program();
-  compile();
-  p=end_program();
-  end_new_file();
+  free_string(lex.current_file);
+  lex=save_lex;
 
-#define POP
-#include "compilation.h"
-#undef POP
-#undef FILE_STATE
+  compilation_depth=save_depth;
 
   if(!p) error("Compilation failed.\n");
   return p;
@@ -1597,7 +1675,7 @@ void add_function(char *name,void (*cfun)(INT32),char *type,INT16 flags)
 }
 
 #ifdef DEBUG
-void check_all_programs()
+void check_all_programs(void)
 {
   struct program *p;
   for(p=first_program;p;p=p->next)
@@ -1624,7 +1702,7 @@ void check_all_programs()
 }
 #endif
 
-void cleanup_program()
+void cleanup_program(void)
 {
 #ifdef FIND_FUNCTION_HASHSIZE
   int e;
@@ -1647,7 +1725,7 @@ void gc_mark_program_as_referenced(struct program *p)
     gc_mark_svalues(p->constants, p->num_constants);
 }
 
-void gc_check_all_programs()
+void gc_check_all_programs(void)
 {
   struct program *p;
   for(p=first_program;p;p=p->next)
@@ -1669,7 +1747,7 @@ void gc_check_all_programs()
   }
 }
 
-void gc_mark_all_programs()
+void gc_mark_all_programs(void)
 {
   struct program *p;
   for(p=first_program;p;p=p->next)
@@ -1677,7 +1755,7 @@ void gc_mark_all_programs()
       gc_mark_program_as_referenced(p);
 }
 
-void gc_free_all_unreferenced_programs()
+void gc_free_all_unreferenced_programs(void)
 {
   struct program *p,*next;
 
@@ -1710,31 +1788,50 @@ void count_memory_in_programs(INT32 *num_, INT32 *size_)
   *num_=num;
   *size_=size;
 }
-void push_locals()
+
+void push_compiler_frame(void)
 {
-  struct locals *l;
-  l=ALLOC_STRUCT(locals);
-  l->current_type=0;
-  l->current_return_type=0;
-  l->next=local_variables;
-  l->current_number_of_locals=0;
-  l->max_number_of_locals=0;
-  local_variables=l;
+  struct compiler_frame *f;
+  f=ALLOC_STRUCT(compiler_frame);
+  f->current_type=0;
+  f->current_return_type=0;
+  f->current_number_of_locals=0;
+  f->max_number_of_locals=0;
+  f->previous=compiler_frame;
+  compiler_frame=f;
 }
 
-void pop_locals()
+void pop_local_variables(int level)
 {
-  struct locals *l;
-  free_all_local_names();
-  l=local_variables->next;
-  if(local_variables->current_type)
-    free_string(local_variables->current_type);
-  if(local_variables->current_return_type)
-    free_string(local_variables->current_return_type);
-  free((char *)local_variables);
+  while(compiler_frame->current_number_of_locals > level)
+  {
+    int e;
+    e=--(compiler_frame->current_number_of_locals);
+    free_string(compiler_frame->variable[e].name);
+    free_string(compiler_frame->variable[e].type);
+  }
+}
 
-  local_variables=l;
-  /* insert check if ( local->next == parent locals ) here */
+
+void pop_compiler_frame(void)
+{
+  struct compiler_frame *f;
+  int e;
+  f=compiler_frame;
+#ifdef DEBUG
+  if(!f)
+    fatal("Popping out of compiler frames\n");
+#endif
+
+  pop_local_variables(0);
+  if(f->current_type)
+    free_string(f->current_type);
+  
+  if(f->current_return_type)
+    free_string(f->current_return_type);
+
+  compiler_frame=f->previous;
+  free((char *)f);
 }
 
 
@@ -1777,6 +1874,58 @@ char *get_storage(struct object *o, struct program *p)
   return o->storage + offset;
 }
 
+struct program *low_program_from_function(struct program *p,
+					  INT32 i)
+{
+  struct svalue *f;
+  struct identifier *id=ID_FROM_INT(p, i);
+  if(!IDENTIFIER_IS_CONSTANT(id->flags)) return 0;
+  if(id->func.offset==-1) return 0;
+  f=PROG_FROM_INT(p,i)->constants + id->func.offset;
+  if(f->type!=T_PROGRAM) return 0;
+  return f->u.program;
+}
+
+struct program *program_from_function(struct svalue *f)
+{
+  struct identifier *id;
+  if(f->type != T_FUNCTION) return 0;
+  if(f->subtype == FUNCTION_BUILTIN) return 0;
+  if(!f->u.object->prog) return 0;
+  return low_program_from_function(f->u.object->prog, f->subtype);
+}
+
+#define FIND_CHILD_HASHSIZE 5003
+struct find_child_cache_s
+{
+  INT32 pid,cid,id;
+};
+
+static struct find_child_cache_s find_child_cache[FIND_CHILD_HASHSIZE];
+
+int find_child(struct program *parent, struct program *child)
+{
+  INT32 h=(parent->id  * 9248339 + child->id) % FIND_CHILD_HASHSIZE;
+  if(find_child_cache[h].pid == parent->id &&
+     find_child_cache[h].cid == child->id)
+  {
+    return find_child_cache[h].id;
+  }else{
+    INT32 i;
+    for(i=0;i<parent->num_identifier_references;i++)
+    {
+      if(low_program_from_function(parent, i)==child)
+      {
+	find_child_cache[h].pid=parent->id;
+	find_child_cache[h].cid=child->id;
+	find_child_cache[h].id=i;
+	return i;
+      }
+    }
+  }
+  return -1;
+}
+
 void yywarning(char *fmt, ...) ATTRIBUTE((format(printf,1,2)))
 {
   char buf[4711];
@@ -1790,8 +1939,8 @@ void yywarning(char *fmt, ...) ATTRIBUTE((format(printf,1,2)))
 
   if(get_master())
   {
-    ref_push_string(current_file);
-    push_int(current_line);
+    ref_push_string(lex.current_file);
+    push_int(lex.current_line);
     push_text(buf);
     SAFE_APPLY_MASTER("compile_warning",3);
     pop_stack();
diff --git a/src/program.h b/src/program.h
index 6444becb754b6d67d8db8e3fbe2dfc2571d0385a..9eba51d6ea8a8adc864636e82b6789bb4ffbaec6 100644
--- a/src/program.h
+++ b/src/program.h
@@ -9,6 +9,7 @@
 #include <stdarg.h>
 #include "global.h"
 #include "types.h"
+#include "svalue.h"
 
 #define LFUN___INIT 0
 #define LFUN_CREATE 1
@@ -127,27 +128,36 @@ struct reference
 struct inherit
 {
   struct program *prog;
+  struct pike_string *name;
   INT16 inherit_level; /* really needed? */
   INT16 identifier_level;
   INT32 storage_offset;
 };
 
+/* program parts have been realloced into one block */
+#define PROGRAM_OPTIMIZED 1
+
+/* program has gone through pass 1 of compiler, prototypes etc. will
+ * not change from now on
+ */
+#define PROGRAM_FIXED 2
+
+/* Program is done and can be cloned */
+#define PROGRAM_FINISHED 4
+
+/* Program has gone trouh first compiler pass */
+#define PROGRAM_PASS_1_DONE 8
+
 struct program
 {
   INT32 refs;
   INT32 id;             /* used to identify program in caches */
+  INT32 flags;
   INT32 storage_needed; /* storage needed in the object struct */
 
   struct program *next;
   struct program *prev;
-  unsigned char *program;
-  struct pike_string **strings;
-  struct inherit *inherits;
-  struct reference *identifier_references;
-  struct identifier *identifiers;
-  unsigned INT16 *identifier_index;
-  struct svalue *constants;
-  char *linenumbers;
+
   void (*init)(struct object *);
   void (*exit)(struct object *);
 #ifdef DEBUG
@@ -155,14 +165,13 @@ struct program
 #endif
 
   SIZE_T total_size;
-  SIZE_T num_linenumbers;
-  SIZE_T program_size;
-  unsigned INT16 num_constants;
-  unsigned INT16 num_strings;
-  unsigned INT16 num_identifiers;
-  unsigned INT16 num_identifier_references;
-  unsigned INT16 num_identifier_indexes;
-  unsigned INT16 num_inherits;
+
+#define FOO(NUMTYPE,TYPE,NAME) TYPE * NAME ;
+#include "program_areas.h"
+
+#define FOO(NUMTYPE,TYPE,NAME) NUMTYPE num_##NAME ;
+#include "program_areas.h"
+  
   INT16 lfuns[NUM_LFUNS];
 };
 
@@ -173,26 +182,39 @@ struct program
 #define PROG_FROM_INT(P,X) PROG_FROM_PTR(P,(P)->identifier_references+(X))
 #define ID_FROM_INT(P,X) ID_FROM_PTR(P,(P)->identifier_references+(X))
 
+#define FIND_LFUN(P,N) ((P)->flags & PROGRAM_FIXED?(P)->lfuns[(N)]:find_identifier(lfun_names[(N)],(P)))
+
 #define free_program(p) do{ struct program *_=(p); if(!--_->refs) really_free_program(_); }while(0)
 
 extern struct object fake_object;
-extern struct program fake_program;
+extern struct program *new_program;
+extern int compiler_pass;
+
+#define FOO(NUMTYPE,TYPE,NAME) void add_to_##NAME(TYPE ARG);
+#include "program_areas.h"
 
 /* Prototypes begin here */
+void ins_int(INT32 i, void (*func)(char tmp));
+void ins_short(INT16 i, void (*func)(char tmp));
 void use_module(struct svalue *s);
 int find_module_identifier(struct pike_string *ident);
 struct program *id_to_program(INT32 id);
-void setup_fake_program();
-void start_new_program();
+void optimize_program(struct program *p);
+void fixate_program(void);
+void low_start_new_program(struct program *p,
+			   struct pike_string *name,
+			   int flags);
+void start_new_program(void);
 void really_free_program(struct program *p);
 void dump_program_desc(struct program *p);
-void toss_current_program();
 void check_program(struct program *p);
-struct program *end_program();
+struct program *end_first_pass(int finish);
+struct program *end_program(void);
 SIZE_T add_storage(SIZE_T size);
 void set_init_callback(void (*init)(struct object *));
 void set_exit_callback(void (*exit)(struct object *));
-int low_reference_inherited_identifier(int e,struct pike_string *name);
+int low_reference_inherited_identifier(int e,
+				       struct pike_string *name);
 int reference_inherited_identifier(struct pike_string *super_name,
 				   struct pike_string *function_name);
 void rename_last_inherit(struct pike_string *n);
@@ -240,27 +262,26 @@ void start_line_numbering(void);
 void store_linenumber(INT32 current_line, struct pike_string *current_file);
 char *get_line(unsigned char *pc,struct program *prog,INT32 *linep);
 void my_yyerror(char *fmt,...)  ATTRIBUTE((format(printf,1,2)));
-void compile();
-struct program *compile_file(struct pike_string *file_name);
-struct program *compile_string(struct pike_string *prog,
-			       struct pike_string *name);
+struct program *compile(struct pike_string *prog);
 void add_function(char *name,void (*cfun)(INT32),char *type,INT16 flags);
-void check_all_programs();
-void cleanup_program();
+void check_all_programs(void);
+void cleanup_program(void);
 void gc_mark_program_as_referenced(struct program *p);
-void gc_check_all_programs();
-void gc_mark_all_programs();
-void gc_free_all_unreferenced_programs();
+void gc_check_all_programs(void);
+void gc_mark_all_programs(void);
+void gc_free_all_unreferenced_programs(void);
 void count_memory_in_programs(INT32 *num_, INT32 *size_);
-void push_locals();
-void pop_locals();
+void push_compiler_frame(void);
+void pop_local_variables(int level);
+void pop_compiler_frame(void);
 char *get_storage(struct object *o, struct program *p);
+struct program *low_program_from_function(struct program *p,
+					  INT32 i);
+struct program *program_from_function(struct svalue *f);
+struct find_child_cache_s;
+int find_child(struct program *parent, struct program *child);
 void yywarning(char *fmt, ...) ATTRIBUTE((format(printf,1,2)));
 /* Prototypes end here */
 
 
 #endif
-
-
-
-
diff --git a/src/program_areas.h b/src/program_areas.h
new file mode 100644
index 0000000000000000000000000000000000000000..e932bf85bd10c69565581681fd8927e605370700
--- /dev/null
+++ b/src/program_areas.h
@@ -0,0 +1,14 @@
+/* Who needs templates anyway? / Hubbe */
+
+/* Program *must* be first! */
+FOO(SIZE_T,unsigned char,program)
+FOO(SIZE_T,char,linenumbers)
+FOO(unsigned INT16,struct inherit,inherits)
+FOO(unsigned INT16,struct pike_string *,strings)
+FOO(unsigned INT16,struct reference,identifier_references)
+FOO(unsigned INT16,struct identifier,identifiers)
+FOO(unsigned INT16,unsigned INT16,identifier_index)
+FOO(unsigned INT16,struct svalue, constants)
+
+#undef FOO
+
diff --git a/src/stralloc.c b/src/stralloc.c
index 4cbbeafb885ec6443e8b322898405496dc1dc581..ed88e1f98f5a7d5195758ea2e575802157195f37 100644
--- a/src/stralloc.c
+++ b/src/stralloc.c
@@ -496,9 +496,17 @@ struct pike_string *add_shared_strings(struct pike_string *a,
   buf=ret->str;
   MEMCPY(buf,a->str,a->len);
   MEMCPY(buf+a->len,b->str,b->len);
-  ret=end_shared_string(ret);
+  return end_shared_string(ret);
+}
 
-  return ret;
+struct pike_string *add_and_free_shared_strings(struct pike_string *a,
+						struct pike_string *b)
+{
+  INT32 alen=a->len;
+  a=realloc_shared_string(a,alen + b->len);
+  MEMCPY(a->str+alen,b->str,b->len);
+  free_string(b);
+  return end_shared_string(a);
 }
 
 /*** replace function ***/
diff --git a/src/stralloc.h b/src/stralloc.h
index aeb3b12cf50d4a62c817a3e487b5543ce2c43bfe..d6fa9557f6de5d5831679038be52788780a4ea80 100644
--- a/src/stralloc.h
+++ b/src/stralloc.h
@@ -33,6 +33,12 @@ struct pike_string *debug_findstring(const struct pike_string *foo);
 
 #define reference_shared_string(s) (s)->refs++
 #define copy_shared_string(to,s) ((to)=(s))->refs++
+#define MAKE_CONSTANT_SHARED_STRING(var, text)	\
+ do { static struct pike_string *str_;		\
+    if(!str_) str_=make_shared_string((text));	\
+    copy_shared_string((var), str_);		\
+ }while(0)
+   
 
 /* Prototypes begin here */
 struct pike_string *binary_findstring(const char *foo, INT32 l);
@@ -56,6 +62,8 @@ struct pike_string *realloc_unlinked_string(struct pike_string *a, INT32 size);
 struct pike_string *realloc_shared_string(struct pike_string *a, INT32 size);
 struct pike_string *add_shared_strings(struct pike_string *a,
 					 struct pike_string *b);
+struct pike_string *add_and_free_shared_strings(struct pike_string *a,
+						struct pike_string *b);
 struct pike_string *string_replace(struct pike_string *str,
 				     struct pike_string *del,
 				     struct pike_string *to);
diff --git a/src/stuff.c b/src/stuff.c
index 26ad4a61c8d0909e51de1a07579e1e904f912cd3..9082e74fb559e8c9057d508bdc1930c31b614f6a 100644
--- a/src/stuff.c
+++ b/src/stuff.c
@@ -3,7 +3,9 @@
 ||| Pike is distributed as GPL (General Public License)
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
+#include "global.h"
 #include "stuff.h"
+#include <stdlib.h>
 
 /* same thing as (int)floor(log((double)x) / log(2.0)) */
 /* Except a bit quicker :) (hopefully) */
@@ -71,3 +73,14 @@ int is_more_than_one_bit(unsigned INT32 x)
          ((x & 0xff00ff00UL) && (x & 0x00ff00ffUL)) ||
          ((x & 0xffff0000UL) && (x & 0x0000ffffUL));
 }
+
+double my_strtod(char *nptr, char **endptr)
+{
+  double tmp=STRTOD(nptr,endptr);
+  if(*endptr>nptr)
+  {
+    if(endptr[0][-1]=='.')
+      endptr[0]--;
+  }
+  return tmp;
+}
diff --git a/src/stuff.h b/src/stuff.h
index fc0fe0dd89d2c5f5fa36a508095e46604a1493e0..a67c07939e2c624275724a8a7d00da20bb3030bf 100644
--- a/src/stuff.h
+++ b/src/stuff.h
@@ -12,6 +12,7 @@
 int my_log2(unsigned INT32 x);
 int count_bits(unsigned INT32 x);
 int is_more_than_one_bit(unsigned INT32 x);
+double my_strtod(char *nptr, char **endptr);
 /* Prototypes end here */
 
 #endif
diff --git a/src/svalue.c b/src/svalue.c
index 2e34b6270f2b17a3936eae4392b185ec3357d2d8..565de67fa9fd87ea0e376d0bf04b4d673fc59816 100644
--- a/src/svalue.c
+++ b/src/svalue.c
@@ -394,6 +394,8 @@ int svalue_is_true(struct svalue *s)
     
 }
 
+#define TWO_TYPES(X,Y) (((X)<<8)|(Y))
+
 int is_eq(struct svalue *a, struct svalue *b)
 {
   check_type(a->type);
@@ -406,8 +408,23 @@ int is_eq(struct svalue *a, struct svalue *b)
 
   if (a->type != b->type)
   {
-    if(a->type == T_OBJECT)
+    switch(TWO_TYPES((1<<a->type),(1<<b->type)))
     {
+    case TWO_TYPES(BIT_FUNCTION,BIT_PROGRAM):
+      return program_from_function(a) == b->u.program;
+    
+    case TWO_TYPES(BIT_PROGRAM,BIT_FUNCTION):
+      return program_from_function(b) == a->u.program;
+
+    case TWO_TYPES(BIT_OBJECT, BIT_ARRAY):
+    case TWO_TYPES(BIT_OBJECT, BIT_MAPPING):
+    case TWO_TYPES(BIT_OBJECT, BIT_MULTISET):
+    case TWO_TYPES(BIT_OBJECT, BIT_OBJECT):
+    case TWO_TYPES(BIT_OBJECT, BIT_FUNCTION):
+    case TWO_TYPES(BIT_OBJECT, BIT_PROGRAM):
+    case TWO_TYPES(BIT_OBJECT, BIT_STRING):
+    case TWO_TYPES(BIT_OBJECT, BIT_INT):
+    case TWO_TYPES(BIT_OBJECT, BIT_FLOAT):
       if(a->u.object->prog->lfuns[LFUN_EQ] != -1)
       {
       a_is_obj:
@@ -423,10 +440,16 @@ int is_eq(struct svalue *a, struct svalue *b)
 	  return 1;
 	}
       }
-    }
-
-    if(b->type == T_OBJECT)
-    {
+    if(b->type != T_OBJECT) return 0;
+
+    case TWO_TYPES(BIT_ARRAY,BIT_OBJECT):
+    case TWO_TYPES(BIT_MAPPING,BIT_OBJECT):
+    case TWO_TYPES(BIT_MULTISET,BIT_OBJECT):
+    case TWO_TYPES(BIT_FUNCTION,BIT_OBJECT):
+    case TWO_TYPES(BIT_PROGRAM,BIT_OBJECT):
+    case TWO_TYPES(BIT_STRING,BIT_OBJECT):
+    case TWO_TYPES(BIT_INT,BIT_OBJECT):
+    case TWO_TYPES(BIT_FLOAT,BIT_OBJECT):
       if(b->u.object->prog->lfuns[LFUN_EQ] != -1)
       {
       b_is_obj:
@@ -443,7 +466,6 @@ int is_eq(struct svalue *a, struct svalue *b)
 	}
       }
     }
-
     return 0;
   }
   switch(a->type)
@@ -993,7 +1015,7 @@ INT32 pike_sizeof(struct svalue *s)
       error("sizeof() on destructed object.\n");
     if(s->u.object->prog->lfuns[LFUN__SIZEOF] == -1)
     {
-      return s->u.object->prog->num_identifier_indexes;
+      return s->u.object->prog->num_identifier_index;
     }else{
       apply_lfun(s->u.object, LFUN__SIZEOF, 0);
       if(sp[-1].type != T_INT)
diff --git a/src/testsuite.in b/src/testsuite.in
index 176e186b97653187e0b3b388f312c298476963dc..d796edd591a4aeaaea3c7505f031b18688eb384b 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -1,13 +1,14 @@
-test_true([["$Id: testsuite.in,v 1.40.2.1 1997/05/19 09:04:56 hubbe Exp $"]])
+test_true([["$Id: testsuite.in,v 1.40.2.2 1997/06/25 22:46:46 hubbe Exp $"]])
 test_eq(1e1,10.0)
 test_eq(1E1,10.0)
 test_eq(1e+1,10.0)
 test_eq(1.1e1,11.0)
 test_eq(1e-1,0.1)
+test_compile_error([[void foo() { return destruct(this_object()); }]])
 test_any([[class foo { constant x=17; }; class bar { inherit foo; constant x=18; }; return bar()->x;]],18)
 test_program([[inline string foo(string s){ while(s[0] == ' ' || s[0] == '\t') s = s[1..]; return(s); } string a() { return foo("   bar"); }]])
 test_true([[lambda(function f) {return 1;}(object_program(this_object()));]])
-test_eq([[class { int `()(){ return 4711; } }()(); ]],4711)
+test_eq([[class c { int `()(){ return 4711; } }()(); ]],4711)
 teste_eval_error(mixed foo=({}); sort(@foo); )
 test_compile_error([[int foo() { return 1} ; constant foo=(["foo":foo]); return foo->foo();]])
 test_compile_error([[class T{void p(object e,object f){lambda::create(f);}}]])
@@ -43,12 +44,12 @@ test_any([[ int e; for(e=0;e<100000;e+=1+(e>>4)) if(decode_value(encode_value(-e
 
 
 test_compile_error(int foo() { LJjjjjJJJ ; })
-test_true(clone(class { constant i=1; })->i)
-test_true(clone(class { constant i=0; mixed `->(string s) { if(s=="i") return 1; }})->i)
-test_true(clone(class { constant i=1; mixed `->(string s) { return 0; }})["i"])
-test_true(clone(class { constant i=0; mixed `[](string s) { if(s=="i") return 1; }})["i"])
-test_true(clone(class { mixed `[]=(mixed a, mixed b) { if(a!=b) throw(1); }})[1]=1)
-test_true(clone(class { mixed `->=(mixed a, mixed b) { if(a!=b) throw(1); }})->i="i")
+test_true(clone(class c { constant i=1; })->i)
+test_true(clone(class c { constant i=0; mixed `->(string s) { if(s=="i") return 1; }})->i)
+test_true(clone(class c { constant i=1; mixed `->(string s) { return 0; }})["i"])
+test_true(clone(class c { constant i=0; mixed `[](string s) { if(s=="i") return 1; }})["i"])
+test_true(clone(class c { mixed `[]=(mixed a, mixed b) { if(a!=b) throw(1); }})[1]=1)
+test_true(clone(class c { mixed `->=(mixed a, mixed b) { if(a!=b) throw(1); }})->i="i")
 
 test_compile(class A {}; class B { inherit A; })
 
@@ -68,9 +69,9 @@ test_program(inherit test;)
 test_program(inherit test; int a() { return foo; } )
 test_define_program(test,[[class TEST { int a() { return 1; } }]])
 test_program(inherit test; inherit TEST; )
-test_compile_error(class { object(Stdio.File) foo; object(Regexp) bar=foo; })
-test_do(class { object foo; object(Regexp) bar=foo; })
-test_do(class { object(Stdio.File) foo; object bar=foo; })
+test_compile_error(class c { object(Stdio.File) foo; object(Regexp) bar=foo; })
+test_do(class c { object foo; object(Regexp) bar=foo; })
+test_do(class c { object(Stdio.File) foo; object bar=foo; })
 test_any(if(int i=1) return i; return 0;,1)
 test_compile(for(int i=0;i<100;i++) return 0;)
 test_compile(foreach(({}),mixed i){})
@@ -338,20 +339,20 @@ ifefun(gc,
 [[
   test_true(intp(gc()));
   test_any([[ array a=({0}); a[0]=a; gc(); a=0; return gc() > 0; ]],1);
-  test_any([[object o=class {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);
-  test_any([[object o=class {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);
+  test_any([[object o=class c {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);
+  test_any([[object o=class c {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);
   test_any([[mapping m=([]); m[m]=m; gc(); m=0; return gc() > 0; ]],1);
   test_any([[multiset m=(<>); m[m]=1; gc(); m=0; return gc() > 0; ]],1);
 ]])
 
 
 test_eq("\377"[0],255)
-test_do(add_constant("foo",clone(class {int i;})))
+test_do(add_constant("foo",clone(class c {int i;})))
 test_eq(foo->i,0)
 test_do(foo->i=17)
 test_eq(foo->i,17)
 test_do(add_constant("foo"));
-test_do(add_constant("foo",clone(class {int *i=({0});})))
+test_do(add_constant("foo",clone(class c {int *i=({0});})))
 test_eq(foo->i[0],0)
 test_do(foo->i[0]=17)
 test_eq(foo->i[0],17)
@@ -380,12 +381,12 @@ test_eq(typeof(0.0),"float")
 test_eq(typeof(all_constants()["all_constants"]),"mixed")
 
 // class
-test_true(programp(class {}))
-test_true(functionp(clone(class { int foo() { return 1; }})->foo))
-test_true(clone(class { int foo() { return 1; }})->foo())
-test_true(clone(class { int i=1; })->i)
-test_false(clone(class { int foo() { return 1; }})->bar)
-test_eq(clone(clone(class { program foo=class { int i=20; }; })->foo)->i,20)
+test_true(programp(class c {}))
+test_true(functionp(clone(class c { int foo() { return 1; }})->foo))
+test_true(clone(class c { int foo() { return 1; }})->foo())
+test_true(clone(class c { int i=1; })->i)
+test_false(clone(class c { int foo() { return 1; }})->bar)
+test_eq(clone(clone(class c { program foo=class c { int i=20; }; })->foo)->i,20)
 
 // type checks
 test_compile_error([[} int foo() { return]]);
@@ -1650,10 +1651,11 @@ test_search3($1,($1[..strlen($1)-3]))
 test_search3($1,($1[1..]))
 ]])
 
+dnl some m4 doesn't handle 8 bit characters...
 test_search4("SUNE")
-test_search4("kapit�l>")
+test_search4("kapit\344l>")
 test_search4("-------------------+")
-test_search4("�-------------------")
+test_search4("\345-------------------")
 test_search4(sprintf("%'argel-bargel glop-glyf?'2000n"))
 
 // - sizeof
@@ -1733,7 +1735,7 @@ test_program(inherit test; inherit test2; mixed a() { setw(20); setb(22); return
 test_program(inherit test2; inherit test; mixed a() { w=20; b=22; return getw()==20 && getb()==22; })
 test_program(inherit test2; inherit test; mixed a() { setw(20); setb(22); return w==20 && b==22; })
 
-test_eval_error(clone(class{int i;void foo(){ destruct(this_object());i=0;}})->foo())
+test_eval_error(clone(class c{int i;void foo(){ destruct(this_object());i=0;}})->foo())
 
 // Pike modules
 // LR
diff --git a/src/version.c b/src/version.c
index b46b54042e853799bdef3da79801b164dd958810..767fbc08c53aba2b235f6c14acc84ebf9bd231b8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -12,5 +12,5 @@
 void f_version(INT32 args)
 {
   pop_n_elems(args);
-  push_text("Pike v0.5b6");
+  push_text("Pike v0.6a1");
 }