/* Generated from "/Users/hww3/devel/pike/src/pike_compiler.cmod" by precompile.pike running Pike v8.1 release 13
 *
 * Do NOT edit this file.
 */

#undef PRECOMPILE_API_VERSION
#define PRECOMPILE_API_VERSION 6



#undef cmod___CMOD__
#define cmod___CMOD__ 1
#line 1 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#line 1 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#line 1 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#line 3488 "/Users/hww3/devel/pike/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike"







#line 3495 "/Users/hww3/devel/pike/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike"
#line 1 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#line 1 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
/* -*- mode: c; encoding: utf-8; -*-
|| This file is part of Pike. For copyright information see COPYRIGHT.
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
|| for more information.
*/

#include "global.h"
#include "program.h"
#include "object.h"
#include "buffer.h"
#include "pike_types.h"
#include "stralloc.h"
#include "las.h"
#include "lex.h"
#include "pike_macros.h"
#include "fsort.h"
#include "pike_error.h"
#include "docode.h"
#include "interpret.h"
#include "main.h"
#include "pike_memory.h"
#include "gc.h"
#include "threads.h"
#include "constants.h"
#include "operators.h"
#include "builtin_functions.h"
#include "mapping.h"
#include "cyclic.h"
#include "opcodes.h"
#include "version.h"
#include "block_allocator.h"
#include "block_alloc.h"
#include "pikecode.h"
#include "pike_compiler.h"
#include "module_support.h"
#include "bitvector.h"
#include "sprintf.h"
#include "cpp.h"

#include <errno.h>
#include <fcntl.h>

#ifdef PIKE_THREADS
static COND_T Pike_compiler_cond;
static THREAD_T Pike_compiler_thread;
static int lock_depth = 0;

PMOD_EXPORT void lock_pike_compiler(void)
{
  if (lock_depth && (Pike_compiler_thread != th_self())) {
    SWAP_OUT_CURRENT_THREAD();
    while (lock_depth && (Pike_compiler_thread != th_self())) {
      co_wait_interpreter(&Pike_compiler_cond);
    }
    SWAP_IN_CURRENT_THREAD();
  }
  lock_depth++;
  Pike_compiler_thread = th_self();
}

PMOD_EXPORT void unlock_pike_compiler(void)
{
#ifdef PIKE_DEBUG
  if (lock_depth < 1) {
    Pike_fatal("Pike compiler running unlocked!\n");
  }
#endif
  lock_depth--;
  co_broadcast(&Pike_compiler_cond);
}
#else
PMOD_EXPORT void lock_pike_compiler(void)
{
}
PMOD_EXPORT void unlock_pike_compiler(void)
{
}
#endif

static void low_enter_compiler(struct object *ce, int inherit);

/* #define COMPILER_DEBUG */
/* #define PROGRAM_BUILD_DEBUG */

#ifdef COMPILER_DEBUG
#define CDFPRINTF(...)	fprintf(stderr, __VA_ARGS__)
#ifndef PIKE_THREADS
/* The CDFPRINTF lines wants to print lock_depth, so fake one of those */
static const int lock_depth = 1;
#endif
#else /* !COMPILER_DEBUG */
#define CDFPRINTF(...)
#endif /* COMPILER_DEBUG */

struct program *reporter_program = NULL;
struct program *compilation_program = 0;
struct program *compilation_env_program = 0;
struct object *compilation_environment = NULL;

/*
 * Supporters.
 *
 * Supporters are used to register that a program being compiled depends on
 * another program that also is being compiled.
 *
 * Every program being compiled has a supporter (in the compilation
 * struct).
 */

struct Supporter *current_supporter=0;


#ifdef PIKE_DEBUG

struct supporter_marker
{
  struct supporter_marker *next;
  void *data;
  int level, verified;
};

#undef INIT_BLOCK
#define INIT_BLOCK(X) do { (X)->level = (X)->verified = 0; }while(0)
PTR_HASH_ALLOC(supporter_marker, 128);

static int supnum;

#define SNUM(X) (get_supporter_marker((X))->level)

static void mark_supporters(struct Supporter *s)
{
  struct supporter_marker *m;

  if(!s) return;
  debug_malloc_touch(s);
  m=get_supporter_marker(s);

  if(m->level) return;
  m->level = -1;

  if(s->magic != 0x500b0127)
  {
#ifdef DEBUG_MALLOC
    describe(s);
#endif
    Pike_fatal("This is not a supporter (addr=%p, magic=%x)!\n",s,s->magic);
  }

  mark_supporters(s->dependants);
  mark_supporters(s->next_dependant);

  m->level=supnum++;

  mark_supporters(s->previous);
  mark_supporters(s->depends_on);
}

static void low_verify_supporters(struct Supporter *s)
{
  struct Supporter *ss;
  struct supporter_marker *m;

  if(!s) return;
  debug_malloc_touch(s);
  m=get_supporter_marker(s);

  if(m->verified) return;
  m->verified = 1;

  low_verify_supporters(s->dependants);
  low_verify_supporters(s->next_dependant);

#if 0
  fprintf(stderr, "low_verify_supporters %p%s, level %d: "
	  "previous %p, depends_on %p, dependants %p, next_dependant %p\n",
	  s, s == current_supporter ? " == current_supporter" : "",
	  m->level, s->previous, s->depends_on, s->dependants, s->next_dependant);
#endif

  if(s->previous && SNUM(s->previous) <= m->level)
    Pike_fatal("Que, numbers out of whack1 (%ld <= %ld)\n",
	       (long)SNUM(s->previous), (long)m->level);

  if(s->depends_on && SNUM(s->depends_on) <= m->level)
    Pike_fatal("Que, numbers out of whack2 (%ld <= %ld)\n",
	       (long)SNUM(s->depends_on), (long)m->level);

  for(ss=s->dependants;ss;ss=ss->next_dependant) {
    if (ss->depends_on != s)
      Pike_fatal("Dependant hasn't got depends_on set properly.\n");
    if(SNUM(ss) >= m->level)
      Pike_fatal("Que, numbers out of whack3 (%ld >= %ld)\n",
		 (long)SNUM(ss), (long)m->level);
  }

  low_verify_supporters(s->previous);
  low_verify_supporters(s->depends_on);
}

void verify_supporters()
{
  if(d_flag)
  {
    supnum=1;
    init_supporter_marker_hash();

#if 0
    fprintf(stderr, "verify_supporters start\n");
#endif

    mark_supporters(current_supporter);
    low_verify_supporters(current_supporter);
#ifdef DO_PIKE_CLEANUP
    {
      size_t e=0;
      for(e=0;e<supporter_marker_hash_table_size;e++)
	while(supporter_marker_hash_table[e])
	  remove_supporter_marker(supporter_marker_hash_table[e]->data);
    }
#endif
    exit_supporter_marker_hash();

#if 0
    fprintf(stderr, "verify_supporters end\n");
#endif
  }
}
#else
#define verify_supporters();
#endif

void init_supporter(struct Supporter *s,
		    supporter_callback *fun,
		    void *data)
{
  CDFPRINTF("th(%ld) init_supporter() supporter=%p data=%p.\n",
            (long) th_self(), s, data);
  verify_supporters();
#ifdef PIKE_DEBUG
  s->magic = 0x500b0127;
#endif
  s->previous=current_supporter;
  current_supporter=s;

  s->depends_on=0;
  s->dependants=0;
  s->next_dependant=0;
  s->fun=fun;
  s->exit_fun=NULL;
  s->data=data;
  s->prog=0;
  verify_supporters();
}

int unlink_current_supporter(struct Supporter *c)
{
  int ret=0;
#ifdef PIKE_DEBUG
  if(c != current_supporter)
    Pike_fatal("Previous unlink failed.\n");
#endif
  debug_malloc_touch(c);
  verify_supporters();
  if(c->depends_on)
  {
#ifdef PIKE_DEBUG
    struct Supporter *s;
    for (s = c->depends_on->dependants; s; s = s->next_dependant)
      if (s == c) Pike_fatal("Dependant already linked in.\n");
#endif
    ret++;
    c->next_dependant = c->depends_on->dependants;
    c->depends_on->dependants=c;
    add_ref(c->self.u.object);
    CDFPRINTF("th(%ld) unlink_current_supporter() "
              "supporter=%p (prog %p) depends on %p (prog %p).\n",
              (long) th_self(), c, c->prog,
              c->depends_on, c->depends_on->prog);
  }
  current_supporter=c->previous;
#ifdef PIKE_DEBUG
  c->previous=0;
#endif
  verify_supporters();
  return ret;
}

void free_supporter(struct Supporter *c)
{
  verify_supporters();
  if (c->depends_on) {
    struct Supporter **s;
    for (s = &c->depends_on->dependants; *s; s = &(*s)->next_dependant)
      if (*s == c) {*s = c->next_dependant; break;}
    c->depends_on = 0;
  }
  if (c->exit_fun) c->exit_fun(c);
  verify_supporters();
}

int call_dependants(struct Supporter *s, int finish)
{
  int ok = 1;
  struct Supporter *tmp;
  CDFPRINTF("th(%ld) call_dependants() supporter=%p (prog %p) "
            "finish=%d.\n", (long) th_self(), s, s->prog, finish);
  verify_supporters();
  while((tmp=s->dependants))
  {
    CDFPRINTF("th(%ld) dependant: %p (prog %p) (data:%p).\n",
              (long) th_self(), tmp, tmp->prog, tmp->data);
    s->dependants=tmp->next_dependant;
#ifdef PIKE_DEBUG
    tmp->next_dependant=0;
#endif
    verify_supporters();
    if (!tmp->fun(tmp, finish)) ok = 0;
    verify_supporters();
    free_object(tmp->self.u.object);
  }
  return ok;
}

int report_compiler_dependency(struct program *p)
{
  int ret=0;
  struct Supporter *c,*cc;

  if (p == Pike_compiler->new_program) {
    /* Depends on self... */
    return 0;
  }

  CDFPRINTF("th(%ld) compiler dependency on %p from %p\n",
            (long)th_self(), p, Pike_compiler->new_program);

  verify_supporters();
  if (Pike_compiler->flags & COMPILATION_FORCE_RESOLVE)
    return 0;
  for(cc=current_supporter;cc;cc=cc->previous)
  {
    if(cc->prog &&
       !(cc->prog->flags & PROGRAM_PASS_1_DONE))
    {
      c=cc->depends_on;
      if(!c) c=cc->previous;
      for(;c;c=c->previous)
      {
	if(c->prog == p)
	{
	  cc->depends_on=c;
          CDFPRINTF("th(%ld) supporter %p (prog %p) "
                    "now depends on %p (prog %p)\n",
                    (long) th_self(), cc, cc->prog, c, c->prog);
	  verify_supporters();
	  ret++; /* dependency registred */
	}
      }
    }
  }
  verify_supporters();
  return ret;
}

extern int yyparse(void);

static void do_yyparse(void)
{
  struct svalue *save_sp = Pike_sp;
  yyparse();  /* Parse da program */
  if (save_sp != Pike_sp) {
#ifdef PIKE_DEBUG
    if (!Pike_compiler->num_parse_error) {
      Pike_fatal("yyparse() left %"PRINTPTRDIFFT"d droppings on the stack!\n",
		 Pike_sp - save_sp);
    }
#endif
    pop_n_elems(Pike_sp - save_sp);
  }
}

/*! @class Reporter
 *!
 *!   API for reporting parse errors and similar.
 */

/*! @decl enum SeverityLevel
 *!   Message severity level.
 *! { NOTICE, WARNING, ERROR, FATAL }
 *!
 *! @constant NOTICE
 *! @constant WARNING
 *! @constant ERROR
 *! @constant FATAL
 *!
 *! @seealso
 *!   @[report()]
 */

/*! @decl void report(SeverityLevel severity, @
 *!                   string filename, int(1..) linenumber, @
 *!                   string subsystem, @
 *!                   string message, mixed ... extra_args)
 *!
 *!   Report a diagnostic from the compiler.
 *!
 *! @param severity
 *!   The severity of the diagnostic.
 *!
 *! @param filename
 *! @param linenumber
 *!   Location which triggered the diagnostic.
 *!
 *! @param subsystem
 *!   Compiler subsystem that generated the diagnostic.
 *!
 *! @param message
 *!   @[sprintf()]-style formatting string with the diagnostic message.
 *!
 *! @param extra_args
 *!   Extra arguments to @[sprintf()].
 *!
 *!   The default implementation does the following:
 *!
 *!   @ul
 *!     @item
 *!       If there's a @[MasterObject()->report()], call it
 *!       with the same arguments as ourselves.
 *!     @item
 *!       Otherwise depending on @[severity]:
 *!       @int
 *!         @value NOTICE
 *!           Ignored.
 *!         @value WARNING
 *!           Calls @[MasterObject()->compile_warning()].
 *!         @value ERROR
 *!         @value FATAL
 *!           Calls @[MasterObject()->compile_error()].
 *!       @endint
 *!   @endul
 *!
 *!   If there's no master object yet, the diagnostic is output to
 *!   @[Stdio.stderr].
 *!
 *! @note
 *!   In Pike 7.8 and earlier @[MasterObject()->report()] was not called.
 *!
 *! @seealso
 *!   @[PikeCompiler()->report()]
 */
/* NOTE: This function MUST NOT use any storage in the Reporter program! */
static void f_reporter_report(INT32 args)
{
  int level;
  struct pike_string *filename;
  INT_TYPE linenumber;
  struct pike_string *subsystem;
  struct pike_string *message;
  struct object *master_ob;

  if ((master_ob = get_master()) && master_ob->prog) {
    int fun = find_identifier("report", master_ob->prog);
    if (fun >= 0) {
      apply_low(master_ob, fun, args);
      return;
    }
  }

  if (args > 5) {
    f_sprintf(args - 4);
    args = 5;
  }
  get_all_args(NULL, args, "%d%W%+%W%W",
	       &level, &filename, &linenumber, &subsystem, &message);

  /* Ignore informational level messages */
  if (level >= REPORT_WARNING) {
    if (master_ob && master_ob->prog) {
      ref_push_string(filename);
      push_int(linenumber);
      ref_push_string(message);
      if (level >= REPORT_ERROR) {
	APPLY_MASTER("compile_error", 3);
	args++;
      } else {
	APPLY_MASTER("compile_warning", 3);
	args++;
      }
    } else {
      /* We hope that errors from compiling the master
       * won't contain wide-strings... */
      if (level >= REPORT_ERROR) {
	fprintf(stderr, "%s:%ld: %s\n",
		filename->str, (long)linenumber, message->str);
      } else {
	fprintf(stderr, "%s:%ld: Warning: %s\n",
		filename->str, (long)linenumber, message->str);
      }
      fflush(stderr);
    }
  }
  pop_n_elems(args);
  push_int(0);
}

/*! @endclass
 */

/*! @module DefaultCompilerEnvironment
 *!
 *!   The @[CompilerEnvironment] object that is used
 *!   for loading C-modules and by @[predef::compile()].
 *!
 *! @note
 *!   @[predef::compile()] is essentially an alias for the
 *!   @[CompilerEnvironment()->compile()] in this object.
 *!
 *! @seealso
 *!   @[CompilerEnvironment], @[predef::compile()]
 */

/*! @decl inherit CompilerEnvironment
 */

/*! @endmodule
 */

/*! @class CompilerEnvironment
 *!
 *!   The compiler environment.
 *!
 *!   By inheriting this class and overloading the functions,
 *!   it is possible to make a custom Pike compiler.
 *!
 *! @note
 *!   Prior to Pike 7.8 this sort of customization has to be done
 *!   either via custom master objects, or via @[CompilationHandler]s.
 *!
 *! @seealso
 *!   @[CompilationHandler], @[MasterObject], @[master()], @[replace_master()]
 */

/*! @decl inherit Reporter
 *!
 *! Implements the @[Reporter] API.
 *!
 *! @seealso
 *!   @[Reporter()->report()], @[Reporter()->SeverityLevel]
 */

/*! @class lock
 *!
 *! This class acts as a lock against other threads accessing the compiler.
 *!
 *! The lock is released when the object is destructed.
 */

static void compiler_environment_lock_event_handler(int e)
{
  switch(e) {
  case PROG_EVENT_INIT:
    lock_pike_compiler();
    break;
  case PROG_EVENT_EXIT:
    unlock_pike_compiler();
    break;
  }
}

/*! @endclass
 */

/*! @decl program compile(string source, CompilationHandler|void handler, @
 *!                       int|void major, int|void minor,@
 *!                       program|void target, object|void placeholder)
 *!
 *!   Compile a string to a program.
 *!
 *!   This function takes a piece of Pike code as a string and
 *!   compiles it into a clonable program.
 *!
 *!   The optional argument @[handler] is used to specify an alternative
 *!   error handler. If it is not specified the current master object will
 *!   be used.
 *!
 *!   The optional arguments @[major] and @[minor] are used to tell the
 *!   compiler to attempt to be compatible with Pike @[major].@[minor].
 *!
 *! @note
 *!   This function essentially performs
 *!   @code
 *!     program compile(mixed ... args)
 *!     {
 *!       return PikeCompiler(@@args)->compile();
 *!     }
 *!   @endcode
 *!
 *! @note
 *!   Note that @[source] must contain the complete source for a program.
 *!   It is not possible to compile a single expression or statement.
 *!
 *!   Also note that @[compile()] does not preprocess the program.
 *!   To preprocess the program you can use @[compile_string()] or
 *!   call the preprocessor manually by calling @[cpp()].
 *!
 *! @seealso
 *!   @[compile_string()], @[compile_file()], @[cpp()], @[master()],
 *!   @[CompilationHandler]
 */
static void f_compilation_env_compile(INT32 args)
{
  apply_current(CE_PIKE_COMPILER_FUN_NUM, args);
  args = 1;
  if (TYPEOF(Pike_sp[-1]) != T_OBJECT) {
    Pike_error("Bad return value from PikeCompiler().\n");
  }
  apply(Pike_sp[-1].u.object, "compile", 0);
  stack_pop_n_elems_keep_top(args);
}

/*! @decl mixed resolv(string identifier, string filename, @
 *!		       object|void handler, object|void compat_handler)
 *!
 *!   Look up @[identifier] in the current context.
 *!
 *!   The default implementation calls the corresponding
 *!   function in the handlers (if any), falling back to
 *!   the master object.
 *!
 *! @returns
 *!   Returns the value of the @[identifier] if found, and
 *!   @[UNDEFINED] if not.
 */
static void f_compilation_env_resolv(INT32 args)
{
  struct pike_string *ident;
  struct pike_string *filename;
  struct object *handler = NULL;
  struct object *compat_handler = NULL;

  get_all_args(NULL, args, "%W%W.%O%O",
	       &ident, &filename, &handler, &compat_handler);

  if(get_master())
  {
    DECLARE_CYCLIC();
    if(BEGIN_CYCLIC(ident, filename))
    {
      my_yyerror("Recursive module dependency in %S.", ident);
    }else{
      SET_CYCLIC_RET(1);

      low_unsafe_apply_handler("resolv", handler, compat_handler, args);
    }
    END_CYCLIC();
  } else {
    pop_n_elems(args);
    push_undefined();
  }
}

/*! @decl object get_compilation_handler(int major, int minor)
 *!
 *!   Get compatibility handler for Pike @[major].@[minor].
 *!
 *!   The default implementation calls the corresponding
 *!   function in the master object.
 *!
 *! @note
 *!   This function is typically called by
 *!   @[PikeCompiler()->get_compilation_handler()].
 *!
 *! @seealso
 *!   @[MasterObject()->get_compilation_handler()].
 */
static void f_compilation_env_get_compilation_handler(INT32 args)
{
  if(get_master())
  {
    APPLY_MASTER("get_compilation_handler", args);
  } else {
    pop_n_elems(args);
    push_undefined();
  }
}

/*! @decl mapping(string:mixed)|object get_default_module()
 *!
 *!   Get the default module for the current compatibility level
 *!   (ie typically the value returned by @[predef::all_constants()]).
 *!
 *!   The default implementation calls the corresponding function
 *!   in the master object.
 *!
 *! @returns
 *!   @mixed
 *!     @type mapping(string:mixed)|object
 *!       Constant table to use.
 *!
 *!     @type int(0..0)
 *!       Use the builtin constant table.
 *!   @endmixed
 *!
 *! @note
 *!   This function is typically called by
 *!   @[Pike_compiler()->get_default_module()].
 *!
 *! @seealso
 *!   @[MasterObject()->get_default_module()].
 */
static void f_compilation_env_get_default_module(INT32 args)
{
  if(get_master())
  {
    APPLY_MASTER("get_default_module", args);
  } else {
    pop_n_elems(args);
    push_undefined();
  }
}

/*! @decl program handle_inherit(string inh, string current_file, @
 *!                              object|void handler)
 *!
 *!   Look up an inherit @[inh].
 *!
 *!   The default implementation calls the corresponding function
 *!   in the master object.
 *!
 *! @seealso
 *!   @[MasterObject()->handle_inherit()].
 */
static void f_compilation_env_handle_inherit(INT32 args)
{
  if(get_master())
  {
    APPLY_MASTER("handle_inherit", args);
  } else {
    pop_n_elems(args);
    push_undefined();
  }
}

/*! @decl program handle_import(string module, string current_file, @
 *!                             object|void handler)
 *!
 *!   Look up an import @[module].
 *!
 *!   The default implementation calls the corresponding function
 *!   in the master object.
 *!
 *! @seealso
 *!   @[MasterObject()->handle_import()].
 */
static void f_compilation_env_handle_import(INT32 args)
{
  if(get_master())
  {
    APPLY_MASTER("handle_import", args);
  } else {
    pop_n_elems(args);
    push_undefined();
  }
}

#if 0
/* @decl int filter_exception(SeverityLevel level, mixed err)
 *
 *   The default implementation calls
 *   @[MasterObject()->compile_exception()] for @[level] @[ERROR]
 *   and @[FATAL].
 *
 * @note
 *   This function is not implemented in Pike 7.8.
 *
 * @seealso
 *   @[MasterObject()->compile_exception()].
 */
static void f_compilation_env_filter_exception(INT32 args)
{
  int level;
  struct svalue *err;

  get_all_args(NULL, args, "%d%*", &level, &err);
  if (args > 2) {
    pop_n_elems(args-2);
    args = 2;
  }

#if 0
  if (level >= REPORT_WARNING) {
    if (level >= REPORT_ERROR) {
      APPLY_MASTER("compile_exception", 1);
      /* FIXME! */
    } else {
      push_int(level);
      push_string(format_exception_for_error_msg(err));
      /* FIXME! */
    }
  }
#endif

  pop_n_elems(args);
  push_undefined();
  return;
}
#endif

/*! @class PikeCompiler
 *!
 *!   The Pike compiler.
 *!
 *!   An object of this class compiles a single string
 *!   of Pike code.
 */

/*! @decl int current_line
 *!
 *!   The current line number (during an active compilation).
 */

/*! @decl string current_file
 *!
 *!   The name of the file currently being compiled (during an active
 *!   compilation).
 */

void node_walker(struct ba_iterator * it, void * UNUSED(data)) {
  do {
    node * tmp = ba_it_val(it);

    /*
     * since we free nodes from here, we might iterate over them again.
     * to avoid that we check for the free mark.
     */
    if (tmp->token == USHRT_MAX) continue;

#ifdef PIKE_DEBUG
    if(!cumulative_parse_error)
    {
      fprintf(stderr,"Free node at %p, (%s:%ld) (token=%d:%s).\n",
              (void *)tmp,
              tmp->current_file->str, (long)tmp->line_number,
              tmp->token, get_token_name(tmp->token));

      debug_malloc_dump_references(tmp,0,2,0);

      if(tmp->token==F_CONSTANT)
        print_tree(tmp);
    }
    /* else */
#endif
    {
      /* Free the node and be happy */
      /* Make sure we don't free any nodes twice */
      if(car_is_node(tmp)) _CAR(tmp)=0;
      if(cdr_is_node(tmp)) _CDR(tmp)=0;
#ifdef PIKE_DEBUG
      if (l_flag > 3) {
        fprintf(stderr, "Freeing node that had %d refs.\n",
                tmp->refs);
      }
#endif /* PIKE_DEBUG */
      /* Force the node to be freed. */
      tmp->refs = 1;
      debug_malloc_touch(tmp->type);
      free_node(tmp);
    }
  } while (ba_it_step(it));
}

static void free_compilation(struct compilation *c)
{
  debug_malloc_touch(c);
  if (c->prog) {
    free_string(c->prog);
    c->prog = NULL;
  }
#ifdef SUPPORT_COMPILER_HANDLERS
  if(c->handler) {
    free_object(c->handler);
    c->handler = NULL;
  }
  if(c->compat_handler) {
    free_object(c->compat_handler);
    c->compat_handler = NULL;
  }
#endif /* SUPPORT_COMPILER_HANDLERS */
  if(c->target) {
    free_program(c->target);
    c->target = NULL;
  }
  if(c->p) {
    free_program(c->p);
    c->p = NULL;
  }
  if(c->placeholder) {
    free_object(c->placeholder);
    c->placeholder = NULL;
  }
  if(c->lex.current_file) {
    free_string(c->lex.current_file);
    c->lex.current_file = NULL;
  }
  if(c->lex.attributes) {
    free_node(c->lex.attributes);
    c->lex.attributes = NULL;
  }
  if (c->resolve_cache) {
    free_mapping(c->resolve_cache);
    c->resolve_cache = NULL;
  }
  free_svalue(& c->default_module);
  SET_SVAL(c->default_module, T_INT, NUMBER_NUMBER, integer, 0);
  free_supporter(&c->supporter);
  verify_supporters();

#ifndef PIKE_DEBUG
  if(cumulative_parse_error)
#endif
  {
    /* NB: The Pike_compiler has already been changed when we run,
     *     so we need to reinstate a compiler that refers to us
     *     during the ba_walk(), so that really_free_node_s() can
     *     find the node_allocator.
     */
    struct program_state fake_compiler, *orig_compiler = Pike_compiler;
    fake_compiler.compiler = c;
    Pike_compiler = &fake_compiler;

    ba_walk(&c->node_allocator, &node_walker, NULL);

    Pike_compiler = orig_compiler;

#ifdef PIKE_DEBUG
    if(!cumulative_parse_error) {
      size_t n, s;
      ba_count_all(&c->node_allocator, &n, &s);
      if (n)
	Pike_fatal("Failed to free %"PRINTSIZET"d nodes when compiling!\n",n);
    }
#endif
  }
  cumulative_parse_error=0;
  ba_destroy(&c->node_allocator);
}

static void run_init(struct compilation *c)
{
  debug_malloc_touch(c);

#ifdef SUPPORT_COMPILER_HANDLERS
  if (c->compat_handler) free_object(c->compat_handler);
  c->compat_handler=0;
#endif /* SUPPORT_COMPILER_HANDLERS */

  if (c->resolve_cache) {
    free_mapping(c->resolve_cache);
    c->resolve_cache = 0;
  }

  c->lex.current_line=1;
  free_string(c->lex.current_file);
  c->lex.current_file=make_shared_string("-");

  c->lex.attributes = NULL;

  if (runtime_options & RUNTIME_STRICT_TYPES)
  {
    c->lex.pragmas = ID_STRICT_TYPES;
  } else {
    c->lex.pragmas = 0;
  }

  c->lex.end = c->prog->str + (c->prog->len << c->prog->size_shift);

  switch(c->prog->size_shift)
  {
    case 0: c->lex.current_lexer = yylex0; break;
    case 1: c->lex.current_lexer = yylex1; break;
    case 2: c->lex.current_lexer = yylex2; break;
  }

  c->lex.pos=c->prog->str;
}

static void run_init2(struct compilation *c)
{
#if 0
  int i;
  struct program *p;
  struct reference *refs;
#endif /* 0 */
  debug_malloc_touch(c);
  Pike_compiler->compiler = c;

  /* Get the proper default module. */
  safe_apply_current2(PC_GET_DEFAULT_MODULE_FUN_NUM, 0, NULL);
  if(TYPEOF(Pike_sp[-1]) == T_INT)
  {
    pop_stack();
    ref_push_mapping(get_builtin_constants());
  }
  assign_svalue(&c->default_module, Pike_sp-1);
  pop_stack();

  use_module(& c->default_module);

  Pike_compiler->compat_major=PIKE_MAJOR_VERSION;
  Pike_compiler->compat_minor=PIKE_MINOR_VERSION;

  if(c->major>=0)
    change_compiler_compatibility(c->major, c->minor);

#if 0
  /* Make all inherited private symbols that weren't overloaded
   * in the first pass local.
   */
  p = c->new_program;
  i = p->num_identifier_references;
  refs = p->identifier_references;
  while (i--) {
    if (refs[i].id_flags & ID_PRIVATE) refs[i].id_flags |= ID_INLINE;
  }
#endif /* 0 */
}

static void run_exit(struct compilation *c)
{
  debug_malloc_touch(c);

#ifdef PIKE_DEBUG
  if(c->num_used_modules)
    Pike_fatal("Failed to pop modules properly.\n");
#endif

#ifdef PIKE_DEBUG
  if (c->compilation_depth != -1) {
    fprintf(stderr, "compile(): compilation_depth is %d\n",
	    c->compilation_depth);
  }
#endif /* PIKE_DEBUG */

  if (c->resolve_cache) {
    free_mapping(c->resolve_cache);
    c->resolve_cache = NULL;
  }

  verify_supporters();
}

static void zap_placeholder(struct compilation *c)
{
  /* fprintf(stderr, "Destructing placeholder.\n"); */
  if (c->placeholder->storage) {
    yyerror("Placeholder already has storage!");
#if 0
    fprintf(stderr, "Placeholder already has storage!\n"
	    "placeholder: %p, storage: %p, prog: %p\n",
	    c->placeholder, c->placeholder->storage, c->placeholder->prog);
#endif
    debug_malloc_touch(c->placeholder);
    destruct(c->placeholder);
  } else {
    /* FIXME: Is this correct? */
    /* It would probably be nicer if it was possible to just call
     * destruct on the object, but this works too. -Hubbe
     */
    free_program(c->placeholder->prog);
    c->placeholder->prog = NULL;
    debug_malloc_touch(c->placeholder);
  }
  free_object(c->placeholder);
  c->placeholder=0;
  verify_supporters();
}

/* NOTE: Must not throw errors! */
static int run_pass1(struct compilation *c)
{
  int ret=0;

  debug_malloc_touch(c);
  run_init(c);

#if 0
  CDFPRINTF("th(%ld) compile() starting compilation_depth=%d\n",
            (long)th_self(), c->compilation_depth);
#endif

  if(c->placeholder && c->placeholder->prog != null_program) {
    yyerror("Placeholder object is not a null_program clone!");
    return 0;
  }
  debug_malloc_touch(c->placeholder);

  if(c->target && !(c->target->flags & PROGRAM_VIRGIN)) {
    yyerror("Placeholder program is not virgin!");
    return 0;
  }

  low_start_new_program(c->target, COMPILER_PASS_FIRST, 0, 0, 0);
  c->supporter.prog = Pike_compiler->new_program;

  CDFPRINTF("th(%ld) %p run_pass1() start: "
            "lock_depth:%d, compilation_depth:%d\n",
            (long)th_self(), Pike_compiler->new_program,
            lock_depth, c->compilation_depth);

  run_init2(c);

  if(c->placeholder)
  {
    if(c->placeholder->prog != null_program)
    {
      yyerror("Placeholder argument is not a null_program clone!");
      c->placeholder=0;
      debug_malloc_touch(c->placeholder);
    }else{
      free_program(c->placeholder->prog);
      add_ref(c->placeholder->prog=Pike_compiler->new_program);
#ifdef PIKE_DEBUG
      c->placeholder->program_id = Pike_compiler->new_program->id;
#endif
      debug_malloc_touch(c->placeholder);
    }
  }

#if 0
  CDFPRINTF("th(%ld) %p compile(): First pass\n",
            (long)th_self(), Pike_compiler->new_program);
#endif

  do_yyparse();  /* Parse da program */

  if (!Pike_compiler->new_program->num_linenumbers) {
    /* The lexer didn't write an initial entry. */
    store_linenumber(0, c->lex.current_file);
#ifdef DEBUG_MALLOC
    if(strcmp(c->lex.current_file->str,"-"))
      debug_malloc_name(Pike_compiler->new_program, c->lex.current_file->str, 0);
#endif
  }

  CDFPRINTF("th(%ld) %p run_pass1() done for %s\n",
            (long)th_self(), Pike_compiler->new_program,
            c->lex.current_file->str);

  ret=unlink_current_supporter(& c->supporter);

  c->p=debug_malloc_pass(end_first_pass(0));

  run_exit(c);

  if(c->placeholder)
  {
    if(!c->p || (c->placeholder->storage))
    {
      debug_malloc_touch(c->placeholder);
      zap_placeholder(c);
    } else {
#ifdef PIKE_DEBUG
      if (c->placeholder->prog != c->p)
	Pike_fatal("Placeholder object got wrong program after first pass.\n");
#endif
      debug_malloc_touch(c->placeholder);
      c->placeholder->storage=c->p->storage_needed ?
	(char *)xcalloc(c->p->storage_needed, 1) :
	(char *)NULL;
      call_c_initializers(c->placeholder);
    }
  }

  verify_supporters();
  return ret;
}

void run_pass_extra(struct compilation *c)
{
  debug_malloc_touch(c);
  debug_malloc_touch(c->placeholder);

  if (!c->p) {
    c->flags &= ~(COMPILER_BUSY);
    c->flags |= COMPILER_DONE;
    return;
  }

  run_init(c);
  low_start_new_program(c->p, COMPILER_PASS_EXTRA, 0, 0, 0);
  free_program(c->p);
  c->p=0;

  run_init2(c);

  CDFPRINTF("th(%ld) %p run_pass_extra() start: "
            "lock_depth:%d, compilation_depth:%d\n",
            (long)th_self(), Pike_compiler->new_program,
            lock_depth, c->compilation_depth);

  verify_supporters();

  do_yyparse();  /* Parse da program */

  CDFPRINTF("th(%ld) %p run_pass2() done for %s\n",
            (long)th_self(), Pike_compiler->new_program,
            c->lex.current_file->str);

  verify_supporters();

  c->p=debug_malloc_pass(end_first_pass(0));

  run_exit(c);
}

void run_pass2(struct compilation *c)
{
  debug_malloc_touch(c);
  debug_malloc_touch(c->placeholder);

  if (!c->p) {
    c->flags &= ~(COMPILER_BUSY);
    c->flags |= COMPILER_DONE;
    return;
  }

  run_init(c);
  low_start_new_program(c->p, COMPILER_PASS_LAST, 0, 0, 0);
  free_program(c->p);
  c->p=0;

  run_init2(c);

  CDFPRINTF("th(%ld) %p run_pass2() start: "
            "lock_depth:%d, compilation_depth:%d\n",
            (long)th_self(), Pike_compiler->new_program,
            lock_depth, c->compilation_depth);

  verify_supporters();

  do_yyparse();  /* Parse da program */

  CDFPRINTF("th(%ld) %p run_pass2() done for %s\n",
            (long)th_self(), Pike_compiler->new_program,
            c->lex.current_file->str);

  verify_supporters();

  c->p=debug_malloc_pass(end_program());

  run_exit(c);
}

static void run_cleanup(struct compilation *c, int delayed)
{
  debug_malloc_touch(c);
  debug_malloc_touch(c->placeholder);
#if 0 /* FIXME */
#ifdef PIKE_THREADS
  if (lock_depth != c->saved_lock_depth) {
    Pike_fatal("compile(): lock_depth:%d saved_lock_depth:%d\n",
	       lock_depth, c->saved_lock_depth);
  }
#endif
#endif /* PIKE_DEBUG */

  unlock_pike_compiler();

  CDFPRINTF("th(%ld) %p run_cleanup(): "
            "lock_depth:%d, compilation_depth:%d\n",
            (long)th_self(), c->target,
            lock_depth, c->compilation_depth);
  if (!c->p)
  {
    /* fprintf(stderr, "Destructing placeholder.\n"); */
    if(c->placeholder) {
      debug_malloc_touch(c->placeholder);
      zap_placeholder(c);
    }

    if(delayed && c->target)
    {
      struct program *p = c->target;

      /* Free the constants in the failed program, to untangle the
       * cyclic references we might have to this program, typically
       * in parent pointers in nested classes. */
      if (p->constants) {
	int i;
	for (i = 0; i < p->num_constants; i++) {
	  free_svalue(&p->constants[i].sval);
	  SET_SVAL(p->constants[i].sval, T_INT, NUMBER_NUMBER,
		   integer, 0);
	}
      }

      /* We have to notify the master object that
       * a previous compile() actually failed, even
       * if we did not know it at the time
       */
      CDFPRINTF("th(%ld) %p unregistering failed delayed compile.\n",
                (long) th_self(), p);
      ref_push_program(p);
      /* FIXME: Shouldn't the compilation handler be used here? */
      SAFE_APPLY_MASTER("unregister",1);
      pop_stack();

      {
#ifdef PIKE_DEBUG
	int refs = p->refs;
#endif

	/* Free the target here to avoid false alarms in the debug
	 * check below. */
	free_program (c->target);
	c->target = NULL;

#ifdef PIKE_DEBUG
	if (refs > 1) {
	  /* Other programs can have indexed out constants from p, which
	   * might be broken themselves and/or keep references to p
	   * through the parent pointer. We should find all those other
	   * programs and invalidate them too, but how can that be done?
	   * The whole delayed compilation thingie is icky icky icky... :P
	   * /mast */
	  fprintf(stderr, "Warning: Program %p still got %d "
		  "external refs after unregister:\n", p, p->refs);
	  locate_references(p);
	  fprintf (stderr, "Describing program:\n");
	  describe_something (p, T_PROGRAM, 0, 0, 0, NULL);
	}
#endif
      }
    }
  }
  else
  {
    if (c->placeholder)
    {
      if (c->target->flags & PROGRAM_FINISHED) {
	JMP_BUF rec;
	/* Initialize the placeholder. */
#ifdef PIKE_DEBUG
	if (c->placeholder->prog != c->p)
	  Pike_fatal("Placeholder object got wrong program after second pass.\n");
#endif
	if(SETJMP(rec))
	{
	  handle_compile_exception (NULL);
	  debug_malloc_touch(c->placeholder);
	  zap_placeholder(c);
	}else{
	  debug_malloc_touch(c->placeholder);
	  call_pike_initializers(c->placeholder,0);
	}
	UNSETJMP(rec);
      }
      else {
	debug_malloc_touch(c->placeholder);
	zap_placeholder(c);
      }
    }
  }
  verify_supporters();
  c->flags &= ~(COMPILER_BUSY);
  c->flags |= COMPILER_DONE;
}

static int call_delayed_pass2(struct Supporter *s, int finish)
{
  int ok = 0;
  struct compilation *cc = s->data;
  debug_malloc_touch(cc);

  debug_malloc_touch(cc->p);

  CDFPRINTF("th(%ld) %p %s delayed compile.\n",
            (long) th_self(), cc->p, finish ? "continuing" : "cleaning up");

  /* Reenter the delayed compilation. */
  add_ref(cc->supporter.self.u.object);
  low_enter_compiler(cc->supporter.self.u.object,
		     SUBTYPEOF(cc->supporter.self));

  if (finish && cc->p) {
    if (cc->flags & COMPILER_NEED_EXTRA_PASS) {
      CDFPRINTF("Running delayed EXTRA PASS\n");
      run_pass_extra(cc);
    }
    run_pass2(cc);
  }
  run_cleanup(cc,1);

  exit_compiler();

  debug_malloc_touch(cc);

#ifdef PIKE_DEBUG
  if(cc->supporter.dependants)
    Pike_fatal("Que???\n");
#endif
  if(cc->p) {
    ok = finish;
    free_program(cc->p); /* later */
    cc->p = NULL;
  }

  CDFPRINTF("th(%ld) %p delayed compile %s.\n",
            (long) th_self(), cc->target, ok ? "done" : "failed");

  verify_supporters();

  return ok;
}

static void compilation_event_handler(int e)
{
  struct compilation *c = THIS_COMPILATION;

  switch (e) {
  case PROG_EVENT_INIT:
    CDFPRINTF("th(%ld) compilation: INIT(%p).\n", (long) th_self(), c);
    memset(c, 0, sizeof(*c));
    ba_init(&c->node_allocator, sizeof(struct node_s), 512);
    SET_SVAL(c->supporter.self, T_OBJECT,
	     Pike_fp->context - Pike_fp->current_object->prog->inherits,
	     object, Pike_fp->current_object); /* NOTE: Not ref-counted! */
    c->supporter.exit_fun = NULL;
    buffer_init(&c->used_modules);
    SET_SVAL(c->default_module, T_MAPPING, 0, mapping, get_builtin_constants());
    add_ref(c->default_module.u.mapping);
    c->major = -1;
    c->minor = -1;
    c->lex.current_line = 1;
    c->lex.current_file = make_shared_string("-");
    c->compilation_depth = -1;
    break;
  case PROG_EVENT_EXIT:
    CDFPRINTF("th(%ld) compilation: EXIT(%p).\n", (long) th_self(), c);
    buffer_free(&c->used_modules);
    free_compilation(c);
    break;
  }
}

/*! @decl void report(SeverityLevel severity, @
 *!                   string filename, int linenumber, @
 *!                   string subsystem, @
 *!                   string message, mixed ... extra_args)
 *!
 *!   Report a diagnostic from the compiler.
 *!
 *!   The default implementation attempts to call the first
 *!   corresponding function in the active handlers in priority order:
 *!
 *!   @ol
 *!     @item
 *!       Call handler->report().
 *!     @item
 *!       Call handler->compile_warning() or handler->compile_error()
 *!       depending on @[severity].
 *!     @item
 *!       Call compat->report().
 *!     @item
 *!       Call compat->compile_warning() or compat->compile_error()
 *!       depending on @[severity].
 *!     @item
 *!       Fallback: Call @[CompilerEnvironment()->report()]
 *!       in the parent object.
 *!   @endol
 *!
 *!   The arguments will be as follows:
 *!   @dl
 *!     @item report()
 *!       The report() function will be called with the same arguments
 *!       as this function.
 *!     @item compile_warning()/compile_error()
 *!       Depending on the @[severity] either compile_warning()
 *!       or compile_error() will be called.
 *!
 *!       They will be called with the @[filename], @[linenumber]
 *!       and formatted @[message] as arguments.
 *!
 *!       Note that these will not be called for the @[NOTICE] severity,
 *!       and that compile_error() will be used for both @[ERROR] and
 *!       @[FATAL].
 *!   @enddl
 *!
 *! @note
 *!   In Pike 7.8 and earlier the report() function was not called
 *!   in the handlers.
 *!
 *! @seealso
 *!   @[CompilerEnvironment()->report()]
 */
static void f_compilation_report(INT32 args)
{
  struct compilation *c = THIS_COMPILATION;
  int level;
  struct pike_string *filename;
  INT_TYPE linenumber;
  struct pike_string *subsystem;
  struct pike_string *message;
  struct object *handler = NULL;
  int fun = -1;

  /* FIXME: get_all_args() ought to have a marker
   *        indicating that we accept more arguments...
   */
  get_all_args(NULL, args, "%d", &level);

#ifdef SUPPORT_COMPILER_HANDLERS
  if ((c->handler || c->compat_handler)) {
    const char *fun_name = "compile_warning";

    if (level >= REPORT_ERROR) fun_name = "compile_error";

    if((handler = c->handler) && handler->prog) {
      if ((fun = find_identifier("report", handler->prog)) != -1) {
	apply_low(handler, fun, args);
	return;
      }
      if ((fun = find_identifier(fun_name, handler->prog)) != -1) {
	goto apply_handler;
      }
    }
    if ((handler = c->compat_handler) && handler->prog) {
      if ((fun = find_identifier("report", handler->prog)) != -1) {
	apply_low(handler, fun, args);
	return;
      }
      if ((fun = find_identifier(fun_name, handler->prog)) != -1) {
	goto apply_handler;
      }
    }
  }
#endif /* SUPPORT_COMPILER_HANDLERS */
  /* Nothing apropriate in any handlers.
   * Call the report() in our parent.
   */
  apply_external(1, CE_REPORT_FUN_NUM, args);
  return;

 apply_handler:
  /* Ignore informational level messages */
  if (level < REPORT_WARNING) return;
  if (args > 5) {
    f_sprintf(args - 4);
    args = 5;
  }
  get_all_args(NULL, args, "%d%W%+%W%W",
	       &level, &filename, &linenumber,
	       &subsystem, &message);

  ref_push_string(filename);
  push_int(linenumber);
  ref_push_string(message);
  apply_low(handler, fun, 3);
  stack_pop_n_elems_keep_top(args);
}

/*! @decl void create(string|void source, @
 *!                   CompilationHandler|void handler, @
 *!                   int|void major, int|void minor,@
 *!                   program|void target, object|void placeholder)
 *!
 *!   Create a PikeCompiler object for a source string.
 *!
 *!   This function takes a piece of Pike code as a string and
 *!   initializes a compiler object accordingly.
 *!
 *! @param source
 *!   Source code to compile.
 *!
 *! @param handler
 *!   The optional argument @[handler] is used to specify an alternative
 *!   error handler. If it is not specified the current master object
 *!   at compile time will be used.
 *!
 *! @param major
 *! @param minor
 *!   The optional arguments @[major] and @[minor] are used to tell the
 *!   compiler to attempt to be compatible with Pike @[major].@[minor].
 *!
 *! @param target
 *!   @[__empty_program()] program to fill in. The virgin program
 *!   returned by @[__empty_program()] will be modified and returned
 *!   by @[compile()] on success.
 *!
 *! @param placeholder
 *!   @[__null_program()] placeholder object to fill in. The object
 *!   will be modified into an instance of the resulting program
 *!   on successfull compile. Note that @[lfun::create()] in the
 *!   program will be called without any arguments.
 *!
 *! @note
 *!   Note that @[source] must contain the complete source for a program.
 *!   It is not possible to compile a single expression or statement.
 *!
 *!   Also note that no preprocessing is performed.
 *!   To preprocess the program you can use @[compile_string()] or
 *!   call the preprocessor manually by calling @[cpp()].
 *!
 *! @note
 *!   Note that all references to @[target] and @[placeholder] should
 *!   removed if @[compile()] failes. On failure the @[placeholder]
 *!   object will be destructed.
 *!
 *! @seealso
 *!   @[compile_string()], @[compile_file()], @[cpp()], @[master()],
 *!   @[CompilationHandler]
 */
static void f_compilation_create(INT32 args)
{
  struct pike_string *aprog = NULL;
  struct object *ahandler = NULL;/* error handler */
  int amajor = -1;
  int aminor = -1;
  struct program *atarget = NULL;
  struct object *aplaceholder = NULL;
  int dependants_ok = 1;
  struct compilation *c = THIS_COMPILATION;

  if (c->flags & COMPILER_BUSY) {
    Pike_error("PikeCompiler object is in use.\n");
  }

  STACK_LEVEL_START(args);

  get_all_args(NULL, args, ".%W%O%d%d%P%O",
	       &aprog, &ahandler,
	       &amajor, &aminor,
	       &atarget, &aplaceholder);

  if (args == 3) {
    SIMPLE_ARG_TYPE_ERROR("create", 4, "int");
  }

  check_c_stack(65536);

  CDFPRINTF("th(%ld) %p compilation create() enter, placeholder=%p\n",
            (long) th_self(), atarget, aplaceholder);

  debug_malloc_touch(c);

  verify_supporters();

  c->flags &= ~COMPILER_DONE;

  if (c->p) free_program(c->p);
  c->p = NULL;

  if (c->prog) free_string(c->prog);
  if ((c->prog=aprog)) add_ref(aprog);

#ifdef SUPPORT_COMPILER_HANDLERS
  if (c->handler) free_object(c->handler);
  if ((c->handler=ahandler)) add_ref(ahandler);
#endif /* SUPPORT_COMPILER_HANDLERS */

  if (c->target) free_program(c->target);
  if ((c->target=atarget)) add_ref(atarget);

  if (c->placeholder) free_object(c->placeholder);
  if ((c->placeholder=aplaceholder)) add_ref(aplaceholder);

  c->major = amajor;
  c->minor = aminor;

  STACK_LEVEL_DONE(args);
  pop_n_elems(args);

  push_int(0);
}

/*! @decl program compile()
 *!
 *!   Compile the current source into a program.
 *!
 *!   This function compiles the current Pike source code
 *!   into a clonable program.
 *!
 *! @seealso
 *!   @[compile_string()], @[compile_file()], @[cpp()], @[master()],
 *!   @[CompilationHandler], @[create()]
 */
static void f_compilation_compile(INT32 args)
{
  int delay, dependants_ok = 1;
  struct program *ret;
#ifdef PIKE_DEBUG
  ONERROR tmp;
#endif
  struct compilation *c = THIS_COMPILATION;

  if (c->flags & COMPILER_BUSY) {
    Pike_error("PikeCompiler in use.\n");
  }

  get_all_args(NULL, args, "");

  check_c_stack(65536);

  CDFPRINTF("th(%ld) %p f_compilation_compile() enter, "
            "placeholder=%p\n", (long) th_self(), c->target, c->placeholder);

  debug_malloc_touch(c);

  verify_supporters();

  if (c->flags & COMPILER_DONE) {
    /* Already compiled. */
    pop_n_elems(args);
    if (c->p) ref_push_program(c->p);
    else push_int(0);
    return;
  }

  if (!c->prog) {
    /* No program text. */
    low_start_new_program(c->target, COMPILER_PASS_FIRST, NULL, 0, NULL);
    c->p = end_program();
    c->flags |= COMPILER_DONE;
    pop_n_elems(args);
    ref_push_program(c->p);
    return;
  }

#ifdef PIKE_DEBUG
  SET_ONERROR(tmp, fatal_on_error,"Compiler exited with longjump!\n");
#endif

  c->flags |= COMPILER_BUSY;

  lock_pike_compiler();
#ifdef PIKE_THREADS
  c->saved_lock_depth = lock_depth;
#endif

  init_supporter(& c->supporter,
		 (supporter_callback *) call_delayed_pass2,
		 (void *)c);

  delay=run_pass1(c);
  dependants_ok = call_dependants(& c->supporter, !!c->p );
#ifdef PIKE_DEBUG
  /* FIXME */
  UNSET_ONERROR(tmp);
#endif

  if(delay)
  {
    CDFPRINTF("th(%ld) %p f_compilation_compile() finish later, "
              "placeholder=%p.\n",
              (long) th_self(), c->target, c->placeholder);
    /* finish later */
    verify_supporters();
    /* We're hanging in the supporter. */
    ret = debug_malloc_pass(c->p);
  }else{
    CDFPRINTF("th(%ld) %p f_compilation_compile() finish now.\n",
              (long) th_self(), c->target);
    if (c->flags & COMPILER_NEED_EXTRA_PASS) {
      CDFPRINTF("Running EXTRA PASS\n");
      run_pass_extra(c);
    }
    /* finish now */
    run_pass2(c);
    debug_malloc_touch(c);
    run_cleanup(c,0);

    ret = debug_malloc_pass(c->p);

    debug_malloc_touch(c);

    if (!dependants_ok) {
      CDFPRINTF("th(%ld) %p f_compilation_compile() reporting failure "
                "since a dependant failed.\n",
                (long) th_self(), c->target);
      throw_error_object(fast_clone_object(compilation_error_program), 0, 0,
			 "Compilation failed.\n");
    }
    if(!ret) {
      CDFPRINTF("th(%ld) %p f_compilation_compile() failed.\n",
                (long) th_self(), c->target);
      throw_error_object(fast_clone_object(compilation_error_program), 0, 0,
			 "Compilation failed.\n");
    }
    debug_malloc_touch(ret);
#ifdef PIKE_DEBUG
    if (a_flag > 2) {
      dump_program_tables(ret, 0);
    }
#endif /* PIKE_DEBUG */
    verify_supporters();
  }
  pop_n_elems(args);
  if (ret)
    ref_push_program(ret);
  else
    push_int(0);
}

/*! @decl mixed resolv(string identifier)
 *!
 *!   Resolve the symbol @[identifier].
 *!
 *!   The default implementation calls @[CompilerEnvironment()->resolv()]
 *!   in the parent object, with the remaining arguments taken from the
 *!   current @[PikeCompiler] context.
 *!
 *! @returns
 *!   Returns the value of @[sym] if found, and @[UNDEFINED] if not.
 */
static void f_compilation_resolv(INT32 args)
{
  struct pike_string *sym;
  struct compilation *c = THIS_COMPILATION;
  struct object *handler;
  int fun = -1;

  get_all_args(NULL, args, "%W", &sym);

  ref_push_string(sym);
  ref_push_string(c->lex.current_file);
#ifdef SUPPORT_COMPILER_HANDLERS
  if (c->handler) {
    ref_push_object(c->handler);
  } else {
    push_undefined();
  }
  if (c->compat_handler) {
    ref_push_object(c->compat_handler);
  } else {
    push_undefined();
  }
#else /* !SUPPORT_COMPILER_HANDLERS */
  push_undefined();
  push_undefined();
#endif /* SUPPORT_COMPILER_HANDLERS */
  apply_external(1, CE_RESOLV_FUN_NUM, 4);
}

/*! @decl object get_compilation_handler(int major, int minor)
 *!
 *!   Get compatibility handler for Pike @[major].@[minor].
 *!
 *! @note
 *!   This function is called by @[change_compiler_compatibility()].
 */
static void f_compilation_get_compilation_handler(INT32 args)
{
  struct compilation *c = THIS_COMPILATION;
  struct object *handler;
  int fun = -1;

#ifdef SUPPORT_COMPILER_HANDLERS
  if (((handler = c->handler) && handler->prog &&
       ((fun = find_identifier("get_compilation_handler", handler->prog)) != -1)) ||
      ((handler = c->compat_handler) && handler->prog &&
       ((fun = find_identifier("get_compilation_handler", handler->prog)) != -1))) {
    apply_low(handler, fun, args);
  } else {
    apply_external(1, CE_GET_COMPILATION_HANDLER_FUN_NUM, args);
  }
#endif /* SUPPORT_COMPILER_HANDLERS */
}

/*! @decl mapping(string:mixed)|object get_default_module()
 *!
 *!   Get the default module for the current compatibility level
 *!   (ie typically the value returned by @[predef::all_constants()]).
 *!
 *!   The default implementation calls the corresponding function
 *!   in the current handler, the current compatibility handler
 *!   or in the parent @[CompilerEnvironment] in that order.
 *!
 *! @returns
 *!   @mixed
 *!     @type mapping(string:mixed)|object
 *!       Constant table to use.
 *!
 *!     @type int(0..0)
 *!       Use the builtin constant table.
 *!   @endmixed
 *!
 *! @note
 *!   This function is called by @[change_compiler_compatibility()].
 */
static void f_compilation_get_default_module(INT32 args)
{
  struct compilation *c = THIS_COMPILATION;
  struct object *handler;
  int fun = -1;

#ifdef SUPPORT_COMPILER_HANDLERS
  if (((handler = c->handler) && handler->prog &&
       ((fun = find_identifier("get_default_module", handler->prog)) != -1)) ||
      ((handler = c->compat_handler) && handler->prog &&
       ((fun = find_identifier("get_default_module", handler->prog)) != -1))) {
    apply_low(handler, fun, args);
  } else {
#endif /* SUPPORT_COMPILER_HANDLERS */
    apply_external(1, CE_GET_DEFAULT_MODULE_FUN_NUM, args);
#ifdef SUPPORT_COMPILER_HANDLERS
  }
#endif /* SUPPORT_COMPILER_HANDLERS */
}

/*! @decl void change_compiler_compatibility(int major, int minor)
 *!
 *!   Change compiler to attempt to be compatible with Pike @[major].@[minor].
 */
static void f_compilation_change_compiler_compatibility(INT32 args)
{
  struct compilation *c = THIS_COMPILATION;
  int major = -1;
  int minor = -1;

  STACK_LEVEL_START(args);

  get_all_args(NULL, args, "%d%d", &major, &minor);

  if ((major == -1) && (minor == -1)) {
    major = PIKE_MAJOR_VERSION;
    minor = PIKE_MINOR_VERSION;
  }

  if ((major == Pike_compiler->compat_major) &&
      (minor == Pike_compiler->compat_minor)) {
    /* Optimization: Already at this compat level. */
    pop_n_elems(args);
    push_int(0);
    return;
  }

  Pike_compiler->compat_major=major;
  Pike_compiler->compat_minor=minor;

#ifdef SUPPORT_COMPILER_HANDLERS
  /* Optimization: The up to date compiler shouldn't need a compat handler. */
  if((major != PIKE_MAJOR_VERSION) || (minor != PIKE_MINOR_VERSION))
  {
    apply_current(PC_GET_COMPILATION_HANDLER_FUN_NUM, args);

    if((TYPEOF(Pike_sp[-1]) == T_OBJECT) && (Pike_sp[-1].u.object->prog))
    {
      if (SUBTYPEOF(Pike_sp[-1])) {
	/* FIXME: */
	Pike_error("Subtyped compat handlers are not supported yet.\n");
      }
      if (c->compat_handler == Pike_sp[-1].u.object) {
	/* Still at the same compat level. */
	pop_stack();
	push_int(0);
	return;
      } else {
	if(c->compat_handler) free_object(c->compat_handler);
	c->compat_handler = Pike_sp[-1].u.object;
	dmalloc_touch_svalue(Pike_sp-1);
	Pike_sp--;
      }
    } else {
      pop_stack();
      if(c->compat_handler) {
	free_object(c->compat_handler);
	c->compat_handler = NULL;
      } else {
	/* No change in compat handler. */
	push_int(0);
	return;
      }
    }
  } else {
    pop_n_elems(args);
    if (c->compat_handler) {
      free_object(c->compat_handler);
      c->compat_handler = NULL;
    } else {
      /* No change in compat handler. */
      push_int(0);
      return;
    }
  }
#else /* !SUPPORT_COMPILER_HANDLERS */
  pop_n_elems(args);
#endif /* SUPPORT_COMPILER_HANDLERS */

  STACK_LEVEL_CHECK(0);

  Pike_fp->args = 0;	/* Clean up the stack frame. */

  apply_current(PC_GET_DEFAULT_MODULE_FUN_NUM, 0);

  if(TYPEOF(Pike_sp[-1]) == T_INT)
  {
    pop_stack();
    ref_push_mapping(get_builtin_constants());
  }

  STACK_LEVEL_CHECK(1);

  assign_svalue(&c->default_module, Pike_sp-1);

  /* Replace the implicit import of all_constants() with
   * the new value.
   */
  if(c->num_used_modules)
  {
    struct svalue *dst = buffer_ptr(&c->used_modules);
    free_svalue( dst );
    dst[0] = Pike_sp[-1];
    Pike_sp--;
    dmalloc_touch_svalue(Pike_sp);
    if(Pike_compiler->module_index_cache)
    {
      free_mapping(Pike_compiler->module_index_cache);
      Pike_compiler->module_index_cache=0;
    }
  }else{
    use_module(Pike_sp-1);
    pop_stack();
  }

  STACK_LEVEL_DONE(0);
  push_int(0);
}

/*! @decl program handle_inherit(string inh)
 *!
 *!   Look up an inherit @[inh] in the current program.
 */
static void f_compilation_handle_inherit(INT32 args)
{
  struct compilation *c = THIS_COMPILATION;
  struct object *handler;
  int fun = -1;

  if (args > 1) pop_n_elems(args-1);

  ref_push_string(c->lex.current_file);
#ifdef SUPPORT_COMPILER_HANDLERS
  if (c->handler && c->handler->prog) {
    ref_push_object(c->handler);
    args = 3;
  }
  else
#endif /* !SUPPORT_COMPILER_HANDLERS */
    args = 2;

#ifdef SUPPORT_COMPILER_HANDLERS
  if (((handler = c->handler) && handler->prog &&
       ((fun = find_identifier("handle_inherit", handler->prog)) != -1)) ||
      ((handler = c->compat_handler) && handler->prog &&
       ((fun = find_identifier("handle_inherit", handler->prog)) != -1))) {
    apply_low(handler, fun, args);
  } else {
#endif /* SUPPORT_COMPILER_HANDLERS */
    apply_external(1, CE_HANDLE_INHERIT_FUN_NUM, args);
#ifdef SUPPORT_COMPILER_HANDLERS
  }
#endif /* SUPPORT_COMPILER_HANDLERS */
}

/*! @decl program handle_import(string module)
 *!
 *!   Look up an import @[module].
 */
static void f_compilation_handle_import(INT32 args)
{
  struct compilation *c = THIS_COMPILATION;
  struct object *handler;
  int fun = -1;

  if (args > 1) pop_n_elems(args-1);

  ref_push_string(c->lex.current_file);
#ifdef SUPPORT_COMPILER_HANDLERS
  if (c->handler && c->handler->prog) {
    ref_push_object(c->handler);
    args = 3;
  }
  else
#endif /* SUPPORT_COMPILER_HANDLERS */
    args = 2;

#ifdef SUPPORT_COMPILER_HANDLERS
  if (((handler = c->handler) && handler->prog &&
       ((fun = find_identifier("handle_import", handler->prog)) != -1)) ||
      ((handler = c->compat_handler) && handler->prog &&
       ((fun = find_identifier("handle_import", handler->prog)) != -1))) {
    apply_low(handler, fun, args);
  } else {
#endif /* SUPPORT_COMPILER_HANDLERS */
    apply_external(1, CE_HANDLE_IMPORT_FUN_NUM, args);
#ifdef SUPPORT_COMPILER_HANDLERS
  }
#endif /* SUPPORT_COMPILER_HANDLERS */
}

/*! @decl int(0..1) pop_type_attribute(string attribute, type a, type b)
 *!
 *!   Type attribute handler.
 *!
 *!   Called during type checking when @expr{a <= b@} and
 *!   @[a] had the type attribute @[attribute] before the
 *!   comparison.
 *!
 *!   The default implementation implements the "deprecated"
 *!   attribute.
 *!
 *! @returns
 *!   Returns @expr{1@} if the type check should be allowed
 *!   (ie @expr{__attribute__(attribute, a) <= b@}), and
 *!   @expr{0@} (zero) otherwise.
 *!
 *! @seealso
 *!   @[push_type_attribute()], @[index_type_attribute()]
 */
static void f_compilation_pop_type_attribute(INT32 args)
{
  struct pike_string *attr;
  struct svalue *a, *b;
  struct compilation *c = THIS_COMPILATION;
  struct pike_string *deprecated_string;

  get_all_args(NULL, args, "%W%*%*", &attr, &a, &b);

  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
    MAKE_CONST_STRING(deprecated_string, "deprecated");
    if ((attr == deprecated_string) &&
	!(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS)) {
      push_svalue(a);
      yytype_report(REPORT_WARNING, NULL, 0, NULL,
		    NULL, 0, NULL,
		    1, "Using deprecated %O value.");
    }
  }
  pop_n_elems(args);
  push_int(1);
}

/*! @decl int(0..1) index_type_attribute(string attribute, type a, type i)
 *!
 *!   Type attribute handler.
 *!
 *!   Called during type checking when a value of the type @[a] is
 *!   indexed with a value of type @[i] and @[a] had the type
 *!   attribute @[attribute] before the comparison.
 *!
 *!   The default implementation implements the "deprecated"
 *!   attribute.
 *!
 *! @returns
 *!   Returns @expr{1@} if the type check should be allowed
 *!   (ie @expr{__attribute__(attribute, a)[i]@}), and
 *!   @expr{0@} (zero) otherwise.
 *!
 *! @seealso
 *!   @[pop_type_attribute()], @[push_type_attribute()]
 */
static void f_compilation_index_type_attribute(INT32 args)
{
  struct pike_string *attr;
  struct svalue *a, *b;
  struct compilation *c = THIS_COMPILATION;
  struct pike_string *deprecated_string;

  get_all_args(NULL, args, "%W%*%*", &attr, &a, &b);

  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
    MAKE_CONST_STRING(deprecated_string, "deprecated");
    if ((attr == deprecated_string) &&
	!(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS)) {
      push_svalue(a);
      yytype_report(REPORT_WARNING, NULL, 0, NULL,
		    NULL, 0, NULL,
		    1, "Indexing a deprecated %O value.");
    }
  }
  pop_n_elems(args);
  push_int(1);
}

/*! @decl int(0..1) suppress_deprecation_warnings()
 *!
 *!   Allows to query whether (during an active compilation) deprecation
 *!   warnings are supposed to be suppressed.
 *!
 *! @returns
 *!   @expr{1@} if deprecation warnings should be suppressed,
 *!   @expr{0@} otherwise.
 */
static void f_compilation_suppress_deprecation_warnings(INT32 args)
{
    struct compilation *c = THIS_COMPILATION;

    pop_n_elems(args);
    push_int(Pike_compiler->compiler_pass != COMPILER_PASS_LAST ||
             c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS);
}

/*! @decl int(0..1) push_type_attribute(string attribute, type a, type b)
 *!
 *!   Type attribute handler.
 *!
 *!   Called during type checking when @expr{a <= b@} and
 *!   @[b] had the type attribute @[attribute] before the
 *!   comparison.
 *!
 *!   The default implementation implements the "deprecated"
 *!   attribute.
 *!
 *! @returns
 *!   Returns @expr{1@} if the type check should be allowed
 *!   (ie @expr{a <= __attribute__(attribute, b)@}), and
 *!   @expr{0@} (zero) otherwise.
 *!
 *! @seealso
 *!   @[pop_type_attribute()], @[index_type_attribute()]
 */
static void f_compilation_push_type_attribute(INT32 args)
{
  struct pike_string *attr;
  struct svalue *a, *b;
  struct compilation *c = THIS_COMPILATION;
  struct pike_string *deprecated_string;

  get_all_args(NULL, args, "%W%*%*", &attr, &a, &b);

  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
    MAKE_CONST_STRING(deprecated_string, "deprecated");
    if ((attr == deprecated_string) &&
	!(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS) &&
	!((TYPEOF(*a) == PIKE_T_TYPE) && (a->u.type == zero_type_string))) {
      /* Don't warn about setting deprecated values to zero. */
      push_svalue(b);
      yytype_report(REPORT_WARNING, NULL, 0, NULL,
		    NULL, 0, NULL,
		    1, "Using deprecated %O value.");
    }
  }
  pop_n_elems(args);
  push_int(1);
}

/*! @decl int(0..1) apply_type_attribute(string attribute, @
 *!                                      type a, type|void b)
 *!
 *!   Type attribute handler.
 *!
 *! @param attribute
 *!   Attribute that @[a] had.
 *!
 *! @param a
 *!   Type of the value being called.
 *!
 *! @param b
 *!   Type of the first argument in the call, or
 *!   @[UNDEFINED] if no more arguments.
 *!
 *!   Called during type checking when @[a] has been successfully
 *!   had a partial evaluation with the argument @[b] and
 *!   @[a] had the type attribute @[attribute] before the
 *!   evaluation.
 *!
 *!   The default implementation implements the "deprecated"
 *!   attribute.
 *!
 *! @returns
 *!   Returns @expr{1@} if the type check should be allowed
 *!   (ie @expr{__attribute__(attribute, a)(b)@}) is valid,
 *!   and @expr{0@} (zero) otherwise.
 *!
 *! @seealso
 *!   @[pop_type_attribute()], @[push_type_attribute()]
 */
static void f_compilation_apply_type_attribute(INT32 args)
{
  struct pike_string *attr;
  struct svalue *a, *b = NULL;
  struct compilation *c = THIS_COMPILATION;
  struct pike_string *deprecated_string;

  get_all_args(NULL, args, "%W%*.%*", &attr, &a, &b);

  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
    MAKE_CONST_STRING(deprecated_string, "deprecated");
    if ((attr == deprecated_string) &&
	!(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS) &&
	(!b ||
	 ((TYPEOF(*b) == T_INT) && (SUBTYPEOF(*b) == NUMBER_UNDEFINED) &&
	  (!b->u.integer)))) {
      /* push_svalue(a); */
      yytype_report(REPORT_WARNING, NULL, 0, NULL,
		    NULL, 0, NULL,
		    0, "Calling a deprecated value.");
    }
  }
  pop_n_elems(args);
  push_int(1);
}

/*! @decl type(mixed) apply_attribute_constant(string attr, @
 *!                                            mixed value, @
 *!                                            type arg_type, @
 *!                                            void cont_type)
 *!
 *!   Handle constant arguments to attributed function argument types.
 *!
 *! @param attr
 *!   Attribute that @[arg_type] had.
 *!
 *! @param value
 *!   Constant value sent as parameter.
 *!
 *! @param arg_type
 *!   Declared type of the function argument.
 *!
 *! @param cont_type
 *!   Continuation function type after the current argument.
 *!
 *!   This function is called when a function is called
 *!   with the constant value @[value] and it has been
 *!   successfully matched against @[arg_type],
 *!   and @[arg_type] had the type attribute @[attr].
 *!
 *!   This function is typically used to perform specialized
 *!   argument checking and to allow for a strengthening
 *!   of the function type based on @[value].
 *!
 *!   The default implementation implements the @expr{"sprintf_format"@},
 *!   @expr{"sscanf_format"@} and @expr{"sscanf_76_format"@} attributes.
 *!
 *! @returns
 *!   Returns a continuation type if it succeeded in strengthening the type.
 *!
 *!   Returns @tt{UNDEFINED@} otherwise (this is not an error indication).
 *!
 *! @seealso
 *!   @[pop_type_attribute()], @[push_type_attribute()]
 */
static void f_compilation_apply_attribute_constant(INT32 args)
{
  struct compilation *c = THIS_COMPILATION;
  struct pike_string *attribute;
  struct pike_string *test;
  struct svalue *sval;
  get_all_args(NULL, args, "%S%*", &attribute, &sval);

  if ((TYPEOF(*sval) == T_INT) && !sval->u.integer) {
    pop_n_elems(args);
    push_undefined();
    return;
  }

  MAKE_CONST_STRING(test, "sprintf_format");
  if (attribute == test) {
    f___handle_sprintf_format(args);
    return;
  }
  MAKE_CONST_STRING(test, "strict_sprintf_format");
  if (attribute == test) {
    f___handle_sprintf_format(args);
    return;
  }
  MAKE_CONST_STRING(test, "sscanf_format");
  if (attribute == test) {
    f___handle_sscanf_format(args);
    return;
  }
  MAKE_CONST_STRING(test, "sscanf_76_format");
  if (attribute == test) {
    f___handle_sscanf_format(args);
    return;
  }
  pop_n_elems(args);
  push_undefined();
}

static void f_compilation__sprintf(INT32 args)
{
  struct compilation *c = THIS_COMPILATION;
  struct string_builder buf;
  init_string_builder_alloc(&buf, 50, 0);
  string_builder_strcat(&buf, "PikeCompiler(");
  if (c->prog) {
    string_builder_strcat(&buf, "\"\", ");
  } else {
    string_builder_strcat(&buf, "UNDEFINED, ");
  }
#ifdef SUPPORT_COMPILER_HANDLERS
  if (c->handler) {
    ref_push_object(c->handler);
    string_builder_sprintf(&buf, "%O, ", Pike_sp-1);
    pop_stack();
  } else {
    string_builder_strcat(&buf, "UNDEFINED, ");
  }
#endif /* SUPPORT_COMPILER_HANDLERS */
  string_builder_sprintf(&buf, "%d, %d, %s, %s)",
			 c->major, c->minor,
			 c->target?"target":"UNDEFINED",
			 c->placeholder?"placeholder":"UNDEFINED");
  pop_n_elems(args);
  push_string(finish_string_builder(&buf));
}

/**
 * Fake being called via PikeCompiler()->compile()
 *
 * This function is used to set up the environment for
 * compiling C efuns and modules.
 *
 * Note: Since this is a stack frame, it will be cleaned up
 *       automatically on error, so no need to use ONERROR().
 *
 * Note: Steals a reference from ce.
 */
static void low_enter_compiler(struct object *ce, int inherit)
{
  struct pike_frame *new_frame = alloc_pike_frame();
#ifdef PROFILING
  new_frame->children_base = Pike_interpreter.accounted_time;
  new_frame->start_time = get_cpu_time() - Pike_interpreter.unlocked_time;
  new_frame->ident = PC_COMPILE_FUN_NUM;	/* Fake call of compile(). */
#endif /* PROFILING */
  new_frame->next = Pike_fp;
  new_frame->current_object = ce;
  /* Note: The compilation environment object hangs on this frame,
   *       so that it will be freed when the frame dies.
   */
  new_frame->current_program = ce->prog;
  add_ref(new_frame->current_program);
  new_frame->context = ce->prog->inherits + inherit;
  new_frame->current_storage = ce->storage + new_frame->context->storage_offset;
#ifdef PIKE_DEBUG
  if (new_frame->context->prog != compilation_program) {
    Pike_fatal("Invalid inherit for compilation context (%p != %p).\n",
	       new_frame->context->prog, compilation_program);
  }
#endif /* PIKE_DEBUG */
  new_frame->fun = new_frame->context->identifier_level + PC_COMPILE_FUN_NUM;
  new_frame->locals = Pike_sp;
  new_frame->save_sp = Pike_sp;
  new_frame->save_mark_sp = Pike_mark_sp;
  new_frame->args = 0;
  new_frame->num_args = 0;
  new_frame->num_locals = 0;
  new_frame->pc = 0;
  new_frame->return_addr = 0;
  new_frame->scope = 0;
  Pike_fp = new_frame;
}

PMOD_EXPORT void enter_compiler(struct pike_string *filename,
				INT_TYPE linenumber)
{
  struct object *ce = parent_clone_object(compilation_program,
					  compilation_environment,
					  CE_PIKE_COMPILER_FUN_NUM, 0);
  struct compilation *c;

  low_enter_compiler(ce, 0);

  c = THIS_COMPILATION;
  if (filename) {
    free_string(c->lex.current_file);
    copy_shared_string(c->lex.current_file, filename);
  }
  if (linenumber) {
    c->lex.current_line = linenumber;
  }
}

/**
 * Reverse the effect of enter_compiler().
 */
PMOD_EXPORT void exit_compiler(void)
{
#ifdef PIKE_DEBUG
  if ((Pike_fp->context->prog != compilation_program) ||
      (Pike_fp->fun != Pike_fp->context->identifier_level + PC_COMPILE_FUN_NUM)) {
    Pike_fatal("exit_compiler(): Frame stack out of whack!\n");
  }
#endif /* PIKE_DEBUG */
  POP_PIKE_FRAME();
}

/**
 * Main entry point for compiler messages originating from C-code.
 *
 * Sends the message along to PikeCompiler()->report().
 *
 * NOTE: The format string fmt (and vargs) is only formatted with
 *       string_builder_vsprintf() if the number of extra
 *       Pike stack arguments (args) is zero.
 *
 * NOTE: This function may be called from functions that sometimes
 *       execute outside of the compilation context, eg by
 *       __handle_sprintf_format(), which can be called directly
 *       by Pike-code, in which case it is a NO-OP.
 */
PMOD_EXPORT void va_yyreport(int severity_level,
			     struct pike_string *file, INT_TYPE line,
			     struct pike_string *system, INT32 args,
			     const char *fmt, va_list vargs)
{
  struct compilation *c = MAYBE_THIS_COMPILATION;
  struct string_builder s;

  if (!c) {
    /* No compiler context. */
    pop_n_elems(args);
    return;
  }

  STACK_LEVEL_START(args);

#ifdef PIKE_DEBUG
  if(Pike_interpreter.recoveries && Pike_sp-Pike_interpreter.evaluator_stack < Pike_interpreter.recoveries->stack_pointer)
    Pike_fatal("Stack error (underflow)\n");
#endif

  /* Convert type errors to warnings in non-strict compat mode. */
  if ((system == type_check_system_string) &&
      (severity_level == REPORT_ERROR) &&
      (Pike_compiler->compat_major != -1) &&
      !(c->lex.pragmas & ID_STRICT_TYPES) &&
      ((Pike_compiler->compat_major < PIKE_MAJOR_VERSION) ||
       ((Pike_compiler->compat_major == PIKE_MAJOR_VERSION) &&
	(Pike_compiler->compat_minor < PIKE_MINOR_VERSION)))) {
    severity_level = REPORT_WARNING;
  }

  /* If we have parse errors we might get erroneous warnings,
   * so don't print them.
   * This has the additional benefit of making it easier to
   * visually locate the actual error message.
   */
  if ((severity_level <= REPORT_WARNING) &&
      Pike_compiler->num_parse_error) {
    pop_n_elems(args);
    return;
  }

  if (severity_level >= REPORT_ERROR) {
    if (Pike_compiler->num_parse_error > 20) {
      pop_n_elems(args);
      return;
    }
    Pike_compiler->num_parse_error++;
    cumulative_parse_error++;
  }

  push_int(severity_level);
  ref_push_string(file?file:c->lex.current_file);
  push_int(line?line:c->lex.current_line);
  ref_push_string(system);
  if (args) {
    int i = args;
    push_text(fmt);
    /* Copy the arguments. */
    while (i--) {
      push_svalue(Pike_sp-(args+5));
    }
  } else {
    init_string_builder(&s, 0);
    string_builder_vsprintf(&s, fmt, vargs);
    push_string(finish_string_builder(&s));
  }

  safe_apply_current(PC_REPORT_FUN_NUM, args + 5);
  pop_stack();
  if (args) pop_n_elems(args);
  STACK_LEVEL_DONE(0);
}

PMOD_EXPORT void low_yyreport(int severity_level,
			      struct pike_string *file, INT_TYPE line,
			      struct pike_string *system,
			      INT32 args, const char *fmt, ...)
{
  va_list vargs;

  va_start(vargs,fmt);
  va_yyreport(severity_level, file, line, system, args, fmt, vargs);
  va_end(vargs);
}

PMOD_EXPORT void yyreport(int severity_level, struct pike_string *system,
			  INT32 args, const char *fmt, ...)
{
  va_list vargs;

  va_start(vargs,fmt);
  va_yyreport(severity_level, NULL, 0, system, args, fmt, vargs);
  va_end(vargs);
}

PMOD_EXPORT void yywarning(char *fmt, ...)
{
  va_list vargs;

  va_start(vargs,fmt);
  va_yyreport(REPORT_WARNING, NULL, 0, parser_system_string, 0, fmt, vargs);
  va_end(vargs);
}

PMOD_EXPORT void my_yyerror(const char *fmt,...)
{
  va_list vargs;
  va_start(vargs,fmt);
  va_yyreport(REPORT_ERROR, NULL, 0, parser_system_string, 0, fmt, vargs);
  va_end(vargs);
}

PMOD_EXPORT void yyerror(const char *str)
{
  my_yyerror("%s", str);
}

/**
 * Main entry point for errors from the type-checking subsystems.
 *
 * The message (if any) will be formatted for the same source
 * position as the got_t.
 *
 * The expect_t will be formatted for the same position as the got_t
 * if there's no expected_file/expected_line.
 *
 * The got_t will be formatted for the current lex position if there's
 * no got_file/got_line.
 */
void yytype_report(int severity_level,
		   struct pike_string *expected_file, INT_TYPE expected_line,
		   struct pike_type *expected_t,
		   struct pike_string *got_file, INT_TYPE got_line,
		   struct pike_type *got_t,
		   INT32 args, const char *fmt, ...)
{
  if (fmt)
  {
    va_list vargs;
    va_start(vargs, fmt);
    va_yyreport(severity_level, got_file, got_line, type_check_system_string,
		args, fmt, vargs);
    va_end(vargs);
  }

  if (expected_t && got_t) {
    yyexplain_nonmatching_types(severity_level,
				expected_file?expected_file:got_file,
				expected_line?expected_line:got_line,
				expected_t,
				got_file, got_line, got_t);
  } else if (expected_t) {
    ref_push_type_value(expected_t);
    low_yyreport(severity_level,
		 expected_file?expected_file:got_file,
		 expected_line?expected_line:got_line,
		 type_check_system_string,
		 1, "Expected: %O.");
  } else if (got_t) {
    ref_push_type_value(got_t);
    low_yyreport(severity_level, got_file, got_line, type_check_system_string,
		 1, "Got     : %O.");
  }
}

void yytype_error(const char *msg, struct pike_type *expected_t,
		  struct pike_type *got_t, unsigned int flags)
{
  yytype_report((flags & YYTE_IS_WARNING)?REPORT_WARNING:REPORT_ERROR,
		NULL, 0, expected_t, NULL, 0, got_t, 0, "%s", msg);
}

struct pike_string *format_exception_for_error_msg (struct svalue *thrown)
{
  struct pike_string *s = NULL;

  push_svalue (thrown);
  SAFE_APPLY_MASTER ("describe_error", 1);

  if (TYPEOF(Pike_sp[-1]) == T_STRING) {
    f_string_trim(1);
    push_constant_text("\n");
    push_constant_text(" ");
    f_replace(3);
    return (--Pike_sp)->u.string;
  }
  else {
    pop_stack();
    return NULL;
  }
}

void handle_compile_exception (const char *yyerror_fmt, ...)
{
  struct svalue thrown;
  struct compilation *c = THIS_COMPILATION;

  CHECK_COMPILER();

  move_svalue (&thrown, &throw_value);
  mark_free_svalue (&throw_value);

  if (yyerror_fmt) {
    va_list args;
    va_start (args, yyerror_fmt);
    va_yyreport(REPORT_ERROR, NULL, 0, parser_system_string, 0,
		yyerror_fmt, args);
    va_end (args);
  }

  push_svalue(&thrown);
  /* safe_apply_current(PC_FILTER_EXCEPTION_FUN_NUM, 1); */
#ifdef SUPPORT_COMPILER_HANDLERS
  low_safe_apply_handler("compile_exception", c->handler, c->compat_handler, 1);
#else /* !SUPPORT_COMPILER_HANDLERS */
  SAFE_APPLY_MASTER("compile_exception", 1);
#endif /* SUPPORT_COMPILER_HANDLERS */

  if (SAFE_IS_ZERO(Pike_sp-1)) {
    struct pike_string *s = format_exception_for_error_msg (&thrown);
    if (s) {
      push_string(s);
      yyreport(REPORT_ERROR, parser_system_string, 1, "%s");
    }
  }

  pop_stack();
  free_svalue(&thrown);
}

/*! @class CompilerState
 *!
 *!   Keeps the state of a single program/class during compilation.
 *!
 *! @note
 *!   Not in use yet!
 */

#define THIS_PROGRAM_STATE  ((struct program_state *)(Pike_fp->current_storage))

static void program_state_event_handler(int UNUSED(event))
{
#if 0
  struct program_state *c = THIS_PROGRAM_STATE;
  switch (event) {
  case PROG_EVENT_INIT:
#define INIT
#include "compilation.h"
    break;
  case PROG_EVENT_EXIT:
#define EXIT
#include "compilation.h"
    break;
  }
#endif /* 0 */
}

/*! @endclass
 */

/*! @endclass
 */

/*! @endclass
 */

/**
 * Strap the compiler by creating the compilation program by hand.
 */
static void compile_compiler(void)
{
  struct program *p = low_allocate_program();
  struct program *p2 = compilation_program = low_allocate_program();
  struct object *co;
  struct inherit *inh;

  p->id = PROG_COMPILERENVIRONMENT_ID;
  p->parent_info_storage = -1;
  /* p->event_handler = compilation_env_event_handler; */
  p->flags |= PROGRAM_HAS_C_METHODS;

#if 0
  /* ADD_STORAGE(struct compilation_env); */
  p->alignment_needed = ALIGNOF(struct compilation_env);
  p->storage_needed = p->xstorage + sizeof(struct compilation_env);
#endif /* 0 */

  /* Add the initial inherit, this is needed for clone_object()
   * to actually call the event handler, and for low_enter_compiler()
   * to find the storage and context. */
  p->inherits = inh = ALLOC_STRUCT(inherit);
  inh->prog = p;
  inh->inherit_level = 0;
  inh->identifier_level = 0;
  inh->parent_identifier = -1;
  inh->parent_offset = OBJECT_PARENT;
  inh->identifier_ref_offset = 0;
  inh->storage_offset = p->xstorage;
  inh->parent = NULL;
  inh->name = NULL;
  inh->annotations = NULL;
  p->num_inherits = 1;

  /* Force clone_object() to accept the program...
   */
  p->flags |= PROGRAM_PASS_1_DONE;
  compilation_environment = clone_object(p, 0);
  p->flags &= ~PROGRAM_PASS_1_DONE;

  /* Once more, this time for p2...
   */

  p2->id = PROG_COMPILERENVIRONMENT_PIKECOMPILER_ID;
  p2->parent_info_storage = 0;
  p2->xstorage = sizeof(struct parent_info);
  p2->event_handler = compilation_event_handler;
  p2->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT|PROGRAM_HAS_C_METHODS;

  /* ADD_STORAGE(struct compilation); */
  p2->alignment_needed = ALIGNOF(struct compilation);
  p2->storage_needed = p2->xstorage + sizeof(struct compilation);

  p2->inherits = inh = ALLOC_STRUCT(inherit);
  inh->prog = p2;
  inh->inherit_level = 0;
  inh->identifier_level = 0;
  inh->parent_identifier = CE_PIKE_COMPILER_FUN_NUM;
  inh->parent_offset = OBJECT_PARENT;
  inh->identifier_ref_offset = 0;
  inh->storage_offset = p2->xstorage;
  inh->parent = NULL;
  inh->name = NULL;
  inh->annotations = NULL;
  p2->num_inherits = 1;

  p2->flags |= PROGRAM_PASS_1_DONE;
  co = parent_clone_object(p2, compilation_environment,
			   CE_PIKE_COMPILER_FUN_NUM, 0);
  p2->flags &= ~PROGRAM_PASS_1_DONE;

  low_enter_compiler(co, 0);

  low_start_new_program(p, COMPILER_PASS_FIRST, NULL, 0, NULL);
  free_program(p);	/* Remove the extra ref we just got... */

  /* NOTE: The order of these identifiers is hard-coded in
   *       the CE_*_FUN_NUM definitions in "pike_compiler.h".
   */

  /* NB: Overloaded properly by inherit of Reporter later on. */
  ADD_FUNCTION("report", f_reporter_report,
	       tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
		      tStr tStr, tMix, tVoid),0);

  ADD_FUNCTION("compile", f_compilation_env_compile,
	       tFunc(tOr(tStr, tVoid) tOr(tObj, tVoid)
		     tOr(tInt, tVoid) tOr(tInt, tVoid)
		     tOr(tPrg(tObj), tVoid) tOr(tObj, tVoid),
		     tPrg(tObj)), 0);

  ADD_FUNCTION("resolv", f_compilation_env_resolv,
	       tFunc(tStr tStr tObj, tMix), 0);

  low_start_new_program(p2, COMPILER_PASS_FIRST, NULL, 0, NULL);

  /* low_start_new_program() has zapped the inherit we created
   * for p2 above, so we need to repair the frame pointer.
   */
  Pike_fp->context = p2->inherits;

  /* MAGIC! We're now executing inside the object being compiled,
   * and have done sufficient stuff to be able to call and use
   * the normal program building functions.
   */

  /* NOTE: The order of these identifiers is hard-coded in
   *       the PC_*_FUN_NUM definitions in "pike_compiler.h".
   */

  ADD_FUNCTION("report", f_compilation_report,
	       tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
		      tStr tStr, tMix, tVoid),0);

  ADD_FUNCTION("compile", f_compilation_compile,
	       tFunc(tNone, tPrg(tObj)), 0);

  ADD_FUNCTION("resolv", f_compilation_resolv,
	       tFunc(tStr tStr tObj, tMix), 0);

  ADD_FUNCTION("create", f_compilation_create,
	       tFunc(tOr(tStr, tVoid) tOr(tObj, tVoid)
		     tOr(tInt, tVoid) tOr(tInt, tVoid)
		     tOr(tPrg(tObj), tVoid) tOr(tObj, tVoid), tVoid),
	       ID_PROTECTED);

  ADD_FUNCTION("get_compilation_handler",
	       f_compilation_get_compilation_handler,
	       tFunc(tInt tInt, tObj), 0);

  ADD_FUNCTION("get_default_module", f_compilation_get_default_module,
	       tFunc(tNone, tOr(tMap(tStr, tMix), tObj)), 0);

  ADD_FUNCTION("change_compiler_compatibility",
	       f_compilation_change_compiler_compatibility,
	       tFunc(tInt tInt, tVoid), 0);

  ADD_FUNCTION("handle_inherit", f_compilation_handle_inherit,
	       tFunc(tStr, tPrg(tObj)), 0);

  ADD_FUNCTION("handle_import", f_compilation_handle_import,
	       tFunc(tStr, tPrg(tObj)), 0);

  ADD_FUNCTION("pop_type_attribute", f_compilation_pop_type_attribute,
	       tFunc(tStr tType(tMix) tType(tMix), tInt01), 0);

  ADD_FUNCTION("push_type_attribute", f_compilation_push_type_attribute,
	       tFunc(tStr tType(tMix) tType(tMix), tInt01), 0);

  ADD_FUNCTION("index_type_attribute", f_compilation_index_type_attribute,
	       tFunc(tStr tType(tMix) tType(tMix), tInt01), 0);

  ADD_FUNCTION("apply_type_attribute", f_compilation_apply_type_attribute,
	       tFunc(tStr tType(tMix) tOr(tType(tMix), tVoid), tInt01), 0);

  ADD_FUNCTION("apply_attribute_constant",
	       f_compilation_apply_attribute_constant,
	       tFunc(tStr tMix tType(tMix) tType(tFunction),
		     tType(tFunction)), 0);

  ADD_FUNCTION("_sprintf", f_compilation__sprintf,
	       tFunc(tInt tOr(tMap(tStr, tMix), tVoid), tStr), ID_PROTECTED);

  ADD_FUNCTION("suppress_deprecation_warnings",
               f_compilation_suppress_deprecation_warnings,
               tFunc(tVoid, tInt), 0);

  start_new_program();
  Pike_compiler->new_program->id =
    PROG_COMPILERENVIRONMENT_PIKECOMPILER_COMPILERSTATE_ID;

  ADD_STORAGE(struct program_state);
  Pike_compiler->new_program->event_handler = program_state_event_handler;
  Pike_compiler->new_program->flags |=
    PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT|PROGRAM_HAS_C_METHODS;

  /* Alias for report above. */
  low_define_alias(NULL, NULL, 0, 1, PC_REPORT_FUN_NUM);

  end_class("CompilerState", 0);

  /* Map some of our variables so that the gc can find them. */
  PIKE_MAP_VARIABLE("prog", OFFSETOF(compilation, prog),
		    tStr, PIKE_T_STRING, ID_HIDDEN);
#ifdef SUPPORT_COMPILER_HANDLERS
  PIKE_MAP_VARIABLE("handler", OFFSETOF(compilation, handler),
		    tObj, PIKE_T_OBJECT, 0);
  PIKE_MAP_VARIABLE("compat_handler", OFFSETOF(compilation, compat_handler),
		    tObj, PIKE_T_OBJECT, 0);
#endif /* SUPPORT_COMPILER_HANDLERS */
  PIKE_MAP_VARIABLE("target", OFFSETOF(compilation, target),
		    tPrg(tObj), PIKE_T_PROGRAM, ID_HIDDEN);
  PIKE_MAP_VARIABLE("placeholder", OFFSETOF(compilation, placeholder),
		    tObj, PIKE_T_OBJECT, ID_HIDDEN);
  PIKE_MAP_VARIABLE("p", OFFSETOF(compilation, p),
		    tPrg(tObj), PIKE_T_PROGRAM, ID_HIDDEN);
  PIKE_MAP_VARIABLE("current_file", OFFSETOF(compilation, lex.current_file),
		    tStr, PIKE_T_STRING, 0);
  PIKE_MAP_VARIABLE("current_line", OFFSETOF(compilation, lex.current_line),
		    tInt, PIKE_T_INT, 0);
  PIKE_MAP_VARIABLE("default_module", OFFSETOF(compilation, default_module),
		    tOr(tMap(tStr,tMix),tObj), PIKE_T_MIXED, 0);

  /* end_class()/end_program() adds the parent_info storage once more.
   * Remove the one we added above, so that we don't get it double.
   */
  p2->xstorage = 0;

  end_class("PikeCompiler", 0);
  /* end_class()/end_program() has zapped the inherit once again,
   * so we need to repair the frame pointer.
   */
  Pike_fp->context = compilation_program->inherits;

  ADD_FUNCTION("get_compilation_handler",
	       f_compilation_env_get_compilation_handler,
	       tFunc(tInt tInt, tObj), 0);

  ADD_FUNCTION("get_default_module",
	       f_compilation_env_get_default_module,
	       tFunc(tNone, tOr(tMap(tStr, tMix), tObj)), 0);

  ADD_FUNCTION("handle_inherit", f_compilation_env_handle_inherit,
	       tFunc(tStr tStr tOr(tObj, tVoid), tPrg(tObj)), 0);

  ADD_FUNCTION("handle_import", f_compilation_env_handle_import,
	       tFunc(tStr tStr tOr(tObj, tVoid), tPrg(tObj)), 0);

  /* Reporter */
  start_new_program();
  {
    struct svalue type_value;

    Pike_compiler->new_program->id = PROG_COMPILERENVIRONMENT_REPORTER_ID;

    ADD_FUNCTION("report", f_reporter_report,
		 tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
			tStr tStr, tMix, tVoid),0);

    /* enum SeverityLevel { NOTICE, WARNING, ERROR, FATAL } */
    SET_SVAL(type_value, PIKE_T_TYPE, 0, type,
	     CONSTTYPE(tName("SeverityLevel", tInt03)));
    simple_add_constant("SeverityLevel", &type_value, 0);
    free_svalue(&type_value);

    add_integer_constant("NOTICE",  REPORT_NOTICE, 0);
    add_integer_constant("WARNING", REPORT_WARNING, 0);
    add_integer_constant("ERROR",   REPORT_ERROR, 0);
    add_integer_constant("FATAL",   REPORT_FATAL, 0);

    reporter_program = end_program();
  }
  add_global_program("Reporter", reporter_program);

  low_inherit(reporter_program, NULL, -1, 0, 0, 0);

  start_new_program();
  Pike_compiler->new_program->id = PROG_COMPILERENVIRONMENT_LOCK_ID;
  Pike_compiler->new_program->event_handler =
    compiler_environment_lock_event_handler;
  Pike_compiler->new_program->flags |= PROGRAM_DESTRUCT_IMMEDIATE;
  end_class("lock", 0);

  init_cpp_compilerenv_classes();

  compilation_env_program = end_program();

  add_global_program("CompilerEnvironment", compilation_env_program);

  exit_compiler();

  ref_push_object(compilation_environment);
  low_add_constant("DefaultCompilerEnvironment", Pike_sp-1);
  pop_stack();
}

void push_compiler_frame(int lexical_scope)
{
  struct compiler_frame *f;
  f=ALLOC_STRUCT(compiler_frame);
  f->previous=Pike_compiler->compiler_frame;
  f->lexical_scope=lexical_scope;
  f->current_type=0;
  f->current_return_type=0;

  f->current_number_of_locals=0;
  f->max_number_of_locals=0;
  f->min_number_of_locals=0;
  f->last_block_level=-1;

  f->current_function_number=-2; /* no function */
  f->recur_label=-1;
  f->is_inline=0;
  f->num_args=-1;
  f->opt_flags = OPT_SIDE_EFFECT|OPT_EXTERNAL_DEPEND; /* FIXME: Should be 0. */
  f->generator_local = -1;
  f->generator_jumptable = NULL;
  Pike_compiler->compiler_frame=f;
}

node *low_pop_local_variables(int level, node *block)
{
  struct compilation *c = THIS_COMPILATION;
  while(Pike_compiler->compiler_frame->current_number_of_locals > level)
  {
    int e;
    e=--(Pike_compiler->compiler_frame->current_number_of_locals);
    if (block) {
      struct local_variable *var = Pike_compiler->compiler_frame->variable + e;
      if (var->name->len) {
	block = mknestednodes(F_COMMA_EXPR,
			      mknode(F_SET_LOCAL_NAME, mkintnode(e),
				     mkstrnode(var->name)),
			      mknode(F_SET_LOCAL_TYPE, mkintnode(e),
				     mktypenode(var->type)),
			      block,
			      mknode(F_POP_VALUE,
				     mknode(F_ASSIGN,
					    mklocalnode(e, 0),
					    mkintnode(0)),
				     NULL),
			      mknode(F_SET_LOCAL_END, mkintnode(e), NULL),
			      NULL);
      } else {
	/* No name; this is typically used for internal temporary variables,
	 * eg for the safe-indexing operators.
	 *
	 * As we're in the middle of an expression, it gets
	 * confused by the void expressions.
	 *
	 * Skip generating variable information, as it will
	 * only be "" and mixed anyway.
	 */
	block = mknestednodes(F_COMMA_EXPR,
			      block,
			      mknode(F_POP_VALUE,
				     mknode(F_ASSIGN,
					    mklocalnode(e, 0),
					    mkintnode(0)),
				     NULL),
			      NULL);
      }
    }
    if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&
	!(Pike_compiler->compiler_frame->variable[e].flags &
	  LOCAL_VAR_IS_USED)) {
      ref_push_string(Pike_compiler->compiler_frame->variable[e].name);
      low_yyreport(REPORT_WARNING,
		   Pike_compiler->compiler_frame->variable[e].file,
		   Pike_compiler->compiler_frame->variable[e].line,
		   parser_system_string,
		   1, "Unused local variable %s.");
    }
    free_string(Pike_compiler->compiler_frame->variable[e].name);
    free_type(Pike_compiler->compiler_frame->variable[e].type);
    if(Pike_compiler->compiler_frame->variable[e].def)
      free_node(Pike_compiler->compiler_frame->variable[e].def);

    free_string(Pike_compiler->compiler_frame->variable[e].file);
  }
  return block;
}

node *pop_local_variables(int level, node *block)
{
#if 1
  struct compilation *c = THIS_COMPILATION;
  /* We need to save the variables Kuppo (but not their names) */
  if(level < Pike_compiler->compiler_frame->min_number_of_locals)
  {
    /* FIXME: Consider using flags to indicate whether a local variable
     *        actually is used from a nested scope. */
    for(;level<Pike_compiler->compiler_frame->min_number_of_locals;level++)
    {
      if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&
	  !(Pike_compiler->compiler_frame->variable[level].flags &
	    LOCAL_VAR_IS_USED)) {
	ref_push_string(Pike_compiler->compiler_frame->variable[level].name);
	low_yyreport(REPORT_WARNING,
		     Pike_compiler->compiler_frame->variable[level].file,
		     Pike_compiler->compiler_frame->variable[level].line,
		     parser_system_string,
		     1, "Unused local variable %s.");
	/* Make sure we only warn once... */
	Pike_compiler->compiler_frame->variable[level].flags |=
	  LOCAL_VAR_IS_USED;
      }
      free_string(Pike_compiler->compiler_frame->variable[level].name);
      copy_shared_string(Pike_compiler->compiler_frame->variable[level].name,
			 empty_pike_string);
      /* FIXME: Do we need to keep the filenames? */
    }
  }
#endif
  return low_pop_local_variables(level, block);
}


void pop_compiler_frame(void)
{
  struct compiler_frame *f;

  f=Pike_compiler->compiler_frame;
#ifdef PIKE_DEBUG
  if(!f)
    Pike_fatal("Popping out of compiler frames\n");
#endif

  low_pop_local_variables(0, NULL);
  if(f->current_type)
    free_type(f->current_type);

  if(f->current_return_type)
    free_type(f->current_return_type);

  if (f->generator_jumptable)
    free(f->generator_jumptable);

  Pike_compiler->compiler_frame=f->previous;
  dmfree((char *)f);
}


PMOD_EXPORT void change_compiler_compatibility(int major, int minor)
{
  CHECK_COMPILER();

  push_int(major);
  push_int(minor);

  safe_apply_current2(PC_CHANGE_COMPILER_COMPATIBILITY_FUN_NUM, 2,
		      "change_compiler_compatibility");
  pop_stack();
}

#define DEFAULT_CMOD_STORAGE	static

/*! @decl constant __null_program
 *!
 *! Program used internally by the compiler to create objects
 *! that are later modified into instances of the compiled program
 *! by the compiler.
 *!
 *! @seealso
 *!   @[__placeholder_object]
 */
struct program *null_program = NULL;

#undef class_null_defined
#define class_null_defined

#ifdef THIS_

#undef THIS
#define THIS THIS_

#endif /* THIS_ */
#line 3226 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
/* This placeholder should be used
 * in the first compiler pass to take the place
 * of unknown things
 */
struct program *placeholder_program = NULL;
struct object *placeholder_object = NULL;

#undef class_placeholder_defined
#define class_placeholder_defined
#define f_placeholder_cq__backtick_28_29_defined
DEFAULT_CMOD_STORAGE void f_placeholder_cq__backtick_28_29(INT32 args) {
#line 3234 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct svalue * params;
#ifdef PIKE_DEBUG
if(args < 0) Pike_fatal("CMOD function argument negative.\n");
#else
STATIC_ASSUME(args >= 0);
#endif
#line 3234 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if (args > 0) {
  INT32 argcnt = 0;
  do {
    dmalloc_touch_svalue(Pike_sp+0+argcnt-args);
#line 3234 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  } while (++argcnt < args-0);
  params=Pike_sp+0-args;
} else params = NULL;
#line 3235 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
    ref_push_object(Pike_fp->current_object);
  }

  }
#define f_placeholder_cq__backtick_5B_5D_defined
DEFAULT_CMOD_STORAGE void f_placeholder_cq__backtick_5B_5D(INT32 args) {
#line 3239 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct svalue * params;
#ifdef PIKE_DEBUG
if(args < 0) Pike_fatal("CMOD function argument negative.\n");
#else
STATIC_ASSUME(args >= 0);
#endif
#line 3239 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if (args > 0) {
  INT32 argcnt = 0;
  do {
    dmalloc_touch_svalue(Pike_sp+0+argcnt-args);
#line 3239 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  } while (++argcnt < args-0);
  params=Pike_sp+0-args;
} else params = NULL;
#line 3240 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
    ref_push_object(Pike_fp->current_object);
  }

  }
#define f_placeholder_cq__sprintf_defined
DEFAULT_CMOD_STORAGE void f_placeholder_cq__sprintf(INT32 args) {
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
INT_TYPE c;
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct mapping * opts;
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args < 1) wrong_number_of_args_error("_sprintf",args,1);
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args > 2) wrong_number_of_args_error("_sprintf",args,2);
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if((TYPEOF(Pike_sp[0-args]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("_sprintf",1,"int");
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
c=Pike_sp[0-args].u.integer;
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if (args > 1 &&
    (TYPEOF(Pike_sp[1-args]) != PIKE_T_INT ||
     Pike_sp[1-args].u.integer)) {
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(TYPEOF(Pike_sp[1-args]) != PIKE_T_MAPPING) SIMPLE_ARG_TYPE_ERROR("_sprintf",2,"mapping(mixed:mixed)|void");
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
debug_malloc_pass(opts=Pike_sp[1-args].u.mapping);
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
} else opts = NULL;
{
    if (c != 'O') {
      push_int(0);
      return;
    }

    push_text("__placeholder_object");
  }
}

#ifdef THIS_

#undef THIS
#define THIS THIS_

#endif /* THIS_ */
/*! @module Pike
 */

/*! @class Annotation
 *!
 *! This class describes the API that the compiler
 *! expects for the annotation syntax.
 *!
 *! @note
 *!   Classes implementing this API typically need
 *!   to be marked @tt{constant@}.
 *!
 *! @seealso
 *!   @[Annotations]
 */
#line 3270 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
PMOD_EXPORT struct program *Annotation_program = NULL;

#undef class_Annotation_defined
#define class_Annotation_defined
/*! @decl optional void end_pass(int pass, program prog, @
   *!                              CompilerEnvironment.PikeCompiler compiler)
   *!
   *! Callback called by the compiler when it is finishing a compilation pass.
   *!
   *! @param pass
   *!   Compilation pass.
   *!
   *! @param prog
   *!   Program being compiled.
   *!
   *! @param compiler
   *!   @[CompilerEnvironment.PikeCompiler] state for the compiler.
   */
  #define f_Annotation_end_pass_defined

#ifdef THIS_

#undef THIS
#define THIS THIS_

#endif /* THIS_ */
/*! @endclass
 */

/*! @module Annotations
 */

/*! @class Implements
 *!
 *! This annotation causes the compiler to validate that
 *! the annotated class implements the specified API.
 */
#line 3305 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
PMOD_EXPORT struct program *Implements_program = NULL;

#undef class_Implements_defined
#define class_Implements_defined
/*! @decl inherit Pike.Annotation
   */
  
#undef inherit_Annotation_Implements_defined
#define inherit_Annotation_Implements_defined
#line 3311 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int Implements_Annotation_inh_num = -1;

#ifdef Implements_Annotation_inh_offset_used
#line 3311 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int Implements_Annotation_inh_offset = -1;

#endif /* Implements_Annotation_inh_offset_used */

#ifdef Implements_Annotation_inh_storage_offset_used
#line 3311 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int Implements_Annotation_inh_storage_offset = -1;

#endif /* Implements_Annotation_inh_storage_offset_used */

#undef var_api_Implements_defined
#define var_api_Implements_defined

#undef THIS
#define THIS ((struct Implements_struct *)(Pike_interpreter.frame_pointer->current_storage + Implements_storage_offset))

#undef THIS_IMPLEMENTS
#define THIS_IMPLEMENTS ((struct Implements_struct *)(Pike_interpreter.frame_pointer->current_storage + Implements_storage_offset))

#undef OBJ2_IMPLEMENTS
#define OBJ2_IMPLEMENTS(o) ((struct Implements_struct *)(o->storage+Implements_storage_offset+Implements_program->inherits[0].storage_offset))

#undef GET_IMPLEMENTS_STORAGE
#define GET_IMPLEMENTS_STORAGE(o) ((struct Implements_struct *)(o->storage+Implements_storage_offset+Implements_program->inherits[0].storage_offset))
static ptrdiff_t Implements_storage_offset;
struct Implements_struct {

#ifdef var_api_Implements_defined
#line 3313 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  struct program * api;

#endif /* var_api_Implements_defined */
};
#ifdef PIKE_DEBUG
/* Ensure the struct is used in a variable declaration, or else gdb might not see it. */
static struct Implements_struct *Implements_gdb_dummy_ptr;
#endif
#define f_Implements_create_defined
DEFAULT_CMOD_STORAGE void f_Implements_create(INT32 args) {
#line 3315 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct program * api;
#line 3315 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args != 1) wrong_number_of_args_error("create",args,1);
#line 3315 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(!(api=program_from_svalue(Pike_sp+0-1))) SIMPLE_ARG_TYPE_ERROR("create",1,"program");
#line 3317 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
    if (THIS->api) Pike_error("Already initialized.\n");
    add_ref(THIS->api = api);
  }

  }
#define f_Implements_end_pass_defined
DEFAULT_CMOD_STORAGE void f_Implements_end_pass(INT32 args) {
#line 3322 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
INT_TYPE pass;
#line 3322 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct program * prog;
struct object * compiler;
#line 3323 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
int compiler_inh_num;
#line 3322 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args != 3) wrong_number_of_args_error("end_pass",args,3);
#line 3322 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if((TYPEOF(Pike_sp[0-3]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("end_pass",1,"int");
#line 3322 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
pass=Pike_sp[0-3].u.integer;
#line 3322 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(!(prog=program_from_svalue(Pike_sp+1-3))) SIMPLE_ARG_TYPE_ERROR("end_pass",2,"program");
if(TYPEOF(Pike_sp[2-3]) != PIKE_T_OBJECT) SIMPLE_ARG_TYPE_ERROR("end_pass",3,"CompilerEnvironment_PikeCompiler");
#line 3323 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
debug_malloc_pass(compiler=Pike_sp[2-3].u.object);
#line 3323 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
compiler_inh_num = SUBTYPEOF(Pike_sp[2-3]);
{
    struct program *api = THIS->api;
    if (!api) Pike_error("Uninitialized.\n");

    /* Only perform the checks in the last pass. */
    if (pass != COMPILER_PASS_LAST) return;

    if (!is_compatible(prog, api)) {
      /* NB: We need to enter the compiler to call yyexplain_*().
       *     Note also that low_enter_compiler() eats a ref to the object.
       */
      add_ref(compiler);
      low_enter_compiler(compiler, compiler_inh_num);
      /* NB: low_enter_compiler invalidates THIS! */
      yyexplain_not_compatible(REPORT_ERROR, prog, api);
      exit_compiler();
    } else if (!implements(prog, api)) {
      /* NB: We need to enter the compiler to call yyexplain_*().
       *     Note also that low_enter_compiler() eats a ref to the object.
       */
      add_ref(compiler);
      low_enter_compiler(compiler, compiler_inh_num);
      /* NB: low_enter_compiler invalidates THIS! */
      yyexplain_not_implements(REPORT_WARNING, prog, api);
      exit_compiler();
    }
  }

  }
#define f_Implements_cq__sprintf_defined
DEFAULT_CMOD_STORAGE void f_Implements_cq__sprintf(INT32 args) {
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
INT_TYPE c;
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct mapping * opts;
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args < 1) wrong_number_of_args_error("_sprintf",args,1);
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args > 2) wrong_number_of_args_error("_sprintf",args,2);
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if((TYPEOF(Pike_sp[0-args]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("_sprintf",1,"int");
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
c=Pike_sp[0-args].u.integer;
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if (args > 1 &&
    (TYPEOF(Pike_sp[1-args]) != PIKE_T_INT ||
     Pike_sp[1-args].u.integer)) {
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(TYPEOF(Pike_sp[1-args]) != PIKE_T_MAPPING) SIMPLE_ARG_TYPE_ERROR("_sprintf",2,"mapping(mixed:mixed)|void");
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
debug_malloc_pass(opts=Pike_sp[1-args].u.mapping);
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
} else opts = NULL;
#line 3354 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
    if (c != 'O') {
      push_undefined();
      return;
    }

    push_text("Pike.Annotations.Implements(%O)");
    if (THIS->api) {
      ref_push_program(THIS->api);
    } else {
      push_undefined();
    }
    f_sprintf(2);
  }
}

#ifdef THIS_

#undef THIS
#define THIS THIS_

#endif /* THIS_ */
/*! @endclass
 */

/*! @class InheritedClass
 *!
 *! This is the class for the @[Inherited] annotation.
 */
#line 3376 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct program *InheritedClass_program = NULL;
PMOD_EXPORT struct object *Inherited_annotation = NULL;

#undef class_InheritedClass_defined
#define class_InheritedClass_defined
/*! @decl inherit Pike.Annotation
   */
  
#undef inherit_Annotation_InheritedClass_defined
#define inherit_Annotation_InheritedClass_defined
#line 3383 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int InheritedClass_Annotation_inh_num = -1;

#ifdef InheritedClass_Annotation_inh_offset_used
#line 3383 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int InheritedClass_Annotation_inh_offset = -1;

#endif /* InheritedClass_Annotation_inh_offset_used */

#ifdef InheritedClass_Annotation_inh_storage_offset_used
#line 3383 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int InheritedClass_Annotation_inh_storage_offset = -1;

#endif /* InheritedClass_Annotation_inh_storage_offset_used */

  #define f_InheritedClass_cq__sprintf_defined
DEFAULT_CMOD_STORAGE void f_InheritedClass_cq__sprintf(INT32 args) {
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
INT_TYPE c;
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct mapping * opts;
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args < 1) wrong_number_of_args_error("_sprintf",args,1);
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args > 2) wrong_number_of_args_error("_sprintf",args,2);
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if((TYPEOF(Pike_sp[0-args]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("_sprintf",1,"int");
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
c=Pike_sp[0-args].u.integer;
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if (args > 1 &&
    (TYPEOF(Pike_sp[1-args]) != PIKE_T_INT ||
     Pike_sp[1-args].u.integer)) {
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(TYPEOF(Pike_sp[1-args]) != PIKE_T_MAPPING) SIMPLE_ARG_TYPE_ERROR("_sprintf",2,"mapping(mixed:mixed)|void");
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
debug_malloc_pass(opts=Pike_sp[1-args].u.mapping);
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
} else opts = NULL;
#line 3390 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
    if (c != 'O') {
      push_undefined();
      return;
    }

    push_text("Pike.Annotations.Inherited");
  }
}

#ifdef THIS_

#undef THIS
#define THIS THIS_

#endif /* THIS_ */
/*! @endclass
 */

/*! @decl constant Inherited = InheritedClass()
 *!
 *! This @[Annotation] informs the compiler that any @[Annotation]
 *! marked with it is to be inherited. The default is that annotations
 *! on classes are not inherited.
 */

#undef extra_defined
#define extra_defined
/*! @class OverrideClass
 *!
 *! This is the class for the @[Override] annotation.
 */
#line 3423 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct program *OverrideClass_program = NULL;
PMOD_EXPORT struct object *Override_annotation = NULL;

#undef class_OverrideClass_defined
#define class_OverrideClass_defined
/*! @decl inherit Pike.Annotation
   */
  
#undef inherit_Annotation_OverrideClass_defined
#define inherit_Annotation_OverrideClass_defined
#line 3430 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int OverrideClass_Annotation_inh_num = -1;

#ifdef OverrideClass_Annotation_inh_offset_used
#line 3430 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int OverrideClass_Annotation_inh_offset = -1;

#endif /* OverrideClass_Annotation_inh_offset_used */

#ifdef OverrideClass_Annotation_inh_storage_offset_used
#line 3430 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int OverrideClass_Annotation_inh_storage_offset = -1;

#endif /* OverrideClass_Annotation_inh_storage_offset_used */
#define f_OverrideClass_end_pass_identifier_defined
DEFAULT_CMOD_STORAGE void f_OverrideClass_end_pass_identifier(INT32 args) {
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
INT_TYPE pass;
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct program * prog;
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
INT_TYPE ref;
struct object * compiler;
#line 3433 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
int compiler_inh_num;
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args != 4) wrong_number_of_args_error("end_pass_identifier",args,4);
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if((TYPEOF(Pike_sp[0-4]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("end_pass_identifier",1,"int");
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
pass=Pike_sp[0-4].u.integer;
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(!(prog=program_from_svalue(Pike_sp+1-4))) SIMPLE_ARG_TYPE_ERROR("end_pass_identifier",2,"program");
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if((TYPEOF(Pike_sp[2-4]) != PIKE_T_INT) || (Pike_sp[2-4].u.integer < 0)) SIMPLE_ARG_TYPE_ERROR("end_pass_identifier",3,"int(31bit)");
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
ref=Pike_sp[2-4].u.integer;
if(TYPEOF(Pike_sp[3-4]) != PIKE_T_OBJECT) SIMPLE_ARG_TYPE_ERROR("end_pass_identifier",4,"CompilerEnvironment_PikeCompiler");
#line 3433 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
debug_malloc_pass(compiler=Pike_sp[3-4].u.object);
#line 3433 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
compiler_inh_num = SUBTYPEOF(Pike_sp[3-4]);
{
    struct reference *ptr;
    struct identifier *id;
    struct pike_string *sym;
    int i;
    int found = -1;

    if (pass != COMPILER_PASS_LAST) return;

    if (!prog || (ref >= prog->num_identifier_references)) return;

    /* Make sure that we can reach ourselves later,
     * in case we need to generate an error.
     */
    ref_push_object(Pike_fp->current_object);

    add_ref(compiler);
    low_enter_compiler(compiler, compiler_inh_num);
    /* NB: low_enter_compiler() invalidates THIS! */

    ptr = prog->identifier_references + ref;

    id = ID_FROM_PTR(prog, ptr);

    sym = id->name;

    /* FIXME: Check that:
     *  * This is not a named lambda().
     *  * Get the symbol name and check that it exists
     *    in one of the parents (lookup ::symbol).
     *  * If the symbol is a variant check also
     *    that the type for previous definition also
     *    covers the new type.
     */
    for(i = 1; i < prog->num_inherits; i++) {
      struct inherit *inh = prog->inherits + i;
      struct reference *r;

      if (inh->inherit_level != 1) continue;

      found = find_shared_string_identifier(sym, inh->prog);
      if (found == -1) continue;
      r = inh->prog->identifier_references + found;
      /* NB: We're looking directly in the references in the
       *     inherited program, NOT in the references of the
       *     program being compiled. Thus the ID_PRIVATE.
       */
      if (r->id_flags & (ID_HIDDEN|ID_PRIVATE)) {
	found = -1;
	continue;
      }
      /* FIXME: Warn if symbol is ID_LOCAL/ID_INLINE? */
      break;
    }

    if (found == -1) {
      my_yyerror("@%O: Symbol ::%S not found.", Pike_sp-1, sym);
    }

    exit_compiler();

    push_undefined();
  }

  }
#define f_OverrideClass_cq__sprintf_defined
DEFAULT_CMOD_STORAGE void f_OverrideClass_cq__sprintf(INT32 args) {
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
INT_TYPE c;
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct mapping * opts;
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args < 1) wrong_number_of_args_error("_sprintf",args,1);
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args > 2) wrong_number_of_args_error("_sprintf",args,2);
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if((TYPEOF(Pike_sp[0-args]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("_sprintf",1,"int");
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
c=Pike_sp[0-args].u.integer;
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if (args > 1 &&
    (TYPEOF(Pike_sp[1-args]) != PIKE_T_INT ||
     Pike_sp[1-args].u.integer)) {
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(TYPEOF(Pike_sp[1-args]) != PIKE_T_MAPPING) SIMPLE_ARG_TYPE_ERROR("_sprintf",2,"mapping(mixed:mixed)|void");
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
debug_malloc_pass(opts=Pike_sp[1-args].u.mapping);
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
} else opts = NULL;
#line 3500 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
    if (c != 'O') {
      push_undefined();
      return;
    }

    push_text("Pike.Annotations.Override");
  }
}

#ifdef THIS_

#undef THIS
#define THIS THIS_

#endif /* THIS_ */
/*! @endclass
 */

/*! @decl constant Override = OverrideClass()
 *!
 *! This @[Annotation] informs the compiler that any symbol
 *! marked with it is expected to also have been inherited.
 */

#undef extra_defined_2
#define extra_defined_2
/*! @class AutoCodecClass
 *!
 *! This is the class that implements the @[AutoCodec] annotstion.
 */
#line 3527 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct program *AutoCodecClass_program = NULL;
struct object *AutoCodec_annotation = NULL;

#undef class_AutoCodecClass_defined
#define class_AutoCodecClass_defined
/*! @decl inherit Annotation
   */
  
#undef inherit_Annotation_AutoCodecClass_defined
#define inherit_Annotation_AutoCodecClass_defined
#line 3534 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int AutoCodecClass_Annotation_inh_num = -1;

#ifdef AutoCodecClass_Annotation_inh_offset_used
#line 3534 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int AutoCodecClass_Annotation_inh_offset = -1;

#endif /* AutoCodecClass_Annotation_inh_offset_used */

#ifdef AutoCodecClass_Annotation_inh_storage_offset_used
#line 3534 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
static int AutoCodecClass_Annotation_inh_storage_offset = -1;

#endif /* AutoCodecClass_Annotation_inh_storage_offset_used */
#define f_AutoCodecClass_end_pass_defined
DEFAULT_CMOD_STORAGE void f_AutoCodecClass_end_pass(INT32 args) {
#line 3536 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
INT_TYPE pass;
#line 3536 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
struct program * prog;
struct object * compiler;
#line 3537 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
int compiler_inh_num;
#line 3536 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(args != 3) wrong_number_of_args_error("end_pass",args,3);
#line 3536 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if((TYPEOF(Pike_sp[0-3]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("end_pass",1,"int");
#line 3536 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
pass=Pike_sp[0-3].u.integer;
#line 3536 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
if(!(prog=program_from_svalue(Pike_sp+1-3))) SIMPLE_ARG_TYPE_ERROR("end_pass",2,"program");
if(TYPEOF(Pike_sp[2-3]) != PIKE_T_OBJECT) SIMPLE_ARG_TYPE_ERROR("end_pass",3,"CompilerEnvironment_PikeCompiler");
#line 3537 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
debug_malloc_pass(compiler=Pike_sp[2-3].u.object);
#line 3537 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
compiler_inh_num = SUBTYPEOF(Pike_sp[2-3]);
{
    int e = Pike_compiler->num_create_args;
    struct pike_type *type = NULL;
    struct pike_type *save_return_type;
    node *n = NULL;
    struct pike_string *encode_string;
    MAKE_CONST_STRING(encode_string, "_encode");
    /* NB: We need to enter the compiler to call define_function() et al.
     *     Note also that low_enter_compiler() eats a ref to the object.
     */
    add_ref(compiler);
    low_enter_compiler(compiler, compiler_inh_num);

    if (!e) {
      push_finished_type(zero_type_string);
    } else {
      if (e < 0) {
	/* Varargs marker. */
	e = -e;
	push_finished_type(prog->identifiers[--e].type);
	pop_type_stack(PIKE_T_ARRAY);
	n = mknode(F_PUSH_ARRAY, mkidentifiernode(e), NULL);
      } else {
	push_finished_type(prog->identifiers[--e].type);
	n = mkidentifiernode(e);
      }
      while (e--) {
	push_finished_type(prog->identifiers[e].type);
	push_type(T_OR);
	n = mknode(F_ARG_LIST, mkidentifiernode(e), n);
      }
    }
    push_unlimited_array_type(PIKE_T_ARRAY);
    push_type(T_VOID);
    push_type(T_MANY);

    type = compiler_pop_type();

    save_return_type = Pike_compiler->compiler_frame->current_return_type;
    Pike_compiler->compiler_frame->current_return_type = type->cdr;

    n = mknode(F_RETURN, mkefuncallnode("aggregate", n), 0);

    define_function(encode_string, type, 0, IDENTIFIER_PIKE_FUNCTION, 0, 0);

    if (pass == COMPILER_PASS_LAST) {
      dooptcode(encode_string, n, type, 0);
    }

    Pike_compiler->compiler_frame->current_return_type = save_return_type;

    free_node(n);
    free_type(type);

    exit_compiler();
  }
}

#ifdef THIS_

#undef THIS
#define THIS THIS_

#endif /* THIS_ */
/*! @endclass
 */

/*! @decl constant AutoCodec = AutoCodecClass()
 *!
 *! This @[Annotation] causes the compiler to automatically
 *! add an implementation of @[_encode()] that returns
 *! an array with suitable arguments to @[lfun::create].
 *!
 *! @note
 *!   This annotation is only useful for classes that
 *!   use the implicit create()-syntax, or have a create()
 *!   that doesn't need any arguments.
 */

#undef extra_defined_3
#define extra_defined_3
/*! @endmodule
 */

/*! @endmodule
 */

#line 3621 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
void low_init_pike_compiler(void)
{
#ifdef PIKE_THREADS
  co_init(&Pike_compiler_cond);
#endif

  compile_compiler();
}


/*
 * Now that the compiler has been compiled,
 * we can use the usual cmod stuff.
 */

void init_pike_compiler(void)
{
  add_program_constant("CompilerEnvironment", compilation_env_program, 0);

#ifndef SUPPORT_COMPILER_HANDLERS
  ADD_INT_CONSTANT("__HAVE_COMPILER_NO_HANDLERS__", 1, 0);
#endif /* !SUPPORT_COMPILER_HANDLERS */

  
#ifdef module_strings_declared
module_strings[0] = 
  make_shared_binary_string("CompilerEnvironment_PikeCompiler",
                            CONSTANT_STRLEN("CompilerEnvironment_PikeCompiler"));
#endif

#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
{ int i=0;
#ifndef tObjImpl_COMPILERENVIRONMENT_PIKECOMPILER
# define tObjImpl_COMPILERENVIRONMENT_PIKECOMPILER "\3\0\177\0\0\t"
{
   struct program *tmp = resolve_program(module_strings[0] /* "CompilerEnvironment_PikeCompiler" */);
   if( tmp ) {
      ___cmod_ext_used[i].from = 9;
      ___cmod_ext_used[i].to = tmp->id;
      i++;
   }
}
#endif /* tObjImpl_COMPILERENVIRONMENT_PIKECOMPILER */
}
set_program_id_to_id( ___cmod_map_program_ids );

#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */

#ifdef class_null_defined

#ifdef PROG_NULL_ID
#line 3222 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  START_NEW_PROGRAM_ID(NULL);
#else
#line 3222 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  start_new_program();

#endif /* PROG_NULL_ID */
#line 3222 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  null_program = Pike_compiler->new_program;

#ifndef tObjImpl_NULL

#undef tObjIs_NULL
#define tObjIs_NULL "\3\1\177\0\0\2"

#undef tObjImpl_NULL
#define tObjImpl_NULL "\3\0\177\0\0\2"

#endif /* tObjImpl_NULL */
#line 3222 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  null_program=end_program();
#line 3222 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#ifdef null_program_fun_num_used
null_program_fun_num=
#endif
 add_program_constant("null",null_program,0);

#endif /* class_null_defined */

#ifdef class_placeholder_defined

#ifdef PROG_PLACEHOLDER_ID
  START_NEW_PROGRAM_ID(PLACEHOLDER);
#else
#line 3232 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  start_new_program();

#endif /* PROG_PLACEHOLDER_ID */
#line 3232 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  placeholder_program = Pike_compiler->new_program;

#ifndef tObjImpl_PLACEHOLDER

#undef tObjIs_PLACEHOLDER
#define tObjIs_PLACEHOLDER "\3\1\177\0\0\3"

#undef tObjImpl_PLACEHOLDER
#define tObjImpl_PLACEHOLDER "\3\0\177\0\0\3"

#endif /* tObjImpl_PLACEHOLDER */

#ifdef f_placeholder_cq__backtick_28_29_defined

#ifdef f_placeholder_cq__backtick_28_29_fun_num_used
  f_placeholder_cq__backtick_28_29_fun_num =
#endif /* f_placeholder_cq__backtick_28_29_fun_num_used */
#line 3234 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("`()", f_placeholder_cq__backtick_28_29, tFuncV(tNone,tMix,tObj), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_placeholder_cq__backtick_28_29_defined */

#ifdef f_placeholder_cq__backtick_5B_5D_defined

#ifdef f_placeholder_cq__backtick_5B_5D_fun_num_used
  f_placeholder_cq__backtick_5B_5D_fun_num =
#endif /* f_placeholder_cq__backtick_5B_5D_fun_num_used */
#line 3239 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("`[]", f_placeholder_cq__backtick_5B_5D, tFuncV(tNone,tMix,tObj), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_placeholder_cq__backtick_5B_5D_defined */

#ifdef f_placeholder_cq__sprintf_defined

#ifdef f_placeholder_cq__sprintf_fun_num_used
  f_placeholder_cq__sprintf_fun_num =
#endif /* f_placeholder_cq__sprintf_fun_num_used */
#line 3244 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("_sprintf", f_placeholder_cq__sprintf, tFunc("\10\200\0\0\0\177\377\377\377" tOr(tMapping,tVoid),tStr), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_placeholder_cq__sprintf_defined */
#line 3232 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  placeholder_program=end_program();
#line 3232 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#ifdef placeholder_program_fun_num_used
placeholder_program_fun_num=
#endif
 add_program_constant("placeholder",placeholder_program,0);

#endif /* class_placeholder_defined */

#ifdef class_Annotation_defined

#ifdef PROG_ANNOTATION_ID
#line 3271 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  START_NEW_PROGRAM_ID(ANNOTATION);
#else
#line 3271 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  start_new_program();

#endif /* PROG_ANNOTATION_ID */
#line 3271 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Annotation_program = Pike_compiler->new_program;

#ifndef tObjImpl_ANNOTATION

#undef tObjIs_ANNOTATION
#define tObjIs_ANNOTATION "\3\1\177\0\0\4"

#undef tObjImpl_ANNOTATION
#define tObjImpl_ANNOTATION "\3\0\177\0\0\4"

#endif /* tObjImpl_ANNOTATION */

#ifdef f_Annotation_end_pass_defined

#ifdef f_Annotation_end_pass_fun_num_used
  f_Annotation_end_pass_fun_num =
#endif /* f_Annotation_end_pass_fun_num_used */
    ADD_FUNCTION2("end_pass", NULL, tFunc("\10\200\0\0\0\177\377\377\377" tPrg(tObj) tName("CompilerEnvironment_PikeCompiler", tObjImpl_COMPILERENVIRONMENT_PIKECOMPILER),tVoid), ID_OPTIONAL, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Annotation_end_pass_defined */
#line 3272 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Pike_compiler->new_program->flags |= PROGRAM_CONSTANT;
#line 3271 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Annotation_program=end_program();
#line 3271 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#ifdef Annotation_program_fun_num_used
Annotation_program_fun_num=
#endif
 add_program_constant("Annotation",Annotation_program,0);

#endif /* class_Annotation_defined */

#ifdef class_Implements_defined

#ifdef PROG_IMPLEMENTS_ID
#line 3306 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  START_NEW_PROGRAM_ID(IMPLEMENTS);
#else
#line 3306 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  start_new_program();

#endif /* PROG_IMPLEMENTS_ID */
#line 3306 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Implements_program = Pike_compiler->new_program;

#ifndef tObjImpl_IMPLEMENTS

#undef tObjIs_IMPLEMENTS
#define tObjIs_IMPLEMENTS "\3\1\177\0\0\5"

#undef tObjImpl_IMPLEMENTS
#define tObjImpl_IMPLEMENTS "\3\0\177\0\0\5"

#endif /* tObjImpl_IMPLEMENTS */

#ifdef THIS_IMPLEMENTS
  Implements_storage_offset = ADD_STORAGE(struct Implements_struct);
#endif /* THIS_IMPLEMENTS */

#ifdef inherit_Annotation_Implements_defined
#line 3311 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Implements_Annotation_inh_num = Pike_compiler->new_program->num_inherits;
#line 3311 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  low_inherit(Annotation_program, NULL, -1, 0, 0, NULL);

#ifdef Implements_Annotation_inh_offset_used
#line 3311 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Implements_Annotation_inh_offset = Pike_compiler->new_program->inherits[Implements_Annotation_inh_num].identifier_level;

#endif /* Implements_Annotation_inh_offset_used */

#ifdef Implements_Annotation_inh_storage_offset_used
#line 3311 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Implements_Annotation_inh_storage_offset = Pike_compiler->new_program->inherits[Implements_Annotation_inh_num].storage_offset;

#endif /* Implements_Annotation_inh_storage_offset_used */

#endif /* inherit_Annotation_Implements_defined */

#ifdef var_api_Implements_defined
#line 3313 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  PIKE_MAP_VARIABLE("api", Implements_storage_offset + OFFSETOF(Implements_struct, api),
                    tPrg(tObj), PIKE_T_PROGRAM, ID_STATIC);
#endif /* var_api_Implements_defined */

#ifdef f_Implements_create_defined

#ifdef f_Implements_create_fun_num_used
  f_Implements_create_fun_num =
#endif /* f_Implements_create_fun_num_used */
#line 3315 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("create", f_Implements_create, tFunc(tPrg(tObj),tVoid), ID_PROTECTED, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Implements_create_defined */

#ifdef f_Implements_end_pass_defined

#ifdef f_Implements_end_pass_fun_num_used
  f_Implements_end_pass_fun_num =
#endif /* f_Implements_end_pass_fun_num_used */
#line 3322 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("end_pass", f_Implements_end_pass, tFunc("\10\200\0\0\0\177\377\377\377" tPrg(tObj) tName("CompilerEnvironment_PikeCompiler", tObjImpl_COMPILERENVIRONMENT_PIKECOMPILER),tVoid), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Implements_end_pass_defined */

#ifdef f_Implements_cq__sprintf_defined

#ifdef f_Implements_cq__sprintf_fun_num_used
  f_Implements_cq__sprintf_fun_num =
#endif /* f_Implements_cq__sprintf_fun_num_used */
#line 3352 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("_sprintf", f_Implements_cq__sprintf, tFunc("\10\200\0\0\0\177\377\377\377" tOr(tMapping,tVoid),tStr), ID_PROTECTED, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Implements_cq__sprintf_defined */
#line 3307 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Pike_compiler->new_program->flags |= PROGRAM_CONSTANT;
#line 3306 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Implements_program=end_program();
#line 3306 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#ifdef Implements_program_fun_num_used
Implements_program_fun_num=
#endif
 add_program_constant("Implements",Implements_program,0);

#endif /* class_Implements_defined */

#ifdef class_InheritedClass_defined

#ifdef PROG_INHERITEDCLASS_ID
#line 3378 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  START_NEW_PROGRAM_ID(INHERITEDCLASS);
#else
#line 3378 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  start_new_program();

#endif /* PROG_INHERITEDCLASS_ID */
#line 3378 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  InheritedClass_program = Pike_compiler->new_program;

#ifndef tObjImpl_INHERITEDCLASS

#undef tObjIs_INHERITEDCLASS
#define tObjIs_INHERITEDCLASS "\3\1\177\0\0\6"

#undef tObjImpl_INHERITEDCLASS
#define tObjImpl_INHERITEDCLASS "\3\0\177\0\0\6"

#endif /* tObjImpl_INHERITEDCLASS */

#ifdef inherit_Annotation_InheritedClass_defined
#line 3383 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  InheritedClass_Annotation_inh_num = Pike_compiler->new_program->num_inherits;
#line 3383 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  low_inherit(Annotation_program, NULL, -1, 0, 0, NULL);

#ifdef InheritedClass_Annotation_inh_offset_used
#line 3383 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  InheritedClass_Annotation_inh_offset = Pike_compiler->new_program->inherits[InheritedClass_Annotation_inh_num].identifier_level;

#endif /* InheritedClass_Annotation_inh_offset_used */

#ifdef InheritedClass_Annotation_inh_storage_offset_used
#line 3383 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  InheritedClass_Annotation_inh_storage_offset = Pike_compiler->new_program->inherits[InheritedClass_Annotation_inh_num].storage_offset;

#endif /* InheritedClass_Annotation_inh_storage_offset_used */

#endif /* inherit_Annotation_InheritedClass_defined */

#ifdef f_InheritedClass_cq__sprintf_defined

#ifdef f_InheritedClass_cq__sprintf_fun_num_used
  f_InheritedClass_cq__sprintf_fun_num =
#endif /* f_InheritedClass_cq__sprintf_fun_num_used */
#line 3388 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("_sprintf", f_InheritedClass_cq__sprintf, tFunc("\10\200\0\0\0\177\377\377\377" tOr(tMapping,tVoid),tStr), ID_PROTECTED, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_InheritedClass_cq__sprintf_defined */
#line 3379 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Pike_compiler->new_program->flags |= PROGRAM_CONSTANT|PROGRAM_NO_EXPLICIT_DESTRUCT;
#line 3378 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  InheritedClass_program=end_program();
#line 3378 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#ifdef InheritedClass_program_fun_num_used
InheritedClass_program_fun_num=
#endif
 add_program_constant("InheritedClass",InheritedClass_program,0);

#endif /* class_InheritedClass_defined */

#ifdef extra_defined
#line 3409 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
  Inherited_annotation = clone_object(InheritedClass_program, 0);
  add_object_constant("Inherited", Inherited_annotation, 0);
  assert(!InheritedClass_program->inherits[0].annotations);
  ref_push_object(Inherited_annotation);
  f_aggregate_multiset(1);
  InheritedClass_program->inherits[0].annotations = Pike_sp[-1].u.multiset;
  Pike_sp--;
}


#endif /* extra_defined */

#ifdef class_OverrideClass_defined

#ifdef PROG_OVERRIDECLASS_ID
  START_NEW_PROGRAM_ID(OVERRIDECLASS);
#else
#line 3425 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  start_new_program();

#endif /* PROG_OVERRIDECLASS_ID */
#line 3425 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  OverrideClass_program = Pike_compiler->new_program;

#ifndef tObjImpl_OVERRIDECLASS

#undef tObjIs_OVERRIDECLASS
#define tObjIs_OVERRIDECLASS "\3\1\177\0\0\a"

#undef tObjImpl_OVERRIDECLASS
#define tObjImpl_OVERRIDECLASS "\3\0\177\0\0\a"

#endif /* tObjImpl_OVERRIDECLASS */

#ifdef inherit_Annotation_OverrideClass_defined
#line 3430 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  OverrideClass_Annotation_inh_num = Pike_compiler->new_program->num_inherits;
#line 3430 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  low_inherit(Annotation_program, NULL, -1, 0, 0, NULL);

#ifdef OverrideClass_Annotation_inh_offset_used
#line 3430 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  OverrideClass_Annotation_inh_offset = Pike_compiler->new_program->inherits[OverrideClass_Annotation_inh_num].identifier_level;

#endif /* OverrideClass_Annotation_inh_offset_used */

#ifdef OverrideClass_Annotation_inh_storage_offset_used
#line 3430 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  OverrideClass_Annotation_inh_storage_offset = Pike_compiler->new_program->inherits[OverrideClass_Annotation_inh_num].storage_offset;

#endif /* OverrideClass_Annotation_inh_storage_offset_used */

#endif /* inherit_Annotation_OverrideClass_defined */

#ifdef f_OverrideClass_end_pass_identifier_defined

#ifdef f_OverrideClass_end_pass_identifier_fun_num_used
  f_OverrideClass_end_pass_identifier_fun_num =
#endif /* f_OverrideClass_end_pass_identifier_fun_num_used */
#line 3432 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("end_pass_identifier", f_OverrideClass_end_pass_identifier, tFunc("\10\200\0\0\0\177\377\377\377" tPrg(tObj) "\10\0\0\0\0\177\377\377\377" tName("CompilerEnvironment_PikeCompiler", tObjImpl_COMPILERENVIRONMENT_PIKECOMPILER),tVoid), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_OverrideClass_end_pass_identifier_defined */

#ifdef f_OverrideClass_cq__sprintf_defined

#ifdef f_OverrideClass_cq__sprintf_fun_num_used
  f_OverrideClass_cq__sprintf_fun_num =
#endif /* f_OverrideClass_cq__sprintf_fun_num_used */
#line 3498 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("_sprintf", f_OverrideClass_cq__sprintf, tFunc("\10\200\0\0\0\177\377\377\377" tOr(tMapping,tVoid),tStr), ID_PROTECTED, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_OverrideClass_cq__sprintf_defined */
#line 3426 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Pike_compiler->new_program->flags |= PROGRAM_CONSTANT|PROGRAM_NO_EXPLICIT_DESTRUCT;
#line 3425 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  OverrideClass_program=end_program();
#line 3425 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#ifdef OverrideClass_program_fun_num_used
OverrideClass_program_fun_num=
#endif
 add_program_constant("OverrideClass",OverrideClass_program,0);

#endif /* class_OverrideClass_defined */

#ifdef extra_defined_2
#line 3518 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
  Override_annotation = clone_object(OverrideClass_program, 0);
  add_object_constant("Override", Override_annotation, 0);
}


#endif /* extra_defined_2 */

#ifdef class_AutoCodecClass_defined

#ifdef PROG_AUTOCODECCLASS_ID
  START_NEW_PROGRAM_ID(AUTOCODECCLASS);
#else
#line 3529 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  start_new_program();

#endif /* PROG_AUTOCODECCLASS_ID */
#line 3529 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  AutoCodecClass_program = Pike_compiler->new_program;

#ifndef tObjImpl_AUTOCODECCLASS

#undef tObjIs_AUTOCODECCLASS
#define tObjIs_AUTOCODECCLASS "\3\1\177\0\0\b"

#undef tObjImpl_AUTOCODECCLASS
#define tObjImpl_AUTOCODECCLASS "\3\0\177\0\0\b"

#endif /* tObjImpl_AUTOCODECCLASS */

#ifdef inherit_Annotation_AutoCodecClass_defined
#line 3534 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  AutoCodecClass_Annotation_inh_num = Pike_compiler->new_program->num_inherits;
#line 3534 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  low_inherit(Annotation_program, NULL, -1, 0, 0, NULL);

#ifdef AutoCodecClass_Annotation_inh_offset_used
#line 3534 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  AutoCodecClass_Annotation_inh_offset = Pike_compiler->new_program->inherits[AutoCodecClass_Annotation_inh_num].identifier_level;

#endif /* AutoCodecClass_Annotation_inh_offset_used */

#ifdef AutoCodecClass_Annotation_inh_storage_offset_used
#line 3534 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  AutoCodecClass_Annotation_inh_storage_offset = Pike_compiler->new_program->inherits[AutoCodecClass_Annotation_inh_num].storage_offset;

#endif /* AutoCodecClass_Annotation_inh_storage_offset_used */

#endif /* inherit_Annotation_AutoCodecClass_defined */

#ifdef f_AutoCodecClass_end_pass_defined

#ifdef f_AutoCodecClass_end_pass_fun_num_used
  f_AutoCodecClass_end_pass_fun_num =
#endif /* f_AutoCodecClass_end_pass_fun_num_used */
#line 3536 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    ADD_FUNCTION2("end_pass", f_AutoCodecClass_end_pass, tFunc("\10\200\0\0\0\177\377\377\377" tPrg(tObj) tName("CompilerEnvironment_PikeCompiler", tObjImpl_COMPILERENVIRONMENT_PIKECOMPILER),tVoid), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_AutoCodecClass_end_pass_defined */
#line 3530 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  Pike_compiler->new_program->flags |= PROGRAM_CONSTANT|PROGRAM_NO_EXPLICIT_DESTRUCT;
#line 3529 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
  AutoCodecClass_program=end_program();
#line 3529 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
#ifdef AutoCodecClass_program_fun_num_used
AutoCodecClass_program_fun_num=
#endif
 add_program_constant("AutoCodecClass",AutoCodecClass_program,0);

#endif /* class_AutoCodecClass_defined */

#ifdef extra_defined_3
#line 3610 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
{
  AutoCodec_annotation = clone_object(AutoCodecClass_program, 0);
  add_object_constant("AutoCodec", AutoCodec_annotation, 0);
}


#endif /* extra_defined_3 */

#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
set_program_id_to_id( 0 );
#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */
#line 3644 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
;

  {
    struct svalue s;
    SET_SVAL(s, T_PROGRAM, 0, program, null_program);
    low_add_constant("__null_program", &s);
  }

  /*! @decl constant __placeholder_object
   *!
   *! Object used internally by the compiler.
   *!
   *! @seealso
   *!   @[__null_program]
   */
  {
    struct svalue s;
    placeholder_object = fast_clone_object(placeholder_program);

    SET_SVAL(s, T_OBJECT, 0, object, placeholder_object);
    low_add_constant("__placeholder_object", &s);
  }

  {
    struct pike_string *attr;
    struct svalue s;
    MAKE_CONST_STRING(attr, "utf8_string");
    SET_SVAL(s, T_TYPE, 0, type, utf8_type_string);
    low_add_efun(attr, &s);
  }
}

void cleanup_pike_compiler(void)
{
  if (Override_annotation) {
    free_object(Override_annotation);
    Override_annotation = NULL;
  }
  if (AutoCodec_annotation) {
    free_object(AutoCodec_annotation);
    AutoCodec_annotation = NULL;
  }
  if (Inherited_annotation) {
    /* Break the circularity. */
    do_free_multiset(InheritedClass_program->inherits[0].annotations);
    InheritedClass_program->inherits[0].annotations = NULL;
    free_object(Inherited_annotation);
    Inherited_annotation = NULL;
  }
  
#ifdef class_null_defined
  if(null_program) {
#line 3222 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    free_program(null_program);
    null_program=0;
  }

#endif /* class_null_defined */

#ifdef class_placeholder_defined
  if(placeholder_program) {
#line 3232 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    free_program(placeholder_program);
    placeholder_program=0;
  }

#endif /* class_placeholder_defined */

#ifdef class_Annotation_defined
  if(Annotation_program) {
#line 3271 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    free_program(Annotation_program);
    Annotation_program=0;
  }

#endif /* class_Annotation_defined */

#ifdef class_Implements_defined
  if(Implements_program) {
#line 3306 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    free_program(Implements_program);
    Implements_program=0;
  }

#endif /* class_Implements_defined */

#ifdef class_InheritedClass_defined
  if(InheritedClass_program) {
#line 3378 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    free_program(InheritedClass_program);
    InheritedClass_program=0;
  }

#endif /* class_InheritedClass_defined */

#ifdef class_OverrideClass_defined
  if(OverrideClass_program) {
#line 3425 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    free_program(OverrideClass_program);
    OverrideClass_program=0;
  }

#endif /* class_OverrideClass_defined */

#ifdef class_AutoCodecClass_defined
  if(AutoCodecClass_program) {
#line 3529 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
    free_program(AutoCodecClass_program);
    AutoCodecClass_program=0;
  }

#endif /* class_AutoCodecClass_defined */

#ifdef module_strings_declared
{
  int i;
  for(i=0; i < 1; i++) {
    if (module_strings[i]) free_string(module_strings[i]);
    module_strings[i] = NULL;
  }
}
#endif
#line 3693 "/Users/hww3/devel/pike/src/pike_compiler.cmod"
;
}

void low_cleanup_pike_compiler(void)
{
  if (compilation_program) {
    free_program(compilation_program);
    compilation_program = 0;
  }
  if (compilation_environment) {
    free_object(compilation_environment);
    compilation_environment = 0;
  }
  if (compilation_env_program) {
    free_program(compilation_env_program);
    compilation_env_program = 0;
  }
  if (reporter_program) {
    free_program(reporter_program);
    reporter_program = 0;
  }

#ifdef PIKE_THREADS
  co_destroy(&Pike_compiler_cond);
#endif
}


#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
static int ___cmod_map_program_ids(int id)
{
  if( (id&0x7f000000) != 0x7f000000 ) return id;
  id = id&0x00ffffff;
  switch(id) {
#ifdef class_null_defined
  case 2:
    return null_program->id;
    break;
#endif
#ifdef class_placeholder_defined
  case 3:
    return placeholder_program->id;
    break;
#endif
#ifdef class_Annotation_defined
  case 4:
    return Annotation_program->id;
    break;
#endif
#ifdef class_Implements_defined
  case 5:
    return Implements_program->id;
    break;
#endif
#ifdef class_InheritedClass_defined
  case 6:
    return InheritedClass_program->id;
    break;
#endif
#ifdef class_OverrideClass_defined
  case 7:
    return OverrideClass_program->id;
    break;
#endif
#ifdef class_AutoCodecClass_defined
  case 8:
    return AutoCodecClass_program->id;
    break;
#endif
  };

  {
    int i = 0;
    while(___cmod_ext_used[i].from ) {
      if( ___cmod_ext_used[i].from == id ) {
        return ___cmod_ext_used[i].to;
      }
      i++;
    }
  }
  return 0;
}
#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */
